public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH 00/28] mtd: spinand: Octal DTR support
@ 2025-10-31 17:26 Miquel Raynal
  2025-10-31 17:26 ` [PATCH 01/28] spi: spi-mem: Make the DTR command operation macro more suitable Miquel Raynal
                   ` (27 more replies)
  0 siblings, 28 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Hello,

This series adds support for 8D-8D-8D in SPI NAND, which can already be
leveraged without any SPI changes as controllers already have this
support for some SPI NOR devices.

The series is a bit long because many preparation patches were needed
in order to have a clean 8D-8D-8D introduction (one of the last
patches), but I believe the split is worth it.

Among the few spi-mem patches, they are needed for building the SPI NAND
changes (especially the ODTR introduction at the end) and therefore an
immutable tag will be needed for merging in the MTD tree (unless all the
series goes through MTD directly ofc).

There is a benchmark in the last Winbond patch, we get +55% read speed
and +26% write speed with this series, at 25MHz!

    1S-8S-8S:
    
       # flash_speed /dev/mtd0 -c1 -d
       eraseblock write speed is 7529 KiB/s
       eraseblock read speed is 15058 KiB/s
    
    8D-8D-8D:
    
       # flash_speed /dev/mtd0 -c1 -d
       eraseblock write speed is 9481 KiB/s
       eraseblock read speed is 23272 KiB/s

I am excited to see this finally upstream! Next step will be to see TI's
PHY tuning series from Santhosh in conjunction with this one to operate at
maximum speed.

Thanks!
Miquèl

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
Miquel Raynal (28):
      spi: spi-mem: Make the DTR command operation macro more suitable
      spi: spi-mem: Create a repeated address operation
      spi: spi-mem: Limit octal DTR constraints to octal DTR situations
      mtd: spinand: Fix kernel doc
      mtd: spinand: Add missing check
      mtd: spinand: Remove stale definitions
      mtd: spinand: Use standard return values
      mtd: spinand: Decouple write enable and write disable operations
      mtd: spinand: Create an array of operation templates
      mtd: spinand: Make use of the operation templates through SPINAND_OP()
      mtd: spinand: Convert vendor drivers to SPINAND_OP()
      mtd: spinand: macronix: Convert vendor specific operation to SPINAND_OP()
      mtd: spinand: winbond: Convert W25N specific operation to SPINAND_OP()
      mtd: spinand: winbond: Convert W35N specific operation to SPINAND_OP()
      mtd: spinand: List vendor specific operations and make sure they are supported
      mtd: spinand: macronix: Register vendor specific operation
      mtd: spinand: winbond: Register W25N vendor specific operation
      mtd: spinand: winbond: Register W35N vendor specific operation
      mtd: spinand: winbond: Fix style
      mtd: spinand: winbond: Rename IO_MODE register macro
      mtd: spinand: winbond: Configure the IO mode after the dummy cycles
      mtd: spinand: Gather all the bus interface steps in one single function
      mtd: spinand: Add support for setting a bus interface
      mtd: spinand: Propagate the bus interface across core helpers
      mtd: spinand: Give the bus interface to the configuration helper
      mtd: spinand: Warn if using SSDR-only vendor commands in a non SSDR mode
      mtd: spinand: Add octal DTR support
      mtd: spinand: winbond: W35N octal DTR support

 drivers/mtd/nand/spi/core.c       | 297 +++++++++++++++++++++++++++++++-------
 drivers/mtd/nand/spi/esmt.c       |   4 +-
 drivers/mtd/nand/spi/gigadevice.c |   8 +-
 drivers/mtd/nand/spi/macronix.c   |  49 ++++++-
 drivers/mtd/nand/spi/micron.c     |   8 +-
 drivers/mtd/nand/spi/toshiba.c    |   3 +-
 drivers/mtd/nand/spi/winbond.c    | 129 ++++++++++++-----
 drivers/spi/spi-mem.c             |  15 +-
 include/linux/mtd/spinand.h       | 246 ++++++++++++++++++++++++++++---
 include/linux/spi/spi-mem.h       |  14 +-
 10 files changed, 646 insertions(+), 127 deletions(-)
---
base-commit: 604a0841a26de188280b47fb7e78dcdaa966a09e
change-id: 20251031-winbond-v6-17-rc1-oddr-385f04684ad9

