Re: [PATCH 1/2] mtd: spinand: winbond: add support for W25N04LW

Dominique MARTINET <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.drivers.mtd
Message-ID <[email protected]>
Md Sadre Alam wrote on Fri, Aug 07, 2026 at 12:13:38PM +0530:
> Add support for Winbond W25N04LW 4Gbit SPI-NAND.
> It has 8-bit on-die ECC and a 4096+256 byte page
> (4096 byte main area, 128 byte usable OOB once
> on-chip ECC hides the 128 byte parity area),
> organized as 2048 blocks of 64 pages each, unlike
> the existing 2048 byte page W25N04KV/W25N04KW parts.

This is pretty good timing, I was just looking at sending a patch for
W25N04LW myself!

I agree with Miquèl that your patch looks odd, you wrote
> +		     NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
but the erase blocks are 256K long so it should be
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),

did you actually test this device?

If it helps, the datasheet for W25N04LWZExx / W25N04LWTBxx is freely
available from digikey here[1]
[1] https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/7182/W25N04LWZExx_W25N04LWTBxx_RevD_2025-08-05.pdf

(And it also supports continuous read, so I'm curious to see if it'd
work with the recent continous read support from Miquèl[2] merged in
7.2... I'm not familiar with the subsystem so will need a bit of time to
plug all the hooks in properly)
[2] https://lore.kernel.org/linux-mtd/20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com/


FWIW, I've confirmed it works with the following diff (at least up to
the point of creating an ubi volume and booting from it); happy to send
this as a patch if this has indeed not been tested
------------
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 9b78c1e6cbc9..43a4886dc4a5 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -335,6 +335,30 @@ static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
 	return 0;
 }
 
+static int w25n04lw_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	region->offset = 128 + (16 * section);
+	region->length = 13;
+
+	return 0;
+}
+
+static int w25n04lw_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 2;
+	region->length = 14;
+
+	return 0;
+}
+
 static const struct mtd_ooblayout_ops w25n01kv_ooblayout = {
 	.ecc = w25n01kv_ooblayout_ecc,
 	.free = w25n02kv_ooblayout_free,
@@ -345,6 +369,11 @@ static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
 	.free = w25n02kv_ooblayout_free,
 };
 
+static const struct mtd_ooblayout_ops w25n04lw_ooblayout = {
+	.ecc = w25n04lw_ooblayout_ecc,
+	.free = w25n04lw_ooblayout_free,
+};
+
 static int w25n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *region)
 {
@@ -768,6 +797,15 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &update_cache_variants),
 		     0,
 		     SPINAND_ECCINFO(&w25n02kv_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),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&w25n04lw_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),
-----------------

Thanks,
-- 
Dominique Martinet | Asmadeus
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.