[PATCH 02/13] mtd: spinand: winbond: Generalize the KV OOB layout
From: Miquel Raynal
Date: Fri Oct 30 2026 - 13:45:52 EST
All W25NxxKV and W25NxxKW chips use the same OOB layout. Rename the
helpers and structures to make it more obvious.
Signed-off-by: Miquel Raynal <miquel.raynal@xxxxxxxxxxx>
---
drivers/mtd/nand/spi/winbond.c | 54 ++++++++++++++++++------------------------
1 file changed, 23 insertions(+), 31 deletions(-)
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 49fa545a4113..4ef30f1a4aa8 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -318,16 +318,11 @@ static int w25n01kv_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0;
}
-static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+static int w25nxxkv_kw_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
{
- int num_sections = 4;
- int offset = 64;
-
- if (mtd->oobsize == 256) {
- num_sections = 8;
- offset = 128;
- }
+ unsigned int offset = mtd->oobsize / 2;
+ unsigned int num_sections = mtd->writesize / 512;
if (section >= num_sections)
return -ERANGE;
@@ -338,24 +333,21 @@ static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0;
}
-static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+/*
+ * The OOB layout is the same for all the W25NxxKV/KW/LV/LW chips: each
+ * 16-byte section holds 4 unprotected "User Data II" bytes followed by
+ * 12 ECC-protected "User Data I" bytes.
+ *
+ * This layout exposes both User Data I and II for backward compatibility.
+ */
+static int w25nxxkv_kw_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
{
- int num_sections = 4;
-
- if (mtd->oobsize == 256)
- num_sections = 8;
+ unsigned int num_sections = mtd->writesize / 512;
if (section >= num_sections)
return -ERANGE;
- /*
- * For at least W25N04KW and W25N04LW, this region is actually
- * split in two:
- * ECC-protected "User Data I" at + 4 offset, length 12
- * unprotected "User Data II" at + 2 offset, length 2
- * This returns the full region for backwards compatibility.
- */
region->offset = (16 * section) + 2;
region->length = 14;
@@ -364,12 +356,12 @@ static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
static const struct mtd_ooblayout_ops w25n01kv_ooblayout = {
.ecc = w25n01kv_ooblayout_ecc,
- .free = w25n02kv_ooblayout_free,
+ .free = w25nxxkv_kw_ooblayout_free,
};
-static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
- .ecc = w25n02kv_ooblayout_ecc,
- .free = w25n02kv_ooblayout_free,
+static const struct mtd_ooblayout_ops w25nxxkv_kw_ooblayout = {
+ .ecc = w25nxxkv_kw_ooblayout_ecc,
+ .free = w25nxxkv_kw_ooblayout_free,
};
static int w25n08lw_ooblayout_ecc(struct mtd_info *mtd, int section,
@@ -786,7 +778,7 @@ static const struct spinand_info winbond_spinand_table[] = {
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
+ SPINAND_ECCINFO(&w25nxxkv_kw_ooblayout, w25n02kv_ecc_get_status)),
SPINAND_INFO("W25N02KW", /* 1.8V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x22),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
@@ -795,7 +787,7 @@ static const struct spinand_info winbond_spinand_table[] = {
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
+ SPINAND_ECCINFO(&w25nxxkv_kw_ooblayout, w25n02kv_ecc_get_status)),
SPINAND_INFO("W35N02JW", /* 1.8V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22),
NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1),
@@ -818,7 +810,7 @@ static const struct spinand_info winbond_spinand_table[] = {
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
+ SPINAND_ECCINFO(&w25nxxkv_kw_ooblayout, w25n02kv_ecc_get_status)),
SPINAND_INFO("W25N04KW", /* 1.8V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x23),
NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 1, 1, 1),
@@ -827,7 +819,7 @@ static const struct spinand_info winbond_spinand_table[] = {
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
+ SPINAND_ECCINFO(&w25nxxkv_kw_ooblayout, w25n02kv_ecc_get_status)),
SPINAND_INFO("W25N04LW", /* 1.8V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb2, 0x23),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
@@ -836,7 +828,7 @@ static const struct spinand_info winbond_spinand_table[] = {
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&w25n08lw_ooblayout, w25n02kv_ecc_get_status)),
+ SPINAND_ECCINFO(&w25nxxkv_kw_ooblayout, w25n02kv_ecc_get_status)),
SPINAND_INFO("W35N04JW", /* 1.8V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23),
NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1),
--
2.56.0