Best regards,
-- 
Miquel Raynal <miquel.raynal@bootlin.com>


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 01/28] spi: spi-mem: Make the DTR command operation macro more suitable
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 15:35   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 02/28] spi: spi-mem: Create a repeated address operation Miquel Raynal
                   ` (26 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

In order to introduce DTR support in SPI NAND, a number of macros had to
be created in the spi-mem layer. One of them remained unused at this
point, SPI_MEM_DTR_OP_CMD. Being in the process of introducing octal DTR
support now, experience shows that as-is the macro is not useful. In
order to be really useful in octal DTR mode, the command opcode (one
byte) must always be transmitted on the 8 data lines on both the rising
and falling edge of the clock. Align the macro with the real needs by
duplicating the opcode in the buffer and doubling its size.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/spi/spi-mem.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 82390712794c5a4dcef1319c19d74b77b6e1e724..81c9c7e793b6ab894675e0198d412d84b8525c2e 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -20,10 +20,10 @@
 		.opcode = __opcode,				\
 	}
 
-#define SPI_MEM_DTR_OP_CMD(__opcode, __buswidth)		\
+#define SPI_MEM_DTR_OP_RPT_CMD(__opcode, __buswidth)		\
 	{							\
-		.nbytes = 1,					\
-		.opcode = __opcode,				\
+		.nbytes = 2,					\
+		.opcode = __opcode | __opcode << 8,		\
 		.buswidth = __buswidth,				\
 		.dtr = true,					\
 	}

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 02/28] spi: spi-mem: Create a repeated address operation
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
  2025-10-31 17:26 ` [PATCH 01/28] spi: spi-mem: Make the DTR command operation macro more suitable Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 15:43   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 03/28] spi: spi-mem: Limit octal DTR constraints to octal DTR situations Miquel Raynal
                   ` (25 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

In octal DTR mode, while the command opcode is *always* repeated,
addresses may either be long enough to cover at least two bytes (in
which case the existing macro works), or otherwise for single byte
addresses, the byte must also be duplicated and sent twice: on each
front of the clock. Create a macro for this common case.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/spi/spi-mem.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 81c9c7e793b6ab894675e0198d412d84b8525c2e..e4db0924898ce5b17d2b6d4269495bb968db2871 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -43,6 +43,14 @@
 		.dtr = true,					\
 	}
 
+#define SPI_MEM_DTR_OP_RPT_ADDR(__val, __buswidth)		\
+	{							\
+		.nbytes = 2,					\
+		.val = __val | __val << 8,			\
+		.buswidth = __buswidth,				\
+		.dtr = true,					\
+	}
+
 #define SPI_MEM_OP_NO_ADDR	{ }
 
 #define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 03/28] spi: spi-mem: Limit octal DTR constraints to octal DTR situations
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
  2025-10-31 17:26 ` [PATCH 01/28] spi: spi-mem: Make the DTR command operation macro more suitable Miquel Raynal
  2025-10-31 17:26 ` [PATCH 02/28] spi: spi-mem: Create a repeated address operation Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 15:53   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 04/28] mtd: spinand: Fix kernel doc Miquel Raynal
                   ` (24 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

In this helper, any operation with a single DTR cycle (like 1S-1S-8D) is
considered requiring a duplicated command opcode. This is wrong as this
constraint only applies to octal DTR operations (8D-8D-8D).

Narrow the application of this constraint to the concerned bus
interface.

Note: none of the possible XD-XD-XD pattern, with X being one of {1, 2,
4} would benefit from this check either as there is only in octal DTR
mode that a single clock edge would be enough to transmit the full
opcode.

Make sure the constraint of expecting two bytes for the command is
applied to the relevant bus interface.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mem.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 064b99204d9ac4bc233307609defa4fbbaf4534a..71e3eaf59df97cf6d04e6e674810f12d037f384b 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -175,8 +175,19 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
 		if (op->data.swap16 && !spi_mem_controller_is_capable(ctlr, swap16))
 			return false;
 
-		if (op->cmd.nbytes != 2)
-			return false;
+		/* Extra 8D-8D-8D limitations */
+		if (op->cmd.dtr && op->cmd.buswidth == 8) {
+			if (op->cmd.nbytes != 2)
+				return false;
+
+			if ((op->addr.nbytes % 2) ||
+			    (op->dummy.nbytes % 2) ||
+			    (op->data.nbytes % 2)) {
+				dev_err(&ctlr->dev,
+					"Even byte numbers not allowed in octal DTR operations\n");
+				return false;
+			}
+		}
 	} else {
 		if (op->cmd.nbytes != 1)
 			return false;

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 04/28] mtd: spinand: Fix kernel doc
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (2 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 03/28] spi: spi-mem: Limit octal DTR constraints to octal DTR situations Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 15:57   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 05/28] mtd: spinand: Add missing check Miquel Raynal
                   ` (23 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

The @data buffer is 5 bytes, not 4, it has been extended for the need of
devices with an extra ID bytes.

Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs")
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/mtd/spinand.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 927c10d7876958276a841a9f1278a74deeb89944..1c741145e49717169152854718f784e0e519ea92 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -287,7 +287,7 @@ struct spinand_device;
 
 /**
  * struct spinand_id - SPI NAND id structure
- * @data: buffer containing the id bytes. Currently 4 bytes large, but can
+ * @data: buffer containing the id bytes. Currently 5 bytes large, but can
  *	  be extended if required
  * @len: ID length
  */

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 05/28] mtd: spinand: Add missing check
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (3 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 04/28] mtd: spinand: Fix kernel doc Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:04   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 06/28] mtd: spinand: Remove stale definitions Miquel Raynal
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

The update cache variant is mandatory, both read and write versions are
being checked, but not this one. All chip drivers seem to implement this
variant, so there should be no breakage.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
The core has been like that since the begining, I do not think this
patch should be backported, hence no Fixes tag. This barely
qualifies as a fix anyway.
---
 drivers/mtd/nand/spi/core.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index e748fa47ef7bffb7f443b37261d138b35eb4cc7a..9d4e82554dab07b676632155ae94a706cf1177df 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1431,6 +1431,9 @@ int spinand_match_and_init(struct spinand_device *spinand,
 
 		op = spinand_select_op_variant(spinand,
 					       info->op_variants.update_cache);
+		if (!op)
+			return -ENOTSUPP;
+
 		spinand->op_templates.update_cache = op;
 
 		return 0;

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 06/28] mtd: spinand: Remove stale definitions
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (4 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 05/28] mtd: spinand: Add missing check Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:05   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 07/28] mtd: spinand: Use standard return values Miquel Raynal
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

SPI NAND command values are directly included in the macros defining the
ops. These are stale definitions, they are unused so drop them.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/mtd/spinand.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 1c741145e49717169152854718f784e0e519ea92..731a3156b2577032e1f9a767044f94aa262c3ec0 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -232,12 +232,6 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(len, buf, 8))
 
-/**
- * Standard SPI NAND flash commands
- */
-#define SPINAND_CMD_PROG_LOAD_X4		0x32
-#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4	0x34
-
 /* feature register */
 #define REG_BLOCK_LOCK		0xa0
 #define BL_ALL_UNLOCKED		0x00

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 07/28] mtd: spinand: Use standard return values
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (5 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 06/28] mtd: spinand: Remove stale definitions Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:06   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 08/28] mtd: spinand: Decouple write enable and write disable operations Miquel Raynal
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Replace -ENOTSUPP with -EOPNOTSUPP which is as relevant in this case but
is standard.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 9d4e82554dab07b676632155ae94a706cf1177df..e6ff5706a65bdd300ce5945846749afa59b2f12a 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1418,28 +1418,28 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		op = spinand_select_op_variant(spinand,
 					       info->op_variants.read_cache);
 		if (!op)
-			return -ENOTSUPP;
+			return -EOPNOTSUPP;
 
 		spinand->op_templates.read_cache = op;
 
 		op = spinand_select_op_variant(spinand,
 					       info->op_variants.write_cache);
 		if (!op)
-			return -ENOTSUPP;
+			return -EOPNOTSUPP;
 
 		spinand->op_templates.write_cache = op;
 
 		op = spinand_select_op_variant(spinand,
 					       info->op_variants.update_cache);
 		if (!op)
-			return -ENOTSUPP;
+			return -EOPNOTSUPP;
 
 		spinand->op_templates.update_cache = op;
 
 		return 0;
 	}
 
-	return -ENOTSUPP;
+	return -EOPNOTSUPP;
 }
 
 static int spinand_detect(struct spinand_device *spinand)

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 08/28] mtd: spinand: Decouple write enable and write disable operations
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (6 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 07/28] mtd: spinand: Use standard return values Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:08   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 09/28] mtd: spinand: Create an array of operation templates Miquel Raynal
                   ` (19 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

In order to introduce templates for all operations and not only for page
helpers (in order to introduce octal DDR support), decouple the WR_EN
and WR_DIS operations into two separate macros.

Adapt the callers accordingly.

There is no functional change.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c   |  2 +-
 drivers/mtd/nand/spi/esmt.c   |  2 +-
 drivers/mtd/nand/spi/micron.c |  2 +-
 include/linux/mtd/spinand.h   | 10 ++++++++--
 4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index e6ff5706a65bdd300ce5945846749afa59b2f12a..d215cefcba3f37057a2ba036d86ae6638885a7f3 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -362,7 +362,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
 
 int spinand_write_enable_op(struct spinand_device *spinand)
 {
-	struct spi_mem_op op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
+	struct spi_mem_op op = SPINAND_WR_EN_1S_0_0_OP;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c
index 9a9325c0bc49726b0421d77680684ae07560bf2e..f880c3b15ceab14676ab65f3d9e8530c713528c8 100644
--- a/drivers/mtd/nand/spi/esmt.c
+++ b/drivers/mtd/nand/spi/esmt.c
@@ -137,7 +137,7 @@ static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len,
 static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from,
 			       size_t len)
 {
-	struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
+	struct spi_mem_op write_op = SPINAND_WR_EN_1S_0_0_OP;
 	struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
 	u8 status;
 	int ret;
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index a49d7cb6a96da701ee981e677f414c57eabb2cec..b8130e04e8e798519ad38c58b5569935c1a447a2 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -251,7 +251,7 @@ static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand,
 static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from,
 				   size_t len)
 {
-	struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
+	struct spi_mem_op write_op = SPINAND_WR_EN_1S_0_0_OP;
 	struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
 	u8 status;
 	int ret;
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 731a3156b2577032e1f9a767044f94aa262c3ec0..8c490a03b2e000bc18d692d72cfd20b151db023c 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -26,8 +26,14 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
-#define SPINAND_WR_EN_DIS_1S_0_0_OP(enable)					\
-	SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1),		\
+#define SPINAND_WR_EN_1S_0_0_OP						\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x06, 1),				\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_WR_DIS_1S_0_0_OP					\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x04, 1),				\
 		   SPI_MEM_OP_NO_ADDR,					\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 09/28] mtd: spinand: Create an array of operation templates
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (7 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 08/28] mtd: spinand: Decouple write enable and write disable operations Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:17   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP() Miquel Raynal
                   ` (18 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Currently, the SPI NAND core implementation directly calls macros to get
the various operations in shape. These macros are specific to the bus
interface, currently only supporting the single SDR interface (any
command following the 1S-XX-XX pattern).

Introducing support for other bus interfaces (such as octal DTR) would
mean that every user of these macros should become aware of the current
bus interface and act accordingly, picking up and adapting to the
current configuration. This would add quite a bit of boilerplate, be
repetitive as well as error prone in case we miss one occurrence.

Instead, let's create a table with all SPI NAND memory operations that
are currently supported. We initialize them with the same single SDR _OP
macros as before. This opens the possibility for users of the individual
macros to make use of these templates instead. This way, when we will add
another bus interface, we can just switch to another set of templates
and all users will magically fill in their spi_mem_op structures with
the correct ops.

The existing read, write and update cache variants are also moved in
this template array, which is barely noticeable by callers as we also
add a structure member pointing to it.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c    | 38 +++++++++++++++++++++++++++----------
 drivers/mtd/nand/spi/winbond.c |  4 ++--
 include/linux/mtd/spinand.h    | 43 +++++++++++++++++++++++++++++++++---------
 3 files changed, 64 insertions(+), 21 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index d215cefcba3f37057a2ba036d86ae6638885a7f3..11d3b28a14339282360a5ef12be715e532105e73 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -184,9 +184,9 @@ static int spinand_init_quad_enable(struct spinand_device *spinand)
 	if (!(spinand->flags & SPINAND_HAS_QE_BIT))
 		return 0;
 
-	if (spinand->op_templates.read_cache->data.buswidth == 4 ||
-	    spinand->op_templates.write_cache->data.buswidth == 4 ||
-	    spinand->op_templates.update_cache->data.buswidth == 4)
+	if (spinand->op_templates->read_cache->data.buswidth == 4 ||
+	    spinand->op_templates->write_cache->data.buswidth == 4 ||
+	    spinand->op_templates->update_cache->data.buswidth == 4)
 		enable = true;
 
 	return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE,
@@ -1154,7 +1154,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 	info.offset = plane << fls(nand->memorg.pagesize);
 
 	info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
-	info.op_tmpl = *spinand->op_templates.update_cache;
+	info.op_tmpl = *spinand->op_templates->update_cache;
 	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
 					  spinand->spimem, &info);
 	if (IS_ERR(desc))
@@ -1162,7 +1162,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 
 	spinand->dirmaps[plane].wdesc = desc;
 
-	info.op_tmpl = *spinand->op_templates.read_cache;
+	info.op_tmpl = *spinand->op_templates->read_cache;
 	desc = spinand_create_rdesc(spinand, &info);
 	if (IS_ERR(desc))
 		return PTR_ERR(desc);
@@ -1177,7 +1177,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 	}
 
 	info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
-	info.op_tmpl = *spinand->op_templates.update_cache;
+	info.op_tmpl = *spinand->op_templates->update_cache;
 	info.op_tmpl.data.ecc = true;
 	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
 					  spinand->spimem, &info);
@@ -1186,7 +1186,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 
 	spinand->dirmaps[plane].wdesc_ecc = desc;
 
-	info.op_tmpl = *spinand->op_templates.read_cache;
+	info.op_tmpl = *spinand->op_templates->read_cache;
 	info.op_tmpl.data.ecc = true;
 	desc = spinand_create_rdesc(spinand, &info);
 	if (IS_ERR(desc))
@@ -1322,6 +1322,22 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand)
 		return spinand->manufacturer->ops->cleanup(spinand);
 }
 
+static void spinand_init_ssdr_templates(struct spinand_device *spinand)
+{
+	struct spinand_mem_ops *tmpl = &spinand->ssdr_op_templates;
+
+	tmpl->reset = (struct spi_mem_op)SPINAND_RESET_1S_0_0_OP;
+	tmpl->readid = (struct spi_mem_op)SPINAND_READID_1S_1S_1S_OP(0, 0, NULL, 0);
+	tmpl->wr_en = (struct spi_mem_op)SPINAND_WR_EN_1S_0_0_OP;
+	tmpl->wr_dis = (struct spi_mem_op)SPINAND_WR_DIS_1S_0_0_OP;
+	tmpl->set_feature = (struct spi_mem_op)SPINAND_SET_FEATURE_1S_1S_1S_OP(0, NULL);
+	tmpl->get_feature = (struct spi_mem_op)SPINAND_GET_FEATURE_1S_1S_1S_OP(0, NULL);
+	tmpl->blk_erase = (struct spi_mem_op)SPINAND_BLK_ERASE_1S_1S_0_OP(0);
+	tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_1S_1S_0_OP(0);
+	tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_1S_1S_0_OP(0);
+	spinand->op_templates = &spinand->ssdr_op_templates;
+}
+
 static const struct spi_mem_op *
 spinand_select_op_variant(struct spinand_device *spinand,
 			  const struct spinand_op_variants *variants)
@@ -1420,21 +1436,21 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		if (!op)
 			return -EOPNOTSUPP;
 
-		spinand->op_templates.read_cache = op;
+		spinand->ssdr_op_templates.read_cache = op;
 
 		op = spinand_select_op_variant(spinand,
 					       info->op_variants.write_cache);
 		if (!op)
 			return -EOPNOTSUPP;
 
-		spinand->op_templates.write_cache = op;
+		spinand->ssdr_op_templates.write_cache = op;
 
 		op = spinand_select_op_variant(spinand,
 					       info->op_variants.update_cache);
 		if (!op)
 			return -EOPNOTSUPP;
 
-		spinand->op_templates.update_cache = op;
+		spinand->ssdr_op_templates.update_cache = op;
 
 		return 0;
 	}
@@ -1549,6 +1565,8 @@ static int spinand_init(struct spinand_device *spinand)
 	if (!spinand->scratchbuf)
 		return -ENOMEM;
 
+	spinand_init_ssdr_templates(spinand);
+
 	ret = spinand_detect(spinand);
 	if (ret)
 		goto err_free_bufs;
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 4870b2d5edb2a1f8081b87bbe9de549c73272d7c..d5799c2df06520de6cb5c5b771ceeb9d11ddf1fb 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -291,7 +291,7 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
 	u8 sr4;
 	int ret;
 
-	op = spinand->op_templates.read_cache;
+	op = spinand->op_templates->read_cache;
 	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
 		hs = false;
 	else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 &&
@@ -355,7 +355,7 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
 	u8 io_mode;
 	int ret;
 
-	op = spinand->op_templates.read_cache;
+	op = spinand->op_templates->read_cache;
 
 	single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
 	dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr);
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 8c490a03b2e000bc18d692d72cfd20b151db023c..4afebaf5f0195b9bc617ea1f125f637f76fff9f8 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -598,6 +598,36 @@ struct spinand_dirmap {
 	struct spi_mem_dirmap_desc *rdesc_ecc;
 };
 
+/**
+ * struct spinand_mem_ops - SPI NAND memory operations
+ * @reset: reset op template
+ * @readid: read ID op template
+ * @wr_en: write enable op template
+ * @wr_dis: write disable op template
+ * @set_feature: set feature op template
+ * @get_feature: get feature op template
+ * @blk_erase: blk erase op template
+ * @page_read: page read op template
+ * @prog_exec: prog exec op template
+ * @read_cache: read cache op template
+ * @write_cache: write cache op template
+ * @update_cache: update cache op template
+ */
+struct spinand_mem_ops {
+	struct spi_mem_op reset;
+	struct spi_mem_op readid;
+	struct spi_mem_op wr_en;
+	struct spi_mem_op wr_dis;
+	struct spi_mem_op set_feature;
+	struct spi_mem_op get_feature;
+	struct spi_mem_op blk_erase;
+	struct spi_mem_op page_read;
+	struct spi_mem_op prog_exec;
+	const struct spi_mem_op *read_cache;
+	const struct spi_mem_op *write_cache;
+	const struct spi_mem_op *update_cache;
+};
+
 /**
  * struct spinand_device - SPI NAND device instance
  * @base: NAND device instance
@@ -605,10 +635,8 @@ struct spinand_dirmap {
  * @lock: lock used to serialize accesses to the NAND
  * @id: NAND ID as returned by READ_ID
  * @flags: NAND flags
- * @op_templates: various SPI mem op templates
- * @op_templates.read_cache: read cache op template
- * @op_templates.write_cache: write cache op template
- * @op_templates.update_cache: update cache op template
+ * @ssdr_op_templates: Templates for all single SDR SPI mem operations
+ * @op_templates: Templates for all SPI mem operations
  * @select_target: select a specific target/die. Usually called before sending
  *		   a command addressing a page or an eraseblock embedded in
  *		   this die. Only required if your chip exposes several dies
@@ -642,11 +670,8 @@ struct spinand_device {
 	struct spinand_id id;
 	u32 flags;
 
-	struct {
-		const struct spi_mem_op *read_cache;
-		const struct spi_mem_op *write_cache;
-		const struct spi_mem_op *update_cache;
-	} op_templates;
+	struct spinand_mem_ops ssdr_op_templates;
+	struct spinand_mem_ops *op_templates;
 
 	struct spinand_dirmap *dirmaps;
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP()
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (8 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 09/28] mtd: spinand: Create an array of operation templates Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:28   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 11/28] mtd: spinand: Convert vendor drivers to SPINAND_OP() Miquel Raynal
                   ` (17 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Create a SPINAND_OP() macro to which we give the name of the operation
we want. This macro retrieves the correct operation template based on
the current bus interface (currently only single SDR, will soon be
extended to octal DTR) and fills it with the usual parameters.

This macro makes the transition from calling directly the low-level
macros into using the (bus interface dependent) templates very smooth.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c    | 26 ++++++-------
 drivers/mtd/nand/spi/winbond.c |  3 +-
 include/linux/mtd/spinand.h    | 87 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 11d3b28a14339282360a5ef12be715e532105e73..d4f46a17f77e15ac0ab26397e88d37119636b003 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -22,8 +22,8 @@
 
 int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
 {
-	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(reg,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
+					  reg, spinand->scratchbuf);
 	int ret;
 
 	ret = spi_mem_exec_op(spinand->spimem, &op);
@@ -36,8 +36,8 @@ int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
 
 int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
 {
-	struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(reg,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, set_feature,
+					  reg, spinand->scratchbuf);
 
 	*spinand->scratchbuf = val;
 	return spi_mem_exec_op(spinand->spimem, &op);
@@ -362,7 +362,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
 
 int spinand_write_enable_op(struct spinand_device *spinand)
 {
-	struct spi_mem_op op = SPINAND_WR_EN_1S_0_0_OP;
+	struct spi_mem_op op = SPINAND_OP(spinand, wr_en);
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -372,7 +372,7 @@ static int spinand_load_page_op(struct spinand_device *spinand,
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	unsigned int row = nanddev_pos_to_row(nand, &req->pos);
-	struct spi_mem_op op = SPINAND_PAGE_READ_1S_1S_0_OP(row);
+	struct spi_mem_op op = SPINAND_OP(spinand, page_read, row);
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -527,7 +527,7 @@ static int spinand_program_op(struct spinand_device *spinand,
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	unsigned int row = nanddev_pos_to_row(nand, &req->pos);
-	struct spi_mem_op op = SPINAND_PROG_EXEC_1S_1S_0_OP(row);
+	struct spi_mem_op op = SPINAND_OP(spinand, prog_exec, row);
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -537,7 +537,7 @@ static int spinand_erase_op(struct spinand_device *spinand,
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	unsigned int row = nanddev_pos_to_row(nand, pos);
-	struct spi_mem_op op = SPINAND_BLK_ERASE_1S_1S_0_OP(row);
+	struct spi_mem_op op = SPINAND_OP(spinand, blk_erase, row);
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -557,8 +557,8 @@ static int spinand_erase_op(struct spinand_device *spinand,
 int spinand_wait(struct spinand_device *spinand, unsigned long initial_delay_us,
 		 unsigned long poll_delay_us, u8 *s)
 {
-	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(REG_STATUS,
-							       spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
+					  REG_STATUS, spinand->scratchbuf);
 	u8 status;
 	int ret;
 
@@ -591,8 +591,8 @@ int spinand_wait(struct spinand_device *spinand, unsigned long initial_delay_us,
 static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
 			      u8 ndummy, u8 *buf)
 {
-	struct spi_mem_op op = SPINAND_READID_1S_1S_1S_OP(
-		naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
+	struct spi_mem_op op = SPINAND_OP(spinand, readid,
+					  naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
 	int ret;
 
 	ret = spi_mem_exec_op(spinand->spimem, &op);
@@ -604,7 +604,7 @@ static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
 
 static int spinand_reset_op(struct spinand_device *spinand)
 {
-	struct spi_mem_op op = SPINAND_RESET_1S_0_0_OP;
+	struct spi_mem_op op = SPINAND_OP(spinand, reset);
 	int ret;
 
 	ret = spi_mem_exec_op(spinand->spimem, &op);
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index d5799c2df06520de6cb5c5b771ceeb9d11ddf1fb..bfec5d037f25b81a3c90feba666fe8283a41ddb1 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -251,7 +251,8 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	u8 mbf = 0;
-	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
+					  0x30, spinand->scratchbuf);
 
 	switch (status & STATUS_ECC_MASK) {
 	case STATUS_ECC_NO_BITFLIPS:
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 4afebaf5f0195b9bc617ea1f125f637f76fff9f8..a8fd04a67cfa9925bd68c57539d86e0816b76274 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -701,6 +701,93 @@ struct spinand_device {
 			     unsigned int retry_mode);
 };
 
+static inline struct spi_mem_op
+spinand_fill_reset_op(struct spinand_device *spinand)
+{
+	return spinand->op_templates->reset;
+}
+
+static inline struct spi_mem_op
+spinand_fill_readid_op(struct spinand_device *spinand,
+		       u8 naddr, u8 ndummy, void *buf, unsigned int len)
+{
+	struct spi_mem_op op = spinand->op_templates->readid;
+
+	op.addr.nbytes = naddr;
+	op.dummy.nbytes = ndummy;
+	op.data.buf.in = buf;
+	op.data.nbytes = len;
+
+	return op;
+}
+
+static inline struct spi_mem_op
+spinand_fill_wr_en_op(struct spinand_device *spinand)
+{
+	return spinand->op_templates->wr_en;
+}
+
+static inline struct spi_mem_op
+spinand_fill_wr_dis_op(struct spinand_device *spinand)
+{
+	return spinand->op_templates->wr_dis;
+}
+
+static inline struct spi_mem_op
+spinand_fill_set_feature_op(struct spinand_device *spinand, u64 reg, const void *valptr)
+{
+	struct spi_mem_op op = spinand->op_templates->set_feature;
+
+	op.addr.val = reg;
+	op.data.buf.out = valptr;
+
+	return op;
+}
+
+static inline struct spi_mem_op
+spinand_fill_get_feature_op(struct spinand_device *spinand, u64 reg, void *valptr)
+{
+	struct spi_mem_op op = spinand->op_templates->get_feature;
+
+	op.addr.val = reg;
+	op.data.buf.in = valptr;
+
+	return op;
+}
+
+static inline struct spi_mem_op
+spinand_fill_blk_erase_op(struct spinand_device *spinand, u64 addr)
+{
+	struct spi_mem_op op = spinand->op_templates->blk_erase;
+
+	op.addr.val = addr;
+
+	return op;
+}
+
+static inline struct spi_mem_op
+spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr)
+{
+	struct spi_mem_op op = spinand->op_templates->page_read;
+
+	op.addr.val = addr;
+
+	return op;
+}
+
+static inline struct spi_mem_op
+spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr)
+{
+	struct spi_mem_op op = spinand->op_templates->prog_exec;
+
+	op.addr.val = addr;
+
+	return op;
+}
+
+#define SPINAND_OP(spinand, op_name, ...)			\
+	spinand_fill_ ## op_name ## _op(spinand, ##__VA_ARGS__)
+
 /**
  * mtd_to_spinand() - Get the SPI NAND device attached to an MTD instance
  * @mtd: MTD instance

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 11/28] mtd: spinand: Convert vendor drivers to SPINAND_OP()
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (9 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP() Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:30   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 12/28] mtd: spinand: macronix: Convert vendor specific operation " Miquel Raynal
                   ` (16 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

This macro allows to silently switch bus interfaces, use it outside of
the core in all places that can be trivially converted.

At this stage there is no functional change expected, until octal DTR
support gets added.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/esmt.c       | 4 ++--
 drivers/mtd/nand/spi/gigadevice.c | 8 ++++----
 drivers/mtd/nand/spi/macronix.c   | 4 ++--
 drivers/mtd/nand/spi/micron.c     | 8 ++++----
 drivers/mtd/nand/spi/toshiba.c    | 3 ++-
 5 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c
index f880c3b15ceab14676ab65f3d9e8530c713528c8..ba95e589e12fb4d934a0cd3746c7b286897ffe92 100644
--- a/drivers/mtd/nand/spi/esmt.c
+++ b/drivers/mtd/nand/spi/esmt.c
@@ -137,8 +137,8 @@ static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len,
 static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from,
 			       size_t len)
 {
-	struct spi_mem_op write_op = SPINAND_WR_EN_1S_0_0_OP;
-	struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
+	struct spi_mem_op write_op = SPINAND_OP(spinand, wr_en);
+	struct spi_mem_op exec_op = SPINAND_OP(spinand, prog_exec, 0);
 	u8 status;
 	int ret;
 
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index 72ad36c9a12693caf863b0d172d4a1f2ac4d5ecd..e4380208edd09445c44a29bb7dd2012a0bb1a1b0 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -266,8 +266,8 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
 					u8 status)
 {
 	u8 status2;
-	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
+					  GD5FXGQXXEXXG_REG_STATUS2, spinand->scratchbuf);
 	int ret;
 
 	switch (status & STATUS_ECC_MASK) {
@@ -309,8 +309,8 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
 					u8 status)
 {
 	u8 status2;
-	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
+					  GD5FXGQXXEXXG_REG_STATUS2, spinand->scratchbuf);
 	int ret;
 
 	switch (status & STATUS_ECC_MASK) {
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index edf63b9996cf029fffa4948566c7afda77d97cee..143cc120bdec1300f8fe60e951c4da9174668677 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -148,8 +148,8 @@ static int macronix_set_cont_read(struct spinand_device *spinand, bool enable)
 static int macronix_set_read_retry(struct spinand_device *spinand,
 					     unsigned int retry_mode)
 {
-	struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MACRONIX_FEATURE_ADDR_READ_RETRY,
-							       spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, set_feature,
+					  MACRONIX_FEATURE_ADDR_READ_RETRY, spinand->scratchbuf);
 
 	*spinand->scratchbuf = retry_mode;
 	return spi_mem_exec_op(spinand->spimem, &op);
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index b8130e04e8e798519ad38c58b5569935c1a447a2..36f6cbbd7462c0c5c208a28acae6e64e1af954da 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -137,8 +137,8 @@ static const struct mtd_ooblayout_ops micron_4_ooblayout = {
 static int micron_select_target(struct spinand_device *spinand,
 				unsigned int target)
 {
-	struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MICRON_DIE_SELECT_REG,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, set_feature,
+					  MICRON_DIE_SELECT_REG, spinand->scratchbuf);
 
 	if (target > 1)
 		return -EINVAL;
@@ -251,8 +251,8 @@ static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand,
 static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from,
 				   size_t len)
 {
-	struct spi_mem_op write_op = SPINAND_WR_EN_1S_0_0_OP;
-	struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
+	struct spi_mem_op write_op = SPINAND_OP(spinand, wr_en);
+	struct spi_mem_op exec_op = SPINAND_OP(spinand, prog_exec, 0);
 	u8 status;
 	int ret;
 
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index 6530257ac0beddf8b9e5a9591c5f5ccc4803c003..ef649162ee680c2d7db9dc9332e705265bc8f234 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -73,7 +73,8 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	u8 mbf = 0;
-	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
+	struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
+					  0x30, spinand->scratchbuf);
 
 	switch (status & STATUS_ECC_MASK) {
 	case STATUS_ECC_NO_BITFLIPS:

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 12/28] mtd: spinand: macronix: Convert vendor specific operation to SPINAND_OP()
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (10 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 11/28] mtd: spinand: Convert vendor drivers to SPINAND_OP() Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:40   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 13/28] mtd: spinand: winbond: Convert W25N " Miquel Raynal
                   ` (15 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Macronix chips require a vendor specific operation to read the ECC
status register. Instead of defining this op only in the function that
needs it, hiding it from the core, make it a proper define like all
other spi-mem operations, and implement the necessary
spinand_fill_*_op() helper to make the SPINAND_OP() macro work. This way
we can use it from any function without any extra handling outside of
this helper when we will convert the core to support octal DDR busses.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/macronix.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 143cc120bdec1300f8fe60e951c4da9174668677..a847ea8f49a8a7005405f6083a4aaac942974998 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -41,6 +41,18 @@ 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));
 
+#define SPINAND_MACRONIX_READ_ECCSR_1S_0_1S(buf)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),				\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_DUMMY(1, 1),				\
+		   SPI_MEM_OP_DATA_IN(1, buf, 1))
+
+static struct spi_mem_op
+spinand_fill_macronix_read_eccsr_op(struct spinand_device *spinand, void *valptr)
+{
+	return (struct spi_mem_op)SPINAND_MACRONIX_READ_ECCSR_1S_0_1S(valptr);
+}
+
 static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
 				      struct mtd_oob_region *region)
 {
@@ -67,12 +79,10 @@ static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
 static int macronix_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
 {
 	struct macronix_priv *priv = spinand->priv;
-	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
-					  SPI_MEM_OP_NO_ADDR,
-					  SPI_MEM_OP_DUMMY(1, 1),
-					  SPI_MEM_OP_DATA_IN(1, eccsr, 1));
+	struct spi_mem_op op = SPINAND_OP(spinand, macronix_read_eccsr, eccsr);
+	int ret;
 
-	int ret = spi_mem_exec_op(spinand->spimem, &op);
+	ret = spi_mem_exec_op(spinand->spimem, &op);
 	if (ret)
 		return ret;
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 13/28] mtd: spinand: winbond: Convert W25N specific operation to SPINAND_OP()
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (11 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 12/28] mtd: spinand: macronix: Convert vendor specific operation " Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:40   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 14/28] mtd: spinand: winbond: Convert W35N " Miquel Raynal
                   ` (14 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Winbond W25N* chips require a vendor specific operation to select the
target. Instead of defining this op only in the function that
needs it, hiding it from the core, make it a proper define like all
other spi-mem operations, and implement the necessary
spinand_fill_*_op() helper to make the SPINAND_OP() macro work. This way
we can use it from any function without any extra handling outside of
this helper when we will convert the core to support octal DDR busses.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index bfec5d037f25b81a3c90feba666fe8283a41ddb1..dde59f8f63f511a298a43a5b43fe07c1d726f179 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -87,6 +87,18 @@ 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));
 
+#define SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(buf)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),				\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT(1, buf, 1))
+
+static struct spi_mem_op
+spinand_fill_winbond_select_target_op(struct spinand_device *spinand, void *valptr)
+{
+	return (struct spi_mem_op)SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(valptr);
+}
+
 static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *region)
 {
@@ -119,12 +131,8 @@ static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
 static int w25m02gv_select_target(struct spinand_device *spinand,
 				  unsigned int target)
 {
-	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),
-					  SPI_MEM_OP_NO_ADDR,
-					  SPI_MEM_OP_NO_DUMMY,
-					  SPI_MEM_OP_DATA_OUT(1,
-							spinand->scratchbuf,
-							1));
+	struct spi_mem_op op = SPINAND_OP(spinand, winbond_select_target,
+					  spinand->scratchbuf);
 
 	*spinand->scratchbuf = target;
 	return spi_mem_exec_op(spinand->spimem, &op);

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 14/28] mtd: spinand: winbond: Convert W35N specific operation to SPINAND_OP()
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (12 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 13/28] mtd: spinand: winbond: Convert W25N " Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-11-05 16:41   ` Tudor Ambarus
  2025-10-31 17:26 ` [PATCH 15/28] mtd: spinand: List vendor specific operations and make sure they are supported Miquel Raynal
                   ` (13 subsequent siblings)
  27 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Winbond W35N* chips require a vendor specific operation to write their
VCR register (a configuration register, typically used for tuning the
number of dummy cycles and switching to a different bus
interface). Instead of defining this op only in the function that needs
it, hiding it from the core, make it a proper define like all other
spi-mem operations, and implement the necessary spinand_fill_*_op()
helper to make the SPINAND_OP() macro work. This way we can use it from
any function without any extra handling outside of this helper when we
will convert the core to support octal DDR busses.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index dde59f8f63f511a298a43a5b43fe07c1d726f179..3003ad7e83ee8f553ec82a0326422916c0ed794c 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -87,6 +87,18 @@ 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));
 
+#define SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(reg, buf)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD(0x81, 1),				\
+		   SPI_MEM_OP_ADDR(3, reg, 1),				\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT(1, buf, 1))
+
+static struct spi_mem_op
+spinand_fill_winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, void *valptr)
+{
+	return (struct spi_mem_op)SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(reg, valptr);
+}
+
 #define SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(buf)			\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),				\
 		   SPI_MEM_OP_NO_ADDR,					\
@@ -329,11 +341,8 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
 
 static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val)
 {
-	struct spi_mem_op op =
-		SPI_MEM_OP(SPI_MEM_OP_CMD(0x81, 1),
-			   SPI_MEM_OP_ADDR(3, reg, 1),
-			   SPI_MEM_OP_NO_DUMMY,
-			   SPI_MEM_OP_DATA_OUT(1, spinand->scratchbuf, 1));
+	struct spi_mem_op op = SPINAND_OP(spinand, winbond_write_vcr,
+					  reg, spinand->scratchbuf);
 	int ret;
 
 	*spinand->scratchbuf = val;

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 15/28] mtd: spinand: List vendor specific operations and make sure they are supported
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (13 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 14/28] mtd: spinand: winbond: Convert W35N " Miquel Raynal
@ 2025-10-31 17:26 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 16/28] mtd: spinand: macronix: Register vendor specific operation Miquel Raynal
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:26 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

It is probably safe to expect that all SPI controller drivers will ever
support all the most basic SPI NAND operations, such as write enable,
register reads, page program, block erases, etc. However, what about
vendor specific operations? So far nobody complained about it, but as we
are about to introduce octal DTR support, and as none of the SPI NAND
instruction set is defined in any standard, we must remain careful about
these extra operations.

One way to make sure we do not blindly get ourselves in strange
situations with vendor commands failing silently is to make the check
once for all, while probing the chip. However at this stage we have no
such list, so let's add the necessary infrastructure to allow:
- registering vendor operations,
- checking they are actually supported when appropriate.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 26 ++++++++++++++++++++++++++
 include/linux/mtd/spinand.h |  5 +++++
 2 files changed, 31 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index d4f46a17f77e15ac0ab26397e88d37119636b003..7c01516c6b6acb41d2cc080d6fbaaa5ace661602 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1338,6 +1338,27 @@ static void spinand_init_ssdr_templates(struct spinand_device *spinand)
 	spinand->op_templates = &spinand->ssdr_op_templates;
 }
 
+static int spinand_support_vendor_ops(struct spinand_device *spinand,
+				      const struct spinand_info *info)
+{
+	int i;
+
+	/*
+	 * The vendor ops array is only used in order to verify this chip and all its memory
+	 * operations are supported. If we see patterns emerging, we could ideally name these
+	 * operations and define them at the SPI NAND core level instead.
+	 * For now, this only serves as a sanity check.
+	 */
+	for (i = 0; i < info->vendor_ops->nops; i++) {
+		const struct spi_mem_op *op = &info->vendor_ops->ops[i];
+
+		if (!spi_mem_supports_op(spinand->spimem, op))
+			return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static const struct spi_mem_op *
 spinand_select_op_variant(struct spinand_device *spinand,
 			  const struct spinand_op_variants *variants)
@@ -1407,6 +1428,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
 	u8 *id = spinand->id.data;
 	struct nand_device *nand = spinand_to_nand(spinand);
 	unsigned int i;
+	int ret;
 
 	for (i = 0; i < table_size; i++) {
 		const struct spinand_info *info = &table[i];
@@ -1452,6 +1474,10 @@ int spinand_match_and_init(struct spinand_device *spinand,
 
 		spinand->ssdr_op_templates.update_cache = op;
 
+		ret = spinand_support_vendor_ops(spinand, info);
+		if (ret)
+			return ret;
+
 		return 0;
 	}
 
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index a8fd04a67cfa9925bd68c57539d86e0816b76274..0565cdeb3f7b652699d420a8c05c3fe53fcc2253 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -492,6 +492,7 @@ struct spinand_user_otp {
  * @op_variants.read_cache: variants of the read-cache operation
  * @op_variants.write_cache: variants of the write-cache operation
  * @op_variants.update_cache: variants of the update-cache operation
+ * @vendor_ops: vendor specific operations
  * @select_target: function used to select a target/die. Required only for
  *		   multi-die chips
  * @configure_chip: Align the chip configuration with the core settings
@@ -516,6 +517,7 @@ struct spinand_info {
 		const struct spinand_op_variants *write_cache;
 		const struct spinand_op_variants *update_cache;
 	} op_variants;
+	const struct spinand_op_variants *vendor_ops;
 	int (*select_target)(struct spinand_device *spinand,
 			     unsigned int target);
 	int (*configure_chip)(struct spinand_device *spinand);
@@ -542,6 +544,9 @@ struct spinand_info {
 		.update_cache = __update,				\
 	}
 
+#define SPINAND_INFO_VENDOR_OPS(__ops)					\
+	.vendor_ops = __ops
+
 #define SPINAND_ECCINFO(__ooblayout, __get_status)			\
 	.eccinfo = {							\
 		.ooblayout = __ooblayout,				\

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 16/28] mtd: spinand: macronix: Register vendor specific operation
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (14 preceding siblings ...)
  2025-10-31 17:26 ` [PATCH 15/28] mtd: spinand: List vendor specific operations and make sure they are supported Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 17/28] mtd: spinand: winbond: Register W25N " Miquel Raynal
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Provide the Macronix specific "read ECC status register" operation so
that the core can verify if it is supported by the controller before
using it.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/macronix.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index a847ea8f49a8a7005405f6083a4aaac942974998..6b7cbcc6e2872d3369b8eb765dede05c7299c896 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -47,6 +47,9 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
 		   SPI_MEM_OP_DUMMY(1, 1),				\
 		   SPI_MEM_OP_DATA_IN(1, buf, 1))
 
+static SPINAND_OP_VARIANTS(macronix_ops,
+		SPINAND_MACRONIX_READ_ECCSR_1S_0_1S(NULL));
+
 static struct spi_mem_op
 spinand_fill_macronix_read_eccsr_op(struct spinand_device *spinand, void *valptr)
 {
@@ -174,6 +177,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 	SPINAND_INFO("MX35LF2GE4AB",
@@ -195,6 +199,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_CONT_READ(macronix_set_cont_read),
@@ -208,6 +213,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_CONT_READ(macronix_set_cont_read),
@@ -278,6 +284,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 	SPINAND_INFO("MX31UF1GE4BC",
@@ -288,6 +295,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 
@@ -301,6 +309,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT |
 		     SPINAND_HAS_PROG_PLANE_SELECT_BIT |
 		     SPINAND_HAS_READ_PLANE_SELECT_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 	SPINAND_INFO("MX35UF4G24AD",
@@ -312,6 +321,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT |
 		     SPINAND_HAS_PROG_PLANE_SELECT_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
@@ -324,6 +334,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
@@ -336,6 +347,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_CONT_READ(macronix_set_cont_read),
@@ -351,6 +363,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 		     SPINAND_HAS_QE_BIT |
 		     SPINAND_HAS_PROG_PLANE_SELECT_BIT |
 		     SPINAND_HAS_READ_PLANE_SELECT_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 	SPINAND_INFO("MX35UF2G24AD",
@@ -362,6 +375,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT |
 		     SPINAND_HAS_PROG_PLANE_SELECT_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
@@ -374,6 +388,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
@@ -386,6 +401,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_CONT_READ(macronix_set_cont_read),
@@ -399,6 +415,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_CONT_READ(macronix_set_cont_read)),
@@ -410,6 +427,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 	SPINAND_INFO("MX35UF1G24AD",
@@ -420,6 +438,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
@@ -432,6 +451,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_CONT_READ(macronix_set_cont_read),
@@ -445,6 +465,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status),
 		     SPINAND_CONT_READ(macronix_set_cont_read)),
@@ -456,6 +477,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 	SPINAND_INFO("MX3UF2GE4BC",
@@ -466,6 +488,7 @@ static const struct spinand_info macronix_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
+		     SPINAND_INFO_VENDOR_OPS(&macronix_ops),
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 				     macronix_ecc_get_status)),
 };

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 17/28] mtd: spinand: winbond: Register W25N vendor specific operation
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (15 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 16/28] mtd: spinand: macronix: Register vendor specific operation Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 18/28] mtd: spinand: winbond: Register W35N " Miquel Raynal
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Provide the Winbond W25N specific "select target" operation to let the
core verify it is supported by the controller before using it.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 3003ad7e83ee8f553ec82a0326422916c0ed794c..36053f35ee5e84eb355343443a28d274cf7ea5c3 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -105,6 +105,9 @@ spinand_fill_winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, void *
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(1, buf, 1))
 
+static SPINAND_OP_VARIANTS(winbond_w25_ops,
+		SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(NULL));
+
 static struct spi_mem_op
 spinand_fill_winbond_select_target_op(struct spinand_device *spinand, void *valptr)
 {
@@ -497,6 +500,7 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &write_cache_variants,
 					      &update_cache_variants),
 		     0,
+		     SPINAND_INFO_VENDOR_OPS(&winbond_w25_ops),
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
 	SPINAND_INFO("W25N02JW", /* high-speed 1.8V */

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 18/28] mtd: spinand: winbond: Register W35N vendor specific operation
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (16 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 17/28] mtd: spinand: winbond: Register W25N " Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 19/28] mtd: spinand: winbond: Fix style Miquel Raynal
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Provide the Winbond W35N specific "write VCR register" operation to let
the core verify it is supported by the controller before using it.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 36053f35ee5e84eb355343443a28d274cf7ea5c3..1c13dba08369c48ca26381c634abcea4e7360f30 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -93,6 +93,9 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(1, buf, 1))
 
+static SPINAND_OP_VARIANTS(winbond_w35_ops,
+		SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(0, NULL));
+
 static struct spi_mem_op
 spinand_fill_winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, void *valptr)
 {
@@ -469,6 +472,7 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &write_cache_octal_variants,
 					      &update_cache_octal_variants),
 		     0,
+		     SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
 		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
 		     SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
 	SPINAND_INFO("W35N02JW", /* 1.8V */
@@ -479,6 +483,7 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &write_cache_octal_variants,
 					      &update_cache_octal_variants),
 		     0,
+		     SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
 		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
 		     SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
 	SPINAND_INFO("W35N04JW", /* 1.8V */
@@ -489,6 +494,7 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &write_cache_octal_variants,
 					      &update_cache_octal_variants),
 		     0,
+		     SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
 		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
 		     SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
 	/* 2G-bit densities */

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 19/28] mtd: spinand: winbond: Fix style
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (17 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 18/28] mtd: spinand: winbond: Register W35N " Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 20/28] mtd: spinand: winbond: Rename IO_MODE register macro Miquel Raynal
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Add a missing new line in the middle of the driver.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 1c13dba08369c48ca26381c634abcea4e7360f30..7eade2251f7b5b2a96c0a7528ca6d64ba6d8233e 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -408,6 +408,7 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
 	default:
 		return -EINVAL;
 	}
+
 	ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_DUMMY_CLOCK_REG, dummy_cycles);
 	if (ret)
 		return ret;

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 20/28] mtd: spinand: winbond: Rename IO_MODE register macro
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (18 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 19/28] mtd: spinand: winbond: Fix style Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 21/28] mtd: spinand: winbond: Configure the IO mode after the dummy cycles Miquel Raynal
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Suffix the macro name with *_REG to align with the rest of the driver.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 7eade2251f7b5b2a96c0a7528ca6d64ba6d8233e..b169636376835157c64bce17a4f32549e1c1eb9f 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -22,7 +22,7 @@
 #define W25N0XJW_SR4			0xD0
 #define W25N0XJW_SR4_HS			BIT(2)
 
-#define W35N01JW_VCR_IO_MODE			0x00
+#define W35N01JW_VCR_IO_MODE_REG	0x00
 #define W35N01JW_VCR_IO_MODE_SINGLE_SDR		0xFF
 #define W35N01JW_VCR_IO_MODE_OCTAL_SDR		0xDF
 #define W35N01JW_VCR_IO_MODE_OCTAL_DDR_DS	0xE7
@@ -392,7 +392,7 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
 	else
 		return -EINVAL;
 
-	ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE, io_mode);
+	ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE_REG, io_mode);
 	if (ret)
 		return ret;
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 21/28] mtd: spinand: winbond: Configure the IO mode after the dummy cycles
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (19 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 20/28] mtd: spinand: winbond: Rename IO_MODE register macro Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 22/28] mtd: spinand: Gather all the bus interface steps in one single function Miquel Raynal
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

When we will change the bus interface, the action that actually performs
the transition is the IO mode register write. This means after the IO
mode register write, we should use the new bus interface. But the
->configure_chip() hook itself is not responsible of making this change
official, it is the caller that must act according to the return value.

Reorganize this helper to first configure the dummy cycles before
possibly switching to another bus interface.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index b169636376835157c64bce17a4f32549e1c1eb9f..1d79a8ae79206af7d823018c4603b3bd36a0dd88 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -381,21 +381,6 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
 
 	op = spinand->op_templates->read_cache;
 
-	single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
-	dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr);
-	if (single && !dtr)
-		io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR;
-	else if (!single && !dtr)
-		io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR;
-	else if (!single && dtr)
-		io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR;
-	else
-		return -EINVAL;
-
-	ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE_REG, io_mode);
-	if (ret)
-		return ret;
-
 	dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
 	switch (dummy_cycles) {
 	case 8:
@@ -413,6 +398,21 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
 	if (ret)
 		return ret;
 
+	single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
+	dtr = (op->cmd.dtr && op->addr.dtr && op->data.dtr);
+	if (single && !dtr)
+		io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR;
+	else if (!single && !dtr)
+		io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR;
+	else if (!single && dtr)
+		io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR;
+	else
+		return -EINVAL;
+
+	ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE_REG, io_mode);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 22/28] mtd: spinand: Gather all the bus interface steps in one single function
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (20 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 21/28] mtd: spinand: winbond: Configure the IO mode after the dummy cycles Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 23/28] mtd: spinand: Add support for setting a bus interface Miquel Raynal
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Writing the quad enable bit in one helper and doing the chip
configuration in another does not make much sense from a bus interface
setup point of view.

Instead, let's create a broader helper which is going to be in charge of
all the bus configuration steps at once. This will specifically allow to
transition to octal DDR mode, and even fallback to quad (if suppoorted)
or single mode otherwise.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 62 +++++++++++++++++++++++++++------------------
 1 file changed, 37 insertions(+), 25 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 7c01516c6b6acb41d2cc080d6fbaaa5ace661602..caf549617f369ada2c1712e863e563ae547ca0e6 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -177,18 +177,9 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand)
 	return 0;
 }
 
-static int spinand_init_quad_enable(struct spinand_device *spinand)
+static int spinand_init_quad_enable(struct spinand_device *spinand,
+				    bool enable)
 {
-	bool enable = false;
-
-	if (!(spinand->flags & SPINAND_HAS_QE_BIT))
-		return 0;
-
-	if (spinand->op_templates->read_cache->data.buswidth == 4 ||
-	    spinand->op_templates->write_cache->data.buswidth == 4 ||
-	    spinand->op_templates->update_cache->data.buswidth == 4)
-		enable = true;
-
 	return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE,
 			       enable ? CFG_QUAD_ENABLE : 0);
 }
@@ -1306,12 +1297,6 @@ static int spinand_manufacturer_init(struct spinand_device *spinand)
 			return ret;
 	}
 
-	if (spinand->configure_chip) {
-		ret = spinand->configure_chip(spinand);
-		if (ret)
-			return ret;
-	}
-
 	return 0;
 }
 
@@ -1517,6 +1502,31 @@ static int spinand_detect(struct spinand_device *spinand)
 	return 0;
 }
 
+static int spinand_configure_chip(struct spinand_device *spinand)
+{
+	bool quad_enable = false;
+	int ret;
+
+	if (spinand->flags & SPINAND_HAS_QE_BIT) {
+		if (spinand->ssdr_op_templates.read_cache->data.buswidth == 4 ||
+		    spinand->ssdr_op_templates.write_cache->data.buswidth == 4 ||
+		    spinand->ssdr_op_templates.update_cache->data.buswidth == 4)
+			quad_enable = true;
+	}
+
+	ret = spinand_init_quad_enable(spinand, quad_enable);
+	if (ret)
+		return ret;
+
+	if (spinand->configure_chip) {
+		ret = spinand->configure_chip(spinand);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
 static int spinand_init_flash(struct spinand_device *spinand)
 {
 	struct device *dev = &spinand->spimem->spi->dev;
@@ -1527,10 +1537,6 @@ static int spinand_init_flash(struct spinand_device *spinand)
 	if (ret)
 		return ret;
 
-	ret = spinand_init_quad_enable(spinand);
-	if (ret)
-		return ret;
-
 	ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
 	if (ret)
 		return ret;
@@ -1543,19 +1549,25 @@ static int spinand_init_flash(struct spinand_device *spinand)
 		return ret;
 	}
 
+	ret = spinand_configure_chip(spinand);
+	if (ret)
+		goto manuf_cleanup;
+
 	/* After power up, all blocks are locked, so unlock them here. */
 	for (i = 0; i < nand->memorg.ntargets; i++) {
 		ret = spinand_select_target(spinand, i);
 		if (ret)
-			break;
+			goto manuf_cleanup;
 
 		ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
 		if (ret)
-			break;
+			goto manuf_cleanup;
 	}
 
-	if (ret)
-		spinand_manufacturer_cleanup(spinand);
+	return 0;
+
+manuf_cleanup:
+	spinand_manufacturer_cleanup(spinand);
 
 	return ret;
 }

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 23/28] mtd: spinand: Add support for setting a bus interface
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (21 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 22/28] mtd: spinand: Gather all the bus interface steps in one single function Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 24/28] mtd: spinand: Propagate the bus interface across core helpers Miquel Raynal
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Create a bus interface enumeration, currently only containing the
one we support: SSDR, for single SDR, so any operation whose command is
sent over a single data line in SDR mode, ie. any operation matching
1S-XX-XX.

The main spinand_device structure gets a new parameter to store this
enumeration, for now unused. Of course it is set to SSDR during the SSDR
templates initialization to further clarify the state we are in at the
moment.

This member is subject to be used to know in which bus configuration we
and be updated by the core when we switch to faster mode(s).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c |  1 +
 include/linux/mtd/spinand.h | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index caf549617f369ada2c1712e863e563ae547ca0e6..fc7263fad7afbd084ecf015dd1d764d6683b46a8 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1321,6 +1321,7 @@ static void spinand_init_ssdr_templates(struct spinand_device *spinand)
 	tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_1S_1S_0_OP(0);
 	tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_1S_1S_0_OP(0);
 	spinand->op_templates = &spinand->ssdr_op_templates;
+	spinand->bus_iface = SSDR;
 }
 
 static int spinand_support_vendor_ops(struct spinand_device *spinand,
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 0565cdeb3f7b652699d420a8c05c3fe53fcc2253..7d059956c81a3a6fd337bab43fb4f1130997ab0f 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -480,6 +480,14 @@ struct spinand_user_otp {
 	const struct spinand_user_otp_ops *ops;
 };
 
+/**
+ * enum spinand_bus_interface - SPI NAND bus interface types
+ * @SSDR: Bus configuration supporting all 1S-XX-XX operations, including dual and quad
+ */
+enum spinand_bus_interface {
+	SSDR,
+};
+
 /**
  * struct spinand_info - Structure used to describe SPI NAND chips
  * @model: model name
@@ -642,6 +650,7 @@ struct spinand_mem_ops {
  * @flags: NAND flags
  * @ssdr_op_templates: Templates for all single SDR SPI mem operations
  * @op_templates: Templates for all SPI mem operations
+ * @bus_iface: Current bus interface
  * @select_target: select a specific target/die. Usually called before sending
  *		   a command addressing a page or an eraseblock embedded in
  *		   this die. Only required if your chip exposes several dies
@@ -677,6 +686,7 @@ struct spinand_device {
 
 	struct spinand_mem_ops ssdr_op_templates;
 	struct spinand_mem_ops *op_templates;
+	enum spinand_bus_interface bus_iface;
 
 	struct spinand_dirmap *dirmaps;
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 24/28] mtd: spinand: Propagate the bus interface across core helpers
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (22 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 23/28] mtd: spinand: Add support for setting a bus interface Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 25/28] mtd: spinand: Give the bus interface to the configuration helper Miquel Raynal
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

For now all drivers provide SSDR variants only. When we add support for
ODTR modes, there will be a need to differentiate the type of variant we
target as well as the need to check if we support one or the other type
of operations.

Pass this parameter to lower level helpers, which for now is unused, in
order to simplify the patch introducing ODTR support.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index fc7263fad7afbd084ecf015dd1d764d6683b46a8..0d98cc1d987e1f6387f6bb243cd3720949b01b0b 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1325,7 +1325,8 @@ static void spinand_init_ssdr_templates(struct spinand_device *spinand)
 }
 
 static int spinand_support_vendor_ops(struct spinand_device *spinand,
-				      const struct spinand_info *info)
+				      const struct spinand_info *info,
+				      enum spinand_bus_interface iface)
 {
 	int i;
 
@@ -1346,7 +1347,7 @@ static int spinand_support_vendor_ops(struct spinand_device *spinand,
 }
 
 static const struct spi_mem_op *
-spinand_select_op_variant(struct spinand_device *spinand,
+spinand_select_op_variant(struct spinand_device *spinand, enum spinand_bus_interface iface,
 			  const struct spinand_op_variants *variants)
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
@@ -1439,28 +1440,28 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		spinand->read_retries = table[i].read_retries;
 		spinand->set_read_retry = table[i].set_read_retry;
 
-		op = spinand_select_op_variant(spinand,
+		op = spinand_select_op_variant(spinand, SSDR,
 					       info->op_variants.read_cache);
 		if (!op)
 			return -EOPNOTSUPP;
 
 		spinand->ssdr_op_templates.read_cache = op;
 
-		op = spinand_select_op_variant(spinand,
+		op = spinand_select_op_variant(spinand, SSDR,
 					       info->op_variants.write_cache);
 		if (!op)
 			return -EOPNOTSUPP;
 
 		spinand->ssdr_op_templates.write_cache = op;
 
-		op = spinand_select_op_variant(spinand,
+		op = spinand_select_op_variant(spinand, SSDR,
 					       info->op_variants.update_cache);
 		if (!op)
 			return -EOPNOTSUPP;
 
 		spinand->ssdr_op_templates.update_cache = op;
 
-		ret = spinand_support_vendor_ops(spinand, info);
+		ret = spinand_support_vendor_ops(spinand, info, SSDR);
 		if (ret)
 			return ret;
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 25/28] mtd: spinand: Give the bus interface to the configuration helper
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (23 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 24/28] mtd: spinand: Propagate the bus interface across core helpers Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 26/28] mtd: spinand: Warn if using SSDR-only vendor commands in a non SSDR mode Miquel Raynal
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

The chip configuration hook is the one responsible to actually switch
the switch between bus interfaces. It is natural to give it the bus
interface we expect with a new parameter. For now the only value we can
give is SSDR, but this is subject to change in the future, so add a bit
of extra logic in the implementations of this callback to make sure
both the core and the chip driver are aligned on the request.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c    |  2 +-
 drivers/mtd/nand/spi/winbond.c | 28 +++++++++++++++++++++-------
 include/linux/mtd/spinand.h    |  6 ++++--
 3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 0d98cc1d987e1f6387f6bb243cd3720949b01b0b..044a84d7b47bf08a14f2310b971cdc85267b0fd2 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1521,7 +1521,7 @@ static int spinand_configure_chip(struct spinand_device *spinand)
 		return ret;
 
 	if (spinand->configure_chip) {
-		ret = spinand->configure_chip(spinand);
+		ret = spinand->configure_chip(spinand, SSDR);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 1d79a8ae79206af7d823018c4603b3bd36a0dd88..419f4303a0dc7518017e2bd422584813dca14d48 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -311,13 +311,17 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
 	return -EINVAL;
 }
 
-static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
+static int w25n0xjw_hs_cfg(struct spinand_device *spinand,
+			   enum spinand_bus_interface iface)
 {
 	const struct spi_mem_op *op;
 	bool hs;
 	u8 sr4;
 	int ret;
 
+	if (iface != SSDR)
+		return -EOPNOTSUPP;
+
 	op = spinand->op_templates->read_cache;
 	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
 		hs = false;
@@ -371,17 +375,25 @@ static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val)
 	return 0;
 }
 
-static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
+static int w35n0xjw_vcr_cfg(struct spinand_device *spinand,
+			    enum spinand_bus_interface iface)
 {
-	const struct spi_mem_op *op;
+	const struct spi_mem_op *ref_op;
 	unsigned int dummy_cycles;
 	bool dtr, single;
 	u8 io_mode;
 	int ret;
 
-	op = spinand->op_templates->read_cache;
+	switch (iface) {
+	case SSDR:
+		ref_op = spinand->ssdr_op_templates.read_cache;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	};
 
-	dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
+	dummy_cycles = ((ref_op->dummy.nbytes * 8) / ref_op->dummy.buswidth) /
+		(ref_op->dummy.dtr ? 2 : 1);
 	switch (dummy_cycles) {
 	case 8:
 	case 12:
@@ -398,8 +410,10 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
 	if (ret)
 		return ret;
 
-	single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
-	dtr = (op->cmd.dtr && op->addr.dtr && op->data.dtr);
+	single = (ref_op->cmd.buswidth == 1 &&
+		  ref_op->addr.buswidth == 1 &&
+		  ref_op->data.buswidth == 1);
+	dtr = (ref_op->cmd.dtr && ref_op->addr.dtr && ref_op->data.dtr);
 	if (single && !dtr)
 		io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR;
 	else if (!single && !dtr)
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 7d059956c81a3a6fd337bab43fb4f1130997ab0f..94348344208861c9e1ca36bd86e206225cbbd816 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -528,7 +528,8 @@ struct spinand_info {
 	const struct spinand_op_variants *vendor_ops;
 	int (*select_target)(struct spinand_device *spinand,
 			     unsigned int target);
-	int (*configure_chip)(struct spinand_device *spinand);
+	int (*configure_chip)(struct spinand_device *spinand,
+			      enum spinand_bus_interface iface);
 	int (*set_cont_read)(struct spinand_device *spinand,
 			     bool enable);
 	struct spinand_fact_otp fact_otp;
@@ -703,7 +704,8 @@ struct spinand_device {
 	const struct spinand_manufacturer *manufacturer;
 	void *priv;
 
-	int (*configure_chip)(struct spinand_device *spinand);
+	int (*configure_chip)(struct spinand_device *spinand,
+			      enum spinand_bus_interface iface);
 	bool cont_read_possible;
 	int (*set_cont_read)(struct spinand_device *spinand,
 			     bool enable);

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 26/28] mtd: spinand: Warn if using SSDR-only vendor commands in a non SSDR mode
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (24 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 25/28] mtd: spinand: Give the bus interface to the configuration helper Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 27/28] mtd: spinand: Add octal DTR support Miquel Raynal
  2025-10-31 17:27 ` [PATCH 28/28] mtd: spinand: winbond: W35N " Miquel Raynal
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Both Macronix and Winbond have chip specific operations which are SSDR
only. Trying to use them in an ODTR setup will fail and doing this is a
pure software bug. Warn explicitly in this case.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/macronix.c | 2 ++
 drivers/mtd/nand/spi/winbond.c  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 6b7cbcc6e2872d3369b8eb765dede05c7299c896..84be5e0402b5db8787178dc0a39901b938b0d2e1 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -53,6 +53,8 @@ static SPINAND_OP_VARIANTS(macronix_ops,
 static struct spi_mem_op
 spinand_fill_macronix_read_eccsr_op(struct spinand_device *spinand, void *valptr)
 {
+	WARN_ON_ONCE(spinand->bus_iface != SSDR);
+
 	return (struct spi_mem_op)SPINAND_MACRONIX_READ_ECCSR_1S_0_1S(valptr);
 }
 
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 419f4303a0dc7518017e2bd422584813dca14d48..90e4ece00cf5e727df87cb2367d9f85a2a6759bb 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -114,6 +114,8 @@ static SPINAND_OP_VARIANTS(winbond_w25_ops,
 static struct spi_mem_op
 spinand_fill_winbond_select_target_op(struct spinand_device *spinand, void *valptr)
 {
+	WARN_ON_ONCE(spinand->bus_iface != SSDR);
+
 	return (struct spi_mem_op)SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(valptr);
 }
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 27/28] mtd: spinand: Add octal DTR support
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (25 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 26/28] mtd: spinand: Warn if using SSDR-only vendor commands in a non SSDR mode Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  2025-10-31 17:27 ` [PATCH 28/28] mtd: spinand: winbond: W35N " Miquel Raynal
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Create a new bus interface named ODTR for "octal DTR", which matches the
following pattern: 8D-8D-8D.

Add octal DTR support for all the existing core operations. Add a second
set of templates for this bus interface.

Give the possibility for drivers to register their read, write and
update cache variants as well as their vendor specific operations.

Check the SPI controller driver supports all the octal DTR commands that
we might need before switching to the ODTR bus interface.

Make the switch by calling ->configure_chip() with the ODTR
parameter. Fallback in case this step fails.

If someone ever attempts to suspend a chip in octal DTR mode, there are
changes that it will loose its configuration at resume. Prevent any
problem by explicitly switching back to SSDR while suspending. Note:
there is a limitation in the current approach, page I/Os are not
available as the dirmaps will be created for the ODTR bus interface if
that option is supported and not switched back to SSDR during
suspend. Switching them is possible but would be costly and would not
bring anything as right after resuming we will switch again to ODTR. In
case this capability is used for debug, developpers should mind to
destroy and recreate suitable direct mappings.

Finally, as a side effect, we increase the buffer for reading IDs to
6. No device at this point returns 6 bytes, but we support 5 bytes IDs,
which means in octal DTR mode we have no other choice than reading an
even number of bytes, hence 6.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 134 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mtd/spinand.h |  85 +++++++++++++++++++++++++++-
 2 files changed, 216 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 044a84d7b47bf08a14f2310b971cdc85267b0fd2..49ee03a7252b8bc16e894b33293e2fd67046bf3b 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1307,6 +1307,11 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand)
 		return spinand->manufacturer->ops->cleanup(spinand);
 }
 
+static bool spinand_op_is_odtr(const struct spi_mem_op *op)
+{
+	return op->cmd.dtr && op->cmd.buswidth == 8;
+}
+
 static void spinand_init_ssdr_templates(struct spinand_device *spinand)
 {
 	struct spinand_mem_ops *tmpl = &spinand->ssdr_op_templates;
@@ -1339,6 +1344,10 @@ static int spinand_support_vendor_ops(struct spinand_device *spinand,
 	for (i = 0; i < info->vendor_ops->nops; i++) {
 		const struct spi_mem_op *op = &info->vendor_ops->ops[i];
 
+		if ((iface == SSDR && spinand_op_is_odtr(op)) ||
+		    (iface == ODTR && !spinand_op_is_odtr(op)))
+			continue;
+
 		if (!spi_mem_supports_op(spinand->spimem, op))
 			return -EOPNOTSUPP;
 	}
@@ -1346,6 +1355,49 @@ static int spinand_support_vendor_ops(struct spinand_device *spinand,
 	return 0;
 }
 
+static int spinand_init_odtr_instruction_set(struct spinand_device *spinand)
+{
+	struct spinand_mem_ops *tmpl = &spinand->odtr_op_templates;
+
+	tmpl->reset = (struct spi_mem_op)SPINAND_RESET_8D_0_0_OP;
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->reset))
+		return -EOPNOTSUPP;
+
+	tmpl->readid = (struct spi_mem_op)SPINAND_READID_8D_8D_8D_OP(0, 0, NULL, 0);
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->readid))
+		return -EOPNOTSUPP;
+
+	tmpl->wr_en = (struct spi_mem_op)SPINAND_WR_EN_8D_0_0_OP;
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->wr_en))
+		return -EOPNOTSUPP;
+
+	tmpl->wr_dis = (struct spi_mem_op)SPINAND_WR_DIS_8D_0_0_OP;
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->wr_dis))
+		return -EOPNOTSUPP;
+
+	tmpl->set_feature = (struct spi_mem_op)SPINAND_SET_FEATURE_8D_8D_8D_OP(0, NULL);
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->set_feature))
+		return -EOPNOTSUPP;
+
+	tmpl->get_feature = (struct spi_mem_op)SPINAND_GET_FEATURE_8D_8D_8D_OP(0, NULL);
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->get_feature))
+		return -EOPNOTSUPP;
+
+	tmpl->blk_erase = (struct spi_mem_op)SPINAND_BLK_ERASE_8D_8D_0_OP(0);
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase))
+		return -EOPNOTSUPP;
+
+	tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read))
+		return -EOPNOTSUPP;
+
+	tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0);
+	if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec))
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
 static const struct spi_mem_op *
 spinand_select_op_variant(struct spinand_device *spinand, enum spinand_bus_interface iface,
 			  const struct spinand_op_variants *variants)
@@ -1361,6 +1413,10 @@ spinand_select_op_variant(struct spinand_device *spinand, enum spinand_bus_inter
 		unsigned int nbytes;
 		int ret;
 
+		if ((iface == SSDR && spinand_op_is_odtr(&op)) ||
+		    (iface == ODTR && !spinand_op_is_odtr(&op)))
+			continue;
+
 		nbytes = nanddev_per_page_oobsize(nand) +
 			 nanddev_page_size(nand);
 
@@ -1440,6 +1496,8 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		spinand->read_retries = table[i].read_retries;
 		spinand->set_read_retry = table[i].set_read_retry;
 
+		/* I/O variants selection with single-spi SDR commands */
+
 		op = spinand_select_op_variant(spinand, SSDR,
 					       info->op_variants.read_cache);
 		if (!op)
@@ -1465,6 +1523,28 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		if (ret)
 			return ret;
 
+		/* I/O variants selection with octo-spi DDR commands (optional) */
+
+		ret = spinand_init_odtr_instruction_set(spinand);
+		if (ret)
+			return 0;
+
+		ret = spinand_support_vendor_ops(spinand, info, ODTR);
+		if (ret)
+			return 0;
+
+		op = spinand_select_op_variant(spinand, ODTR,
+					       info->op_variants.read_cache);
+		spinand->odtr_op_templates.read_cache = op;
+
+		op = spinand_select_op_variant(spinand, ODTR,
+					       info->op_variants.write_cache);
+		spinand->odtr_op_templates.write_cache = op;
+
+		op = spinand_select_op_variant(spinand, ODTR,
+					       info->op_variants.update_cache);
+		spinand->odtr_op_templates.update_cache = op;
+
 		return 0;
 	}
 
@@ -1506,9 +1586,34 @@ static int spinand_detect(struct spinand_device *spinand)
 
 static int spinand_configure_chip(struct spinand_device *spinand)
 {
-	bool quad_enable = false;
+	bool odtr = false, quad_enable = false;
 	int ret;
 
+	if (spinand->odtr_op_templates.read_cache &&
+	    spinand->odtr_op_templates.write_cache &&
+	    spinand->odtr_op_templates.update_cache)
+		odtr = true;
+
+	if (odtr) {
+		if (!spinand->configure_chip)
+			goto try_ssdr;
+
+		/* ODTR bus interface configuration happens here */
+		ret = spinand->configure_chip(spinand, ODTR);
+		if (ret) {
+			spinand->odtr_op_templates.read_cache = NULL;
+			spinand->odtr_op_templates.write_cache = NULL;
+			spinand->odtr_op_templates.update_cache = NULL;
+			goto try_ssdr;
+		}
+
+		spinand->op_templates = &spinand->odtr_op_templates;
+		spinand->bus_iface = ODTR;
+
+		return 0;
+	}
+
+try_ssdr:
 	if (spinand->flags & SPINAND_HAS_QE_BIT) {
 		if (spinand->ssdr_op_templates.read_cache->data.buswidth == 4 ||
 		    spinand->ssdr_op_templates.write_cache->data.buswidth == 4 ||
@@ -1590,6 +1695,32 @@ static void spinand_mtd_resume(struct mtd_info *mtd)
 	spinand_ecc_enable(spinand, false);
 }
 
+static int spinand_mtd_suspend(struct mtd_info *mtd)
+{
+	struct spinand_device *spinand = mtd_to_spinand(mtd);
+	int ret;
+
+	/*
+	 * Return to SSDR interface in the suspend path to make sure the
+	 * reset operation is correctly processed upon resume.
+	 *
+	 * Note: Once back in SSDR mode, every operation but the page helpers
+	 * (dirmap based I/O accessors) will work. Page accesses would require
+	 * destroying and recreating the dirmaps twice to work, which would be
+	 * impacting for no reason, as this is just a transitional state.
+	 */
+	if (spinand->bus_iface == ODTR) {
+		ret = spinand->configure_chip(spinand, SSDR);
+		if (ret)
+			return ret;
+
+		spinand->op_templates = &spinand->ssdr_op_templates;
+		spinand->bus_iface = SSDR;
+	}
+
+	return 0;
+}
+
 static int spinand_init(struct spinand_device *spinand)
 {
 	struct device *dev = &spinand->spimem->spi->dev;
@@ -1659,6 +1790,7 @@ static int spinand_init(struct spinand_device *spinand)
 	mtd->_block_isreserved = spinand_mtd_block_isreserved;
 	mtd->_erase = spinand_mtd_erase;
 	mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
+	mtd->_suspend = spinand_mtd_suspend;
 	mtd->_resume = spinand_mtd_resume;
 
 	if (spinand_user_otp_size(spinand) || spinand_fact_otp_size(spinand)) {
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 94348344208861c9e1ca36bd86e206225cbbd816..eb8ae164b3aa21398636e347fbf810d49d62ff7d 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -238,6 +238,77 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(len, buf, 8))
 
+/**
+ * Octal DDR SPI NAND flash operations
+ */
+
+#define SPINAND_RESET_8D_0_0_OP						\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xff, 8),			\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_READID_8D_8D_8D_OP(naddr, ndummy, buf, len)		\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9f, 8),			\
+		   SPI_MEM_DTR_OP_ADDR(naddr, 0, 8),			\
+		   SPI_MEM_DTR_OP_DUMMY(ndummy, 8),			\
+		   SPI_MEM_DTR_OP_DATA_IN(len, buf, 8))
+
+#define SPINAND_WR_EN_8D_0_0_OP						\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x06, 8),			\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_WR_DIS_8D_0_0_OP					\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x04, 8),			\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_SET_FEATURE_8D_8D_8D_OP(reg, valptr)			\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x1f, 8),			\
+		   SPI_MEM_DTR_OP_RPT_ADDR(reg, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_DTR_OP_DATA_OUT(2, valptr, 8))
+
+#define SPINAND_GET_FEATURE_8D_8D_8D_OP(reg, valptr)			\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x0f, 8),			\
+		   SPI_MEM_DTR_OP_RPT_ADDR(reg, 8),			\
+		   SPI_MEM_DTR_OP_DUMMY(14, 8),				\
+		   SPI_MEM_DTR_OP_DATA_IN(2, valptr, 8))
+
+#define SPINAND_BLK_ERASE_8D_8D_0_OP(addr)				\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xd8, 8),			\
+		   SPI_MEM_DTR_OP_ADDR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_PAGE_READ_8D_8D_0_OP(addr)				\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x13, 8),			\
+		   SPI_MEM_DTR_OP_ADDR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8),			\
+		   SPI_MEM_DTR_OP_ADDR(2, addr, 8),			\
+		   SPI_MEM_DTR_OP_DUMMY(ndummy, 8),			\
+		   SPI_MEM_DTR_OP_DATA_IN(len, buf, 8),			\
+		   SPI_MEM_OP_MAX_FREQ(freq))
+
+#define SPINAND_PROG_EXEC_8D_8D_0_OP(addr)				\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x10, 8),			\
+		   SPI_MEM_DTR_OP_ADDR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
+#define SPINAND_PROG_LOAD_8D_8D_8D_OP(reset, addr, buf, len)		\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD((reset ? 0xc2 : 0xc4), 8),	\
+		   SPI_MEM_DTR_OP_ADDR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_DTR_OP_DATA_OUT(len, buf, 8))
+
 /* feature register */
 #define REG_BLOCK_LOCK		0xa0
 #define BL_ALL_UNLOCKED		0x00
@@ -261,7 +332,7 @@
 struct spinand_op;
 struct spinand_device;
 
-#define SPINAND_MAX_ID_LEN	5
+#define SPINAND_MAX_ID_LEN	6
 /*
  * For erase, write and read operation, we got the following timings :
  * tBERS (erase) 1ms to 4ms
@@ -287,7 +358,7 @@ struct spinand_device;
 
 /**
  * struct spinand_id - SPI NAND id structure
- * @data: buffer containing the id bytes. Currently 5 bytes large, but can
+ * @data: buffer containing the id bytes. Currently 6 bytes large, but can
  *	  be extended if required
  * @len: ID length
  */
@@ -483,9 +554,11 @@ struct spinand_user_otp {
 /**
  * enum spinand_bus_interface - SPI NAND bus interface types
  * @SSDR: Bus configuration supporting all 1S-XX-XX operations, including dual and quad
+ * @ODTR: Bus configuration supporting only 8D-8D-8D operations
  */
 enum spinand_bus_interface {
 	SSDR,
+	ODTR,
 };
 
 /**
@@ -650,6 +723,7 @@ struct spinand_mem_ops {
  * @id: NAND ID as returned by READ_ID
  * @flags: NAND flags
  * @ssdr_op_templates: Templates for all single SDR SPI mem operations
+ * @odtr_op_templates: Templates for all octal DTR SPI mem operations
  * @op_templates: Templates for all SPI mem operations
  * @bus_iface: Current bus interface
  * @select_target: select a specific target/die. Usually called before sending
@@ -686,6 +760,7 @@ struct spinand_device {
 	u32 flags;
 
 	struct spinand_mem_ops ssdr_op_templates;
+	struct spinand_mem_ops odtr_op_templates;
 	struct spinand_mem_ops *op_templates;
 	enum spinand_bus_interface bus_iface;
 
@@ -755,6 +830,9 @@ spinand_fill_set_feature_op(struct spinand_device *spinand, u64 reg, const void
 {
 	struct spi_mem_op op = spinand->op_templates->set_feature;
 
+	if (op.cmd.dtr && op.cmd.buswidth == 8)
+		reg |= reg << 8;
+
 	op.addr.val = reg;
 	op.data.buf.out = valptr;
 
@@ -766,6 +844,9 @@ spinand_fill_get_feature_op(struct spinand_device *spinand, u64 reg, void *valpt
 {
 	struct spi_mem_op op = spinand->op_templates->get_feature;
 
+	if (op.cmd.dtr && op.cmd.buswidth == 8)
+		reg |= reg << 8;
+
 	op.addr.val = reg;
 	op.data.buf.in = valptr;
 

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* [PATCH 28/28] mtd: spinand: winbond: W35N octal DTR support
  2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
                   ` (26 preceding siblings ...)
  2025-10-31 17:27 ` [PATCH 27/28] mtd: spinand: Add octal DTR support Miquel Raynal
@ 2025-10-31 17:27 ` Miquel Raynal
  27 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-10-31 17:27 UTC (permalink / raw)
  To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
  Cc: Tudor Ambarus, Pratyush Yadav, Thomas Petazzoni, Steam Lin,
	Santhosh Kumar K, linux-spi, linux-kernel, linux-mtd,
	Miquel Raynal

Extend the support for the W35N chip family by supporting the ODTR bus
interface. The chip is capable to run in this mode, which brings a
significant performance improvement.

1S-8S-8S:

   # flash_speed /dev/mtd0 -c1 -d
   eraseblock write speed is 7529 KiB/s
   eraseblock read speed is 15058 KiB/s

8D-8D-8D:

   # flash_speed /dev/mtd0 -c1 -d
   eraseblock write speed is 9481 KiB/s
   eraseblock read speed is 23272 KiB/s

This is +55% read speed and +26% write speed with the same hardware.

Tests have been conducted with a TI AM62A7 using the Cadence quad SPI
controller.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/winbond.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 90e4ece00cf5e727df87cb2367d9f85a2a6759bb..8430ae307be0fefded8e27109403a59b9b17b089 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -36,6 +36,8 @@
  */
 
 static SPINAND_OP_VARIANTS(read_cache_octal_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(0, 24, NULL, 0, 120 * HZ_PER_MHZ),
+		SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(0, 16, NULL, 0, 86 * HZ_PER_MHZ),
 		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 3, NULL, 0, 120 * HZ_PER_MHZ),
 		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 2, NULL, 0, 105 * HZ_PER_MHZ),
 		SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 20, NULL, 0, 0),
@@ -48,11 +50,13 @@ static SPINAND_OP_VARIANTS(read_cache_octal_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
 
 static SPINAND_OP_VARIANTS(write_cache_octal_variants,
+		SPINAND_PROG_LOAD_8D_8D_8D_OP(true, 0, NULL, 0),
 		SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0),
 		SPINAND_PROG_LOAD_1S_1S_8S_OP(0, NULL, 0),
 		SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
 
 static SPINAND_OP_VARIANTS(update_cache_octal_variants,
+		SPINAND_PROG_LOAD_8D_8D_8D_OP(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD_1S_8S_8S_OP(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
 
@@ -93,13 +97,22 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(1, buf, 1))
 
+#define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf)			\
+	SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8),			\
+		   SPI_MEM_DTR_OP_ADDR(4, reg, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8))
+
 static SPINAND_OP_VARIANTS(winbond_w35_ops,
-		SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(0, NULL));
+		SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(0, NULL),
+		SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(0, NULL));
 
 static struct spi_mem_op
 spinand_fill_winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, void *valptr)
 {
-	return (struct spi_mem_op)SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(reg, valptr);
+	return (spinand->bus_iface == SSDR) ?
+		(struct spi_mem_op)SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(reg, valptr) :
+		(struct spi_mem_op)SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, valptr);
 }
 
 #define SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(buf)			\
@@ -390,6 +403,9 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand,
 	case SSDR:
 		ref_op = spinand->ssdr_op_templates.read_cache;
 		break;
+	case ODTR:
+		ref_op = spinand->odtr_op_templates.read_cache;
+		break;
 	default:
 		return -EOPNOTSUPP;
 	};

-- 
2.51.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 01/28] spi: spi-mem: Make the DTR command operation macro more suitable
  2025-10-31 17:26 ` [PATCH 01/28] spi: spi-mem: Make the DTR command operation macro more suitable Miquel Raynal
@ 2025-11-05 15:35   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 15:35 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 02/28] spi: spi-mem: Create a repeated address operation
  2025-10-31 17:26 ` [PATCH 02/28] spi: spi-mem: Create a repeated address operation Miquel Raynal
@ 2025-11-05 15:43   ` Tudor Ambarus
  2025-11-19 17:10     ` Miquel Raynal
  0 siblings, 1 reply; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 15:43 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 10/31/25 6:26 PM, Miquel Raynal wrote:
> In octal DTR mode, while the command opcode is *always* repeated,

this info is wrong: opcode can be repeated, inverted or a dedicated 16bit,
so please fix this to not mislead readers

> addresses may either be long enough to cover at least two bytes (in
> which case the existing macro works), or otherwise for single byte
> addresses, the byte must also be duplicated and sent twice: on each
> front of the clock. Create a macro for this common case.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  include/linux/spi/spi-mem.h | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
> index 81c9c7e793b6ab894675e0198d412d84b8525c2e..e4db0924898ce5b17d2b6d4269495bb968db2871 100644
> --- a/include/linux/spi/spi-mem.h
> +++ b/include/linux/spi/spi-mem.h
> @@ -43,6 +43,14 @@
>  		.dtr = true,					\
>  	}
>  
> +#define SPI_MEM_DTR_OP_RPT_ADDR(__val, __buswidth)		\

I find the name too generic. This is an macro for 1 byte addresses, right?

> +	{							\
> +		.nbytes = 2,					\
> +		.val = __val | __val << 8,			\
> +		.buswidth = __buswidth,				\
> +		.dtr = true,					\
> +	}
> +
>  #define SPI_MEM_OP_NO_ADDR	{ }
>  
>  #define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\
> 

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 03/28] spi: spi-mem: Limit octal DTR constraints to octal DTR situations
  2025-10-31 17:26 ` [PATCH 03/28] spi: spi-mem: Limit octal DTR constraints to octal DTR situations Miquel Raynal
@ 2025-11-05 15:53   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 15:53 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 04/28] mtd: spinand: Fix kernel doc
  2025-10-31 17:26 ` [PATCH 04/28] mtd: spinand: Fix kernel doc Miquel Raynal
@ 2025-11-05 15:57   ` Tudor Ambarus
  2025-11-19 17:18     ` Miquel Raynal
  0 siblings, 1 reply; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 15:57 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 10/31/25 6:26 PM, Miquel Raynal wrote:
> The @data buffer is 5 bytes, not 4, it has been extended for the need of
> devices with an extra ID bytes.
> 
> Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs")

no fixes tag for documentation.

with that:
Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

(commit msg can be updated to smth like "update kernel doc comment" too)

> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  include/linux/mtd/spinand.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 927c10d7876958276a841a9f1278a74deeb89944..1c741145e49717169152854718f784e0e519ea92 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -287,7 +287,7 @@ struct spinand_device;
>  
>  /**
>   * struct spinand_id - SPI NAND id structure
> - * @data: buffer containing the id bytes. Currently 4 bytes large, but can
> + * @data: buffer containing the id bytes. Currently 5 bytes large, but can
>   *	  be extended if required
>   * @len: ID length
>   */
> 


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 05/28] mtd: spinand: Add missing check
  2025-10-31 17:26 ` [PATCH 05/28] mtd: spinand: Add missing check Miquel Raynal
@ 2025-11-05 16:04   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:04 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 06/28] mtd: spinand: Remove stale definitions
  2025-10-31 17:26 ` [PATCH 06/28] mtd: spinand: Remove stale definitions Miquel Raynal
@ 2025-11-05 16:05   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:05 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 07/28] mtd: spinand: Use standard return values
  2025-10-31 17:26 ` [PATCH 07/28] mtd: spinand: Use standard return values Miquel Raynal
@ 2025-11-05 16:06   ` Tudor Ambarus
  2025-11-19 17:20     ` Miquel Raynal
  0 siblings, 1 reply; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:06 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 10/31/25 6:26 PM, Miquel Raynal wrote:
> Replace -ENOTSUP

do you care to fix all mtd? :)

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 08/28] mtd: spinand: Decouple write enable and write disable operations
  2025-10-31 17:26 ` [PATCH 08/28] mtd: spinand: Decouple write enable and write disable operations Miquel Raynal
@ 2025-11-05 16:08   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:08 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 09/28] mtd: spinand: Create an array of operation templates
  2025-10-31 17:26 ` [PATCH 09/28] mtd: spinand: Create an array of operation templates Miquel Raynal
@ 2025-11-05 16:17   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:17 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

I like it!

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP()
  2025-10-31 17:26 ` [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP() Miquel Raynal
@ 2025-11-05 16:28   ` Tudor Ambarus
  2025-11-19 17:23     ` Miquel Raynal
  0 siblings, 1 reply; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:28 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 10/31/25 6:26 PM, Miquel Raynal wrote:
> index 4afebaf5f0195b9bc617ea1f125f637f76fff9f8..a8fd04a67cfa9925bd68c57539d86e0816b76274 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -701,6 +701,93 @@ struct spinand_device {
>  			     unsigned int retry_mode);
>  };
>  
> +static inline struct spi_mem_op

Do we still do inlines?

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 11/28] mtd: spinand: Convert vendor drivers to SPINAND_OP()
  2025-10-31 17:26 ` [PATCH 11/28] mtd: spinand: Convert vendor drivers to SPINAND_OP() Miquel Raynal
@ 2025-11-05 16:30   ` Tudor Ambarus
  2025-11-19 17:24     ` Miquel Raynal
  0 siblings, 1 reply; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:30 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 10/31/25 6:26 PM, Miquel Raynal wrote:
> This macro allows to silently switch bus interfaces, use it outside of
> the core in all places that can be trivially converted.
> 
> At this stage there is no functional change expected, until octal DTR
> support gets added.
> 

Shouldn't this be squashed to the previous patch?

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 12/28] mtd: spinand: macronix: Convert vendor specific operation to SPINAND_OP()
  2025-10-31 17:26 ` [PATCH 12/28] mtd: spinand: macronix: Convert vendor specific operation " Miquel Raynal
@ 2025-11-05 16:40   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:40 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 13/28] mtd: spinand: winbond: Convert W25N specific operation to SPINAND_OP()
  2025-10-31 17:26 ` [PATCH 13/28] mtd: spinand: winbond: Convert W25N " Miquel Raynal
@ 2025-11-05 16:40   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:40 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

no inline, good :)

Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 14/28] mtd: spinand: winbond: Convert W35N specific operation to SPINAND_OP()
  2025-10-31 17:26 ` [PATCH 14/28] mtd: spinand: winbond: Convert W35N " Miquel Raynal
@ 2025-11-05 16:41   ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-05 16:41 UTC (permalink / raw)
  To: Miquel Raynal, Mark Brown, Richard Weinberger,
	Vignesh Raghavendra
  Cc: Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd


Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 02/28] spi: spi-mem: Create a repeated address operation
  2025-11-05 15:43   ` Tudor Ambarus
@ 2025-11-19 17:10     ` Miquel Raynal
  2025-11-20  8:49       ` Tudor Ambarus
  0 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-11-19 17:10 UTC (permalink / raw)
  To: Tudor Ambarus
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

Hi Tudor,

First, thank you very much for all this precious feedback! I am happy to
get feedback not only on the spi-mem side, but also on the NAND changes!

On 05/11/2025 at 16:43:58 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:

> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>> In octal DTR mode, while the command opcode is *always* repeated,
>
> this info is wrong: opcode can be repeated, inverted or a dedicated 16bit,
> so please fix this to not mislead readers

I didn't know :) But yeah I had SPI NAND mind which was obviously
wrong. I'll correct.

>> addresses may either be long enough to cover at least two bytes (in
>> which case the existing macro works), or otherwise for single byte
>> addresses, the byte must also be duplicated and sent twice: on each
>> front of the clock. Create a macro for this common case.
>> 
>> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
>> ---
>>  include/linux/spi/spi-mem.h | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>> 
>> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
>> index 81c9c7e793b6ab894675e0198d412d84b8525c2e..e4db0924898ce5b17d2b6d4269495bb968db2871 100644
>> --- a/include/linux/spi/spi-mem.h
>> +++ b/include/linux/spi/spi-mem.h
>> @@ -43,6 +43,14 @@
>>  		.dtr = true,					\
>>  	}
>>  
>> +#define SPI_MEM_DTR_OP_RPT_ADDR(__val, __buswidth)		\
>
> I find the name too generic. This is an macro for 1 byte addresses,
> right?

Yes it is. The name mimics the "dtr command repeat" macro name. Maybe
you want to include the info that it is  carrying a single byte? maybe
"*RPT_SINGLE_BYTE_ADDR"? but that's a big too long IMO. Any other idea?

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 04/28] mtd: spinand: Fix kernel doc
  2025-11-05 15:57   ` Tudor Ambarus
