All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
@ 2022-10-06  3:14 mikhail.kshevetskiy
  2022-10-06  3:14 ` [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided mikhail.kshevetskiy
                   ` (5 more replies)
  0 siblings, 6 replies; 19+ messages in thread
From: mikhail.kshevetskiy @ 2022-10-06  3:14 UTC (permalink / raw)
  To: u-boot
  Cc: Dario Binacchi, Michael Trimarchi, Stefan Roese,
	mikhail.kshevetskiy, agnau

From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>

In the description of struct mtd_ooblayout_ops we see:

 * @free: function returning a free region in the OOB area.
 *	  Should return -ERANGE if %section exceeds the total number of
 *	  free sections.

but corresponding field of the structure named as 'rfree'. This is
wrong. Fix it the asme way as was done previously in linux kernel.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
 drivers/mtd/mtdcore.c                | 4 ++--
 drivers/mtd/nand/raw/denali.c        | 2 +-
 drivers/mtd/nand/raw/octeontx_nand.c | 2 +-
 drivers/mtd/nand/raw/rockchip_nfc.c  | 2 +-
 drivers/mtd/nand/spi/core.c          | 2 +-
 drivers/mtd/nand/spi/gigadevice.c    | 2 +-
 drivers/mtd/nand/spi/macronix.c      | 2 +-
 drivers/mtd/nand/spi/micron.c        | 2 +-
 drivers/mtd/nand/spi/toshiba.c       | 2 +-
 drivers/mtd/nand/spi/winbond.c       | 2 +-
 include/linux/mtd/mtd.h              | 4 ++--
 11 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index aa78d41a55..df8f3b8284 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1208,10 +1208,10 @@ int mtd_ooblayout_free(struct mtd_info *mtd, int section,
 	if (!mtd || section < 0)
 		return -EINVAL;
 
-	if (!mtd->ooblayout || !mtd->ooblayout->rfree)
+	if (!mtd->ooblayout || !mtd->ooblayout->free)
 		return -ENOTSUPP;
 
-	return mtd->ooblayout->rfree(mtd, section, oobfree);
+	return mtd->ooblayout->free(mtd, section, oobfree);
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
 
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index c827f80281..ed24b84d82 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1166,7 +1166,7 @@ static int denali_ooblayout_free(struct mtd_info *mtd, int section,
 
 static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
 	.ecc = denali_ooblayout_ecc,
-	.rfree = denali_ooblayout_free,
+	.free = denali_ooblayout_free,
 };
 
 static int denali_multidev_fixup(struct denali_nand_info *denali)
diff --git a/drivers/mtd/nand/raw/octeontx_nand.c b/drivers/mtd/nand/raw/octeontx_nand.c
index b338b204f3..4023bbcec6 100644
--- a/drivers/mtd/nand/raw/octeontx_nand.c
+++ b/drivers/mtd/nand/raw/octeontx_nand.c
@@ -435,7 +435,7 @@ static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
 
 static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
 	.ecc = nand_ooblayout_ecc_lp,
-	.rfree = nand_ooblayout_free_lp,
+	.free = nand_ooblayout_free_lp,
 };
 
 static inline struct octeontx_nand_chip *to_otx_nand(struct nand_chip *nand)
diff --git a/drivers/mtd/nand/raw/rockchip_nfc.c b/drivers/mtd/nand/raw/rockchip_nfc.c
index d016d25575..1ab429f430 100644
--- a/drivers/mtd/nand/raw/rockchip_nfc.c
+++ b/drivers/mtd/nand/raw/rockchip_nfc.c
@@ -849,7 +849,7 @@ static int rk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
 }
 
 static const struct mtd_ooblayout_ops rk_nfc_ooblayout_ops = {
-	.rfree = rk_nfc_ooblayout_free,
+	.free = rk_nfc_ooblayout_free,
 	.ecc = rk_nfc_ooblayout_ecc,
 };
 
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 134bf22c80..4edb7ae952 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1021,7 +1021,7 @@ static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
 
 static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
 	.ecc = spinand_noecc_ooblayout_ecc,
-	.rfree = spinand_noecc_ooblayout_free,
+	.free = spinand_noecc_ooblayout_free,
 };
 
 static int spinand_init(struct spinand_device *spinand)
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index a2c93486f4..25d9f80d26 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -154,7 +154,7 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
 
 static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
 	.ecc = gd5fxgqxxexxg_ooblayout_ecc,
