From: Ahmed Naseef <naseefkm@gmail.com>
Cc: Ahmed Naseef <naseefkm@gmail.com>,
Miquel Raynal <miquel.raynal@bootlin.com>,
Richard Weinberger <richard@nod.at>,
Vignesh Raghavendra <vigneshr@ti.com>,
linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org
Subject: [PATCH v2] mtd: spinand: add support for Dosilicon DS35Q1GA/DS35M1GA
Date: Tue, 9 Dec 2025 11:16:02 +0400 [thread overview]
Message-ID: <20251209071604.36482-1-naseefkm@gmail.com> (raw)
Add support for Dosilicon DS35Q1GA (3.3V) and DS35M1GA (1.8V) SPI NAND.
These are 1Gbit (128MB) devices with:
- 2048 byte pages + 64 byte OOB
- 64 pages per block, 1024 blocks
- On-die 4-bit ECC per 512 byte sector
The 64-byte OOB area is divided into 4 segments of 16 bytes, with each
segment containing 8 bytes of user data (M2+M1) and 8 bytes of ECC
parity (R1). This provides 30 bytes of usable OOB space after reserving
2 bytes for the bad block marker.
Tested on Genexis Platinum 4410 (EcoNet EN751221) by writing known
patterns to OOB and verifying ECC parity placement in R1 regions.
Datasheet:
https://www.dosilicon.com/resources/SPI%20NAND/DS35X1GAXXX_rev08.pdf
Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
---
Changes in v2:
- Rebased on rc1 (updated SPINAND_OP_VARIANTS macros)
- Fixed OOB layout based on hardware testing:
- ECC regions: bytes 8-15, 24-31, 40-47, 56-63 (32 bytes total)
- Free regions: bytes 2-7, 16-23, 32-39, 48-55 (30 bytes total)
- Updated commit message
---
drivers/mtd/nand/spi/Makefile | 4 +-
drivers/mtd/nand/spi/core.c | 1 +
drivers/mtd/nand/spi/dosilicon.c | 91 ++++++++++++++++++++++++++++++++
include/linux/mtd/spinand.h | 1 +
4 files changed, 95 insertions(+), 2 deletions(-)
create mode 100644 drivers/mtd/nand/spi/dosilicon.c
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 6d3d203df..a47bd22cd 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o otp.o
-spinand-objs += alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o
-spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o
+spinand-objs += alliancememory.o ato.o dosilicon.o esmt.o fmsh.o foresee.o gigadevice.o
+spinand-objs += macronix.o micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.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 d20728657..0346916b0 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1227,6 +1227,7 @@ static const struct nand_ops spinand_ops = {
static const struct spinand_manufacturer *spinand_manufacturers[] = {
&alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer,
+ &dosilicon_spinand_manufacturer,
&esmt_8c_spinand_manufacturer,
&esmt_c8_spinand_manufacturer,
&fmsh_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/dosilicon.c b/drivers/mtd/nand/spi/dosilicon.c
new file mode 100644
index 000000000..f99899866
--- /dev/null
+++ b/drivers/mtd/nand/spi/dosilicon.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Ahmed Naseef <naseefkm@gmail.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_DOSILICON 0xE5
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+static int ds35xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 8 + (section * 16);
+ region->length = 8;
+
+ return 0;
+}
+
+static int ds35xx_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ if (section == 0) {
+ /* reserve 2 bytes for the BBM */
+ region->offset = 2;
+ region->length = 6;
+ } else {
+ region->offset = section * 16;
+ region->length = 8;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops ds35xx_ooblayout = {
+ .ecc = ds35xx_ooblayout_ecc,
+ .free = ds35xx_ooblayout_free,
+};
+
+static const struct spinand_info dosilicon_spinand_table[] = {
+ SPINAND_INFO("DS35Q1GA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&ds35xx_ooblayout, NULL)),
+ SPINAND_INFO("DS35M1GA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&ds35xx_ooblayout, NULL)),
+};
+
+static const struct spinand_manufacturer_ops dosilicon_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer dosilicon_spinand_manufacturer = {
+ .id = SPINAND_MFR_DOSILICON,
+ .name = "Dosilicon",
+ .chips = dosilicon_spinand_table,
+ .nchips = ARRAY_SIZE(dosilicon_spinand_table),
+ .ops = &dosilicon_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index ce76f5c63..c50a43b44 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -354,6 +354,7 @@ struct spinand_manufacturer {
/* SPI NAND manufacturers */
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
extern const struct spinand_manufacturer ato_spinand_manufacturer;
+extern const struct spinand_manufacturer dosilicon_spinand_manufacturer;
extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer;
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
--
2.34.1
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
WARNING: multiple messages have this Message-ID (diff)
From: Ahmed Naseef <naseefkm@gmail.com>
Cc: Ahmed Naseef <naseefkm@gmail.com>,
Miquel Raynal <miquel.raynal@bootlin.com>,
Richard Weinberger <richard@nod.at>,
Vignesh Raghavendra <vigneshr@ti.com>,
linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org
Subject: [PATCH v2] mtd: spinand: add support for Dosilicon DS35Q1GA/DS35M1GA
Date: Tue, 9 Dec 2025 11:16:02 +0400 [thread overview]
Message-ID: <20251209071604.36482-1-naseefkm@gmail.com> (raw)
Add support for Dosilicon DS35Q1GA (3.3V) and DS35M1GA (1.8V) SPI NAND.
These are 1Gbit (128MB) devices with:
- 2048 byte pages + 64 byte OOB
- 64 pages per block, 1024 blocks
- On-die 4-bit ECC per 512 byte sector
The 64-byte OOB area is divided into 4 segments of 16 bytes, with each
segment containing 8 bytes of user data (M2+M1) and 8 bytes of ECC
parity (R1). This provides 30 bytes of usable OOB space after reserving
2 bytes for the bad block marker.
Tested on Genexis Platinum 4410 (EcoNet EN751221) by writing known
patterns to OOB and verifying ECC parity placement in R1 regions.
Datasheet:
https://www.dosilicon.com/resources/SPI%20NAND/DS35X1GAXXX_rev08.pdf
Signed-off-by: Ahmed Naseef <naseefkm@gmail.com>
---
Changes in v2:
- Rebased on rc1 (updated SPINAND_OP_VARIANTS macros)
- Fixed OOB layout based on hardware testing:
- ECC regions: bytes 8-15, 24-31, 40-47, 56-63 (32 bytes total)
- Free regions: bytes 2-7, 16-23, 32-39, 48-55 (30 bytes total)
- Updated commit message
---
drivers/mtd/nand/spi/Makefile | 4 +-
drivers/mtd/nand/spi/core.c | 1 +
drivers/mtd/nand/spi/dosilicon.c | 91 ++++++++++++++++++++++++++++++++
include/linux/mtd/spinand.h | 1 +
4 files changed, 95 insertions(+), 2 deletions(-)
create mode 100644 drivers/mtd/nand/spi/dosilicon.c
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 6d3d203df..a47bd22cd 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o otp.o
-spinand-objs += alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o
-spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o
+spinand-objs += alliancememory.o ato.o dosilicon.o esmt.o fmsh.o foresee.o gigadevice.o
+spinand-objs += macronix.o micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.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 d20728657..0346916b0 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1227,6 +1227,7 @@ static const struct nand_ops spinand_ops = {
static const struct spinand_manufacturer *spinand_manufacturers[] = {
&alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer,
+ &dosilicon_spinand_manufacturer,
&esmt_8c_spinand_manufacturer,
&esmt_c8_spinand_manufacturer,
&fmsh_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/dosilicon.c b/drivers/mtd/nand/spi/dosilicon.c
new file mode 100644
index 000000000..f99899866
--- /dev/null
+++ b/drivers/mtd/nand/spi/dosilicon.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Ahmed Naseef <naseefkm@gmail.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_DOSILICON 0xE5
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+static int ds35xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 8 + (section * 16);
+ region->length = 8;
+
+ return 0;
+}
+
+static int ds35xx_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ if (section == 0) {
+ /* reserve 2 bytes for the BBM */
+ region->offset = 2;
+ region->length = 6;
+ } else {
+ region->offset = section * 16;
+ region->length = 8;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops ds35xx_ooblayout = {
+ .ecc = ds35xx_ooblayout_ecc,
+ .free = ds35xx_ooblayout_free,
+};
+
+static const struct spinand_info dosilicon_spinand_table[] = {
+ SPINAND_INFO("DS35Q1GA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&ds35xx_ooblayout, NULL)),
+ SPINAND_INFO("DS35M1GA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&ds35xx_ooblayout, NULL)),
+};
+
+static const struct spinand_manufacturer_ops dosilicon_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer dosilicon_spinand_manufacturer = {
+ .id = SPINAND_MFR_DOSILICON,
+ .name = "Dosilicon",
+ .chips = dosilicon_spinand_table,
+ .nchips = ARRAY_SIZE(dosilicon_spinand_table),
+ .ops = &dosilicon_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index ce76f5c63..c50a43b44 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -354,6 +354,7 @@ struct spinand_manufacturer {
/* SPI NAND manufacturers */
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
extern const struct spinand_manufacturer ato_spinand_manufacturer;
+extern const struct spinand_manufacturer dosilicon_spinand_manufacturer;
extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer;
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
--
2.34.1
next reply other threads:[~2025-12-09 7:16 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-09 7:16 Ahmed Naseef [this message]
2025-12-09 7:16 ` [PATCH v2] mtd: spinand: add support for Dosilicon DS35Q1GA/DS35M1GA Ahmed Naseef
2025-12-09 8:56 ` Miquel Raynal
2025-12-09 8:56 ` Miquel Raynal
2026-01-19 10:12 ` Miquel Raynal
2026-01-19 10:12 ` Miquel Raynal
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251209071604.36482-1-naseefkm@gmail.com \
--to=naseefkm@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=miquel.raynal@bootlin.com \
--cc=richard@nod.at \
--cc=vigneshr@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.