@ 2025-11-19 17:18     ` Miquel Raynal
  2025-11-20  8:05       ` Tudor Ambarus
  0 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-11-19 17:18 UTC (permalink / raw)
  To: Tudor Ambarus
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

On 05/11/2025 at 16:57:39 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:

> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>> The @data buffer is 5 bytes, not 4, it has been extended for the need of
>> devices with an extra ID bytes.
>> 
>> Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs")
>
> no fixes tag for documentation.
>
> with that:
> Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>
>
> (commit msg can be updated to smth like "update kernel doc comment"
> too)

I partially disagree. Tell me if I'm wrong, but may I guess that you
have backports in mind? As opposed to backporting comment fixes which
might not make much sense indeed, _fixing_ a comment makes sense. We
know that stable maintainers, even though they ask people to Cc stable
for backports, they automatically pick with the help of AI almost any
commit with a Fixes tag. I believe it is wrong to not mark such commit
and even change the title (because "fix" in the title may also lead to
an automatic backport) to circumvent their tooling. The tooling must
adapt, not the accuracy of the commits. Plus, backporting this kind of
commit is harmless, so I wouldn't care too much?

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 07/28] mtd: spinand: Use standard return values
  2025-11-05 16:06   ` Tudor Ambarus
@ 2025-11-19 17:20     ` Miquel Raynal
  0 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-11-19 17:20 UTC (permalink / raw)
  To: Tudor Ambarus
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