-	.rfree = gd5fxgqxxexxg_ooblayout_free,
+	.free = gd5fxgqxxexxg_ooblayout_free,
 };
 
 static const struct spinand_info gigadevice_spinand_table[] = {
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 6d643a8000..6a1d6a1793 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -51,7 +51,7 @@ static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
 
 static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
 	.ecc = mx35lfxge4ab_ooblayout_ecc,
-	.rfree = mx35lfxge4ab_ooblayout_free,
+	.free = mx35lfxge4ab_ooblayout_free,
 };
 
 static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index 6bacf14aaf..3f5848aacd 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -75,7 +75,7 @@ static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
 
 static const struct mtd_ooblayout_ops micron_8_ooblayout = {
 	.ecc = micron_8_ooblayout_ecc,
-	.rfree = micron_8_ooblayout_free,
+	.free = micron_8_ooblayout_free,
 };
 
 static int micron_select_target(struct spinand_device *spinand,
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index c2cd3b426b..2a7b201bb1 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -68,7 +68,7 @@ static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,
 
 static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = {
 	.ecc = tx58cxgxsxraix_ooblayout_ecc,
-	.rfree = tx58cxgxsxraix_ooblayout_free,
+	.free = tx58cxgxsxraix_ooblayout_free,
 };
 
 static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index c119486efb..119fa135b1 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -61,7 +61,7 @@ static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
 
 static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
 	.ecc = w25m02gv_ooblayout_ecc,
-	.rfree = w25m02gv_ooblayout_free,
+	.free = w25m02gv_ooblayout_free,
 };
 
 static int w25m02gv_select_target(struct spinand_device *spinand,
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index ff635bd716..03ccf28b06 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -129,8 +129,8 @@ struct mtd_oob_region {
 struct mtd_ooblayout_ops {
 	int (*ecc)(struct mtd_info *mtd, int section,
 		   struct mtd_oob_region *oobecc);
-	int (*rfree)(struct mtd_info *mtd, int section,
-		     struct mtd_oob_region *oobfree);
+	int (*free)(struct mtd_info *mtd, int section,
+		    struct mtd_oob_region *oobfree);
 };
 
 /*
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided
  2022-10-06  3:14 [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description mikhail.kshevetskiy
@ 2022-10-06  3:14 ` mikhail.kshevetskiy
  2022-10-06  6:56   ` Michael Nazzareno Trimarchi
  2022-10-06  3:14 ` [PATCH 3/7] mtd/spinand: rework detect procedure for different READ_ID operation mikhail.kshevetskiy
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: mikhail.kshevetskiy @ 2022-10-06  3:14 UTC (permalink / raw)
  To: u-boot
  Cc: Dario Binacchi, Michael Trimarchi, Stefan Roese,
	mikhail.kshevetskiy, agnau

From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>

'mtd erase' command should not erase bad blocks. To force bad block erasing
there is 'mtd erase.dontskipbad' command (this command sets 'scrub' flag
to true in the erase_info structure). Unfortunately nand layer ignore
scrub flag and try to erases bad blocks unconditionally. This is wrong.

Add checks to allow bad block erasing only if scrub flag is set.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
 drivers/mtd/nand/core.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
index 99c29670c7..a4fb7602c9 100644
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -174,7 +174,10 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
 	nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last);
 	while (nanddev_pos_cmp(&pos, &last) <= 0) {
 		schedule();
-		ret = nanddev_erase(nand, &pos);
+		if (!einfo->scrub && nanddev_isbad(nand, &pos))
+			ret = -EIO;
+		else
+			ret = nanddev_erase(nand, &pos);
 		if (ret) {
 			einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/7] mtd/spinand: rework detect procedure for different READ_ID operation
  2022-10-06  3:14 [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description mikhail.kshevetskiy
  2022-10-06  3:14 ` [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided mikhail.kshevetskiy
@ 2022-10-06  3:14 ` mikhail.kshevetskiy
  2022-10-06  3:14 ` [PATCH 4/7] mtd/spinand: sync core spinand code with linux-5.10.118 mikhail.kshevetskiy
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: mikhail.kshevetskiy @ 2022-10-06  3:14 UTC (permalink / raw)
  To: u-boot
  Cc: Dario Binacchi, Michael Trimarchi, Stefan Roese,
	mikhail.kshevetskiy, agnau

From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>

Currently there are 3 different variants of read_id implementation:
1. opcode only. Found in GD5FxGQ4xF.
2. opcode + 1 addr byte. Found in GD5GxGQ4xA/E
3. opcode + 1 dummy byte. Found in other currently supported chips.

Original implementation was for variant 1 and let detect function
of chips with variant 2 and 3 to ignore the first byte. This isn't
robust:

1. For chips of variant 2, if SPI master doesn't keep MOSI low
during read, chip will get a random id offset, and the entire id
buffer will shift by that offset, causing detect failure.

2. For chips of variant 1, if it happens to get a devid that equals
to manufacture id of variant 2 or 3 chips, it'll get incorrectly
detected.

This patch reworks detect procedure to address problems above. New
logic do detection for all variants separatedly, in 1-2-3 order.
Since all current detect methods do exactly the same id matching
procedure, unify them into core.c and remove detect method from
manufacture_ops.

This is a rework of Chuanhong Guo <gch981213@gmail.com> patch
submitted to linux kernel

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
 drivers/mtd/nand/spi/core.c       | 104 +++++++++++++++++++-----------
 drivers/mtd/nand/spi/gigadevice.c |  30 ++-------
 drivers/mtd/nand/spi/macronix.c   |  45 +++++--------
 drivers/mtd/nand/spi/micron.c     |  50 ++++++--------
 drivers/mtd/nand/spi/toshiba.c    |  66 +++++++++----------
 drivers/mtd/nand/spi/winbond.c    |  34 ++--------
 include/linux/mtd/spinand.h       |  66 ++++++++++++-------
 7 files changed, 187 insertions(+), 208 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 4edb7ae952..e42c061049 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -17,6 +17,7 @@
 #include <linux/mtd/spinand.h>
 #include <linux/of.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi-mem.h>
 #else
@@ -451,9 +452,11 @@ out:
 	return status & STATUS_BUSY ? -ETIMEDOUT : 0;
 }
 
-static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
+static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
+			      u8 ndummy, u8 *buf)
 {
-	struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf,
+	struct spi_mem_op op = SPINAND_READID_OP(naddr, ndummy,
+						 spinand->scratchbuf,
 						 SPINAND_MAX_ID_LEN);
 	int ret;
 
@@ -807,21 +810,6 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs)
 	return ret;
 }
 
-const struct spi_mem_op *
-spinand_find_supported_op(struct spinand_device *spinand,
-			  const struct spi_mem_op *ops,
-			  unsigned int nops)
-{
-	unsigned int i;
-
-	for (i = 0; i < nops; i++) {
-		if (spi_mem_supports_op(spinand->slave, &ops[i]))
-			return &ops[i];
-	}
-
-	return NULL;
-}
-
 static const struct nand_ops spinand_ops = {
 	.erase = spinand_erase,
 	.markbad = spinand_markbad,
@@ -836,24 +824,62 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&winbond_spinand_manufacturer,
 };
 
-static int spinand_manufacturer_detect(struct spinand_device *spinand)
+static int spinand_manufacturer_match(struct spinand_device *spinand,
+				      enum spinand_readid_method rdid_method)
 {
+	u8 *id = spinand->id.data;
 	unsigned int i;
 	int ret;
 
 	for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) {
-		ret = spinand_manufacturers[i]->ops->detect(spinand);
-		if (ret > 0) {
-			spinand->manufacturer = spinand_manufacturers[i];
-			return 0;
-		} else if (ret < 0) {
-			return ret;
-		}
-	}
+		const struct spinand_manufacturer *manufacturer =
+			spinand_manufacturers[i];
 
+		if (id[0] != manufacturer->id)
+			continue;
+
+		ret = spinand_match_and_init(spinand,
+					     manufacturer->chips,
+					     manufacturer->nchips,
+					     rdid_method);
+		if (ret < 0)
+			continue;
+
+		spinand->manufacturer = manufacturer;
+		return 0;
+	}
 	return -ENOTSUPP;
 }
 
+static int spinand_id_detect(struct spinand_device *spinand)
+{
+	u8 *id = spinand->id.data;
+	int ret;
+
+	ret = spinand_read_id_op(spinand, 0, 0, id);
+	if (ret)
+		return ret;
+	ret = spinand_manufacturer_match(spinand, SPINAND_READID_METHOD_OPCODE);
+	if (!ret)
+		return 0;
+
+	ret = spinand_read_id_op(spinand, 1, 0, id);
+	if (ret)
+		return ret;
+	ret = spinand_manufacturer_match(spinand,
+					 SPINAND_READID_METHOD_OPCODE_ADDR);
+	if (!ret)
+		return 0;
+
+	ret = spinand_read_id_op(spinand, 0, 1, id);
+	if (ret)
+		return ret;
+	ret = spinand_manufacturer_match(spinand,
+					 SPINAND_READID_METHOD_OPCODE_DUMMY);
+
+	return ret;
+}
+
 static int spinand_manufacturer_init(struct spinand_device *spinand)
 {
 	if (spinand->manufacturer->ops->init)
@@ -909,9 +935,9 @@ spinand_select_op_variant(struct spinand_device *spinand,
  * @spinand: SPI NAND object
  * @table: SPI NAND device description table
  * @table_size: size of the device description table
+ * @rdid_method: read id method to match
  *
- * Should be used by SPI NAND manufacturer drivers when they want to find a
- * match between a device ID retrieved through the READ_ID command and an
+ * Match between a device ID retrieved through the READ_ID command and an
  * entry in the SPI NAND description table. If a match is found, the spinand
  * object will be initialized with information provided by the matching
  * spinand_info entry.
@@ -920,8 +946,10 @@ spinand_select_op_variant(struct spinand_device *spinand,
  */
 int spinand_match_and_init(struct spinand_device *spinand,
 			   const struct spinand_info *table,
-			   unsigned int table_size, u8 devid)
+			   unsigned int table_size,
+			   enum spinand_readid_method rdid_method)
 {
+	u8 *id = spinand->id.data;
 	struct nand_device *nand = spinand_to_nand(spinand);
 	unsigned int i;
 
@@ -929,13 +957,17 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		const struct spinand_info *info = &table[i];
 		const struct spi_mem_op *op;
 
-		if (devid != info->devid)
+		if (rdid_method != info->devid.method)
+			continue;
+
+		if (memcmp(id + 1, info->devid.id, info->devid.len))
 			continue;
 
 		nand->memorg = table[i].memorg;
 		nand->eccreq = table[i].eccreq;
 		spinand->eccinfo = table[i].eccinfo;
 		spinand->flags = table[i].flags;
+		spinand->id.len = 1 + table[i].devid.len;
 		spinand->select_target = table[i].select_target;
 
 		op = spinand_select_op_variant(spinand,
@@ -971,13 +1003,7 @@ static int spinand_detect(struct spinand_device *spinand)
 	if (ret)
 		return ret;
 
-	ret = spinand_read_id_op(spinand, spinand->id.data);
-	if (ret)
-		return ret;
-
-	spinand->id.len = SPINAND_MAX_ID_LEN;
-
-	ret = spinand_manufacturer_detect(spinand);
+	ret = spinand_id_detect(spinand);
 	if (ret) {
 		dev_err(spinand->slave->dev, "unknown raw ID %*phN\n",
 			SPINAND_MAX_ID_LEN, spinand->id.data);
@@ -1081,11 +1107,11 @@ static int spinand_init(struct spinand_device *spinand)
 	for (i = 0; i < nand->memorg.ntargets; i++) {
 		ret = spinand_select_target(spinand, i);
 		if (ret)
-			goto err_free_bufs;
+			goto err_manuf_cleanup;
 
 		ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
 		if (ret)
-			goto err_free_bufs;
+			goto err_manuf_cleanup;
 	}
 
 	ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index 25d9f80d26..370ffb765e 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -158,7 +158,8 @@ static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
 };
 
 static const struct spinand_info gigadevice_spinand_table[] = {
-	SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
+	SPINAND_INFO("GD5F1GQ4UExxG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&gd5fxgq4_read_cache_variants,
@@ -167,7 +168,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
 		     0,
 		     SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
 				     gd5fxgq4xexxg_ecc_get_status)),
-	SPINAND_INFO("GD5F1GQ5UExxG", 0x51,
+	SPINAND_INFO("GD5F1GQ5UExxG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
@@ -178,33 +180,13 @@ static const struct spinand_info gigadevice_spinand_table[] = {
 				     gd5fxgq5xexxg_ecc_get_status)),
 };
 
-static int gigadevice_spinand_detect(struct spinand_device *spinand)
-{
-	u8 *id = spinand->id.data;
-	int ret;
-
-	/*
-	 * For GD NANDs, There is an address byte needed to shift in before IDs
-	 * are read out, so the first byte in raw_id is dummy.
-	 */
-	if (id[1] != SPINAND_MFR_GIGADEVICE)
-		return 0;
-
-	ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
-				     ARRAY_SIZE(gigadevice_spinand_table),
-				     id[2]);
-	if (ret)
-		return ret;
-
-	return 1;
-}
-
 static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
-	.detect = gigadevice_spinand_detect,
 };
 
 const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
 	.id = SPINAND_MFR_GIGADEVICE,
 	.name = "GigaDevice",
+	.chips = gigadevice_spinand_table,
+	.nchips = ARRAY_SIZE(gigadevice_spinand_table),
 	.ops = &gigadevice_spinand_manuf_ops,
 };
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 6a1d6a1793..8c88883665 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -105,7 +105,8 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
 }
 
 static const struct spinand_info macronix_spinand_table[] = {
-	SPINAND_INFO("MX35LF1GE4AB", 0x12,
+	SPINAND_INFO("MX35LF1GE4AB",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -114,7 +115,8 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
-	SPINAND_INFO("MX35LF2GE4AB", 0x22,
+	SPINAND_INFO("MX35LF2GE4AB",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -122,7 +124,8 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
-	SPINAND_INFO("MX35UF4GE4AD", 0xb7,
+	SPINAND_INFO("MX35UF4GE4AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -131,7 +134,8 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
-	SPINAND_INFO("MX35UF2GE4AD", 0xa6,
+	SPINAND_INFO("MX35UF2GE4AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -140,7 +144,8 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
-	SPINAND_INFO("MX35UF2GE4AC", 0xa2,
+	SPINAND_INFO("MX35UF2GE4AC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -149,7 +154,8 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
-	SPINAND_INFO("MX35UF1GE4AD", 0x96,
+	SPINAND_INFO("MX35UF1GE4AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -158,7 +164,8 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
-	SPINAND_INFO("MX35UF1GE4AC", 0x92,
+	SPINAND_INFO("MX35UF1GE4AC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -170,33 +177,13 @@ static const struct spinand_info macronix_spinand_table[] = {
 
 };
 
-static int macronix_spinand_detect(struct spinand_device *spinand)
-{
-	u8 *id = spinand->id.data;
-	int ret;
-
-	/*
-	 * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
-	 * raw_id is garbage.
-	 */
-	if (id[1] != SPINAND_MFR_MACRONIX)
-		return 0;
-
-	ret = spinand_match_and_init(spinand, macronix_spinand_table,
-				     ARRAY_SIZE(macronix_spinand_table),
-				     id[2]);
-	if (ret)
-		return ret;
-
-	return 1;
-}
-
 static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
-	.detect = macronix_spinand_detect,
 };
 
 const struct spinand_manufacturer macronix_spinand_manufacturer = {
 	.id = SPINAND_MFR_MACRONIX,
 	.name = "Macronix",
+	.chips = macronix_spinand_table,
+	.nchips = ARRAY_SIZE(macronix_spinand_table),
 	.ops = &macronix_spinand_manuf_ops,
 };
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index 3f5848aacd..9e6cf35ea0 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -120,7 +120,8 @@ static int micron_8_ecc_get_status(struct spinand_device *spinand,
 
 static const struct spinand_info micron_spinand_table[] = {
 	/* M79A 2Gb 3.3V */
-	SPINAND_INFO("MT29F2G01ABAGD", 0x24,
+	SPINAND_INFO("MT29F2G01ABAGD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -130,7 +131,8 @@ static const struct spinand_info micron_spinand_table[] = {
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M79A 2Gb 1.8V */
-	SPINAND_INFO("MT29F2G01ABBGD", 0x25,
+	SPINAND_INFO("MT29F2G01ABBGD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -140,7 +142,8 @@ static const struct spinand_info micron_spinand_table[] = {
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M78A 1Gb 3.3V */
-	SPINAND_INFO("MT29F1G01ABAFD", 0x14,
+	SPINAND_INFO("MT29F1G01ABAFD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -150,7 +153,8 @@ static const struct spinand_info micron_spinand_table[] = {
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M78A 1Gb 1.8V */
-	SPINAND_INFO("MT29F1G01ABAFD", 0x15,
+	SPINAND_INFO("MT29F1G01ABAFD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -160,7 +164,8 @@ static const struct spinand_info micron_spinand_table[] = {
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M79A 4Gb 3.3V */
-	SPINAND_INFO("MT29F4G01ADAGD", 0x36,
+	SPINAND_INFO("MT29F4G01ADAGD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 2),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -171,7 +176,8 @@ static const struct spinand_info micron_spinand_table[] = {
 				     micron_8_ecc_get_status),
 		     SPINAND_SELECT_TARGET(micron_select_target)),
 	/* M70A 4Gb 3.3V */
-	SPINAND_INFO("MT29F4G01ABAFD", 0x34,
+	SPINAND_INFO("MT29F4G01ABAFD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -181,7 +187,8 @@ static const struct spinand_info micron_spinand_table[] = {
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M70A 4Gb 1.8V */
-	SPINAND_INFO("MT29F4G01ABBFD", 0x35,
+	SPINAND_INFO("MT29F4G01ABBFD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -191,7 +198,8 @@ static const struct spinand_info micron_spinand_table[] = {
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M70A 8Gb 3.3V */
-	SPINAND_INFO("MT29F8G01ADAFD", 0x46,
+	SPINAND_INFO("MT29F8G01ADAFD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -202,7 +210,8 @@ static const struct spinand_info micron_spinand_table[] = {
 				     micron_8_ecc_get_status),
 		     SPINAND_SELECT_TARGET(micron_select_target)),
 	/* M70A 8Gb 1.8V */
-	SPINAND_INFO("MT29F8G01ADBFD", 0x47,
+	SPINAND_INFO("MT29F8G01ADBFD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -214,26 +223,6 @@ static const struct spinand_info micron_spinand_table[] = {
 		     SPINAND_SELECT_TARGET(micron_select_target)),
 };
 
-static int micron_spinand_detect(struct spinand_device *spinand)
-{
-	u8 *id = spinand->id.data;
-	int ret;
-
-	/*
-	 * Micron SPI NAND read ID need a dummy byte,
-	 * so the first byte in raw_id is dummy.
-	 */
-	if (id[1] != SPINAND_MFR_MICRON)
-		return 0;
-
-	ret = spinand_match_and_init(spinand, micron_spinand_table,
-				     ARRAY_SIZE(micron_spinand_table), id[2]);
-	if (ret)
-		return ret;
-
-	return 1;
-}
-
 static int micron_spinand_init(struct spinand_device *spinand)
 {
 	/*
@@ -248,12 +237,13 @@ static int micron_spinand_init(struct spinand_device *spinand)
 }
 
 static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
-	.detect = micron_spinand_detect,
 	.init = micron_spinand_init,
 };
 
 const struct spinand_manufacturer micron_spinand_manufacturer = {
 	.id = SPINAND_MFR_MICRON,
 	.name = "Micron",
+	.chips = micron_spinand_table,
+	.nchips = ARRAY_SIZE(micron_spinand_table),
 	.ops = &micron_spinand_manuf_ops,
 };
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index 2a7b201bb1..872634f0fe 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -111,7 +111,8 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
 
 static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 1Gb (1st generation) */
-	SPINAND_INFO("TC58CVG0S3HRAIG", 0xC2,
+	SPINAND_INFO("TC58CVG0S3HRAIG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -121,7 +122,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 3.3V 2Gb (1st generation) */
-	SPINAND_INFO("TC58CVG1S3HRAIG", 0xCB,
+	SPINAND_INFO("TC58CVG1S3HRAIG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -131,7 +133,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 3.3V 4Gb (1st generation) */
-	SPINAND_INFO("TC58CVG2S0HRAIG", 0xCD,
+	SPINAND_INFO("TC58CVG2S0HRAIG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -141,7 +144,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 1.8V 1Gb (1st generation) */
-	SPINAND_INFO("TC58CYG0S3HRAIG", 0xB2,
+	SPINAND_INFO("TC58CYG0S3HRAIG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -151,7 +155,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 1.8V 2Gb (1st generation) */
-	SPINAND_INFO("TC58CYG1S3HRAIG", 0xBB,
+	SPINAND_INFO("TC58CYG1S3HRAIG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -161,7 +166,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 1.8V 4Gb (1st generation) */
-	SPINAND_INFO("TC58CYG2S0HRAIG", 0xBD,
+	SPINAND_INFO("TC58CYG2S0HRAIG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -176,7 +182,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	 * QE_BIT.
 	 */
 	/* 3.3V 1Gb (2nd generation) */
-	SPINAND_INFO("TC58CVG0S3HRAIJ", 0xE2,
+	SPINAND_INFO("TC58CVG0S3HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -186,7 +193,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 3.3V 2Gb (2nd generation) */
-	SPINAND_INFO("TC58CVG1S3HRAIJ", 0xEB,
+	SPINAND_INFO("TC58CVG1S3HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -196,7 +204,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 3.3V 4Gb (2nd generation) */
-	SPINAND_INFO("TC58CVG2S0HRAIJ", 0xED,
+	SPINAND_INFO("TC58CVG2S0HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -206,7 +215,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 3.3V 8Gb (2nd generation) */
-	SPINAND_INFO("TH58CVG3S0HRAIJ", 0xE4,
+	SPINAND_INFO("TH58CVG3S0HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
 		     NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -216,7 +226,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 1.8V 1Gb (2nd generation) */
-	SPINAND_INFO("TC58CYG0S3HRAIJ", 0xD2,
+	SPINAND_INFO("TC58CYG0S3HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),
 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -226,7 +237,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 1.8V 2Gb (2nd generation) */
-	SPINAND_INFO("TC58CYG1S3HRAIJ", 0xDB,
+	SPINAND_INFO("TC58CYG1S3HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),
 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -236,7 +248,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 1.8V 4Gb (2nd generation) */
-	SPINAND_INFO("TC58CYG2S0HRAIJ", 0xDD,
+	SPINAND_INFO("TC58CYG2S0HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),
 		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -246,7 +259,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
 		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
 				     tx58cxgxsxraix_ecc_get_status)),
 	/* 1.8V 8Gb (2nd generation) */
-	SPINAND_INFO("TH58CYG3S0HRAIJ", 0xD4,
+	SPINAND_INFO("TH58CYG3S0HRAIJ",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
 		     NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -257,33 +271,13 @@ static const struct spinand_info toshiba_spinand_table[] = {
 				     tx58cxgxsxraix_ecc_get_status)),
 };
 
-static int toshiba_spinand_detect(struct spinand_device *spinand)
-{
-	u8 *id = spinand->id.data;
-	int ret;
-
-	/*
-	 * Toshiba SPI NAND read ID needs a dummy byte,
-	 * so the first byte in id is garbage.
-	 */
-	if (id[1] != SPINAND_MFR_TOSHIBA)
-		return 0;
-
-	ret = spinand_match_and_init(spinand, toshiba_spinand_table,
-				     ARRAY_SIZE(toshiba_spinand_table),
-				     id[2]);
-	if (ret)
-		return ret;
-
-	return 1;
-}
-
 static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
-	.detect = toshiba_spinand_detect,
 };
 
 const struct spinand_manufacturer toshiba_spinand_manufacturer = {
 	.id = SPINAND_MFR_TOSHIBA,
 	.name = "Toshiba",
+	.chips = toshiba_spinand_table,
+	.nchips = ARRAY_SIZE(toshiba_spinand_table),
 	.ops = &toshiba_spinand_manuf_ops,
 };
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 119fa135b1..84469f7a89 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -79,7 +79,8 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
 }
 
 static const struct spinand_info winbond_spinand_table[] = {
-	SPINAND_INFO("W25M02GV", 0xAB,
+	SPINAND_INFO("W25M02GV",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
 		     NAND_ECCREQ(1, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -88,7 +89,8 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
-	SPINAND_INFO("W25N01GV", 0xAA,
+	SPINAND_INFO("W25N01GV",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
 		     NAND_ECCREQ(1, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -98,31 +100,6 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
 };
 
-/**
- * winbond_spinand_detect - initialize device related part in spinand_device
- * struct if it is a Winbond device.
- * @spinand: SPI NAND device structure
- */
-static int winbond_spinand_detect(struct spinand_device *spinand)
-{
-	u8 *id = spinand->id.data;
-	int ret;
-
-	/*
-	 * Winbond SPI NAND read ID need a dummy byte,
-	 * so the first byte in raw_id is dummy.
-	 */
-	if (id[1] != SPINAND_MFR_WINBOND)
-		return 0;
-
-	ret = spinand_match_and_init(spinand, winbond_spinand_table,
-				     ARRAY_SIZE(winbond_spinand_table), id[2]);
-	if (ret)
-		return ret;
-
-	return 1;
-}
-
 static int winbond_spinand_init(struct spinand_device *spinand)
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
@@ -142,12 +119,13 @@ static int winbond_spinand_init(struct spinand_device *spinand)
 }
 
 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
-	.detect = winbond_spinand_detect,
 	.init = winbond_spinand_init,
 };
 
 const struct spinand_manufacturer winbond_spinand_manufacturer = {
 	.id = SPINAND_MFR_WINBOND,
 	.name = "Winbond",
+	.chips = winbond_spinand_table,
+	.nchips = ARRAY_SIZE(winbond_spinand_table),
 	.ops = &winbond_spinand_manuf_ops,
 };
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 15bcd59f34..1ae4dc6b15 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -39,9 +39,9 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
-#define SPINAND_READID_OP(ndummy, buf, len)				\
+#define SPINAND_READID_OP(naddr, ndummy, buf, len)			\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),				\
-		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_ADDR(naddr, 0, 1),			\
 		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 1))
 
@@ -153,37 +153,46 @@ struct spinand_device;
  * @data: buffer containing the id bytes. Currently 4 bytes large, but can
  *	  be extended if required
  * @len: ID length
- *
- * struct_spinand_id->data contains all bytes returned after a READ_ID command,
- * including dummy bytes if the chip does not emit ID bytes right after the
- * READ_ID command. The responsibility to extract real ID bytes is left to
- * struct_manufacurer_ops->detect().
  */
 struct spinand_id {
 	u8 data[SPINAND_MAX_ID_LEN];
 	int len;
 };
 
+enum spinand_readid_method {
+	SPINAND_READID_METHOD_OPCODE,
+	SPINAND_READID_METHOD_OPCODE_ADDR,
+	SPINAND_READID_METHOD_OPCODE_DUMMY,
+};
+
+/**
+ * struct spinand_devid - SPI NAND device id structure
+ * @id: device id of current chip
+ * @len: number of bytes in device id
+ * @method: method to read chip id
+ *	    There are 3 possible variants:
+ *	    SPINAND_READID_METHOD_OPCODE: chip id is returned immediately
+ *	    after read_id opcode.
+ *	    SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after
+ *	    read_id opcode + 1-byte address.
+ *	    SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after
+ *	    read_id opcode + 1 dummy byte.
+ */
+struct spinand_devid {
+	const u8 *id;
+	const u8 len;
+	const enum spinand_readid_method method;
+};
+
 /**
  * struct manufacurer_ops - SPI NAND manufacturer specific operations
- * @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
- *	    the core calls the struct_manufacurer_ops->detect() hook of each
- *	    registered manufacturer until one of them return 1. Note that
- *	    the first thing to check in this hook is that the manufacturer ID
- *	    in struct_spinand_device->id matches the manufacturer whose
- *	    ->detect() hook has been called. Should return 1 if there's a
- *	    match, 0 if the manufacturer ID does not match and a negative
- *	    error code otherwise. When true is returned, the core assumes
- *	    that properties of the NAND chip (spinand->base.memorg and
- *	    spinand->base.eccreq) have been filled
  * @init: initialize a SPI NAND device
  * @cleanup: cleanup a SPI NAND device
  *
  * Each SPI NAND manufacturer driver should implement this interface so that
- * NAND chips coming from this vendor can be detected and initialized properly.
+ * NAND chips coming from this vendor can be initialized properly.
  */
 struct spinand_manufacturer_ops {
-	int (*detect)(struct spinand_device *spinand);
 	int (*init)(struct spinand_device *spinand);
 	void (*cleanup)(struct spinand_device *spinand);
 };
@@ -192,11 +201,16 @@ struct spinand_manufacturer_ops {
  * struct spinand_manufacturer - SPI NAND manufacturer instance
  * @id: manufacturer ID
  * @name: manufacturer name
+ * @devid_len: number of bytes in device ID
+ * @chips: supported SPI NANDs under current manufacturer
+ * @nchips: number of SPI NANDs available in chips array
  * @ops: manufacturer operations
  */
 struct spinand_manufacturer {
 	u8 id;
 	char *name;
+	const struct spinand_info *chips;
+	const size_t nchips;
 	const struct spinand_manufacturer_ops *ops;
 };
 
@@ -268,7 +282,7 @@ struct spinand_ecc_info {
  */
 struct spinand_info {
 	const char *model;
-	u8 devid;
+	struct spinand_devid devid;
 	u32 flags;
 	struct nand_memory_organization memorg;
 	struct nand_ecc_req eccreq;
@@ -282,6 +296,13 @@ struct spinand_info {
 			     unsigned int target);
 };
 
+#define SPINAND_ID(__method, ...)					\
+	{								\
+		.id = (const u8[]){ __VA_ARGS__ },			\
+		.len = sizeof((u8[]){ __VA_ARGS__ }),			\
+		.method = __method,					\
+	}
+
 #define SPINAND_INFO_OP_VARIANTS(__read, __write, __update)		\
 	{								\
 		.read_cache = __read,					\
@@ -440,9 +461,10 @@ static inline void spinand_set_ofnode(struct spinand_device *spinand,
 }
 #endif /* __UBOOT__ */
 
-int spinand_match_and_init(struct spinand_device *dev,
+int spinand_match_and_init(struct spinand_device *spinand,
 			   const struct spinand_info *table,
-			   unsigned int table_size, u8 devid);
+			   unsigned int table_size,
+			   enum spinand_readid_method rdid_method);
 
 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
 int spinand_select_target(struct spinand_device *spinand, unsigned int target);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 4/7] mtd/spinand: sync core spinand code with linux-5.10.118
  2022-10-06  3:14 [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description mikhail.kshevetskiy
  2022-10-06  3:14 ` [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided mikhail.kshevetskiy
  2022-10-06  3:14 ` [PATCH 3/7] mtd/spinand: rework detect procedure for different READ_ID operation mikhail.kshevetskiy
@ 2022-10-06  3:14 ` mikhail.kshevetskiy
  2022-10-06  3:15 ` [PATCH 5/7] mtd/spinand: sync supported devices with linux-5.15.43 mikhail.kshevetskiy
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: mikhail.kshevetskiy @ 2022-10-06  3:14 UTC (permalink / raw)
  To: u-boot
  Cc: Dario Binacchi, Michael Trimarchi, Stefan Roese,
	mikhail.kshevetskiy, agnau

From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
 drivers/mtd/nand/spi/core.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index e42c061049..d0c7d82010 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -326,6 +326,13 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
 	u16 column = 0;
 	int ret;
 
+	/*
+	 * Looks like PROGRAM LOAD (AKA write cache) does not necessarily reset
+	 * the cache content to 0xFF (depends on vendor implementation), so we
+	 * must fill the page cache entirely even if we only want to program
+	 * the data portion of the page, otherwise we might corrupt the BBM or
+	 * user data previously programmed in OOB area.
+	 */
 	memset(spinand->databuf, 0xff,
 	       nanddev_page_size(nand) +
 	       nanddev_per_page_oobsize(nand));
@@ -598,12 +605,12 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
 		if (ret == -EBADMSG) {
 			ecc_failed = true;
 			mtd->ecc_stats.failed++;
-			ret = 0;
 		} else {
 			mtd->ecc_stats.corrected += ret;
 			max_bitflips = max_t(unsigned int, max_bitflips, ret);
 		}
 
+		ret = 0;
 		ops->retlen += iter.req.datalen;
 		ops->oobretlen += iter.req.ooblen;
 	}
@@ -669,16 +676,9 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
 		.oobbuf.in = marker,
 		.mode = MTD_OPS_RAW,
 	};
-	int ret;
-
-	ret = spinand_select_target(spinand, pos->target);
-	if (ret)
-		return ret;
-
-	ret = spinand_read_page(spinand, &req, false);
-	if (ret)
-		return ret;
 
+	spinand_select_target(spinand, pos->target);
+	spinand_read_page(spinand, &req, false);
 	if (marker[0] != 0xff || marker[1] != 0xff)
 		return true;
 
@@ -722,6 +722,10 @@ static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
 	if (ret)
 		return ret;
 
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
 	return spinand_write_page(spinand, &req);
 }
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 5/7] mtd/spinand: sync supported devices with linux-5.15.43
  2022-10-06  3:14 [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description mikhail.kshevetskiy
                   ` (2 preceding siblings ...)
  2022-10-06  3:14 ` [PATCH 4/7] mtd/spinand: sync core spinand code with linux-5.10.118 mikhail.kshevetskiy
@ 2022-10-06  3:15 ` mikhail.kshevetskiy
  2022-10-06  3:15 ` [PATCH 6/7] mtd/spinand: add Winbond W25N02KV flash support, fix Winbond flashes identifications mikhail.kshevetskiy
  2022-10-07 11:34 ` [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description Michael Nazzareno Trimarchi
  5 siblings, 0 replies; 19+ messages in thread
From: mikhail.kshevetskiy @ 2022-10-06  3:15 UTC (permalink / raw)
  To: u-boot
  Cc: Dario Binacchi, Michael Trimarchi, Stefan Roese,
	mikhail.kshevetskiy, agnau

From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
 drivers/mtd/nand/spi/Makefile     |   2 +-
 drivers/mtd/nand/spi/core.c       |   1 +
 drivers/mtd/nand/spi/gigadevice.c | 223 ++++++++++++++++++++++++++----
 drivers/mtd/nand/spi/macronix.c   | 145 +++++++++++++++++--
 drivers/mtd/nand/spi/micron.c     | 144 +++++++++++++------
 drivers/mtd/nand/spi/paragon.c    | 133 ++++++++++++++++++
 drivers/mtd/nand/spi/toshiba.c    |  38 ++---
 drivers/mtd/nand/spi/winbond.c    |   6 +-
 include/linux/mtd/nand.h          |   5 +-
 include/linux/mtd/spinand.h       |  31 +++++
 10 files changed, 626 insertions(+), 102 deletions(-)
 create mode 100644 drivers/mtd/nand/spi/paragon.c

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 6c65b187e8..3051de4f7e 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index d0c7d82010..52a15b30ef 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -824,6 +824,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&gigadevice_spinand_manufacturer,
 	&macronix_spinand_manufacturer,
 	&micron_spinand_manufacturer,
+	&paragon_spinand_manufacturer,
 	&toshiba_spinand_manufacturer,
 	&winbond_spinand_manufacturer,
 };
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index 370ffb765e..0635808715 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -7,13 +7,13 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_GIGADEVICE			0xC8
+
 #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS	(1 << 4)
 #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS	(3 << 4)
 
@@ -22,8 +22,12 @@
 
 #define GD5FXGQXXEXXG_REG_STATUS2		0xf0
 
-/* Q4 devices, QUADIO: Dummy bytes valid for 1 and 2 GBit variants */
-static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
+#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK		(7 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS	(0 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS	(1 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR	(7 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -31,14 +35,13 @@ static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
-/* Q5 devices, QUADIO: Dummy bytes only valid for 1 GBit variants */
-static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
-		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
-		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+static SPINAND_OP_VARIANTS(read_cache_variants_f,
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
-		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
 
 static SPINAND_OP_VARIANTS(write_cache_variants,
 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
@@ -48,7 +51,65 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
-static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 8;
+	region->length = 8;
+
+	return 0;
+}
+
+static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	if (section) {
+		region->offset = 16 * section;
+		region->length = 8;
+	} else {
+		/* section 0 has one byte reserved for bad block mark */
+		region->offset = 1;
+		region->length = 7;
+	}
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+	.ecc = gd5fxgq4xa_ooblayout_ecc,
+	.free = gd5fxgq4xa_ooblayout_free,
+};
+
+static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
+					 u8 status)
+{
+	switch (status & STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
+		/* 1-7 bits are flipped. return the maximum. */
+		return 7;
+
+	case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
+		return 8;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
 				       struct mtd_oob_region *region)
 {
 	if (section)
@@ -60,7 +121,7 @@ static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
 	return 0;
 }
 
-static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
+static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
 					struct mtd_oob_region *region)
 {
 	if (section)
@@ -73,7 +134,42 @@ static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
 	return 0;
 }
 
-static int gd5fxgq4xexxg_ecc_get_status(struct spinand_device *spinand,
+/* Valid for Q4/Q5 and Q6 (untested) devices */
+static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
+	.ecc = gd5fxgqx_variant2_ooblayout_ecc,
+	.free = gd5fxgqx_variant2_ooblayout_free,
+};
+
+static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 128;
+	oobregion->length = 128;
+
+	return 0;
+}
+
+static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
+					 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 1;
+	oobregion->length = 127;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
+	.ecc = gd5fxgq4xc_ooblayout_256_ecc,
+	.free = gd5fxgq4xc_ooblayout_256_free,
+};
+
+static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
 					u8 status)
 {
 	u8 status2;
@@ -152,31 +248,106 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
 	return -EINVAL;
 }
 
-static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
-	.ecc = gd5fxgqxxexxg_ooblayout_ecc,
-	.free = gd5fxgqxxexxg_ooblayout_free,
-};
+static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
+					u8 status)
+{
+	switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
+	case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
+		return 3;
+
+	case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
+		return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
+	}
+
+	return -EINVAL;
+}
 
 static const struct spinand_info gigadevice_spinand_table[] = {
+	SPINAND_INFO("GD5F1GQ4xA",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+				     gd5fxgq4xa_ecc_get_status)),
+	SPINAND_INFO("GD5F2GQ4xA",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+				     gd5fxgq4xa_ecc_get_status)),
+	SPINAND_INFO("GD5F4GQ4xA",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
+		     NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+				     gd5fxgq4xa_ecc_get_status)),
+	SPINAND_INFO("GD5F4GQ4RC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+				     gd5fxgq4ufxxg_ecc_get_status)),
+	SPINAND_INFO("GD5F4GQ4UC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+				     gd5fxgq4ufxxg_ecc_get_status)),
 	SPINAND_INFO("GD5F1GQ4UExxG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+				     gd5fxgq4uexxg_ecc_get_status)),
+	SPINAND_INFO("GD5F1GQ4UFxxG",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&gd5fxgq4_read_cache_variants,
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     0,
-		     SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
-				     gd5fxgq4xexxg_ecc_get_status)),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+				     gd5fxgq4ufxxg_ecc_get_status)),
 	SPINAND_INFO("GD5F1GQ5UExxG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
-		     SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     0,
-		     SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
 				     gd5fxgq5xexxg_ecc_get_status)),
 };
 
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 8c88883665..8b27f697cb 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -6,7 +6,6 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
@@ -16,7 +15,6 @@
 #define SPINAND_MFR_MACRONIX		0xC2
 #define MACRONIX_ECCSR_MASK		0x0F
 
-
 static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -62,7 +60,6 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
 					  SPI_MEM_OP_DATA_IN(1, eccsr, 1));
 
 	int ret = spi_mem_exec_op(spinand->slave, &op);
-
 	if (ret)
 		return ret;
 
@@ -107,7 +104,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
 static const struct spinand_info macronix_spinand_table[] = {
 	SPINAND_INFO("MX35LF1GE4AB",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
-		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -117,16 +114,124 @@ static const struct spinand_info macronix_spinand_table[] = {
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35LF2GE4AB",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
-		     NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+	SPINAND_INFO("MX35LF2GE4AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35LF4GE4AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
+		     NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35LF1G24AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+	SPINAND_INFO("MX35LF2G24AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+	SPINAND_INFO("MX35LF4G24AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+	SPINAND_INFO("MX31LF1GE4BC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX31UF1GE4BC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+
+	SPINAND_INFO("MX35LF2G14AC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35UF4G24AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF4GE4AD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35UF2G14AC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35UF2G24AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -136,7 +241,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF2GE4AD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -146,7 +251,17 @@ static const struct spinand_info macronix_spinand_table[] = {
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF2GE4AC",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
-		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35UF1G14AC",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -154,9 +269,19 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     mx35lf1ge4ab_ecc_get_status)),
+	SPINAND_INFO("MX35UF1G24AD",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF1GE4AD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -166,7 +291,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 				     mx35lf1ge4ab_ecc_get_status)),
 	SPINAND_INFO("MX35UF1GE4AC",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
-		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(4, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index 9e6cf35ea0..b044a80877 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -7,11 +7,9 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
-#include <linux/bitops.h>
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_MICRON		0x2c
@@ -32,7 +30,7 @@
 
 #define MICRON_SELECT_DIE(x)	((x) << 6)
 
-static SPINAND_OP_VARIANTS(read_cache_variants,
+static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -40,14 +38,27 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
-static SPINAND_OP_VARIANTS(write_cache_variants,
+static SPINAND_OP_VARIANTS(x4_write_cache_variants,
 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
 
-static SPINAND_OP_VARIANTS(update_cache_variants,
+static SPINAND_OP_VARIANTS(x4_update_cache_variants,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
+/* Micron  MT29F2G01AAAED Device */
+static SPINAND_OP_VARIANTS(x4_read_cache_variants,
+			   SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+			   SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+			   SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+			   SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(x1_write_cache_variants,
+			   SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(x1_update_cache_variants,
+			   SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
 static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *region)
 {
@@ -78,6 +89,47 @@ static const struct mtd_ooblayout_ops micron_8_ooblayout = {
 	.free = micron_8_ooblayout_free,
 };
 
+static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+	if (section >= spinand->base.memorg.pagesize /
+			mtd->ecc_step_size)
+		return -ERANGE;
+
+	region->offset = (section * 16) + 8;
+	region->length = 8;
+
+	return 0;
+}
+
+static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+	if (section >= spinand->base.memorg.pagesize /
+			mtd->ecc_step_size)
+		return -ERANGE;
+
+	if (section) {
+		region->offset = 16 * section;
+		region->length = 8;
+	} else {
+		/* section 0 has two bytes reserved for the BBM */
+		region->offset = 2;
+		region->length = 6;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_4_ooblayout = {
+	.ecc = micron_4_ooblayout_ecc,
+	.free = micron_4_ooblayout_free,
+};
+
 static int micron_select_target(struct spinand_device *spinand,
 				unsigned int target)
 {
@@ -122,55 +174,55 @@ static const struct spinand_info micron_spinand_table[] = {
 	/* M79A 2Gb 3.3V */
 	SPINAND_INFO("MT29F2G01ABAGD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     0,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M79A 2Gb 1.8V */
 	SPINAND_INFO("MT29F2G01ABBGD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     0,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M78A 1Gb 3.3V */
 	SPINAND_INFO("MT29F1G01ABAFD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     0,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M78A 1Gb 1.8V */
 	SPINAND_INFO("MT29F1G01ABAFD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     0,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M79A 4Gb 3.3V */
 	SPINAND_INFO("MT29F4G01ADAGD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 2),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     0,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status),
@@ -178,33 +230,33 @@ static const struct spinand_info micron_spinand_table[] = {
 	/* M70A 4Gb 3.3V */
 	SPINAND_INFO("MT29F4G01ABAFD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     SPINAND_HAS_CR_FEAT_BIT,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M70A 4Gb 1.8V */
 	SPINAND_INFO("MT29F4G01ABBFD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     SPINAND_HAS_CR_FEAT_BIT,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status)),
 	/* M70A 8Gb 3.3V */
 	SPINAND_INFO("MT29F8G01ADAFD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     SPINAND_HAS_CR_FEAT_BIT,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status),
@@ -212,15 +264,25 @@ static const struct spinand_info micron_spinand_table[] = {
 	/* M70A 8Gb 1.8V */
 	SPINAND_INFO("MT29F8G01ADBFD",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
 		     NAND_ECCREQ(8, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+					      &x4_write_cache_variants,
+					      &x4_update_cache_variants),
 		     SPINAND_HAS_CR_FEAT_BIT,
 		     SPINAND_ECCINFO(&micron_8_ooblayout,
 				     micron_8_ecc_get_status),
 		     SPINAND_SELECT_TARGET(micron_select_target)),
+	/* M69A 2Gb 3.3V */
+	SPINAND_INFO("MT29F2G01AAAED",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
+					      &x1_write_cache_variants,
+					      &x1_update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
 };
 
 static int micron_spinand_init(struct spinand_device *spinand)
diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
new file mode 100644
index 0000000000..771167503d
--- /dev/null
+++ b/drivers/mtd/nand/spi/paragon.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Jeff Kletsky
+ *
+ * Author: Jeff Kletsky <git-commits@allycomm.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+
+#define SPINAND_MFR_PARAGON	0xa1
+
+
+#define PN26G0XA_STATUS_ECC_BITMASK		(3 << 4)
+
+#define PN26G0XA_STATUS_ECC_NONE_DETECTED	(0 << 4)
+#define PN26G0XA_STATUS_ECC_1_7_CORRECTED	(1 << 4)
+#define PN26G0XA_STATUS_ECC_ERRORED		(2 << 4)
+#define PN26G0XA_STATUS_ECC_8_CORRECTED		(3 << 4)
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+
+static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
+	region->length = 13;
+
+	return 0;
+}
+
+static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 4)
+		return -ERANGE;
+
+	if (section == 4) {
+		region->offset = 64;
+		region->length = 64;
+	} else {
+		region->offset = 4 + (15 * section);
+		region->length = 2;
+	}
+
+	return 0;
+}
+
+static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
+				   u8 status)
+{
+	switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
+	case PN26G0XA_STATUS_ECC_NONE_DETECTED:
+		return 0;
+
+	case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
+		return 7;	/* Return upper limit by convention */
+
+	case PN26G0XA_STATUS_ECC_8_CORRECTED:
+		return 8;
+
+	case PN26G0XA_STATUS_ECC_ERRORED:
+		return -EBADMSG;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
+	.ecc = pn26g0xa_ooblayout_ecc,
+	.free = pn26g0xa_ooblayout_free,
+};
+
+
+static const struct spinand_info paragon_spinand_table[] = {
+	SPINAND_INFO("PN26G01A",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+				     pn26g0xa_ecc_get_status)),
+	SPINAND_INFO("PN26G02A",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe2),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+				     pn26g0xa_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer paragon_spinand_manufacturer = {
+	.id = SPINAND_MFR_PARAGON,
+	.name = "Paragon",
+	.chips = paragon_spinand_table,
+	.nchips = ARRAY_SIZE(paragon_spinand_table),
+	.ops = &paragon_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index 872634f0fe..fb3fa54afa 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -7,13 +7,13 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
 #include <linux/bug.h>
 #include <linux/mtd/spinand.h>
 
+/* Kioxia is new name of Toshiba memory. */
 #define SPINAND_MFR_TOSHIBA		0x98
 #define TOSH_STATUS_ECC_HAS_BITFLIPS_T	(3 << 4)
 
@@ -31,7 +31,7 @@ static SPINAND_OP_VARIANTS(update_cache_x4_variants,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
-/**
+/*
  * Backward compatibility for 1st generation Serial NAND devices
  * which don't support Quad Program Load operation.
  */
@@ -42,7 +42,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
 static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
-				     struct mtd_oob_region *region)
+					struct mtd_oob_region *region)
 {
 	if (section > 0)
 		return -ERANGE;
@@ -54,7 +54,7 @@ static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
 }
 
 static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,
-				      struct mtd_oob_region *region)
+					 struct mtd_oob_region *region)
 {
 	if (section > 0)
 		return -ERANGE;
@@ -72,7 +72,7 @@ static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = {
 };
 
 static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
-				      u8 status)
+					 u8 status)
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	u8 mbf = 0;
@@ -113,7 +113,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 1Gb (1st generation) */
 	SPINAND_INFO("TC58CVG0S3HRAIG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -124,7 +124,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 2Gb (1st generation) */
 	SPINAND_INFO("TC58CVG1S3HRAIG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -135,7 +135,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 4Gb (1st generation) */
 	SPINAND_INFO("TC58CVG2S0HRAIG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -146,7 +146,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 1.8V 1Gb (1st generation) */
 	SPINAND_INFO("TC58CYG0S3HRAIG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -157,7 +157,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 1.8V 2Gb (1st generation) */
 	SPINAND_INFO("TC58CYG1S3HRAIG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -168,7 +168,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 1.8V 4Gb (1st generation) */
 	SPINAND_INFO("TC58CYG2S0HRAIG",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -184,7 +184,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 1Gb (2nd generation) */
 	SPINAND_INFO("TC58CVG0S3HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
@@ -195,7 +195,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 2Gb (2nd generation) */
 	SPINAND_INFO("TC58CVG1S3HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
@@ -206,7 +206,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 4Gb (2nd generation) */
 	SPINAND_INFO("TC58CVG2S0HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
@@ -217,7 +217,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 3.3V 8Gb (2nd generation) */
 	SPINAND_INFO("TH58CVG3S0HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
-		     NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
@@ -228,7 +228,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 1.8V 1Gb (2nd generation) */
 	SPINAND_INFO("TC58CYG0S3HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),
-		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
@@ -239,7 +239,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 1.8V 2Gb (2nd generation) */
 	SPINAND_INFO("TC58CYG1S3HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),
-		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
@@ -250,7 +250,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 1.8V 4Gb (2nd generation) */
 	SPINAND_INFO("TC58CYG2S0HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),
-		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
@@ -261,7 +261,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
 	/* 1.8V 8Gb (2nd generation) */
 	SPINAND_INFO("TH58CYG3S0HRAIJ",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
-		     NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+		     NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
 		     NAND_ECCREQ(8, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_x4_variants,
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 84469f7a89..7f991ed75e 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -8,11 +8,9 @@
  */
 
 #ifndef __UBOOT__
-#include <malloc.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
-#include <linux/bitops.h>
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_WINBOND		0xEF
@@ -81,7 +79,7 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
 static const struct spinand_info winbond_spinand_table[] = {
 	SPINAND_INFO("W25M02GV",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
-		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
 		     NAND_ECCREQ(1, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
@@ -91,7 +89,7 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
 	SPINAND_INFO("W25N01GV",
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
-		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(1, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 7774c17ad5..852917667e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -19,6 +19,7 @@
  * @oobsize: OOB area size
  * @pages_per_eraseblock: number of pages per eraseblock
  * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
+ * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN
  * @planes_per_lun: number of planes per LUN
  * @luns_per_target: number of LUN per target (target is a synonym for die)
  * @ntargets: total number of targets exposed by the NAND device
@@ -29,18 +30,20 @@ struct nand_memory_organization {
 	unsigned int oobsize;
 	unsigned int pages_per_eraseblock;
 	unsigned int eraseblocks_per_lun;
+	unsigned int max_bad_eraseblocks_per_lun;
 	unsigned int planes_per_lun;
 	unsigned int luns_per_target;
 	unsigned int ntargets;
 };
 
-#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt)	\
+#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt)	\
 	{							\
 		.bits_per_cell = (bpc),				\
 		.pagesize = (ps),				\
 		.oobsize = (os),				\
 		.pages_per_eraseblock = (ppe),			\
 		.eraseblocks_per_lun = (epl),			\
+		.max_bad_eraseblocks_per_lun = (mbb),		\
 		.planes_per_lun = (ppl),			\
 		.luns_per_target = (lpt),			\
 		.ntargets = (nt),				\
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 1ae4dc6b15..e8d6feb970 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -75,30 +75,60 @@
 		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 1))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len) \
+	SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),		\
+		   SPI_MEM_OP_ADDR(3, addr, 1),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 1))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len)	\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),				\
 		   SPI_MEM_OP_ADDR(2, addr, 1),				\
 		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 2))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len)	\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),				\
+		   SPI_MEM_OP_ADDR(3, addr, 1),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 2))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len)	\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),				\
 		   SPI_MEM_OP_ADDR(2, addr, 1),				\
 		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len)	\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),				\
+		   SPI_MEM_OP_ADDR(3, addr, 1),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 4))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len)	\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),				\
 		   SPI_MEM_OP_ADDR(2, addr, 2),				\
 		   SPI_MEM_OP_DUMMY(ndummy, 2),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 2))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),				\
+		   SPI_MEM_OP_ADDR(3, addr, 2),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 2),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 2))
+
 #define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len)	\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),				\
 		   SPI_MEM_OP_ADDR(2, addr, 4),				\
 		   SPI_MEM_OP_DUMMY(ndummy, 4),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),				\
+		   SPI_MEM_OP_ADDR(3, addr, 4),				\
+		   SPI_MEM_OP_DUMMY(ndummy, 4),				\
+		   SPI_MEM_OP_DATA_IN(len, buf, 4))
+
 #define SPINAND_PROG_EXEC_OP(addr)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),				\
 		   SPI_MEM_OP_ADDR(3, addr, 1),				\
@@ -218,6 +248,7 @@ struct spinand_manufacturer {
 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
+extern const struct spinand_manufacturer paragon_spinand_manufacturer;
 extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
 extern const struct spinand_manufacturer winbond_spinand_manufacturer;
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 6/7] mtd/spinand: add Winbond W25N02KV flash support, fix Winbond flashes identifications
  2022-10-06  3:14 [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description mikhail.kshevetskiy
                   ` (3 preceding siblings ...)
  2022-10-06  3:15 ` [PATCH 5/7] mtd/spinand: sync supported devices with linux-5.15.43 mikhail.kshevetskiy
@ 2022-10-06  3:15 ` mikhail.kshevetskiy
  2022-10-07 11:34 ` [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description Michael Nazzareno Trimarchi
  5 siblings, 0 replies; 19+ messages in thread
From: mikhail.kshevetskiy @ 2022-10-06  3:15 UTC (permalink / raw)
  To: u-boot
  Cc: Dario Binacchi, Michael Trimarchi, Stefan Roese,
	mikhail.kshevetskiy, agnau

From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>

Winbond uses 3 bytes to identify flash: vendor_id, dev_id_0, dev_id_1,
but current driver uses only first 2 bytes of it for devices
idenfification. As result Winbond W25N02KV flash (id_bytes: EF, AA, 22)
is identified as W25N01GV (id_bytes: EF, AA, 21).

Fix this and add W25N02KV flash support.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
 drivers/mtd/nand/spi/winbond.c | 80 +++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 7f991ed75e..19e5c863e8 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/kernel.h>
 #endif
+#include <linux/bug.h>
 #include <linux/mtd/spinand.h>
 
 #define SPINAND_MFR_WINBOND		0xEF
@@ -76,9 +77,75 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
 	return spi_mem_exec_op(spinand->slave, &op);
 }
 
+static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = 64 + (16 * section);
+	region->length = 13;
+
+	return 0;
+}
+
+static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 2;
+	region->length = 14;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
+	.ecc = w25n02kv_ooblayout_ecc,
+	.free = w25n02kv_ooblayout_free,
+};
+
+static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
+				   u8 status)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+	u8 mbf = 0;
+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
+
+	switch (status & STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	case STATUS_ECC_HAS_BITFLIPS:
+		/*
+		 * Let's try to retrieve the real maximum number of bitflips
+		 * in order to avoid forcing the wear-leveling layer to move
+		 * data around if it's not necessary.
+		 */
+		if (spi_mem_exec_op(spinand->slave, &op))
+			return nand->eccreq.strength;
+
+		mbf >>= 4;
+
+		if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
+			return nand->eccreq.strength;
+
+		return mbf;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
 static const struct spinand_info winbond_spinand_table[] = {
 	SPINAND_INFO("W25M02GV",
-		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
 		     NAND_ECCREQ(1, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -88,7 +155,7 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
 	SPINAND_INFO("W25N01GV",
-		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(1, 512),
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -96,6 +163,15 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &update_cache_variants),
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+	SPINAND_INFO("W25N02KV",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
 };
 
 static int winbond_spinand_init(struct spinand_device *spinand)
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided
  2022-10-06  3:14 ` [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided mikhail.kshevetskiy
@ 2022-10-06  6:56   ` Michael Nazzareno Trimarchi
  2022-10-06 15:52     ` Mikhail Kshevetskiy
  0 siblings, 1 reply; 19+ messages in thread
From: Michael Nazzareno Trimarchi @ 2022-10-06  6:56 UTC (permalink / raw)
  To: mikhail.kshevetskiy; +Cc: u-boot, Dario Binacchi, Stefan Roese, agnau

Hi

On Thu, Oct 6, 2022 at 5:15 AM <mikhail.kshevetskiy@iopsys.eu> wrote:
>
> From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
>
> 'mtd erase' command should not erase bad blocks. To force bad block erasing
> there is 'mtd erase.dontskipbad' command (this command sets 'scrub' flag
> to true in the erase_info structure). Unfortunately nand layer ignore
> scrub flag and try to erases bad blocks unconditionally. This is wrong.
>
> Add checks to allow bad block erasing only if scrub flag is set.
>
> Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> ---
>  drivers/mtd/nand/core.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> index 99c29670c7..a4fb7602c9 100644
> --- a/drivers/mtd/nand/core.c
> +++ b/drivers/mtd/nand/core.c
> @@ -174,7 +174,10 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
>         nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last);
>         while (nanddev_pos_cmp(&pos, &last) <= 0) {
>                 schedule();
> -               ret = nanddev_erase(nand, &pos);
> +               if (!einfo->scrub && nanddev_isbad(nand, &pos))

The nandev_erase already check it here:

if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {

> +                       ret = -EIO;
> +               else
> +                       ret = nanddev_erase(nand, &pos);

erase opt should already take in account scrub.

Please extend the problem

Michael
>                 if (ret) {
>                         einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
>
> --
> 2.35.1
>


-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided
  2022-10-06  6:56   ` Michael Nazzareno Trimarchi
@ 2022-10-06 15:52     ` Mikhail Kshevetskiy
  2022-10-06 16:03       ` Michael Nazzareno Trimarchi
  0 siblings, 1 reply; 19+ messages in thread
From: Mikhail Kshevetskiy @ 2022-10-06 15:52 UTC (permalink / raw)
  To: Michael Nazzareno Trimarchi; +Cc: u-boot, Dario Binacchi, Stefan Roese, agnau

On Thu, 6 Oct 2022 08:56:08 +0200
Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:

> [External email]
> 
> 
> 
> 
> 
> Hi
> 
> On Thu, Oct 6, 2022 at 5:15 AM <mikhail.kshevetskiy@iopsys.eu> wrote:
> >
> > From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> >
> > 'mtd erase' command should not erase bad blocks. To force bad block erasing
> > there is 'mtd erase.dontskipbad' command (this command sets 'scrub' flag
> > to true in the erase_info structure). Unfortunately nand layer ignore
> > scrub flag and try to erases bad blocks unconditionally. This is wrong.
> >
> > Add checks to allow bad block erasing only if scrub flag is set.
> >
> > Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > ---
> >  drivers/mtd/nand/core.c | 5 ++++-
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > index 99c29670c7..a4fb7602c9 100644
> > --- a/drivers/mtd/nand/core.c
> > +++ b/drivers/mtd/nand/core.c
> > @@ -174,7 +174,10 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct
> > erase_info *einfo) nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1,
> > &last); while (nanddev_pos_cmp(&pos, &last) <= 0) {
> >                 schedule();
> > -               ret = nanddev_erase(nand, &pos);
> > +               if (!einfo->scrub && nanddev_isbad(nand, &pos))
> 
> The nandev_erase already check it here:
> 
> if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
>

no it does not work. see nanddev_erase() code

if block is bad or reserverved, than warning is printed, than block is erased.

 
> > +                       ret = -EIO;
> > +               else
> > +                       ret = nanddev_erase(nand, &pos);
> 
> erase opt should already take in account scrub.
> 
> Please extend the problem
> 
> Michael
> >                 if (ret) {
> >                         einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
> >
> > --
> > 2.35.1
> >
> 
> 
> --
> Michael Nazzareno Trimarchi
> Co-Founder & Chief Executive Officer
> M. +39 347 913 2170
> michael@amarulasolutions.com
> __________________________________
> 
> Amarula Solutions BV
> Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> T. +31 (0)85 111 9172
> info@amarulasolutions.com
> https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C0271cbe11c804a8dfde608daa767e01b%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006361837818885%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=ZmdqQp%2FXl4XC7yFKmFEYWocIEsqQGYk8b2UI9i2cibo%3D&amp;reserved=0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided
  2022-10-06 15:52     ` Mikhail Kshevetskiy
@ 2022-10-06 16:03       ` Michael Nazzareno Trimarchi
  2022-10-06 16:17         ` Mikhail Kshevetskiy
  0 siblings, 1 reply; 19+ messages in thread
From: Michael Nazzareno Trimarchi @ 2022-10-06 16:03 UTC (permalink / raw)
  To: Mikhail Kshevetskiy; +Cc: u-boot, Dario Binacchi, Stefan Roese, agnau

On Thu, Oct 6, 2022 at 5:52 PM Mikhail Kshevetskiy
<mikhail.kshevetskiy@iopsys.eu> wrote:
>
> On Thu, 6 Oct 2022 08:56:08 +0200
> Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:
>
> > [External email]
> >
> >
> >
> >
> >
> > Hi
> >
> > On Thu, Oct 6, 2022 at 5:15 AM <mikhail.kshevetskiy@iopsys.eu> wrote:
> > >
> > > From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > >
> > > 'mtd erase' command should not erase bad blocks. To force bad block erasing
> > > there is 'mtd erase.dontskipbad' command (this command sets 'scrub' flag
> > > to true in the erase_info structure). Unfortunately nand layer ignore
> > > scrub flag and try to erases bad blocks unconditionally. This is wrong.
> > >
> > > Add checks to allow bad block erasing only if scrub flag is set.
> > >
> > > Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > > ---
> > >  drivers/mtd/nand/core.c | 5 ++++-
> > >  1 file changed, 4 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > > index 99c29670c7..a4fb7602c9 100644
> > > --- a/drivers/mtd/nand/core.c
> > > +++ b/drivers/mtd/nand/core.c
> > > @@ -174,7 +174,10 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct
> > > erase_info *einfo) nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1,
> > > &last); while (nanddev_pos_cmp(&pos, &last) <= 0) {
> > >                 schedule();
> > > -               ret = nanddev_erase(nand, &pos);
> > > +               if (!einfo->scrub && nanddev_isbad(nand, &pos))
> >
> > The nandev_erase already check it here:
> >
> > if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
> >
>
> no it does not work. see nanddev_erase() code
>

Let me re-formulate it. What execution path are you taking into account?

The nand are erased using the cmd/nand interface and the erase command
there calls nand_erase_opts that take in account it.

Michael



The nand is erased using the
> if block is bad or reserverved, than warning is printed, than block is erased.
>
>
> > > +                       ret = -EIO;
> > > +               else
> > > +                       ret = nanddev_erase(nand, &pos);
> >
> > erase opt should already take in account scrub.
> >
> > Please extend the problem
> >
> > Michael
> > >                 if (ret) {
> > >                         einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
> > >
> > > --
> > > 2.35.1
> > >
> >
> >
> > --
> > Michael Nazzareno Trimarchi
> > Co-Founder & Chief Executive Officer
> > M. +39 347 913 2170
> > michael@amarulasolutions.com
> > __________________________________
> >
> > Amarula Solutions BV
> > Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> > T. +31 (0)85 111 9172
> > info@amarulasolutions.com
> > https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C0271cbe11c804a8dfde608daa767e01b%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006361837818885%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=ZmdqQp%2FXl4XC7yFKmFEYWocIEsqQGYk8b2UI9i2cibo%3D&amp;reserved=0



-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided
  2022-10-06 16:03       ` Michael Nazzareno Trimarchi
@ 2022-10-06 16:17         ` Mikhail Kshevetskiy
  2022-10-06 18:09           ` Michael Nazzareno Trimarchi
  0 siblings, 1 reply; 19+ messages in thread
From: Mikhail Kshevetskiy @ 2022-10-06 16:17 UTC (permalink / raw)
  To: Michael Nazzareno Trimarchi; +Cc: u-boot, Dario Binacchi, Stefan Roese, agnau

On Thu, 6 Oct 2022 18:03:17 +0200
Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:

> [External email]
> 
> 
> 
> 
> 
> On Thu, Oct 6, 2022 at 5:52 PM Mikhail Kshevetskiy
> <mikhail.kshevetskiy@iopsys.eu> wrote:
> >
> > On Thu, 6 Oct 2022 08:56:08 +0200
> > Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:
> >
> > > [External email]
> > >
> > >
> > >
> > >
> > >
> > > Hi
> > >
> > > On Thu, Oct 6, 2022 at 5:15 AM <mikhail.kshevetskiy@iopsys.eu> wrote:
> > > >
> > > > From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > > >
> > > > 'mtd erase' command should not erase bad blocks. To force bad block
> > > > erasing there is 'mtd erase.dontskipbad' command (this command sets
> > > > 'scrub' flag to true in the erase_info structure). Unfortunately nand
> > > > layer ignore scrub flag and try to erases bad blocks unconditionally.
> > > > This is wrong.
> > > >
> > > > Add checks to allow bad block erasing only if scrub flag is set.
> > > >
> > > > Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > > > ---
> > > >  drivers/mtd/nand/core.c | 5 ++++-
> > > >  1 file changed, 4 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > > > index 99c29670c7..a4fb7602c9 100644
> > > > --- a/drivers/mtd/nand/core.c
> > > > +++ b/drivers/mtd/nand/core.c
> > > > @@ -174,7 +174,10 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct
> > > > erase_info *einfo) nanddev_offs_to_pos(nand, einfo->addr + einfo->len -
> > > > 1, &last); while (nanddev_pos_cmp(&pos, &last) <= 0) {
> > > >                 schedule();
> > > > -               ret = nanddev_erase(nand, &pos);
> > > > +               if (!einfo->scrub && nanddev_isbad(nand, &pos))
> > >
> > > The nandev_erase already check it here:
> > >
> > > if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
> > >
> >
> > no it does not work. see nanddev_erase() code
> >
> 
> Let me re-formulate it. What execution path are you taking into account?
> 
> The nand are erased using the cmd/nand interface and the erase command
> there calls nand_erase_opts that take in account it.

spi-nand flash

cmd/mtd.c -> do_mtd_erase() -> .... -> nanddev_mtd_erase() -> nanddev_erase()


> 
> Michael
> 
> 
> 
> The nand is erased using the
> > if block is bad or reserverved, than warning is printed, than block is
> > erased.
> >
> >
> > > > +                       ret = -EIO;
> > > > +               else
> > > > +                       ret = nanddev_erase(nand, &pos);
> > >
> > > erase opt should already take in account scrub.
> > >
> > > Please extend the problem
> > >
> > > Michael
> > > >                 if (ret) {
> > > >                         einfo->fail_addr = nanddev_pos_to_offs(nand,
> > > > &pos);
> > > >
> > > > --
> > > > 2.35.1
> > > >
> > >
> > >
> > > --
> > > Michael Nazzareno Trimarchi
> > > Co-Founder & Chief Executive Officer
> > > M. +39 347 913 2170
> > > michael@amarulasolutions.com
> > > __________________________________
> > >
> > > Amarula Solutions BV
> > > Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> > > T. +31 (0)85 111 9172
> > > info@amarulasolutions.com
> > > https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C220e94cc3ad54f5ccca108daa7b44fe6%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006690117535825%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=zTEEwU%2BKnLWNDq5xs77MmD6SI%2F31bRf3fEx%2Fyaa65%2FU%3D&amp;reserved=0
> 
> 
> 
> --
> Michael Nazzareno Trimarchi
> Co-Founder & Chief Executive Officer
> M. +39 347 913 2170
> michael@amarulasolutions.com
> __________________________________
> 
> Amarula Solutions BV
> Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> T. +31 (0)85 111 9172
> info@amarulasolutions.com
> https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C220e94cc3ad54f5ccca108daa7b44fe6%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006690117535825%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=zTEEwU%2BKnLWNDq5xs77MmD6SI%2F31bRf3fEx%2Fyaa65%2FU%3D&amp;reserved=0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided
  2022-10-06 16:17         ` Mikhail Kshevetskiy
@ 2022-10-06 18:09           ` Michael Nazzareno Trimarchi
  2022-10-10 13:32             ` Mikhail Kshevetskiy
  0 siblings, 1 reply; 19+ messages in thread
From: Michael Nazzareno Trimarchi @ 2022-10-06 18:09 UTC (permalink / raw)
  To: Mikhail Kshevetskiy; +Cc: u-boot, Dario Binacchi, Stefan Roese, agnau

Hi Mikhail

On Thu, Oct 6, 2022 at 6:17 PM Mikhail Kshevetskiy
<mikhail.kshevetskiy@iopsys.eu> wrote:
>
> On Thu, 6 Oct 2022 18:03:17 +0200
> Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:
>
> > [External email]
> >
> >
> >
> >
> >
> > On Thu, Oct 6, 2022 at 5:52 PM Mikhail Kshevetskiy
> > <mikhail.kshevetskiy@iopsys.eu> wrote:
> > >
> > > On Thu, 6 Oct 2022 08:56:08 +0200
> > > Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:
> > >
> > > > [External email]
> > > >
> > > >
> > > >
> > > >
> > > >
> > > > Hi
> > > >
> > > > On Thu, Oct 6, 2022 at 5:15 AM <mikhail.kshevetskiy@iopsys.eu> wrote:
> > > > >
> > > > > From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > > > >
> > > > > 'mtd erase' command should not erase bad blocks. To force bad block
> > > > > erasing there is 'mtd erase.dontskipbad' command (this command sets
> > > > > 'scrub' flag to true in the erase_info structure). Unfortunately nand
> > > > > layer ignore scrub flag and try to erases bad blocks unconditionally.
> > > > > This is wrong.
> > > > >
> > > > > Add checks to allow bad block erasing only if scrub flag is set.
> > > > >
> > > > > Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > > > > ---
> > > > >  drivers/mtd/nand/core.c | 5 ++++-
> > > > >  1 file changed, 4 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > > > > index 99c29670c7..a4fb7602c9 100644
> > > > > --- a/drivers/mtd/nand/core.c
> > > > > +++ b/drivers/mtd/nand/core.c
> > > > > @@ -174,7 +174,10 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct
> > > > > erase_info *einfo) nanddev_offs_to_pos(nand, einfo->addr + einfo->len -
> > > > > 1, &last); while (nanddev_pos_cmp(&pos, &last) <= 0) {
> > > > >                 schedule();
> > > > > -               ret = nanddev_erase(nand, &pos);
> > > > > +               if (!einfo->scrub && nanddev_isbad(nand, &pos))
> > > >
> > > > The nandev_erase already check it here:
> > > >
> > > > if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
> > > >
> > >
> > > no it does not work. see nanddev_erase() code
> > >
> >
> > Let me re-formulate it. What execution path are you taking into account?
> >
> > The nand are erased using the cmd/nand interface and the erase command
> > there calls nand_erase_opts that take in account it.
>
> spi-nand flash
>
> cmd/mtd.c -> do_mtd_erase() -> .... -> nanddev_mtd_erase() -> nanddev_erase()
>

Ok now it's clear. I'm thinking and i have create a patch if we can
use somenthing like this

Not tested


@@ -393,7 +394,7 @@ out_put_mtd:
 static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc,
                        char *const argv[])
 {
-       struct erase_info erase_op = {};
+       nand_erase_options_t opts = {};
        struct mtd_info *mtd;
        u64 off, len;
        bool scrub;
@@ -431,26 +432,11 @@ static int do_mtd_erase(struct cmd_tbl *cmdtp,
int flag, int argc,
        printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
               off, off + len - 1, mtd_div_by_eb(len, mtd));

-       erase_op.mtd = mtd;
-       erase_op.addr = off;
-       erase_op.len = mtd->erasesize;
-       erase_op.scrub = scrub;
-
-       while (len) {
-               ret = mtd_erase(mtd, &erase_op);
-
-               if (ret) {
-                       /* Abort if its not a bad block error */
-                       if (ret != -EIO)
-                               break;
-                       printf("Skipping bad block at 0x%08llx\n",
-                              erase_op.addr);
-               }
-
-               len -= mtd->erasesize;
-               erase_op.addr += mtd->erasesize;
-       }
+       opts.offset = off;
+       opts.length = len;
+       opts.scrub = scrub;

+       ret = nand_erase_opts(mtd, &opts);
        if (ret && ret != -EIO)
                ret = CMD_RET_FAILURE;
        else

Michael


>
> >
> > Michael
> >
> >
> >
> > The nand is erased using the
> > > if block is bad or reserverved, than warning is printed, than block is
> > > erased.
> > >
> > >
> > > > > +                       ret = -EIO;
> > > > > +               else
> > > > > +                       ret = nanddev_erase(nand, &pos);
> > > >
> > > > erase opt should already take in account scrub.
> > > >
> > > > Please extend the problem
> > > >
> > > > Michael
> > > > >                 if (ret) {
> > > > >                         einfo->fail_addr = nanddev_pos_to_offs(nand,
> > > > > &pos);
> > > > >
> > > > > --
> > > > > 2.35.1
> > > > >
> > > >
> > > >
> > > > --
> > > > Michael Nazzareno Trimarchi
> > > > Co-Founder & Chief Executive Officer
> > > > M. +39 347 913 2170
> > > > michael@amarulasolutions.com
> > > > __________________________________
> > > >
> > > > Amarula Solutions BV
> > > > Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> > > > T. +31 (0)85 111 9172
> > > > info@amarulasolutions.com
> > > > https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C220e94cc3ad54f5ccca108daa7b44fe6%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006690117535825%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=zTEEwU%2BKnLWNDq5xs77MmD6SI%2F31bRf3fEx%2Fyaa65%2FU%3D&amp;reserved=0
> >
> >
> >
> > --
> > Michael Nazzareno Trimarchi
> > Co-Founder & Chief Executive Officer
> > M. +39 347 913 2170
> > michael@amarulasolutions.com
> > __________________________________
> >
> > Amarula Solutions BV
> > Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> > T. +31 (0)85 111 9172
> > info@amarulasolutions.com
> > https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C220e94cc3ad54f5ccca108daa7b44fe6%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006690117535825%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=zTEEwU%2BKnLWNDq5xs77MmD6SI%2F31bRf3fEx%2Fyaa65%2FU%3D&amp;reserved=0



--
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
  2022-10-06  3:14 [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description mikhail.kshevetskiy
                   ` (4 preceding siblings ...)
  2022-10-06  3:15 ` [PATCH 6/7] mtd/spinand: add Winbond W25N02KV flash support, fix Winbond flashes identifications mikhail.kshevetskiy
@ 2022-10-07 11:34 ` Michael Nazzareno Trimarchi
  2022-10-07 11:58   ` Fabio Estevam
  5 siblings, 1 reply; 19+ messages in thread
From: Michael Nazzareno Trimarchi @ 2022-10-07 11:34 UTC (permalink / raw)
  To: mikhail.kshevetskiy, Simon Glass
  Cc: u-boot, Dario Binacchi, Stefan Roese, agnau

Hi mikhail

On Thu, Oct 6, 2022 at 5:15 AM <mikhail.kshevetskiy@iopsys.eu> wrote:
>
> From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
>
> In the description of struct mtd_ooblayout_ops we see:
>
>  * @free: function returning a free region in the OOB area.
>  *        Should return -ERANGE if %section exceeds the total number of
>  *        free sections.
>
> but corresponding field of the structure named as 'rfree'. This is
> wrong. Fix it the asme way as was done previously in linux kernel.
>

About this change, there was a commit from Simon 8d38a8459b0
that was renamed. You ask basically to revert it

Michael

> Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> ---
>  drivers/mtd/mtdcore.c                | 4 ++--
>  drivers/mtd/nand/raw/denali.c        | 2 +-
>  drivers/mtd/nand/raw/octeontx_nand.c | 2 +-
>  drivers/mtd/nand/raw/rockchip_nfc.c  | 2 +-
>  drivers/mtd/nand/spi/core.c          | 2 +-
>  drivers/mtd/nand/spi/gigadevice.c    | 2 +-
>  drivers/mtd/nand/spi/macronix.c      | 2 +-
>  drivers/mtd/nand/spi/micron.c        | 2 +-
>  drivers/mtd/nand/spi/toshiba.c       | 2 +-
>  drivers/mtd/nand/spi/winbond.c       | 2 +-
>  include/linux/mtd/mtd.h              | 4 ++--
>  11 files changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
> index aa78d41a55..df8f3b8284 100644
> --- a/drivers/mtd/mtdcore.c
> +++ b/drivers/mtd/mtdcore.c
> @@ -1208,10 +1208,10 @@ int mtd_ooblayout_free(struct mtd_info *mtd, int section,
>         if (!mtd || section < 0)
>                 return -EINVAL;
>
> -       if (!mtd->ooblayout || !mtd->ooblayout->rfree)
> +       if (!mtd->ooblayout || !mtd->ooblayout->free)
>                 return -ENOTSUPP;
>
> -       return mtd->ooblayout->rfree(mtd, section, oobfree);
> +       return mtd->ooblayout->free(mtd, section, oobfree);
>  }
>  EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
>
> diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
> index c827f80281..ed24b84d82 100644
> --- a/drivers/mtd/nand/raw/denali.c
> +++ b/drivers/mtd/nand/raw/denali.c
> @@ -1166,7 +1166,7 @@ static int denali_ooblayout_free(struct mtd_info *mtd, int section,
>
>  static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
>         .ecc = denali_ooblayout_ecc,
> -       .rfree = denali_ooblayout_free,
> +       .free = denali_ooblayout_free,
>  };
>
>  static int denali_multidev_fixup(struct denali_nand_info *denali)
> diff --git a/drivers/mtd/nand/raw/octeontx_nand.c b/drivers/mtd/nand/raw/octeontx_nand.c
> index b338b204f3..4023bbcec6 100644
> --- a/drivers/mtd/nand/raw/octeontx_nand.c
> +++ b/drivers/mtd/nand/raw/octeontx_nand.c
> @@ -435,7 +435,7 @@ static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
>
>  static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
>         .ecc = nand_ooblayout_ecc_lp,
> -       .rfree = nand_ooblayout_free_lp,
> +       .free = nand_ooblayout_free_lp,
>  };
>
>  static inline struct octeontx_nand_chip *to_otx_nand(struct nand_chip *nand)
> diff --git a/drivers/mtd/nand/raw/rockchip_nfc.c b/drivers/mtd/nand/raw/rockchip_nfc.c
> index d016d25575..1ab429f430 100644
> --- a/drivers/mtd/nand/raw/rockchip_nfc.c
> +++ b/drivers/mtd/nand/raw/rockchip_nfc.c
> @@ -849,7 +849,7 @@ static int rk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
>  }
>
>  static const struct mtd_ooblayout_ops rk_nfc_ooblayout_ops = {
> -       .rfree = rk_nfc_ooblayout_free,
> +       .free = rk_nfc_ooblayout_free,
>         .ecc = rk_nfc_ooblayout_ecc,
>  };
>
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 134bf22c80..4edb7ae952 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1021,7 +1021,7 @@ static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
>
>  static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
>         .ecc = spinand_noecc_ooblayout_ecc,
> -       .rfree = spinand_noecc_ooblayout_free,
> +       .free = spinand_noecc_ooblayout_free,
>  };
>
>  static int spinand_init(struct spinand_device *spinand)
> diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
> index a2c93486f4..25d9f80d26 100644
> --- a/drivers/mtd/nand/spi/gigadevice.c
> +++ b/drivers/mtd/nand/spi/gigadevice.c
> @@ -154,7 +154,7 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
>
>  static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
>         .ecc = gd5fxgqxxexxg_ooblayout_ecc,
> -       .rfree = gd5fxgqxxexxg_ooblayout_free,
> +       .free = gd5fxgqxxexxg_ooblayout_free,
>  };
>
>  static const struct spinand_info gigadevice_spinand_table[] = {
> diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
> index 6d643a8000..6a1d6a1793 100644
> --- a/drivers/mtd/nand/spi/macronix.c
> +++ b/drivers/mtd/nand/spi/macronix.c
> @@ -51,7 +51,7 @@ static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
>
>  static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
>         .ecc = mx35lfxge4ab_ooblayout_ecc,
> -       .rfree = mx35lfxge4ab_ooblayout_free,
> +       .free = mx35lfxge4ab_ooblayout_free,
>  };
>
>  static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
> diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
> index 6bacf14aaf..3f5848aacd 100644
> --- a/drivers/mtd/nand/spi/micron.c
> +++ b/drivers/mtd/nand/spi/micron.c
> @@ -75,7 +75,7 @@ static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
>
>  static const struct mtd_ooblayout_ops micron_8_ooblayout = {
>         .ecc = micron_8_ooblayout_ecc,
> -       .rfree = micron_8_ooblayout_free,
> +       .free = micron_8_ooblayout_free,
>  };
>
>  static int micron_select_target(struct spinand_device *spinand,
> diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
> index c2cd3b426b..2a7b201bb1 100644
> --- a/drivers/mtd/nand/spi/toshiba.c
> +++ b/drivers/mtd/nand/spi/toshiba.c
> @@ -68,7 +68,7 @@ static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,
>
>  static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = {
>         .ecc = tx58cxgxsxraix_ooblayout_ecc,
> -       .rfree = tx58cxgxsxraix_ooblayout_free,
> +       .free = tx58cxgxsxraix_ooblayout_free,
>  };
>
>  static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
> diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
> index c119486efb..119fa135b1 100644
> --- a/drivers/mtd/nand/spi/winbond.c
> +++ b/drivers/mtd/nand/spi/winbond.c
> @@ -61,7 +61,7 @@ static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
>
>  static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
>         .ecc = w25m02gv_ooblayout_ecc,
> -       .rfree = w25m02gv_ooblayout_free,
> +       .free = w25m02gv_ooblayout_free,
>  };
>
>  static int w25m02gv_select_target(struct spinand_device *spinand,
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index ff635bd716..03ccf28b06 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -129,8 +129,8 @@ struct mtd_oob_region {
>  struct mtd_ooblayout_ops {
>         int (*ecc)(struct mtd_info *mtd, int section,
>                    struct mtd_oob_region *oobecc);
> -       int (*rfree)(struct mtd_info *mtd, int section,
> -                    struct mtd_oob_region *oobfree);
> +       int (*free)(struct mtd_info *mtd, int section,
> +                   struct mtd_oob_region *oobfree);
>  };
>
>  /*
> --
> 2.35.1
>


-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
  2022-10-07 11:34 ` [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description Michael Nazzareno Trimarchi
@ 2022-10-07 11:58   ` Fabio Estevam
  2022-10-07 11:59     ` Michael Nazzareno Trimarchi
  2022-11-24 15:09     ` Frieder Schrempf
  0 siblings, 2 replies; 19+ messages in thread
From: Fabio Estevam @ 2022-10-07 11:58 UTC (permalink / raw)
  To: Michael Nazzareno Trimarchi
  Cc: mikhail.kshevetskiy, Simon Glass, u-boot, Dario Binacchi,
	Stefan Roese, agnau

On Fri, Oct 7, 2022 at 8:34 AM Michael Nazzareno Trimarchi
<michael@amarulasolutions.com> wrote:

> About this change, there was a commit from Simon 8d38a8459b0
> that was renamed. You ask basically to revert it

Correct, what about fixing it like this?

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index ff635bd716..09f5269887 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -122,7 +122,7 @@ struct mtd_oob_region {
  * @ecc: function returning an ECC region in the OOB area.
  *      Should return -ERANGE if %section exceeds the total number of
  *      ECC sections.
- * @free: function returning a free region in the OOB area.
+ * @rfree: function returning a free region in the OOB area.
  *       Should return -ERANGE if %section exceeds the total number of
  *       free sections.
  */

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
  2022-10-07 11:58   ` Fabio Estevam
@ 2022-10-07 11:59     ` Michael Nazzareno Trimarchi
  2022-10-07 14:01       ` Michael Nazzareno Trimarchi
  2022-11-24 15:09     ` Frieder Schrempf
  1 sibling, 1 reply; 19+ messages in thread
From: Michael Nazzareno Trimarchi @ 2022-10-07 11:59 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: mikhail.kshevetskiy, Simon Glass, u-boot, Dario Binacchi,
	Stefan Roese, agnau

Hi

On Fri, Oct 7, 2022 at 1:58 PM Fabio Estevam <festevam@gmail.com> wrote:
>
> On Fri, Oct 7, 2022 at 8:34 AM Michael Nazzareno Trimarchi
> <michael@amarulasolutions.com> wrote:
>
> > About this change, there was a commit from Simon 8d38a8459b0
> > that was renamed. You ask basically to revert it
>
> Correct, what about fixing it like this?
>
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index ff635bd716..09f5269887 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -122,7 +122,7 @@ struct mtd_oob_region {
>   * @ecc: function returning an ECC region in the OOB area.
>   *      Should return -ERANGE if %section exceeds the total number of
>   *      ECC sections.
> - * @free: function returning a free region in the OOB area.
> + * @rfree: function returning a free region in the OOB area.
>   *       Should return -ERANGE if %section exceeds the total number of
>   *       free sections.
>   */

That's is anyway a fix

Michael


-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
  2022-10-07 11:59     ` Michael Nazzareno Trimarchi
@ 2022-10-07 14:01       ` Michael Nazzareno Trimarchi
  0 siblings, 0 replies; 19+ messages in thread
From: Michael Nazzareno Trimarchi @ 2022-10-07 14:01 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: mikhail.kshevetskiy, Simon Glass, u-boot, Dario Binacchi,
	Stefan Roese, agnau

Hi Fabio

If you send the change of the comment, I will queue it

Michael

On Fri, Oct 7, 2022 at 1:59 PM Michael Nazzareno Trimarchi
<michael@amarulasolutions.com> wrote:
>
> Hi
>
> On Fri, Oct 7, 2022 at 1:58 PM Fabio Estevam <festevam@gmail.com> wrote:
> >
> > On Fri, Oct 7, 2022 at 8:34 AM Michael Nazzareno Trimarchi
> > <michael@amarulasolutions.com> wrote:
> >
> > > About this change, there was a commit from Simon 8d38a8459b0
> > > that was renamed. You ask basically to revert it
> >
> > Correct, what about fixing it like this?
> >
> > diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> > index ff635bd716..09f5269887 100644
> > --- a/include/linux/mtd/mtd.h
> > +++ b/include/linux/mtd/mtd.h
> > @@ -122,7 +122,7 @@ struct mtd_oob_region {
> >   * @ecc: function returning an ECC region in the OOB area.
> >   *      Should return -ERANGE if %section exceeds the total number of
> >   *      ECC sections.
> > - * @free: function returning a free region in the OOB area.
> > + * @rfree: function returning a free region in the OOB area.
> >   *       Should return -ERANGE if %section exceeds the total number of
> >   *       free sections.
> >   */
>
> That's is anyway a fix
>
> Michael
>
>
> --
> Michael Nazzareno Trimarchi
> Co-Founder & Chief Executive Officer
> M. +39 347 913 2170
> michael@amarulasolutions.com
> __________________________________
>
> Amarula Solutions BV
> Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> T. +31 (0)85 111 9172
> info@amarulasolutions.com
> www.amarulasolutions.com



-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided
  2022-10-06 18:09           ` Michael Nazzareno Trimarchi
@ 2022-10-10 13:32             ` Mikhail Kshevetskiy
  0 siblings, 0 replies; 19+ messages in thread
From: Mikhail Kshevetskiy @ 2022-10-10 13:32 UTC (permalink / raw)
  To: Michael Nazzareno Trimarchi; +Cc: u-boot, Dario Binacchi, Stefan Roese, agnau

On Thu, 6 Oct 2022 20:09:11 +0200
Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:

> [External email]
> 
> 
> 
> 
> 
> Hi Mikhail
> 
> On Thu, Oct 6, 2022 at 6:17 PM Mikhail Kshevetskiy
> <mikhail.kshevetskiy@iopsys.eu> wrote:
> >
> > On Thu, 6 Oct 2022 18:03:17 +0200
> > Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:
> >
> > > [External email]
> > >
> > >
> > >
> > >
> > >
> > > On Thu, Oct 6, 2022 at 5:52 PM Mikhail Kshevetskiy
> > > <mikhail.kshevetskiy@iopsys.eu> wrote:
> > > >
> > > > On Thu, 6 Oct 2022 08:56:08 +0200
> > > > Michael Nazzareno Trimarchi <michael@amarulasolutions.com> wrote:
> > > >
> > > > > [External email]
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > Hi
> > > > >
> > > > > On Thu, Oct 6, 2022 at 5:15 AM <mikhail.kshevetskiy@iopsys.eu> wrote:
> > > > > >
> > > > > > From: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > > > > >
> > > > > > 'mtd erase' command should not erase bad blocks. To force bad block
> > > > > > erasing there is 'mtd erase.dontskipbad' command (this command sets
> > > > > > 'scrub' flag to true in the erase_info structure). Unfortunately
> > > > > > nand layer ignore scrub flag and try to erases bad blocks
> > > > > > unconditionally. This is wrong.
> > > > > >
> > > > > > Add checks to allow bad block erasing only if scrub flag is set.
> > > > > >
> > > > > > Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> > > > > > ---
> > > > > >  drivers/mtd/nand/core.c | 5 ++++-
> > > > > >  1 file changed, 4 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > > > > > index 99c29670c7..a4fb7602c9 100644
> > > > > > --- a/drivers/mtd/nand/core.c
> > > > > > +++ b/drivers/mtd/nand/core.c
> > > > > > @@ -174,7 +174,10 @@ int nanddev_mtd_erase(struct mtd_info *mtd,
> > > > > > struct erase_info *einfo) nanddev_offs_to_pos(nand, einfo->addr +
> > > > > > einfo->len - 1, &last); while (nanddev_pos_cmp(&pos, &last) <= 0) {
> > > > > >                 schedule();
> > > > > > -               ret = nanddev_erase(nand, &pos);
> > > > > > +               if (!einfo->scrub && nanddev_isbad(nand, &pos))
> > > > >
> > > > > The nandev_erase already check it here:
> > > > >
> > > > > if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
> > > > >
> > > >
> > > > no it does not work. see nanddev_erase() code
> > > >
> > >
> > > Let me re-formulate it. What execution path are you taking into account?
> > >
> > > The nand are erased using the cmd/nand interface and the erase command
> > > there calls nand_erase_opts that take in account it.
> >
> > spi-nand flash
> >
> > cmd/mtd.c -> do_mtd_erase() -> .... -> nanddev_mtd_erase() ->
> > nanddev_erase()
> >
> 
> Ok now it's clear. I'm thinking and i have create a patch if we can
> use somenthing like this
> 
> Not tested
> 
> 
> @@ -393,7 +394,7 @@ out_put_mtd:
>  static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc,
>                         char *const argv[])
>  {
> -       struct erase_info erase_op = {};
> +       nand_erase_options_t opts = {};
>         struct mtd_info *mtd;
>         u64 off, len;
>         bool scrub;
> @@ -431,26 +432,11 @@ static int do_mtd_erase(struct cmd_tbl *cmdtp,
> int flag, int argc,
>         printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
>                off, off + len - 1, mtd_div_by_eb(len, mtd));
> 
> -       erase_op.mtd = mtd;
> -       erase_op.addr = off;
> -       erase_op.len = mtd->erasesize;
> -       erase_op.scrub = scrub;
> -
> -       while (len) {
> -               ret = mtd_erase(mtd, &erase_op);
> -
> -               if (ret) {
> -                       /* Abort if its not a bad block error */
> -                       if (ret != -EIO)
> -                               break;
> -                       printf("Skipping bad block at 0x%08llx\n",
> -                              erase_op.addr);
> -               }
> -
> -               len -= mtd->erasesize;
> -               erase_op.addr += mtd->erasesize;
> -       }
> +       opts.offset = off;
> +       opts.length = len;
> +       opts.scrub = scrub;
> 
> +       ret = nand_erase_opts(mtd, &opts);
>         if (ret && ret != -EIO)
>                 ret = CMD_RET_FAILURE;
>         else
> 
> Michael

no, we can't do it.

cmd/mtd.c can be used without CONFIG_MTD_RAW_NAND and I think your fix will
break mtd command for non-nand flashes.

spi-nand flashes directly registers itself with mtd layer (nand_register()
function is not used), so it much more simple use cmd/mtd than cmd/nand.



> 
> 
> >
> > >
> > > Michael
> > >
> > >
> > >
> > > The nand is erased using the
> > > > if block is bad or reserverved, than warning is printed, than block is
> > > > erased.
> > > >
> > > >
> > > > > > +                       ret = -EIO;
> > > > > > +               else
> > > > > > +                       ret = nanddev_erase(nand, &pos);
> > > > >
> > > > > erase opt should already take in account scrub.
> > > > >
> > > > > Please extend the problem
> > > > >
> > > > > Michael
> > > > > >                 if (ret) {
> > > > > >                         einfo->fail_addr = nanddev_pos_to_offs(nand,
> > > > > > &pos);
> > > > > >
> > > > > > --
> > > > > > 2.35.1
> > > > > >
> > > > >
> > > > >
> > > > > --
> > > > > Michael Nazzareno Trimarchi
> > > > > Co-Founder & Chief Executive Officer
> > > > > M. +39 347 913 2170
> > > > > michael@amarulasolutions.com
> > > > > __________________________________
> > > > >
> > > > > Amarula Solutions BV
> > > > > Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> > > > > T. +31 (0)85 111 9172
> > > > > info@amarulasolutions.com
> > > > > https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C315a2da790414f5cb22108daa7c5e5e2%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006765651063852%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=ouhzZ4pEofl7llK8OQHpatkrdksZozIgzY5IY9P%2BIL8%3D&amp;reserved=0
> > >
> > >
> > >
> > > --
> > > Michael Nazzareno Trimarchi
> > > Co-Founder & Chief Executive Officer
> > > M. +39 347 913 2170
> > > michael@amarulasolutions.com
> > > __________________________________
> > >
> > > Amarula Solutions BV
> > > Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> > > T. +31 (0)85 111 9172
> > > info@amarulasolutions.com
> > > https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C315a2da790414f5cb22108daa7c5e5e2%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006765651063852%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=ouhzZ4pEofl7llK8OQHpatkrdksZozIgzY5IY9P%2BIL8%3D&amp;reserved=0
> 
> 
> 
> --
> Michael Nazzareno Trimarchi
> Co-Founder & Chief Executive Officer
> M. +39 347 913 2170
> michael@amarulasolutions.com
> __________________________________
> 
> Amarula Solutions BV
> Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
> T. +31 (0)85 111 9172
> info@amarulasolutions.com
> https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.amarulasolutions.com%2F&amp;data=05%7C01%7Cmikhail.kshevetskiy%40iopsys.eu%7C315a2da790414f5cb22108daa7c5e5e2%7C7ff78d652de440f586750569e5c7a65d%7C0%7C0%7C638006765651063852%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=ouhzZ4pEofl7llK8OQHpatkrdksZozIgzY5IY9P%2BIL8%3D&amp;reserved=0


Maybe it's better accept my change and fix nand_erase_opts() instead ?
Bad block table is autocleaned in nanddev_erase() function.

diff --git a/drivers/mtd/nand/raw/nand_util.c b/drivers/mtd/nand/raw/nand_util.c
index b2345dca7f..b35571dfd5 100644
--- a/drivers/mtd/nand/raw/nand_util.c
+++ b/drivers/mtd/nand/raw/nand_util.c
@@ -75,6 +75,7 @@ int nand_erase_opts(struct mtd_info *mtd,
 	erase.mtd = mtd;
 	erase.len = mtd->erasesize;
 	erase.addr = opts->offset;
+	erase.scrub = opts->scrub;
 	erase_length = lldiv(opts->length + mtd->erasesize - 1,
 			     mtd->erasesize);
 
@@ -82,23 +83,6 @@ int nand_erase_opts(struct mtd_info *mtd,
 	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
 	cleanmarker.totlen = cpu_to_je32(8);
 
-	/* scrub option allows to erase badblock. To prevent internal
-	 * check from erase() method, set block check method to dummy
-	 * and disable bad block table while erasing.
-	 */
-	if (opts->scrub) {
-		erase.scrub = opts->scrub;
-		/*
-		 * We don't need the bad block table anymore...
-		 * after scrub, there are no bad blocks left!
-		 */
-		if (chip->bbt) {
-			kfree(chip->bbt);
-		}
-		chip->bbt = NULL;
-		chip->options &= ~NAND_BBT_SCANNED;
-	}
-
 	for (erased_length = 0;
 	     erased_length < erase_length;
 	     erase.addr += mtd->erasesize) {
@@ -109,34 +93,24 @@ int nand_erase_opts(struct mtd_info *mtd,
 			puts("Size of erase exceeds limit\n");
 			return -EFBIG;
 		}
-		if (!opts->scrub) {
-			int ret = mtd_block_isbad(mtd, erase.addr);
-			if (ret > 0) {
+
+		erased_length++;
+
+		result = mtd_erase(mtd, &erase);
+		if (result != 0) {
+			if (!opts->scrub && result == -EIO) {
 				if (!opts->quiet)
 					printf("\rSkipping bad block at  "
 					       "0x%08llx                 "
 					       "                         \n",
 					       erase.addr);
 
-				if (!opts->spread)
-					erased_length++;
-
-				continue;
-
-			} else if (ret < 0) {
-				printf("\n%s: MTD get bad block failed: %d\n",
-				       mtd_device,
-				       ret);
-				return -1;
+				if (opts->spread)
+					erased_length--;
+			} else {
+				printf("\n%s: MTD Erase failure: %d\n",
+				       mtd_device, result);
 			}
-		}
-
-		erased_length++;
-
-		result = mtd_erase(mtd, &erase);
-		if (result != 0) {
-			printf("\n%s: MTD Erase failure: %d\n",
-			       mtd_device, result);
 			continue;
 		}
 
---
Mikhail Kshevetskiy

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
  2022-10-07 11:58   ` Fabio Estevam
  2022-10-07 11:59     ` Michael Nazzareno Trimarchi
@ 2022-11-24 15:09     ` Frieder Schrempf
  2022-12-05 16:11       ` Simon Glass
  1 sibling, 1 reply; 19+ messages in thread
From: Frieder Schrempf @ 2022-11-24 15:09 UTC (permalink / raw)
  To: Fabio Estevam, Michael Nazzareno Trimarchi
  Cc: mikhail.kshevetskiy, Simon Glass, u-boot, Dario Binacchi,
	Stefan Roese, agnau

On 07.10.22 13:58, Fabio Estevam wrote:
> On Fri, Oct 7, 2022 at 8:34 AM Michael Nazzareno Trimarchi
> <michael@amarulasolutions.com> wrote:
> 
>> About this change, there was a commit from Simon 8d38a8459b0
>> that was renamed. You ask basically to revert it
> 
> Correct, what about fixing it like this?
> 
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index ff635bd716..09f5269887 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -122,7 +122,7 @@ struct mtd_oob_region {
>   * @ecc: function returning an ECC region in the OOB area.
>   *      Should return -ERANGE if %section exceeds the total number of
>   *      ECC sections.
> - * @free: function returning a free region in the OOB area.
> + * @rfree: function returning a free region in the OOB area.
>   *       Should return -ERANGE if %section exceeds the total number of
>   *       free sections.
>   */

But do we really want to stay out of sync with the Linux kernel code? Is
the reasoning behind Simon's change in 8d38a8459b0 still valid today?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
  2022-11-24 15:09     ` Frieder Schrempf
@ 2022-12-05 16:11       ` Simon Glass
  2022-12-05 16:15         ` Michael Nazzareno Trimarchi
  0 siblings, 1 reply; 19+ messages in thread
From: Simon Glass @ 2022-12-05 16:11 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Fabio Estevam, Michael Nazzareno Trimarchi, mikhail.kshevetskiy,
	u-boot, Dario Binacchi, Stefan Roese, agnau

Hi Frieder,

On Fri, 25 Nov 2022 at 04:09, Frieder Schrempf
<frieder.schrempf@kontron.de> wrote:
>
> On 07.10.22 13:58, Fabio Estevam wrote:
> > On Fri, Oct 7, 2022 at 8:34 AM Michael Nazzareno Trimarchi
> > <michael@amarulasolutions.com> wrote:
> >
> >> About this change, there was a commit from Simon 8d38a8459b0
> >> that was renamed. You ask basically to revert it
> >
> > Correct, what about fixing it like this?
> >
> > diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> > index ff635bd716..09f5269887 100644
> > --- a/include/linux/mtd/mtd.h
> > +++ b/include/linux/mtd/mtd.h
> > @@ -122,7 +122,7 @@ struct mtd_oob_region {
> >   * @ecc: function returning an ECC region in the OOB area.
> >   *      Should return -ERANGE if %section exceeds the total number of
> >   *      ECC sections.
> > - * @free: function returning a free region in the OOB area.
> > + * @rfree: function returning a free region in the OOB area.
> >   *       Should return -ERANGE if %section exceeds the total number of
> >   *       free sections.
> >   */
>
> But do we really want to stay out of sync with the Linux kernel code? Is
> the reasoning behind Simon's change in 8d38a8459b0 still valid today?

See here:

https://patchwork.ozlabs.org/project/uboot/cover/20200203143618.74619-1-sjg@chromium.org/

I don't believe this patch even builds for sandbox:

drivers/mtd/mtdcore.c: In function ‘mtd_ooblayout_free’:
drivers/mtd/mtdcore.c:1214:58: error: macro "free" passed 3 arguments,
but takes just 1
 1214 |         return mtd->ooblayout->free(mtd, section, oobfree);

See malloc.h for the #define for free()

Regards,
Simon

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description
  2022-12-05 16:11       ` Simon Glass
@ 2022-12-05 16:15         ` Michael Nazzareno Trimarchi
  0 siblings, 0 replies; 19+ messages in thread
From: Michael Nazzareno Trimarchi @ 2022-12-05 16:15 UTC (permalink / raw)
  To: Simon Glass
  Cc: Frieder Schrempf, Fabio Estevam, mikhail.kshevetskiy, u-boot,
	Dario Binacchi, Stefan Roese, agnau

Hi

On Mon, Dec 5, 2022 at 5:11 PM Simon Glass <sjg@chromium.org> wrote:
>
> Hi Frieder,
>
> On Fri, 25 Nov 2022 at 04:09, Frieder Schrempf
> <frieder.schrempf@kontron.de> wrote:
> >
> > On 07.10.22 13:58, Fabio Estevam wrote:
> > > On Fri, Oct 7, 2022 at 8:34 AM Michael Nazzareno Trimarchi
> > > <michael@amarulasolutions.com> wrote:
> > >
> > >> About this change, there was a commit from Simon 8d38a8459b0
> > >> that was renamed. You ask basically to revert it
> > >
> > > Correct, what about fixing it like this?
> > >
> > > diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> > > index ff635bd716..09f5269887 100644
> > > --- a/include/linux/mtd/mtd.h
> > > +++ b/include/linux/mtd/mtd.h
> > > @@ -122,7 +122,7 @@ struct mtd_oob_region {
> > >   * @ecc: function returning an ECC region in the OOB area.
> > >   *      Should return -ERANGE if %section exceeds the total number of
> > >   *      ECC sections.
> > > - * @free: function returning a free region in the OOB area.
> > > + * @rfree: function returning a free region in the OOB area.
> > >   *       Should return -ERANGE if %section exceeds the total number of
> > >   *       free sections.
> > >   */
> >
> > But do we really want to stay out of sync with the Linux kernel code? Is
> > the reasoning behind Simon's change in 8d38a8459b0 still valid today?
>

We will be stay in sync to linux as much as possible

Michael

> See here:
>
> https://patchwork.ozlabs.org/project/uboot/cover/20200203143618.74619-1-sjg@chromium.org/
>
> I don't believe this patch even builds for sandbox:
>
> drivers/mtd/mtdcore.c: In function ‘mtd_ooblayout_free’:
> drivers/mtd/mtdcore.c:1214:58: error: macro "free" passed 3 arguments,
> but takes just 1
>  1214 |         return mtd->ooblayout->free(mtd, section, oobfree);
>
> See malloc.h for the #define for free()
>
> Regards,
> Simon



-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2022-12-05 16:16 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06  3:14 [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description mikhail.kshevetskiy
2022-10-06  3:14 ` [PATCH 2/7] mtd/nand: try to erase bad blocks only if scrub flag is provided mikhail.kshevetskiy
2022-10-06  6:56   ` Michael Nazzareno Trimarchi
2022-10-06 15:52     ` Mikhail Kshevetskiy
2022-10-06 16:03       ` Michael Nazzareno Trimarchi
2022-10-06 16:17         ` Mikhail Kshevetskiy
2022-10-06 18:09           ` Michael Nazzareno Trimarchi
2022-10-10 13:32             ` Mikhail Kshevetskiy
2022-10-06  3:14 ` [PATCH 3/7] mtd/spinand: rework detect procedure for different READ_ID operation mikhail.kshevetskiy
2022-10-06  3:14 ` [PATCH 4/7] mtd/spinand: sync core spinand code with linux-5.10.118 mikhail.kshevetskiy
2022-10-06  3:15 ` [PATCH 5/7] mtd/spinand: sync supported devices with linux-5.15.43 mikhail.kshevetskiy
2022-10-06  3:15 ` [PATCH 6/7] mtd/spinand: add Winbond W25N02KV flash support, fix Winbond flashes identifications mikhail.kshevetskiy
2022-10-07 11:34 ` [PATCH 1/7] mtd: replace name of 'rfree' field with 'free' in struct mtd_ooblayout_ops to better match it's description Michael Nazzareno Trimarchi
2022-10-07 11:58   ` Fabio Estevam
2022-10-07 11:59     ` Michael Nazzareno Trimarchi
2022-10-07 14:01       ` Michael Nazzareno Trimarchi
2022-11-24 15:09     ` Frieder Schrempf
2022-12-05 16:11       ` Simon Glass
2022-12-05 16:15         ` Michael Nazzareno Trimarchi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.