On 05/11/2025 at 17:06:44 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:

> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>> Replace -ENOTSUP
>
> do you care to fix all mtd? :)

Call myself lazy :) I preferred to fix the return codes before adding
another path, otherwise I'd have had to add yet another ENOTSUP value,
which felt wrong-er!

> Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP()
  2025-11-05 16:28   ` Tudor Ambarus
@ 2025-11-19 17:23     ` Miquel Raynal
  2025-11-20  8:35       ` Tudor Ambarus
  0 siblings, 1 reply; 51+ messages in thread
From: Miquel Raynal @ 2025-11-19 17:23 UTC (permalink / raw)
  To: Tudor Ambarus
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

On 05/11/2025 at 17:28:29 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:

> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>> index 4afebaf5f0195b9bc617ea1f125f637f76fff9f8..a8fd04a67cfa9925bd68c57539d86e0816b76274 100644
>> --- a/include/linux/mtd/spinand.h
>> +++ b/include/linux/mtd/spinand.h
>> @@ -701,6 +701,93 @@ struct spinand_device {
>>  			     unsigned int retry_mode);
>>  };
>>  
>> +static inline struct spi_mem_op
>
> Do we still do inlines?

Defining functions in headers like that, I think yes? (static inline,
not just inline). The full line is something like:

+static inline struct spi_mem_op
+spinand_fill_reset_op(struct spinand_device *spinand)
+{

So it's not an inline declaration of a variable, but the definition of a
function (just saying, in case the diff mislead you).

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 11/28] mtd: spinand: Convert vendor drivers to SPINAND_OP()
  2025-11-05 16:30   ` Tudor Ambarus
@ 2025-11-19 17:24     ` Miquel Raynal
  0 siblings, 0 replies; 51+ messages in thread
From: Miquel Raynal @ 2025-11-19 17:24 UTC (permalink / raw)
  To: Tudor Ambarus
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd

On 05/11/2025 at 17:30:20 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:

> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>> This macro allows to silently switch bus interfaces, use it outside of
>> the core in all places that can be trivially converted.
>> 
>> At this stage there is no functional change expected, until octal DTR
>> support gets added.
>> 
>
> Shouldn't this be squashed to the previous patch?

That's right, there is no strong reason to do it in two patches. I think
this comes from the order in which I progressively converted the
drivers, I'll squash.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 04/28] mtd: spinand: Fix kernel doc
  2025-11-19 17:18     ` Miquel Raynal
@ 2025-11-20  8:05       ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-20  8:05 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 11/19/25 7:18 PM, Miquel Raynal wrote:
> On 05/11/2025 at 16:57:39 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:
> 
>> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>>> The @data buffer is 5 bytes, not 4, it has been extended for the need of
>>> devices with an extra ID bytes.
>>>
>>> Fixes: 34a956739d29 ("mtd: spinand: Add support for 5-byte IDs")
>>
>> no fixes tag for documentation.
>>
>> with that:
>> Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>
>>
>> (commit msg can be updated to smth like "update kernel doc comment"
>> too)
> 
> I partially disagree. Tell me if I'm wrong, but may I guess that you
> have backports in mind? As opposed to backporting comment fixes which


yes, I was thinking on stable rules, where trivial fixes like this,
are not accepted. But you didn't cc stable, so I think that's fine.

> might not make much sense indeed, _fixing_ a comment makes sense. We
> know that stable maintainers, even though they ask people to Cc stable
> for backports, they automatically pick with the help of AI almost any
> commit with a Fixes tag. I believe it is wrong to not mark such commit
> and even change the title (because "fix" in the title may also lead to
> an automatic backport) to circumvent their tooling. The tooling must
> adapt, not the accuracy of the commits. Plus, backporting this kind of
> commit is harmless, so I wouldn't care too much?

okay

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP()
  2025-11-19 17:23     ` Miquel Raynal
@ 2025-11-20  8:35       ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-20  8:35 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 11/19/25 7:23 PM, Miquel Raynal wrote:
> On 05/11/2025 at 17:28:29 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:
> 
>> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>>> index 4afebaf5f0195b9bc617ea1f125f637f76fff9f8..a8fd04a67cfa9925bd68c57539d86e0816b76274 100644
>>> --- a/include/linux/mtd/spinand.h
>>> +++ b/include/linux/mtd/spinand.h
>>> @@ -701,6 +701,93 @@ struct spinand_device {
>>>  			     unsigned int retry_mode);
>>>  };
>>>  
>>> +static inline struct spi_mem_op
>>
>> Do we still do inlines?
> 
> Defining functions in headers like that, I think yes? (static inline,
> not just inline). The full line is something like:
> 
> +static inline struct spi_mem_op
> +spinand_fill_reset_op(struct spinand_device *spinand)
> +{
> 
> So it's not an inline declaration of a variable, but the definition of a
> function (just saying, in case the diff mislead you).

I saw it's a static inline function. Check this please:
https://lore.kernel.org/all/Pine.LNX.4.64.0601021105000.3668@g5.osdl.org/T/#u

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

* Re: [PATCH 02/28] spi: spi-mem: Create a repeated address operation
  2025-11-19 17:10     ` Miquel Raynal
@ 2025-11-20  8:49       ` Tudor Ambarus
  0 siblings, 0 replies; 51+ messages in thread
From: Tudor Ambarus @ 2025-11-20  8:49 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
	Pratyush Yadav, Thomas Petazzoni, Steam Lin, Santhosh Kumar K,
	linux-spi, linux-kernel, linux-mtd



On 11/19/25 7:10 PM, Miquel Raynal wrote:
> Hi Tudor,
> 

Hi, Miquel!

> First, thank you very much for all this precious feedback! I am happy to
> get feedback not only on the spi-mem side, but also on the NAND changes!

yeah, I had a spare window and reviewed as much as I could. The set won't go
in this cycle anyway, I plan to review the rest as well. But not just now :)

> 
> On 05/11/2025 at 16:43:58 +01, Tudor Ambarus <tudor.ambarus@linaro.org> wrote:
> 
>> On 10/31/25 6:26 PM, Miquel Raynal wrote:
>>> In octal DTR mode, while the command opcode is *always* repeated,
>>
>> this info is wrong: opcode can be repeated, inverted or a dedicated 16bit,
>> so please fix this to not mislead readers
> 
> I didn't know :) But yeah I had SPI NAND mind which was obviously
> wrong. I'll correct.
> 
>>> addresses may either be long enough to cover at least two bytes (in
>>> which case the existing macro works), or otherwise for single byte
>>> addresses, the byte must also be duplicated and sent twice: on each
>>> front of the clock. Create a macro for this common case.
>>>
>>> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
>>> ---
>>>  include/linux/spi/spi-mem.h | 8 ++++++++
>>>  1 file changed, 8 insertions(+)
>>>
>>> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
>>> index 81c9c7e793b6ab894675e0198d412d84b8525c2e..e4db0924898ce5b17d2b6d4269495bb968db2871 100644
>>> --- a/include/linux/spi/spi-mem.h
>>> +++ b/include/linux/spi/spi-mem.h
>>> @@ -43,6 +43,14 @@
>>>  		.dtr = true,					\
>>>  	}
>>>  
>>> +#define SPI_MEM_DTR_OP_RPT_ADDR(__val, __buswidth)		\
>>
>> I find the name too generic. This is an macro for 1 byte addresses,
>> right?
> 
> Yes it is. The name mimics the "dtr command repeat" macro name. Maybe
> you want to include the info that it is  carrying a single byte? maybe
> "*RPT_SINGLE_BYTE_ADDR"? but that's a big too long IMO. Any other idea?
Let's keep it as you proposed, I see how they are used in patch 27/28 and
it looks alright.

Cheers,
ta

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

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

end of thread, other threads:[~2025-11-20  8:49 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-31 17:26 [PATCH 00/28] mtd: spinand: Octal DTR support Miquel Raynal
2025-10-31 17:26 ` [PATCH 01/28] spi: spi-mem: Make the DTR command operation macro more suitable Miquel Raynal
2025-11-05 15:35   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 02/28] spi: spi-mem: Create a repeated address operation Miquel Raynal
2025-11-05 15:43   ` Tudor Ambarus
2025-11-19 17:10     ` Miquel Raynal
2025-11-20  8:49       ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 03/28] spi: spi-mem: Limit octal DTR constraints to octal DTR situations Miquel Raynal
2025-11-05 15:53   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 04/28] mtd: spinand: Fix kernel doc Miquel Raynal
2025-11-05 15:57   ` Tudor Ambarus
2025-11-19 17:18     ` Miquel Raynal
2025-11-20  8:05       ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 05/28] mtd: spinand: Add missing check Miquel Raynal
2025-11-05 16:04   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 06/28] mtd: spinand: Remove stale definitions Miquel Raynal
2025-11-05 16:05   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 07/28] mtd: spinand: Use standard return values Miquel Raynal
2025-11-05 16:06   ` Tudor Ambarus
2025-11-19 17:20     ` Miquel Raynal
2025-10-31 17:26 ` [PATCH 08/28] mtd: spinand: Decouple write enable and write disable operations Miquel Raynal
2025-11-05 16:08   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 09/28] mtd: spinand: Create an array of operation templates Miquel Raynal
2025-11-05 16:17   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 10/28] mtd: spinand: Make use of the operation templates through SPINAND_OP() Miquel Raynal
2025-11-05 16:28   ` Tudor Ambarus
2025-11-19 17:23     ` Miquel Raynal
2025-11-20  8:35       ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 11/28] mtd: spinand: Convert vendor drivers to SPINAND_OP() Miquel Raynal
2025-11-05 16:30   ` Tudor Ambarus
2025-11-19 17:24     ` Miquel Raynal
2025-10-31 17:26 ` [PATCH 12/28] mtd: spinand: macronix: Convert vendor specific operation " Miquel Raynal
2025-11-05 16:40   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 13/28] mtd: spinand: winbond: Convert W25N " Miquel Raynal
2025-11-05 16:40   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 14/28] mtd: spinand: winbond: Convert W35N " Miquel Raynal
2025-11-05 16:41   ` Tudor Ambarus
2025-10-31 17:26 ` [PATCH 15/28] mtd: spinand: List vendor specific operations and make sure they are supported Miquel Raynal
2025-10-31 17:27 ` [PATCH 16/28] mtd: spinand: macronix: Register vendor specific operation Miquel Raynal
2025-10-31 17:27 ` [PATCH 17/28] mtd: spinand: winbond: Register W25N " Miquel Raynal
2025-10-31 17:27 ` [PATCH 18/28] mtd: spinand: winbond: Register W35N " Miquel Raynal
2025-10-31 17:27 ` [PATCH 19/28] mtd: spinand: winbond: Fix style Miquel Raynal
2025-10-31 17:27 ` [PATCH 20/28] mtd: spinand: winbond: Rename IO_MODE register macro Miquel Raynal
2025-10-31 17:27 ` [PATCH 21/28] mtd: spinand: winbond: Configure the IO mode after the dummy cycles Miquel Raynal
2025-10-31 17:27 ` [PATCH 22/28] mtd: spinand: Gather all the bus interface steps in one single function Miquel Raynal
2025-10-31 17:27 ` [PATCH 23/28] mtd: spinand: Add support for setting a bus interface Miquel Raynal
2025-10-31 17:27 ` [PATCH 24/28] mtd: spinand: Propagate the bus interface across core helpers Miquel Raynal
2025-10-31 17:27 ` [PATCH 25/28] mtd: spinand: Give the bus interface to the configuration helper Miquel Raynal
2025-10-31 17:27 ` [PATCH 26/28] mtd: spinand: Warn if using SSDR-only vendor commands in a non SSDR mode Miquel Raynal
2025-10-31 17:27 ` [PATCH 27/28] mtd: spinand: Add octal DTR support Miquel Raynal
2025-10-31 17:27 ` [PATCH 28/28] mtd: spinand: winbond: W35N " Miquel Raynal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox