All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/17] mtd: spinand: Add Octal DTR SPI (8D-8D-8D) mode support
@ 2022-01-01  7:42 ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Hi,
This series proposes patches for adding the following functionality
in SPI NAND core:

- Octal DTR SPI (8D-8D-8D) mode support

- ctrl_ops support

- Winbond W35N01JW SPI NAND chip support

This series has been tested on TI J721e EVM with the Winbond W35N01JW
flash with following test utilities:

- nandtest
  Test log: https://pastebin.com/raw/PusiLYVQ

- mtd_stresstest
  Test log: https://pastebin.com/raw/gBtV2CAf

- UBIFS LTP stress test (NAND_XL_STRESS_DD_RW_UBIFS).
  Test log: https://pastebin.com/raw/J8WyLsz1

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

---
Changes in v3:

- Added support for ctrl_ops, data_ops and ctrl_ops_variants.

- Made the implementation generic in terms of spinand protocol and SPI mode
  changes.

- Added option to disable Octal DTR mode.

- Removed spinand_patch_op(), adjust_op() manufacturer_op.

- Removed Power-on-Reset functionality and its call from mtd_suspend(), now 
  just disable Octal DTR at suspend.


Changes in v2:

- Removed *_ALL_ARGS() macros from spi-mem.h, and redefined DTR macros.

- Renamed spinand_setup_op() to spinand_patch_op(). Reduced one
  conditional check from this function. Had to keep tweaking in hot-path
  to avoid complicated implementation "hacks".

- Changes in commit messages and added comments.

- Dropped "Reject 8D-8D-8D op_templates if octal_dtr_enale() is
  missing in manufacturer_op" patch.

- Reduced PoR reset delay.

- Splitted "mtd: spinand: Add support for Winbond W35N01JW SPI NAND
  flash" into 3 independent patches.


Apurva Nandan (17):
  spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  mtd: spinand: Define macros for Octal DTR ops
  mtd: spinand: Add enum spinand_protocol to indicate current SPI IO
    mode
  mtd: spinand: Rename 'op_templates' to 'data_ops'
  mtd: spinand: Define ctrl_ops for non-page read/write op templates
  mtd: spinand: Define default ctrl_ops in the core
  mtd: spinand: Switch from op macros usage to 'ctrl_ops' in the core
  mtd: spinand: Add support for manufacturer-based ctrl_ops variations
  mtd: spinand: Add change_mode() in manufacturer_ops
  mtd: spinand: Add pointer to probed flash's spinand_info
  mtd: spinand: Allow enabling/disabling Octal DTR mode in the core
  mtd: spinand: Add mtd_suspend() to disable Octal DTR mode at suspend
  mtd: spinand: winbond: Add support for write volatile configuration
    register op
  mtd: spinand: winbond: Add octal_dtr_enable/disable() in
    manufacturer_ops
  mtd: spianand: winbond: Add change_mode() manufacturer_ops
  mtd: spinand: winbond: Rename cache op_variants struct variable
  mtd: spinand: winbond: Add support for Winbond W35N01JW SPI NAND flash

 drivers/mtd/nand/spi/core.c    | 213 +++++++++++++++++++++++++----
 drivers/mtd/nand/spi/winbond.c | 242 +++++++++++++++++++++++++++++++--
 include/linux/mtd/spinand.h    | 154 +++++++++++++++++++--
 include/linux/spi/spi-mem.h    |  41 ++++++
 4 files changed, 599 insertions(+), 51 deletions(-)

-- 
2.25.1


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

* [PATCH v3 00/17] mtd: spinand: Add Octal DTR SPI (8D-8D-8D) mode support
@ 2022-01-01  7:42 ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Hi,
This series proposes patches for adding the following functionality
in SPI NAND core:

- Octal DTR SPI (8D-8D-8D) mode support

- ctrl_ops support

- Winbond W35N01JW SPI NAND chip support

This series has been tested on TI J721e EVM with the Winbond W35N01JW
flash with following test utilities:

- nandtest
  Test log: https://pastebin.com/raw/PusiLYVQ

- mtd_stresstest
  Test log: https://pastebin.com/raw/gBtV2CAf

- UBIFS LTP stress test (NAND_XL_STRESS_DD_RW_UBIFS).
  Test log: https://pastebin.com/raw/J8WyLsz1

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

---
Changes in v3:

- Added support for ctrl_ops, data_ops and ctrl_ops_variants.

- Made the implementation generic in terms of spinand protocol and SPI mode
  changes.

- Added option to disable Octal DTR mode.

- Removed spinand_patch_op(), adjust_op() manufacturer_op.

- Removed Power-on-Reset functionality and its call from mtd_suspend(), now 
  just disable Octal DTR at suspend.


Changes in v2:

- Removed *_ALL_ARGS() macros from spi-mem.h, and redefined DTR macros.

- Renamed spinand_setup_op() to spinand_patch_op(). Reduced one
  conditional check from this function. Had to keep tweaking in hot-path
  to avoid complicated implementation "hacks".

- Changes in commit messages and added comments.

- Dropped "Reject 8D-8D-8D op_templates if octal_dtr_enale() is
  missing in manufacturer_op" patch.

- Reduced PoR reset delay.

- Splitted "mtd: spinand: Add support for Winbond W35N01JW SPI NAND
  flash" into 3 independent patches.


Apurva Nandan (17):
  spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  mtd: spinand: Define macros for Octal DTR ops
  mtd: spinand: Add enum spinand_protocol to indicate current SPI IO
    mode
  mtd: spinand: Rename 'op_templates' to 'data_ops'
  mtd: spinand: Define ctrl_ops for non-page read/write op templates
  mtd: spinand: Define default ctrl_ops in the core
  mtd: spinand: Switch from op macros usage to 'ctrl_ops' in the core
  mtd: spinand: Add support for manufacturer-based ctrl_ops variations
  mtd: spinand: Add change_mode() in manufacturer_ops
  mtd: spinand: Add pointer to probed flash's spinand_info
  mtd: spinand: Allow enabling/disabling Octal DTR mode in the core
  mtd: spinand: Add mtd_suspend() to disable Octal DTR mode at suspend
  mtd: spinand: winbond: Add support for write volatile configuration
    register op
  mtd: spinand: winbond: Add octal_dtr_enable/disable() in
    manufacturer_ops
  mtd: spianand: winbond: Add change_mode() manufacturer_ops
  mtd: spinand: winbond: Rename cache op_variants struct variable
  mtd: spinand: winbond: Add support for Winbond W35N01JW SPI NAND flash

 drivers/mtd/nand/spi/core.c    | 213 +++++++++++++++++++++++++----
 drivers/mtd/nand/spi/winbond.c | 242 +++++++++++++++++++++++++++++++--
 include/linux/mtd/spinand.h    | 154 +++++++++++++++++++--
 include/linux/spi/spi-mem.h    |  41 ++++++
 4 files changed, 599 insertions(+), 51 deletions(-)

-- 
2.25.1


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

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

* [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Setting dtr field of spi_mem_op is useful when creating templates
for DTR ops in spinand.h. Also, 2 bytes cmd phases are required when
operating in Octal DTR SPI mode.

Create new templates for dtr mode cmd, address, dummy and data phase
in spi_mem_op, which set the dtr field to 1 and also allow passing
the nbytes for the cmd phase.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/spi/spi-mem.h | 41 +++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 85e2ff7b840d..682378a9c600 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -20,6 +20,14 @@
 		.nbytes = 1,					\
 	}
 
+#define SPI_MEM_OP_CMD_DTR(__nbytes, __opcode, __buswidth)	\
+	{							\
+		.nbytes = __nbytes,				\
+		.opcode = __opcode,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)		\
 	{							\
 		.nbytes = __nbytes,				\
@@ -27,6 +35,14 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_ADDR_DTR(__nbytes, __val, __buswidth)	\
+	{							\
+		.nbytes = __nbytes,				\
+		.val = __val,					\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_NO_ADDR	{ }
 
 #define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\
@@ -35,6 +51,13 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_DUMMY_DTR(__nbytes, __buswidth)		\
+	{							\
+		.nbytes = __nbytes,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_NO_DUMMY	{ }
 
 #define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)		\
@@ -45,6 +68,15 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_DATA_IN_DTR(__nbytes, __buf, __buswidth)	\
+	{							\
+		.dir = SPI_MEM_DATA_IN,				\
+		.nbytes = __nbytes,				\
+		.buf.in = __buf,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)	\
 	{							\
 		.dir = SPI_MEM_DATA_OUT,			\
@@ -53,6 +85,15 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_DATA_OUT_DTR(__nbytes, __buf, __buswidth)	\
+	{							\
+		.dir = SPI_MEM_DATA_OUT,			\
+		.nbytes = __nbytes,				\
+		.buf.out = __buf,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_NO_DATA	{ }
 
 /**
-- 
2.25.1


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

* [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Setting dtr field of spi_mem_op is useful when creating templates
for DTR ops in spinand.h. Also, 2 bytes cmd phases are required when
operating in Octal DTR SPI mode.

Create new templates for dtr mode cmd, address, dummy and data phase
in spi_mem_op, which set the dtr field to 1 and also allow passing
the nbytes for the cmd phase.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/spi/spi-mem.h | 41 +++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 85e2ff7b840d..682378a9c600 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -20,6 +20,14 @@
 		.nbytes = 1,					\
 	}
 
+#define SPI_MEM_OP_CMD_DTR(__nbytes, __opcode, __buswidth)	\
+	{							\
+		.nbytes = __nbytes,				\
+		.opcode = __opcode,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)		\
 	{							\
 		.nbytes = __nbytes,				\
@@ -27,6 +35,14 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_ADDR_DTR(__nbytes, __val, __buswidth)	\
+	{							\
+		.nbytes = __nbytes,				\
+		.val = __val,					\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_NO_ADDR	{ }
 
 #define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\
@@ -35,6 +51,13 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_DUMMY_DTR(__nbytes, __buswidth)		\
+	{							\
+		.nbytes = __nbytes,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_NO_DUMMY	{ }
 
 #define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)		\
@@ -45,6 +68,15 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_DATA_IN_DTR(__nbytes, __buf, __buswidth)	\
+	{							\
+		.dir = SPI_MEM_DATA_IN,				\
+		.nbytes = __nbytes,				\
+		.buf.in = __buf,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)	\
 	{							\
 		.dir = SPI_MEM_DATA_OUT,			\
@@ -53,6 +85,15 @@
 		.buswidth = __buswidth,				\
 	}
 
+#define SPI_MEM_OP_DATA_OUT_DTR(__nbytes, __buf, __buswidth)	\
+	{							\
+		.dir = SPI_MEM_DATA_OUT,			\
+		.nbytes = __nbytes,				\
+		.buf.out = __buf,				\
+		.buswidth = __buswidth,				\
+		.dtr = 1,					\
+	}
+
 #define SPI_MEM_OP_NO_DATA	{ }
 
 /**
-- 
2.25.1


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

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

* [PATCH v3 02/17] mtd: spinand: Define macros for Octal DTR ops
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Define new op templates for reset, write enable, set_feature,
get_feature, block_erase, read/write page operations for Octal DTR SPI
mode. These templates will be used in data_ops and ctrl_ops for
performing all flash operations.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/mtd/spinand.h | 54 +++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6988956b8492..69e06e741717 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -26,12 +26,24 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_RESET_OP_OCTAL_DTR					\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0xffff, 8),			\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_WR_EN_DIS_OP(enable)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1),		\
 		   SPI_MEM_OP_NO_ADDR,					\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_WR_EN_DIS_OP_OCTAL_DTR(enable)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, (enable) ? 0x0606 : 0x0404, 8),\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_READID_OP(naddr, ndummy, buf, len)			\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),				\
 		   SPI_MEM_OP_ADDR(naddr, 0, 1),			\
@@ -44,24 +56,48 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(1, valptr, 1))
 
+#define SPINAND_SET_FEATURE_OP_OCTAL_DTR(reg, valptr)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x1f1f, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, reg, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT_DTR(2, valptr, 8))
+
 #define SPINAND_GET_FEATURE_OP(reg, valptr)				\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1),				\
 		   SPI_MEM_OP_ADDR(1, reg, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_IN(1, valptr, 1))
 
+#define SPINAND_GET_FEATURE_OP_OCTAL_DTR(reg, valptr)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x0f0f, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, reg, 8),			\
+		   SPI_MEM_OP_DUMMY_DTR(14, 8),				\
+		   SPI_MEM_OP_DATA_IN_DTR(2, valptr, 8))
+
 #define SPINAND_BLK_ERASE_OP(addr)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1),				\
 		   SPI_MEM_OP_ADDR(3, addr, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_BLK_ERASE_OP_OCTAL_DTR(addr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0xd8d8, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_PAGE_READ_OP(addr)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1),				\
 		   SPI_MEM_OP_ADDR(3, addr, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_PAGE_READ_OP_OCTAL_DTR(addr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x1313, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len)	\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),		\
 		   SPI_MEM_OP_ADDR(2, addr, 1),				\
@@ -122,12 +158,24 @@
 		   SPI_MEM_OP_DUMMY(ndummy, 4),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(addr, ndummy, buf, len) \
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x9d9d, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_DUMMY_DTR(ndummy, 8),			\
+		   SPI_MEM_OP_DATA_IN_DTR(len, buf, 8))
+
 #define SPINAND_PROG_EXEC_OP(addr)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),				\
 		   SPI_MEM_OP_ADDR(3, addr, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_PROG_EXEC_OP_OCTAL_DTR(addr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x1010, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_PROG_LOAD(reset, addr, buf, len)			\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1),		\
 		   SPI_MEM_OP_ADDR(2, addr, 1),				\
@@ -140,6 +188,12 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(len, buf, 4))
 
+#define SPINAND_PROG_LOAD_OCTALIO_DTR(reset, addr, buf, len)		\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, reset ? 0x0202 : 0x8484, 8),	\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT_DTR(len, buf, 8))
+
 /**
  * Standard SPI NAND flash commands
  */
-- 
2.25.1


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

* [PATCH v3 02/17] mtd: spinand: Define macros for Octal DTR ops
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Define new op templates for reset, write enable, set_feature,
get_feature, block_erase, read/write page operations for Octal DTR SPI
mode. These templates will be used in data_ops and ctrl_ops for
performing all flash operations.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/mtd/spinand.h | 54 +++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6988956b8492..69e06e741717 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -26,12 +26,24 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_RESET_OP_OCTAL_DTR					\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0xffff, 8),			\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_WR_EN_DIS_OP(enable)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1),		\
 		   SPI_MEM_OP_NO_ADDR,					\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_WR_EN_DIS_OP_OCTAL_DTR(enable)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, (enable) ? 0x0606 : 0x0404, 8),\
+		   SPI_MEM_OP_NO_ADDR,					\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_READID_OP(naddr, ndummy, buf, len)			\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),				\
 		   SPI_MEM_OP_ADDR(naddr, 0, 1),			\
@@ -44,24 +56,48 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(1, valptr, 1))
 
+#define SPINAND_SET_FEATURE_OP_OCTAL_DTR(reg, valptr)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x1f1f, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, reg, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT_DTR(2, valptr, 8))
+
 #define SPINAND_GET_FEATURE_OP(reg, valptr)				\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1),				\
 		   SPI_MEM_OP_ADDR(1, reg, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_IN(1, valptr, 1))
 
+#define SPINAND_GET_FEATURE_OP_OCTAL_DTR(reg, valptr)			\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x0f0f, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, reg, 8),			\
+		   SPI_MEM_OP_DUMMY_DTR(14, 8),				\
+		   SPI_MEM_OP_DATA_IN_DTR(2, valptr, 8))
+
 #define SPINAND_BLK_ERASE_OP(addr)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1),				\
 		   SPI_MEM_OP_ADDR(3, addr, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_BLK_ERASE_OP_OCTAL_DTR(addr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0xd8d8, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_PAGE_READ_OP(addr)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1),				\
 		   SPI_MEM_OP_ADDR(3, addr, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_PAGE_READ_OP_OCTAL_DTR(addr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x1313, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len)	\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),		\
 		   SPI_MEM_OP_ADDR(2, addr, 1),				\
@@ -122,12 +158,24 @@
 		   SPI_MEM_OP_DUMMY(ndummy, 4),				\
 		   SPI_MEM_OP_DATA_IN(len, buf, 4))
 
+#define SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(addr, ndummy, buf, len) \
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x9d9d, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_DUMMY_DTR(ndummy, 8),			\
+		   SPI_MEM_OP_DATA_IN_DTR(len, buf, 8))
+
 #define SPINAND_PROG_EXEC_OP(addr)					\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),				\
 		   SPI_MEM_OP_ADDR(3, addr, 1),				\
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_NO_DATA)
 
+#define SPINAND_PROG_EXEC_OP_OCTAL_DTR(addr)				\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x1010, 8),			\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_NO_DATA)
+
 #define SPINAND_PROG_LOAD(reset, addr, buf, len)			\
 	SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1),		\
 		   SPI_MEM_OP_ADDR(2, addr, 1),				\
@@ -140,6 +188,12 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT(len, buf, 4))
 
+#define SPINAND_PROG_LOAD_OCTALIO_DTR(reset, addr, buf, len)		\
+	SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, reset ? 0x0202 : 0x8484, 8),	\
+		   SPI_MEM_OP_ADDR_DTR(2, addr, 8),			\
+		   SPI_MEM_OP_NO_DUMMY,					\
+		   SPI_MEM_OP_DATA_OUT_DTR(len, buf, 8))
+
 /**
  * Standard SPI NAND flash commands
  */
-- 
2.25.1


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

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

* [PATCH v3 03/17] mtd: spinand: Add enum spinand_protocol to indicate current SPI IO mode
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Unlike Dual and Quad SPI modes flashes, Octal DTR SPI NAND flashes
require all instructions to be made in 8D-8D-8D protocol when the
flash is in Octal DTR mode. Hence, storing the current SPI IO mode
becomes necessary for operating the flash and switching between modes.

Store the current SPI IO mode in the spinand struct using a
spinand_protocol enum. This would act as a flag, denoting that the
core should use the given SPI protocol all types of flash operations.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c |  2 ++
 include/linux/mtd/spinand.h | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 2c8685f1f2fa..7d8c2873ab29 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1155,6 +1155,7 @@ static void spinand_mtd_resume(struct mtd_info *mtd)
 	struct spinand_device *spinand = mtd_to_spinand(mtd);
 	int ret;
 
+	spinand->protocol = SPINAND_1S_1S_1S;
 	ret = spinand_reset_op(spinand);
 	if (ret)
 		return;
@@ -1181,6 +1182,7 @@ static int spinand_init(struct spinand_device *spinand)
 	if (!spinand->scratchbuf)
 		return -ENOMEM;
 
+	spinand->protocol = SPINAND_1S_1S_1S;
 	ret = spinand_detect(spinand);
 	if (ret)
 		goto err_free_bufs;
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 69e06e741717..77927afcea0f 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -194,6 +194,18 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT_DTR(len, buf, 8))
 
+/**
+ * enum spinand_protocol - List of SPI protocols to denote the op protocol and
+ *			   SPI NAND flash IO modes.
+ */
+enum spinand_protocol {
+	SPINAND_1S_1S_1S,
+	SPINAND_2S_2S_2S,
+	SPINAND_4S_4S_4S,
+	SPINAND_8S_8S_8S,
+	SPINAND_8D_8D_8D,
+};
+
 /**
  * Standard SPI NAND flash commands
  */
@@ -461,6 +473,8 @@ struct spinand_dirmap {
  *		   this die. Only required if your chip exposes several dies
  * @cur_target: currently selected target/die
  * @eccinfo: on-die ECC information
+ * @protocol: SPI IO protocol in operation. Update on successful transition into
+ *	      a different SPI IO protocol.
  * @cfg_cache: config register cache. One entry per die
  * @databuf: bounce buffer for data
  * @oobbuf: bounce buffer for OOB data
@@ -492,6 +506,8 @@ struct spinand_device {
 
 	struct spinand_ecc_info eccinfo;
 
+	enum spinand_protocol protocol;
+
 	u8 *cfg_cache;
 	u8 *databuf;
 	u8 *oobbuf;
-- 
2.25.1


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

* [PATCH v3 03/17] mtd: spinand: Add enum spinand_protocol to indicate current SPI IO mode
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Unlike Dual and Quad SPI modes flashes, Octal DTR SPI NAND flashes
require all instructions to be made in 8D-8D-8D protocol when the
flash is in Octal DTR mode. Hence, storing the current SPI IO mode
becomes necessary for operating the flash and switching between modes.

Store the current SPI IO mode in the spinand struct using a
spinand_protocol enum. This would act as a flag, denoting that the
core should use the given SPI protocol all types of flash operations.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c |  2 ++
 include/linux/mtd/spinand.h | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 2c8685f1f2fa..7d8c2873ab29 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1155,6 +1155,7 @@ static void spinand_mtd_resume(struct mtd_info *mtd)
 	struct spinand_device *spinand = mtd_to_spinand(mtd);
 	int ret;
 
+	spinand->protocol = SPINAND_1S_1S_1S;
 	ret = spinand_reset_op(spinand);
 	if (ret)
 		return;
@@ -1181,6 +1182,7 @@ static int spinand_init(struct spinand_device *spinand)
 	if (!spinand->scratchbuf)
 		return -ENOMEM;
 
+	spinand->protocol = SPINAND_1S_1S_1S;
 	ret = spinand_detect(spinand);
 	if (ret)
 		goto err_free_bufs;
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 69e06e741717..77927afcea0f 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -194,6 +194,18 @@
 		   SPI_MEM_OP_NO_DUMMY,					\
 		   SPI_MEM_OP_DATA_OUT_DTR(len, buf, 8))
 
+/**
+ * enum spinand_protocol - List of SPI protocols to denote the op protocol and
+ *			   SPI NAND flash IO modes.
+ */
+enum spinand_protocol {
+	SPINAND_1S_1S_1S,
+	SPINAND_2S_2S_2S,
+	SPINAND_4S_4S_4S,
+	SPINAND_8S_8S_8S,
+	SPINAND_8D_8D_8D,
+};
+
 /**
  * Standard SPI NAND flash commands
  */
@@ -461,6 +473,8 @@ struct spinand_dirmap {
  *		   this die. Only required if your chip exposes several dies
  * @cur_target: currently selected target/die
  * @eccinfo: on-die ECC information
+ * @protocol: SPI IO protocol in operation. Update on successful transition into
+ *	      a different SPI IO protocol.
  * @cfg_cache: config register cache. One entry per die
  * @databuf: bounce buffer for data
  * @oobbuf: bounce buffer for OOB data
@@ -492,6 +506,8 @@ struct spinand_device {
 
 	struct spinand_ecc_info eccinfo;
 
+	enum spinand_protocol protocol;
+
 	u8 *cfg_cache;
 	u8 *databuf;
 	u8 *oobbuf;
-- 
2.25.1


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

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

* [PATCH v3 04/17] mtd: spinand: Rename 'op_templates' to 'data_ops'
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Manufacturers have been deviating from the standard SPI operations for
NAND flashes. There have been variations in non-page read/write
instructions too. Additionally, operations, including non-page r/w ops,
vary when flash is in different SPI mode, eg. Octal DTR.

To avoid live-patching in hot-paths or vendor-specific adjustment,
it is better to have a set of operation templates and variants for
non-page read/write operations as well. These would get initialized at
the probe time or when flash changes modes. These would be called
'ctrl_ops'.

To make code better understandable, create two types of op templates
which are: data_ops and ctrl_ops. Reason for having two different type
of templates is the difference in their use cases i.e. it is possible
to have ops of different protocol for read/write/update simulatneously
in the data_ops, but all the ops in the ctrl_ops follow same protocol.

Rename op_templates to data_ops, and the ctrl_ops would be introduced
in later commits.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 32 ++++++++++++++++----------------
 include/linux/mtd/spinand.h | 26 +++++++++++++-------------
 2 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 7d8c2873ab29..481516c9db79 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->data_ops.read_cache->data.buswidth == 4 ||
+	    spinand->data_ops.write_cache->data.buswidth == 4 ||
+	    spinand->data_ops.update_cache->data.buswidth == 4)
 		enable = true;
 
 	return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE,
@@ -849,7 +849,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 	/* The plane number is passed in MSB just above the column address */
 	info.offset = plane << fls(nand->memorg.pagesize);
 
-	info.op_tmpl = *spinand->op_templates.update_cache;
+	info.op_tmpl = *spinand->data_ops.update_cache;
 	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
 					  spinand->spimem, &info);
 	if (IS_ERR(desc))
@@ -857,7 +857,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->data_ops.read_cache;
 	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
 					  spinand->spimem, &info);
 	if (IS_ERR(desc))
@@ -976,8 +976,8 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand)
 }
 
 static const struct spi_mem_op *
-spinand_select_op_variant(struct spinand_device *spinand,
-			  const struct spinand_op_variants *variants)
+spinand_select_data_op_variant(struct spinand_device *spinand,
+			       const struct spinand_op_variants *variants)
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	unsigned int i;
@@ -1050,23 +1050,23 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		spinand->id.len = 1 + table[i].devid.len;
 		spinand->select_target = table[i].select_target;
 
-		op = spinand_select_op_variant(spinand,
-					       info->op_variants.read_cache);
+		op = spinand_select_data_op_variant(spinand,
+					info->data_ops_variants.read_cache);
 		if (!op)
 			return -ENOTSUPP;
 
-		spinand->op_templates.read_cache = op;
+		spinand->data_ops.read_cache = op;
 
-		op = spinand_select_op_variant(spinand,
-					       info->op_variants.write_cache);
+		op = spinand_select_data_op_variant(spinand,
+					info->data_ops_variants.write_cache);
 		if (!op)
 			return -ENOTSUPP;
 
-		spinand->op_templates.write_cache = op;
+		spinand->data_ops.write_cache = op;
 
-		op = spinand_select_op_variant(spinand,
-					       info->op_variants.update_cache);
-		spinand->op_templates.update_cache = op;
+		op = spinand_select_data_op_variant(spinand,
+					info->data_ops_variants.update_cache);
+		spinand->data_ops.update_cache = op;
 
 		return 0;
 	}
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 77927afcea0f..439d8ce40e1d 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -391,10 +391,10 @@ struct spinand_ondie_ecc_conf {
  * @memorg: memory organization
  * @eccreq: ECC requirements
  * @eccinfo: on-die ECC info
- * @op_variants: operations variants
- * @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
+ * @data_ops_variants: operations variants for page read/writes
+ * @data_ops_variants.read_cache: variants of the read-cache operation
+ * @data_ops_variants.write_cache: variants of the write-cache operation
+ * @data_ops_variants.update_cache: variants of the update-cache operation
  * @select_target: function used to select a target/die. Required only for
  *		   multi-die chips
  *
@@ -412,7 +412,7 @@ struct spinand_info {
 		const struct spinand_op_variants *read_cache;
 		const struct spinand_op_variants *write_cache;
 		const struct spinand_op_variants *update_cache;
-	} op_variants;
+	} data_ops_variants;
 	int (*select_target)(struct spinand_device *spinand,
 			     unsigned int target);
 };
@@ -440,14 +440,14 @@ struct spinand_info {
 #define SPINAND_SELECT_TARGET(__func)					\
 	.select_target = __func,
 
-#define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants,	\
-		     __flags, ...)					\
+#define SPINAND_INFO(__model, __id, __memorg, __eccreq,			\
+		     __data_ops_variants, __flags, ...)			\
 	{								\
 		.model = __model,					\
 		.devid = __id,						\
 		.memorg = __memorg,					\
 		.eccreq = __eccreq,					\
-		.op_variants = __op_variants,				\
+		.data_ops_variants = __data_ops_variants,		\
 		.flags = __flags,					\
 		__VA_ARGS__						\
 	}
@@ -464,10 +464,10 @@ 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
+ * @data_ops: various SPI mem op templates for reading and writing on pages
+ * @data_ops.read_cache: read cache op template
+ * @data_ops.write_cache: write cache op template
+ * @data_ops.update_cache: update cache op template
  * @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
@@ -496,7 +496,7 @@ struct spinand_device {
 		const struct spi_mem_op *read_cache;
 		const struct spi_mem_op *write_cache;
 		const struct spi_mem_op *update_cache;
-	} op_templates;
+	} data_ops;
 
 	struct spinand_dirmap *dirmaps;
 
-- 
2.25.1


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

* [PATCH v3 04/17] mtd: spinand: Rename 'op_templates' to 'data_ops'
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Manufacturers have been deviating from the standard SPI operations for
NAND flashes. There have been variations in non-page read/write
instructions too. Additionally, operations, including non-page r/w ops,
vary when flash is in different SPI mode, eg. Octal DTR.

To avoid live-patching in hot-paths or vendor-specific adjustment,
it is better to have a set of operation templates and variants for
non-page read/write operations as well. These would get initialized at
the probe time or when flash changes modes. These would be called
'ctrl_ops'.

To make code better understandable, create two types of op templates
which are: data_ops and ctrl_ops. Reason for having two different type
of templates is the difference in their use cases i.e. it is possible
to have ops of different protocol for read/write/update simulatneously
in the data_ops, but all the ops in the ctrl_ops follow same protocol.

Rename op_templates to data_ops, and the ctrl_ops would be introduced
in later commits.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 32 ++++++++++++++++----------------
 include/linux/mtd/spinand.h | 26 +++++++++++++-------------
 2 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 7d8c2873ab29..481516c9db79 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->data_ops.read_cache->data.buswidth == 4 ||
+	    spinand->data_ops.write_cache->data.buswidth == 4 ||
+	    spinand->data_ops.update_cache->data.buswidth == 4)
 		enable = true;
 
 	return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE,
@@ -849,7 +849,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 	/* The plane number is passed in MSB just above the column address */
 	info.offset = plane << fls(nand->memorg.pagesize);
 
-	info.op_tmpl = *spinand->op_templates.update_cache;
+	info.op_tmpl = *spinand->data_ops.update_cache;
 	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
 					  spinand->spimem, &info);
 	if (IS_ERR(desc))
@@ -857,7 +857,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->data_ops.read_cache;
 	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
 					  spinand->spimem, &info);
 	if (IS_ERR(desc))
@@ -976,8 +976,8 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand)
 }
 
 static const struct spi_mem_op *
-spinand_select_op_variant(struct spinand_device *spinand,
-			  const struct spinand_op_variants *variants)
+spinand_select_data_op_variant(struct spinand_device *spinand,
+			       const struct spinand_op_variants *variants)
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	unsigned int i;
@@ -1050,23 +1050,23 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		spinand->id.len = 1 + table[i].devid.len;
 		spinand->select_target = table[i].select_target;
 
-		op = spinand_select_op_variant(spinand,
-					       info->op_variants.read_cache);
+		op = spinand_select_data_op_variant(spinand,
+					info->data_ops_variants.read_cache);
 		if (!op)
 			return -ENOTSUPP;
 
-		spinand->op_templates.read_cache = op;
+		spinand->data_ops.read_cache = op;
 
-		op = spinand_select_op_variant(spinand,
-					       info->op_variants.write_cache);
+		op = spinand_select_data_op_variant(spinand,
+					info->data_ops_variants.write_cache);
 		if (!op)
 			return -ENOTSUPP;
 
-		spinand->op_templates.write_cache = op;
+		spinand->data_ops.write_cache = op;
 
-		op = spinand_select_op_variant(spinand,
-					       info->op_variants.update_cache);
-		spinand->op_templates.update_cache = op;
+		op = spinand_select_data_op_variant(spinand,
+					info->data_ops_variants.update_cache);
+		spinand->data_ops.update_cache = op;
 
 		return 0;
 	}
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 77927afcea0f..439d8ce40e1d 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -391,10 +391,10 @@ struct spinand_ondie_ecc_conf {
  * @memorg: memory organization
  * @eccreq: ECC requirements
  * @eccinfo: on-die ECC info
- * @op_variants: operations variants
- * @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
+ * @data_ops_variants: operations variants for page read/writes
+ * @data_ops_variants.read_cache: variants of the read-cache operation
+ * @data_ops_variants.write_cache: variants of the write-cache operation
+ * @data_ops_variants.update_cache: variants of the update-cache operation
  * @select_target: function used to select a target/die. Required only for
  *		   multi-die chips
  *
@@ -412,7 +412,7 @@ struct spinand_info {
 		const struct spinand_op_variants *read_cache;
 		const struct spinand_op_variants *write_cache;
 		const struct spinand_op_variants *update_cache;
-	} op_variants;
+	} data_ops_variants;
 	int (*select_target)(struct spinand_device *spinand,
 			     unsigned int target);
 };
@@ -440,14 +440,14 @@ struct spinand_info {
 #define SPINAND_SELECT_TARGET(__func)					\
 	.select_target = __func,
 
-#define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants,	\
-		     __flags, ...)					\
+#define SPINAND_INFO(__model, __id, __memorg, __eccreq,			\
+		     __data_ops_variants, __flags, ...)			\
 	{								\
 		.model = __model,					\
 		.devid = __id,						\
 		.memorg = __memorg,					\
 		.eccreq = __eccreq,					\
-		.op_variants = __op_variants,				\
+		.data_ops_variants = __data_ops_variants,		\
 		.flags = __flags,					\
 		__VA_ARGS__						\
 	}
@@ -464,10 +464,10 @@ 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
+ * @data_ops: various SPI mem op templates for reading and writing on pages
+ * @data_ops.read_cache: read cache op template
+ * @data_ops.write_cache: write cache op template
+ * @data_ops.update_cache: update cache op template
  * @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
@@ -496,7 +496,7 @@ struct spinand_device {
 		const struct spi_mem_op *read_cache;
 		const struct spi_mem_op *write_cache;
 		const struct spi_mem_op *update_cache;
-	} op_templates;
+	} data_ops;
 
 	struct spinand_dirmap *dirmaps;
 
-- 
2.25.1


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

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

* [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

'ctrl_ops' are op templates for non-page read/write operations,
which are: reset, get_feature, set_feature, write_enable, block_erase,
page_read and program_execute ops. The 'ctrl_ops' struct contains in it
op templates for each of this op, as well as enum spinand_protocol
denoting protocol of all these ops.

We require these new op templates because of deviation in standard
SPINAND ops by manufacturers and also due to changes when there is a
change in SPI protocol/mode. This prevents the core from live-patching
and vendor-specific adjustments in ops.

Define 'ctrl_ops', add macros to initialize it and add it in
spinand_device.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 439d8ce40e1d..e5df6220ec1e 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -356,6 +356,35 @@ struct spinand_op_variants {
 			sizeof(struct spi_mem_op),			\
 	}
 
+struct spinand_ctrl_ops {
+	const struct {
+		struct spi_mem_op reset;
+		struct spi_mem_op get_feature;
+		struct spi_mem_op set_feature;
+		struct spi_mem_op write_enable;
+		struct spi_mem_op block_erase;
+		struct spi_mem_op page_read;
+		struct spi_mem_op program_execute;
+	} ops;
+	const enum spinand_protocol protocol;
+};
+
+#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
+			 __write_enable, __block_erase, __page_read,		\
+			 __program_execute)					\
+	{									\
+		.ops = {							\
+			.reset = __reset,					\
+			.get_feature = __get_feature,				\
+			.set_feature = __set_feature,				\
+			.write_enable = __write_enable,				\
+			.block_erase = __block_erase,				\
+			.page_read = __page_read,				\
+			.program_execute = __program_execute,			\
+		},								\
+		.protocol = __protocol,						\
+	}
+
 /**
  * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
  *		      chip
@@ -468,6 +497,8 @@ struct spinand_dirmap {
  * @data_ops.read_cache: read cache op template
  * @data_ops.write_cache: write cache op template
  * @data_ops.update_cache: update cache op template
+ * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
+ *	      non page-read/write ops.
  * @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
@@ -498,6 +529,8 @@ struct spinand_device {
 		const struct spi_mem_op *update_cache;
 	} data_ops;
 
+	const struct spinand_ctrl_ops *ctrl_ops;
+
 	struct spinand_dirmap *dirmaps;
 
 	int (*select_target)(struct spinand_device *spinand,
-- 
2.25.1


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

* [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

'ctrl_ops' are op templates for non-page read/write operations,
which are: reset, get_feature, set_feature, write_enable, block_erase,
page_read and program_execute ops. The 'ctrl_ops' struct contains in it
op templates for each of this op, as well as enum spinand_protocol
denoting protocol of all these ops.

We require these new op templates because of deviation in standard
SPINAND ops by manufacturers and also due to changes when there is a
change in SPI protocol/mode. This prevents the core from live-patching
and vendor-specific adjustments in ops.

Define 'ctrl_ops', add macros to initialize it and add it in
spinand_device.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 439d8ce40e1d..e5df6220ec1e 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -356,6 +356,35 @@ struct spinand_op_variants {
 			sizeof(struct spi_mem_op),			\
 	}
 
+struct spinand_ctrl_ops {
+	const struct {
+		struct spi_mem_op reset;
+		struct spi_mem_op get_feature;
+		struct spi_mem_op set_feature;
+		struct spi_mem_op write_enable;
+		struct spi_mem_op block_erase;
+		struct spi_mem_op page_read;
+		struct spi_mem_op program_execute;
+	} ops;
+	const enum spinand_protocol protocol;
+};
+
+#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
+			 __write_enable, __block_erase, __page_read,		\
+			 __program_execute)					\
+	{									\
+		.ops = {							\
+			.reset = __reset,					\
+			.get_feature = __get_feature,				\
+			.set_feature = __set_feature,				\
+			.write_enable = __write_enable,				\
+			.block_erase = __block_erase,				\
+			.page_read = __page_read,				\
+			.program_execute = __program_execute,			\
+		},								\
+		.protocol = __protocol,						\
+	}
+
 /**
  * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
  *		      chip
@@ -468,6 +497,8 @@ struct spinand_dirmap {
  * @data_ops.read_cache: read cache op template
  * @data_ops.write_cache: write cache op template
  * @data_ops.update_cache: update cache op template
+ * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
+ *	      non page-read/write ops.
  * @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
@@ -498,6 +529,8 @@ struct spinand_device {
 		const struct spi_mem_op *update_cache;
 	} data_ops;
 
+	const struct spinand_ctrl_ops *ctrl_ops;
+
 	struct spinand_dirmap *dirmaps;
 
 	int (*select_target)(struct spinand_device *spinand,
-- 
2.25.1


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

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

* [PATCH v3 06/17] mtd: spinand: Define default ctrl_ops in the core
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add default ctrl_ops in the core, which can be used when the op
templates are commonly used ones. Till now, the core had used only
fixed ctrl operations, so the default 'ctrl_ops' is just these ops
macros initialized with default arguments. The default protocol is
1S_1S_1S.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 481516c9db79..4a75eb06bb52 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -904,6 +904,16 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&winbond_spinand_manufacturer,
 };
 
+static const struct spinand_ctrl_ops spinand_default_ctrl_ops =
+			SPINAND_CTRL_OPS(SPINAND_1S_1S_1S,
+					 SPINAND_RESET_OP,
+					 SPINAND_GET_FEATURE_OP(0, NULL),
+					 SPINAND_SET_FEATURE_OP(0, NULL),
+					 SPINAND_WR_EN_DIS_OP(true),
+					 SPINAND_BLK_ERASE_OP(0),
+					 SPINAND_PAGE_READ_OP(0),
+					 SPINAND_PROG_EXEC_OP(0));
+
 static int spinand_manufacturer_match(struct spinand_device *spinand,
 				      enum spinand_readid_method rdid_method)
 {
@@ -1156,6 +1166,8 @@ static void spinand_mtd_resume(struct mtd_info *mtd)
 	int ret;
 
 	spinand->protocol = SPINAND_1S_1S_1S;
+	spinand->ctrl_ops = &spinand_default_ctrl_ops;
+
 	ret = spinand_reset_op(spinand);
 	if (ret)
 		return;
@@ -1183,6 +1195,8 @@ static int spinand_init(struct spinand_device *spinand)
 		return -ENOMEM;
 
 	spinand->protocol = SPINAND_1S_1S_1S;
+	spinand->ctrl_ops = &spinand_default_ctrl_ops;
+
 	ret = spinand_detect(spinand);
 	if (ret)
 		goto err_free_bufs;
-- 
2.25.1


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

* [PATCH v3 06/17] mtd: spinand: Define default ctrl_ops in the core
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add default ctrl_ops in the core, which can be used when the op
templates are commonly used ones. Till now, the core had used only
fixed ctrl operations, so the default 'ctrl_ops' is just these ops
macros initialized with default arguments. The default protocol is
1S_1S_1S.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 481516c9db79..4a75eb06bb52 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -904,6 +904,16 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&winbond_spinand_manufacturer,
 };
 
+static const struct spinand_ctrl_ops spinand_default_ctrl_ops =
+			SPINAND_CTRL_OPS(SPINAND_1S_1S_1S,
+					 SPINAND_RESET_OP,
+					 SPINAND_GET_FEATURE_OP(0, NULL),
+					 SPINAND_SET_FEATURE_OP(0, NULL),
+					 SPINAND_WR_EN_DIS_OP(true),
+					 SPINAND_BLK_ERASE_OP(0),
+					 SPINAND_PAGE_READ_OP(0),
+					 SPINAND_PROG_EXEC_OP(0));
+
 static int spinand_manufacturer_match(struct spinand_device *spinand,
 				      enum spinand_readid_method rdid_method)
 {
@@ -1156,6 +1166,8 @@ static void spinand_mtd_resume(struct mtd_info *mtd)
 	int ret;
 
 	spinand->protocol = SPINAND_1S_1S_1S;
+	spinand->ctrl_ops = &spinand_default_ctrl_ops;
+
 	ret = spinand_reset_op(spinand);
 	if (ret)
 		return;
@@ -1183,6 +1195,8 @@ static int spinand_init(struct spinand_device *spinand)
 		return -ENOMEM;
 
 	spinand->protocol = SPINAND_1S_1S_1S;
+	spinand->ctrl_ops = &spinand_default_ctrl_ops;
+
 	ret = spinand_detect(spinand);
 	if (ret)
 		goto err_free_bufs;
-- 
2.25.1


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

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

* [PATCH v3 07/17] mtd: spinand: Switch from op macros usage to 'ctrl_ops' in the core
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Make use of the ctrl_ops struct, to introduce the usage of templates
in non-page read/write operations as well. These templates are
initialized at the probe time or at SPI modes switches.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 4a75eb06bb52..30e90527ee3c 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -22,9 +22,11 @@
 
 static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
 {
-	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg,
-						      spinand->scratchbuf);
 	int ret;
+	struct spi_mem_op op = spinand->ctrl_ops->ops.get_feature;
+
+	op.data.buf.out = spinand->scratchbuf;
+	memset(&op.addr.val, reg, op.addr.nbytes);
 
 	ret = spi_mem_exec_op(spinand->spimem, &op);
 	if (ret)
@@ -36,10 +38,12 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
 
 static int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
 {
-	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(reg,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.set_feature;
+
+	op.data.buf.out = spinand->scratchbuf;
+	memset(&op.addr.val, reg, op.addr.nbytes);
+	memset(spinand->scratchbuf, val, op.data.nbytes);
 
-	*spinand->scratchbuf = val;
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
 
@@ -341,7 +345,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
 
 static int spinand_write_enable_op(struct spinand_device *spinand)
 {
-	struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.write_enable;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -351,7 +355,9 @@ 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_OP(row);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.page_read;
+
+	op.addr.val = row;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -475,7 +481,9 @@ 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_OP(row);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.program_execute;
+
+	op.addr.val = row;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -485,7 +493,9 @@ 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_OP(row);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.block_erase;
+
+	op.addr.val = row;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -495,11 +505,13 @@ static int spinand_wait(struct spinand_device *spinand,
 			unsigned long poll_delay_us,
 			u8 *s)
 {
-	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.get_feature;
 	u8 status;
 	int ret;
 
+	op.data.buf.out = spinand->scratchbuf;
+	memset(&op.addr.val, REG_STATUS, op.addr.nbytes);
+
 	ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0,
 				  initial_delay_us,
 				  poll_delay_us,
@@ -542,7 +554,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_OP;
+	struct spi_mem_op op = spinand->ctrl_ops->ops.reset;
 	int ret;
 
 	ret = spi_mem_exec_op(spinand->spimem, &op);
-- 
2.25.1


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

* [PATCH v3 07/17] mtd: spinand: Switch from op macros usage to 'ctrl_ops' in the core
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Make use of the ctrl_ops struct, to introduce the usage of templates
in non-page read/write operations as well. These templates are
initialized at the probe time or at SPI modes switches.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 4a75eb06bb52..30e90527ee3c 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -22,9 +22,11 @@
 
 static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
 {
-	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg,
-						      spinand->scratchbuf);
 	int ret;
+	struct spi_mem_op op = spinand->ctrl_ops->ops.get_feature;
+
+	op.data.buf.out = spinand->scratchbuf;
+	memset(&op.addr.val, reg, op.addr.nbytes);
 
 	ret = spi_mem_exec_op(spinand->spimem, &op);
 	if (ret)
@@ -36,10 +38,12 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
 
 static int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
 {
-	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(reg,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.set_feature;
+
+	op.data.buf.out = spinand->scratchbuf;
+	memset(&op.addr.val, reg, op.addr.nbytes);
+	memset(spinand->scratchbuf, val, op.data.nbytes);
 
-	*spinand->scratchbuf = val;
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
 
@@ -341,7 +345,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
 
 static int spinand_write_enable_op(struct spinand_device *spinand)
 {
-	struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.write_enable;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -351,7 +355,9 @@ 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_OP(row);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.page_read;
+
+	op.addr.val = row;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -475,7 +481,9 @@ 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_OP(row);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.program_execute;
+
+	op.addr.val = row;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -485,7 +493,9 @@ 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_OP(row);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.block_erase;
+
+	op.addr.val = row;
 
 	return spi_mem_exec_op(spinand->spimem, &op);
 }
@@ -495,11 +505,13 @@ static int spinand_wait(struct spinand_device *spinand,
 			unsigned long poll_delay_us,
 			u8 *s)
 {
-	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS,
-						      spinand->scratchbuf);
+	struct spi_mem_op op = spinand->ctrl_ops->ops.get_feature;
 	u8 status;
 	int ret;
 
+	op.data.buf.out = spinand->scratchbuf;
+	memset(&op.addr.val, REG_STATUS, op.addr.nbytes);
+
 	ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0,
 				  initial_delay_us,
 				  poll_delay_us,
@@ -542,7 +554,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_OP;
+	struct spi_mem_op op = spinand->ctrl_ops->ops.reset;
 	int ret;
 
 	ret = spi_mem_exec_op(spinand->spimem, &op);
-- 
2.25.1


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

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

* [PATCH v3 08/17] mtd: spinand: Add support for manufacturer-based ctrl_ops variations
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add ctrl_ops_variants, which can be used by the manufacturers' codes
to define their SPI control operation variants. Add a macro to easily
define ctrl_ops_varinats. This can be used to list out all the
supported ctrl ops with their respective protocols by the vendors.

Add spinand_select_ctrl_ops_variant() helper function to search for
a supported ctrl_ops variant with the required SPI protocol in a given
list of variants.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h | 17 +++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 30e90527ee3c..9688fdfc174e 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1031,6 +1031,42 @@ spinand_select_data_op_variant(struct spinand_device *spinand,
 	return NULL;
 }
 
+static const struct spinand_ctrl_ops *
+spinand_select_ctrl_ops_variant(struct spinand_device *spinand,
+				const struct spinand_ctrl_ops_variants *variants,
+				const enum spinand_protocol protocol)
+{
+	unsigned int i;
+
+	for (i = 0; i < variants->nvariants; i++) {
+		const struct spinand_ctrl_ops *ctrl_ops =
+			&variants->ctrl_ops_list[i];
+
+		if (ctrl_ops->protocol != protocol)
+			continue;
+
+		if (!spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.reset) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.get_feature) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.set_feature) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.write_enable) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.block_erase) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.page_read) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.program_execute))
+			continue;
+
+		return ctrl_ops;
+	}
+
+	return NULL;
+}
+
 /**
  * spinand_match_and_init() - Try to find a match between a device ID and an
  *			      entry in a spinand_info table
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index e5df6220ec1e..5dae0649f2fb 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -385,6 +385,18 @@ struct spinand_ctrl_ops {
 		.protocol = __protocol,						\
 	}
 
+struct spinand_ctrl_ops_variants {
+	const struct spinand_ctrl_ops *ctrl_ops_list;
+	unsigned int nvariants;
+};
+
+#define SPINAND_CTRL_OPS_VARIANTS(name, ...)					\
+	const struct spinand_ctrl_ops_variants name = {				\
+		.ctrl_ops_list = (struct spinand_ctrl_ops[]){ __VA_ARGS__ },	\
+		.nvariants = sizeof((struct spinand_ctrl_ops[]){ __VA_ARGS__ })/\
+			     sizeof(struct spinand_ctrl_ops),			\
+	}
+
 /**
  * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
  *		      chip
@@ -442,6 +454,8 @@ struct spinand_info {
 		const struct spinand_op_variants *write_cache;
 		const struct spinand_op_variants *update_cache;
 	} data_ops_variants;
+
+	const struct spinand_ctrl_ops_variants *ctrl_ops_variants;
 	int (*select_target)(struct spinand_device *spinand,
 			     unsigned int target);
 };
@@ -460,6 +474,9 @@ struct spinand_info {
 		.update_cache = __update,				\
 	}
 
+#define SPINAND_INFO_CTRL_OPS_VARIANTS(__ctrl_ops_variants)		\
+	.ctrl_ops_variants = __ctrl_ops_variants
+
 #define SPINAND_ECCINFO(__ooblayout, __get_status)			\
 	.eccinfo = {							\
 		.ooblayout = __ooblayout,				\
-- 
2.25.1


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

* [PATCH v3 08/17] mtd: spinand: Add support for manufacturer-based ctrl_ops variations
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add ctrl_ops_variants, which can be used by the manufacturers' codes
to define their SPI control operation variants. Add a macro to easily
define ctrl_ops_varinats. This can be used to list out all the
supported ctrl ops with their respective protocols by the vendors.

Add spinand_select_ctrl_ops_variant() helper function to search for
a supported ctrl_ops variant with the required SPI protocol in a given
list of variants.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h | 17 +++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 30e90527ee3c..9688fdfc174e 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1031,6 +1031,42 @@ spinand_select_data_op_variant(struct spinand_device *spinand,
 	return NULL;
 }
 
+static const struct spinand_ctrl_ops *
+spinand_select_ctrl_ops_variant(struct spinand_device *spinand,
+				const struct spinand_ctrl_ops_variants *variants,
+				const enum spinand_protocol protocol)
+{
+	unsigned int i;
+
+	for (i = 0; i < variants->nvariants; i++) {
+		const struct spinand_ctrl_ops *ctrl_ops =
+			&variants->ctrl_ops_list[i];
+
+		if (ctrl_ops->protocol != protocol)
+			continue;
+
+		if (!spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.reset) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.get_feature) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.set_feature) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.write_enable) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.block_erase) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.page_read) ||
+		    !spi_mem_supports_op(spinand->spimem,
+					 &ctrl_ops->ops.program_execute))
+			continue;
+
+		return ctrl_ops;
+	}
+
+	return NULL;
+}
+
 /**
  * spinand_match_and_init() - Try to find a match between a device ID and an
  *			      entry in a spinand_info table
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index e5df6220ec1e..5dae0649f2fb 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -385,6 +385,18 @@ struct spinand_ctrl_ops {
 		.protocol = __protocol,						\
 	}
 
+struct spinand_ctrl_ops_variants {
+	const struct spinand_ctrl_ops *ctrl_ops_list;
+	unsigned int nvariants;
+};
+
+#define SPINAND_CTRL_OPS_VARIANTS(name, ...)					\
+	const struct spinand_ctrl_ops_variants name = {				\
+		.ctrl_ops_list = (struct spinand_ctrl_ops[]){ __VA_ARGS__ },	\
+		.nvariants = sizeof((struct spinand_ctrl_ops[]){ __VA_ARGS__ })/\
+			     sizeof(struct spinand_ctrl_ops),			\
+	}
+
 /**
  * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
  *		      chip
@@ -442,6 +454,8 @@ struct spinand_info {
 		const struct spinand_op_variants *write_cache;
 		const struct spinand_op_variants *update_cache;
 	} data_ops_variants;
+
+	const struct spinand_ctrl_ops_variants *ctrl_ops_variants;
 	int (*select_target)(struct spinand_device *spinand,
 			     unsigned int target);
 };
@@ -460,6 +474,9 @@ struct spinand_info {
 		.update_cache = __update,				\
 	}
 
+#define SPINAND_INFO_CTRL_OPS_VARIANTS(__ctrl_ops_variants)		\
+	.ctrl_ops_variants = __ctrl_ops_variants
+
 #define SPINAND_ECCINFO(__ooblayout, __get_status)			\
 	.eccinfo = {							\
 		.ooblayout = __ooblayout,				\
-- 
2.25.1


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

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

* [PATCH v3 09/17] mtd: spinand: Add change_mode() in manufacturer_ops
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Introduce change_mode() manufacturer_op to let the vendor provide the
implementation of switching of SPI IO modes.

The method to switch to different SPI IO mode may vary across
manufacturers. For example, for Winbond, Octal DTR is enabled by
writing values to the volatile configuration register. So, let the
manufacturer's code have their own implementation for switching to
any given SPI IO mode. Manufacturer's code need to take care, if
the requested protocol change is allowed/needed and how to apply
it.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/mtd/spinand.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 5dae0649f2fb..ad924271a248 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -298,6 +298,7 @@ struct spinand_devid {
 /**
  * struct manufacurer_ops - SPI NAND manufacturer specific operations
  * @init: initialize a SPI NAND device
+ * @change_mode: switch the SPI NAND flash to a specific SPI protocol
  * @cleanup: cleanup a SPI NAND device
  *
  * Each SPI NAND manufacturer driver should implement this interface so that
@@ -305,6 +306,8 @@ struct spinand_devid {
  */
 struct spinand_manufacturer_ops {
 	int (*init)(struct spinand_device *spinand);
+	int (*change_mode)(struct spinand_device *spinand,
+			   const enum spinand_protocol protocol);
 	void (*cleanup)(struct spinand_device *spinand);
 };
 
-- 
2.25.1


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

* [PATCH v3 09/17] mtd: spinand: Add change_mode() in manufacturer_ops
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Introduce change_mode() manufacturer_op to let the vendor provide the
implementation of switching of SPI IO modes.

The method to switch to different SPI IO mode may vary across
manufacturers. For example, for Winbond, Octal DTR is enabled by
writing values to the volatile configuration register. So, let the
manufacturer's code have their own implementation for switching to
any given SPI IO mode. Manufacturer's code need to take care, if
the requested protocol change is allowed/needed and how to apply
it.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 include/linux/mtd/spinand.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 5dae0649f2fb..ad924271a248 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -298,6 +298,7 @@ struct spinand_devid {
 /**
  * struct manufacurer_ops - SPI NAND manufacturer specific operations
  * @init: initialize a SPI NAND device
+ * @change_mode: switch the SPI NAND flash to a specific SPI protocol
  * @cleanup: cleanup a SPI NAND device
  *
  * Each SPI NAND manufacturer driver should implement this interface so that
@@ -305,6 +306,8 @@ struct spinand_devid {
  */
 struct spinand_manufacturer_ops {
 	int (*init)(struct spinand_device *spinand);
+	int (*change_mode)(struct spinand_device *spinand,
+			   const enum spinand_protocol protocol);
 	void (*cleanup)(struct spinand_device *spinand);
 };
 
-- 
2.25.1


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

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

* [PATCH v3 10/17] mtd: spinand: Add pointer to probed flash's spinand_info
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

The data_ops_variants and ctrl_ops_variants defined in manufacturer's
code are required again when changing flash modes, because they hold
the op templates for the new protocol. It would be useful to have a
pointer to the device description entry i.e. probed flash's
spinand_info table in the spinand_device struct itself.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 1 +
 include/linux/mtd/spinand.h | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 9688fdfc174e..1a602e4dd6bd 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1107,6 +1107,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		spinand->flags = table[i].flags;
 		spinand->id.len = 1 + table[i].devid.len;
 		spinand->select_target = table[i].select_target;
+		spinand->desc_entry = &table[i];
 
 		op = spinand_select_data_op_variant(spinand,
 					info->data_ops_variants.read_cache);
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index ad924271a248..a8c071983a27 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -534,6 +534,8 @@ struct spinand_dirmap {
  *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
  *		the stack
  * @manufacturer: SPI NAND manufacturer information
+ * @desc_entry: pointer to device description entry in the manufacturer's
+ *		spinand_info tables
  * @priv: manufacturer private data
  */
 struct spinand_device {
@@ -566,6 +568,7 @@ struct spinand_device {
 	u8 *oobbuf;
 	u8 *scratchbuf;
 	const struct spinand_manufacturer *manufacturer;
+	const struct spinand_info *desc_entry;
 	void *priv;
 };
 
-- 
2.25.1


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

* [PATCH v3 10/17] mtd: spinand: Add pointer to probed flash's spinand_info
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

The data_ops_variants and ctrl_ops_variants defined in manufacturer's
code are required again when changing flash modes, because they hold
the op templates for the new protocol. It would be useful to have a
pointer to the device description entry i.e. probed flash's
spinand_info table in the spinand_device struct itself.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 1 +
 include/linux/mtd/spinand.h | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 9688fdfc174e..1a602e4dd6bd 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1107,6 +1107,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
 		spinand->flags = table[i].flags;
 		spinand->id.len = 1 + table[i].devid.len;
 		spinand->select_target = table[i].select_target;
+		spinand->desc_entry = &table[i];
 
 		op = spinand_select_data_op_variant(spinand,
 					info->data_ops_variants.read_cache);
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index ad924271a248..a8c071983a27 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -534,6 +534,8 @@ struct spinand_dirmap {
  *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
  *		the stack
  * @manufacturer: SPI NAND manufacturer information
+ * @desc_entry: pointer to device description entry in the manufacturer's
+ *		spinand_info tables
  * @priv: manufacturer private data
  */
 struct spinand_device {
@@ -566,6 +568,7 @@ struct spinand_device {
 	u8 *oobbuf;
 	u8 *scratchbuf;
 	const struct spinand_manufacturer *manufacturer;
+	const struct spinand_info *desc_entry;
 	void *priv;
 };
 
-- 
2.25.1


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

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

* [PATCH v3 11/17] mtd: spinand: Allow enabling/disabling Octal DTR mode in the core
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Enable Octal DTR SPI mode, i.e. 8D-8D-8D mode, if the SPI NAND flash
device supports it. Mixed OSPI (1S-1S-8S & 1S-8S-8S), mixed DTR modes
(1S-1D-8D), etc. aren't supported yet.

The method to switch to Octal DTR SPI mode may vary across
manufacturers. For example, for Winbond, it is enabled by writing
values to the volatile configuration register. So, let the
manufacturer's code have their own implementation for switching to
Octal DTR SPI mode.

Check for the SPI NAND device's support for Octal DTR mode using
spinand flags, and if the data_ops and ctrl_ops are 8D-8D-8D, call
change_mode() manufacturer op. If the SPI controller doesn't
supports these modes, the selected data_ops and ctrl_ops will
prevent switching to the Octal DTR mode. And finally update the
spinand protocol and ctrl_ops on success. Similarly, for disabling
Octal DTR mode, call change_mode(), and update protocol and ctrl_ops.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 79 +++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h |  1 +
 2 files changed, 80 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 1a602e4dd6bd..2fd08085db6f 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1067,6 +1067,81 @@ spinand_select_ctrl_ops_variant(struct spinand_device *spinand,
 	return NULL;
 }
 
+static bool spinand_op_is_octal_dtr(const struct spi_mem_op *op)
+{
+	return  op->cmd.buswidth == 8 && op->cmd.dtr &&
+		op->addr.buswidth == 8 && op->addr.dtr &&
+		op->data.buswidth == 8 && op->data.dtr;
+}
+
+static int spinand_init_octal_dtr_enable(struct spinand_device *spinand)
+{
+	struct device *dev = &spinand->spimem->spi->dev;
+	const struct spinand_ctrl_ops *octal_dtr_ctrl_ops;
+	int ret;
+
+	if (!(spinand->flags & SPINAND_HAS_OCTAL_DTR_BIT))
+		return 0;
+
+	if (!(spinand_op_is_octal_dtr(spinand->data_ops.read_cache) &&
+	      spinand_op_is_octal_dtr(spinand->data_ops.write_cache) &&
+	      spinand_op_is_octal_dtr(spinand->data_ops.update_cache)))
+		return 0;
+
+	octal_dtr_ctrl_ops = spinand_select_ctrl_ops_variant(spinand,
+					spinand->desc_entry->ctrl_ops_variants,
+					SPINAND_8D_8D_8D);
+
+	if (!octal_dtr_ctrl_ops)
+		return 0;
+
+	if (!spinand->manufacturer->ops->change_mode) {
+		dev_dbg(dev,
+			"Missing ->change_mode(), unable to switch mode\n");
+		return -EINVAL;
+	}
+
+	ret = spinand->manufacturer->ops->change_mode(spinand,
+						      SPINAND_8D_8D_8D);
+	if (ret) {
+		dev_err(dev,
+			"Failed to enable Octal DTR SPI mode (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	spinand->protocol = SPINAND_8D_8D_8D;
+	spinand->ctrl_ops = octal_dtr_ctrl_ops;
+
+	dev_dbg(dev,
+		"%s SPI NAND switched to Octal DTR SPI (8D-8D-8D) mode\n",
+		spinand->manufacturer->name);
+	return 0;
+}
+
+static int spinand_init_octal_dtr_disable(struct spinand_device *spinand)
+{
+	struct device *dev = &spinand->spimem->spi->dev;
+	int ret;
+
+	if (!spinand->manufacturer->ops->change_mode)
+		return -EINVAL;
+
+	ret = spinand->manufacturer->ops->change_mode(spinand,
+						      SPINAND_1S_1S_1S);
+
+	if (ret) {
+		dev_err(dev,
+			"Failed to disable Octal DTR SPI mode (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	spinand->protocol = SPINAND_1S_1S_1S;
+	spinand->ctrl_ops = &spinand_default_ctrl_ops;
+	return 0;
+}
+
 /**
  * spinand_match_and_init() - Try to find a match between a device ID and an
  *			      entry in a spinand_info table
@@ -1203,6 +1278,10 @@ static int spinand_init_flash(struct spinand_device *spinand)
 			break;
 	}
 
+	ret = spinand_init_octal_dtr_enable(spinand);
+	if (ret)
+		return ret;
+
 	if (ret)
 		spinand_manufacturer_cleanup(spinand);
 
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index a8c071983a27..f12aa4516fab 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -417,6 +417,7 @@ struct spinand_ecc_info {
 
 #define SPINAND_HAS_QE_BIT		BIT(0)
 #define SPINAND_HAS_CR_FEAT_BIT		BIT(1)
+#define SPINAND_HAS_OCTAL_DTR_BIT	BIT(2)
 
 /**
  * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
-- 
2.25.1


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

* [PATCH v3 11/17] mtd: spinand: Allow enabling/disabling Octal DTR mode in the core
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Enable Octal DTR SPI mode, i.e. 8D-8D-8D mode, if the SPI NAND flash
device supports it. Mixed OSPI (1S-1S-8S & 1S-8S-8S), mixed DTR modes
(1S-1D-8D), etc. aren't supported yet.

The method to switch to Octal DTR SPI mode may vary across
manufacturers. For example, for Winbond, it is enabled by writing
values to the volatile configuration register. So, let the
manufacturer's code have their own implementation for switching to
Octal DTR SPI mode.

Check for the SPI NAND device's support for Octal DTR mode using
spinand flags, and if the data_ops and ctrl_ops are 8D-8D-8D, call
change_mode() manufacturer op. If the SPI controller doesn't
supports these modes, the selected data_ops and ctrl_ops will
prevent switching to the Octal DTR mode. And finally update the
spinand protocol and ctrl_ops on success. Similarly, for disabling
Octal DTR mode, call change_mode(), and update protocol and ctrl_ops.

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 79 +++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h |  1 +
 2 files changed, 80 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 1a602e4dd6bd..2fd08085db6f 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1067,6 +1067,81 @@ spinand_select_ctrl_ops_variant(struct spinand_device *spinand,
 	return NULL;
 }
 
+static bool spinand_op_is_octal_dtr(const struct spi_mem_op *op)
+{
+	return  op->cmd.buswidth == 8 && op->cmd.dtr &&
+		op->addr.buswidth == 8 && op->addr.dtr &&
+		op->data.buswidth == 8 && op->data.dtr;
+}
+
+static int spinand_init_octal_dtr_enable(struct spinand_device *spinand)
+{
+	struct device *dev = &spinand->spimem->spi->dev;
+	const struct spinand_ctrl_ops *octal_dtr_ctrl_ops;
+	int ret;
+
+	if (!(spinand->flags & SPINAND_HAS_OCTAL_DTR_BIT))
+		return 0;
+
+	if (!(spinand_op_is_octal_dtr(spinand->data_ops.read_cache) &&
+	      spinand_op_is_octal_dtr(spinand->data_ops.write_cache) &&
+	      spinand_op_is_octal_dtr(spinand->data_ops.update_cache)))
+		return 0;
+
+	octal_dtr_ctrl_ops = spinand_select_ctrl_ops_variant(spinand,
+					spinand->desc_entry->ctrl_ops_variants,
+					SPINAND_8D_8D_8D);
+
+	if (!octal_dtr_ctrl_ops)
+		return 0;
+
+	if (!spinand->manufacturer->ops->change_mode) {
+		dev_dbg(dev,
+			"Missing ->change_mode(), unable to switch mode\n");
+		return -EINVAL;
+	}
+
+	ret = spinand->manufacturer->ops->change_mode(spinand,
+						      SPINAND_8D_8D_8D);
+	if (ret) {
+		dev_err(dev,
+			"Failed to enable Octal DTR SPI mode (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	spinand->protocol = SPINAND_8D_8D_8D;
+	spinand->ctrl_ops = octal_dtr_ctrl_ops;
+
+	dev_dbg(dev,
+		"%s SPI NAND switched to Octal DTR SPI (8D-8D-8D) mode\n",
+		spinand->manufacturer->name);
+	return 0;
+}
+
+static int spinand_init_octal_dtr_disable(struct spinand_device *spinand)
+{
+	struct device *dev = &spinand->spimem->spi->dev;
+	int ret;
+
+	if (!spinand->manufacturer->ops->change_mode)
+		return -EINVAL;
+
+	ret = spinand->manufacturer->ops->change_mode(spinand,
+						      SPINAND_1S_1S_1S);
+
+	if (ret) {
+		dev_err(dev,
+			"Failed to disable Octal DTR SPI mode (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	spinand->protocol = SPINAND_1S_1S_1S;
+	spinand->ctrl_ops = &spinand_default_ctrl_ops;
+	return 0;
+}
+
 /**
  * spinand_match_and_init() - Try to find a match between a device ID and an
  *			      entry in a spinand_info table
@@ -1203,6 +1278,10 @@ static int spinand_init_flash(struct spinand_device *spinand)
 			break;
 	}
 
+	ret = spinand_init_octal_dtr_enable(spinand);
+	if (ret)
+		return ret;
+
 	if (ret)
 		spinand_manufacturer_cleanup(spinand);
 
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index a8c071983a27..f12aa4516fab 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -417,6 +417,7 @@ struct spinand_ecc_info {
 
 #define SPINAND_HAS_QE_BIT		BIT(0)
 #define SPINAND_HAS_CR_FEAT_BIT		BIT(1)
+#define SPINAND_HAS_OCTAL_DTR_BIT	BIT(2)
 
 /**
  * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
-- 
2.25.1


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

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

* [PATCH v3 12/17] mtd: spinand: Add mtd_suspend() to disable Octal DTR mode at suspend
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

The flash might or might not have gone a power-down during sleep.
Hence, its SPI IO mode is unpredictable for the core at the time of
resume. To ensure proper reinitialization during resume, disable the
Octal DTR SPI IO mode and bring the flash to 1S-1S-1S mode when
performing suspend using mtd_suspend().

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 2fd08085db6f..9d1c72634e5a 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1307,6 +1307,16 @@ 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);
+
+	if (spinand->ctrl_ops->protocol == SPINAND_8D_8D_8D)
+		return spinand_init_octal_dtr_disable(spinand);
+
+	return 0;
+}
+
 static int spinand_init(struct spinand_device *spinand)
 {
 	struct device *dev = &spinand->spimem->spi->dev;
@@ -1381,6 +1391,7 @@ static int spinand_init(struct spinand_device *spinand)
 	mtd->_erase = spinand_mtd_erase;
 	mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
 	mtd->_resume = spinand_mtd_resume;
+	mtd->_suspend = spinand_mtd_suspend;
 
 	if (nand->ecc.engine) {
 		ret = mtd_ooblayout_count_freebytes(mtd);
-- 
2.25.1


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

* [PATCH v3 12/17] mtd: spinand: Add mtd_suspend() to disable Octal DTR mode at suspend
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

The flash might or might not have gone a power-down during sleep.
Hence, its SPI IO mode is unpredictable for the core at the time of
resume. To ensure proper reinitialization during resume, disable the
Octal DTR SPI IO mode and bring the flash to 1S-1S-1S mode when
performing suspend using mtd_suspend().

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 2fd08085db6f..9d1c72634e5a 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1307,6 +1307,16 @@ 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);
+
+	if (spinand->ctrl_ops->protocol == SPINAND_8D_8D_8D)
+		return spinand_init_octal_dtr_disable(spinand);
+
+	return 0;
+}
+
 static int spinand_init(struct spinand_device *spinand)
 {
 	struct device *dev = &spinand->spimem->spi->dev;
@@ -1381,6 +1391,7 @@ static int spinand_init(struct spinand_device *spinand)
 	mtd->_erase = spinand_mtd_erase;
 	mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
 	mtd->_resume = spinand_mtd_resume;
+	mtd->_suspend = spinand_mtd_suspend;
 
 	if (nand->ecc.engine) {
 		ret = mtd_ooblayout_count_freebytes(mtd);
-- 
2.25.1


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

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

* [PATCH v3 13/17] mtd: spinand: winbond: Add support for write volatile configuration register op
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Volatile configuration register are a different set of configuration
registers, i.e. they differ from the status registers. A different
SPI instruction is required to write to these registers. Any changes
to the Volatile Configuration Register get transferred directly to
the Internal Configuration Register and instantly reflect on the
device operation.

In Winbond W35N01JW, these volatile configuration register must be
configured in order to switch to Octal DTR SPI mode.

Add support for writing to volatile configuration registers using a
new WRITE_VCR_OP template.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c    |  2 +-
 drivers/mtd/nand/spi/winbond.c | 43 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h    |  1 +
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 9d1c72634e5a..21d3b4ebdeaa 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -343,7 +343,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
 		engine_conf->status = status;
 }
 
-static int spinand_write_enable_op(struct spinand_device *spinand)
+int spinand_write_enable_op(struct spinand_device *spinand)
 {
 	struct spi_mem_op op = spinand->ctrl_ops->ops.write_enable;
 
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 76684428354e..3e0829f58350 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -7,6 +7,7 @@
  *	Boris Brezillon <boris.brezillon@bootlin.com>
  */
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/mtd/spinand.h>
@@ -114,6 +115,48 @@ static int winbond_spinand_init(struct spinand_device *spinand)
 	return 0;
 }
 
+/**
+ * winbond_write_vcr_op() - write values onto the volatile configuration
+ *			    registers (VCR)
+ * @spinand: the spinand device
+ * @reg: the address of the particular reg in the VCR to be written on
+ * @val: the value to be written on the reg in the VCR
+ *
+ * Volatile configuration registers are a separate set of configuration
+ * registers, i.e. they differ from the status registers SR-1/2/3. A different
+ * SPI instruction is required to write to these registers. Any changes
+ * to the Volatile Configuration Register get transferred directly to
+ * the Internal Configuration Register and instantly reflect on the
+ * device operation.
+ */
+static int winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, u8 val)
+{
+	int ret;
+	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));
+
+	*spinand->scratchbuf = val;
+
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	/*
+	 * Write VCR operation doesn't set the busy bit in SR, so can't perform
+	 * a status poll. Minimum time of 50ns is needed to complete the write.
+	 * So, give thrice the minimum required delay.
+	 */
+	ndelay(150);
+	return 0;
+}
+
 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
 	.init = winbond_spinand_init,
 };
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index f12aa4516fab..4c1925ee327a 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -638,5 +638,6 @@ int spinand_match_and_init(struct spinand_device *spinand,
 
 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
 int spinand_select_target(struct spinand_device *spinand, unsigned int target);
+int spinand_write_enable_op(struct spinand_device *spinand);
 
 #endif /* __LINUX_MTD_SPINAND_H */
-- 
2.25.1


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

* [PATCH v3 13/17] mtd: spinand: winbond: Add support for write volatile configuration register op
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Volatile configuration register are a different set of configuration
registers, i.e. they differ from the status registers. A different
SPI instruction is required to write to these registers. Any changes
to the Volatile Configuration Register get transferred directly to
the Internal Configuration Register and instantly reflect on the
device operation.

In Winbond W35N01JW, these volatile configuration register must be
configured in order to switch to Octal DTR SPI mode.

Add support for writing to volatile configuration registers using a
new WRITE_VCR_OP template.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/core.c    |  2 +-
 drivers/mtd/nand/spi/winbond.c | 43 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h    |  1 +
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 9d1c72634e5a..21d3b4ebdeaa 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -343,7 +343,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
 		engine_conf->status = status;
 }
 
-static int spinand_write_enable_op(struct spinand_device *spinand)
+int spinand_write_enable_op(struct spinand_device *spinand)
 {
 	struct spi_mem_op op = spinand->ctrl_ops->ops.write_enable;
 
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 76684428354e..3e0829f58350 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -7,6 +7,7 @@
  *	Boris Brezillon <boris.brezillon@bootlin.com>
  */
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/mtd/spinand.h>
@@ -114,6 +115,48 @@ static int winbond_spinand_init(struct spinand_device *spinand)
 	return 0;
 }
 
+/**
+ * winbond_write_vcr_op() - write values onto the volatile configuration
+ *			    registers (VCR)
+ * @spinand: the spinand device
+ * @reg: the address of the particular reg in the VCR to be written on
+ * @val: the value to be written on the reg in the VCR
+ *
+ * Volatile configuration registers are a separate set of configuration
+ * registers, i.e. they differ from the status registers SR-1/2/3. A different
+ * SPI instruction is required to write to these registers. Any changes
+ * to the Volatile Configuration Register get transferred directly to
+ * the Internal Configuration Register and instantly reflect on the
+ * device operation.
+ */
+static int winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, u8 val)
+{
+	int ret;
+	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));
+
+	*spinand->scratchbuf = val;
+
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	/*
+	 * Write VCR operation doesn't set the busy bit in SR, so can't perform
+	 * a status poll. Minimum time of 50ns is needed to complete the write.
+	 * So, give thrice the minimum required delay.
+	 */
+	ndelay(150);
+	return 0;
+}
+
 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
 	.init = winbond_spinand_init,
 };
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index f12aa4516fab..4c1925ee327a 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -638,5 +638,6 @@ int spinand_match_and_init(struct spinand_device *spinand,
 
 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
 int spinand_select_target(struct spinand_device *spinand, unsigned int target);
+int spinand_write_enable_op(struct spinand_device *spinand);
 
 #endif /* __LINUX_MTD_SPINAND_H */
-- 
2.25.1


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

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

* [PATCH v3 14/17] mtd: spinand: winbond: Add octal_dtr_enable/disable() in manufacturer_ops
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add implementation of octal_dtr_enable() and octal_dtr_disable()
manufacturer_ops for Winbond. To switch to Ocatl DTR mode, setting
programmable dummy cycles and SPI IO mode using the volatile
configuration register is required. To function at max 120MHz SPI clock
in Octal DTR mode, 12 programmable dummy clock cycle setting is
required. (Default number of dummy cycle are 8 clocks)

Set the programmable dummy cycle to 12 clocks, and SPI IO mode to
Octal DTR with Data Strobe in the VCR. Also, perform a READ ID
operation in Octal DTR SPI mode to ensure the switch was successful.
To disable Octal DTR mode, restore the VCR registers to their default
values and verify it using READ ID operation.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 85 ++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 3e0829f58350..c7478faf6cee 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -16,6 +16,16 @@
 
 #define WINBOND_CFG_BUF_READ		BIT(3)
 
+/* Octal DTR SPI mode (8D-8D-8D) with Data Strobe output*/
+#define WINBOND_VCR_IO_MODE_OCTAL_DTR	0xE7
+#define WINBOND_VCR_IO_MODE_SINGLE_STR	0xFF
+#define WINBOND_VCR_IO_MODE_ADDR	0x00
+
+/* Use 12 dummy clk cycles for using Octal DTR SPI at max 120MHZ */
+#define WINBOND_VCR_DUMMY_CLK_COUNT	12
+#define WINBOND_VCR_DUMMY_CLK_DEFAULT	0xFF
+#define WINBOND_VCR_DUMMY_CLK_ADDR	0x01
+
 static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
@@ -157,6 +167,81 @@ static int winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, u8 val)
 	return 0;
 }
 
+static int winbond_spinand_octal_dtr_enable(struct spinand_device *spinand)
+{
+	int ret;
+	struct spi_mem_op op;
+
+	ret = winbond_write_vcr_op(spinand, WINBOND_VCR_DUMMY_CLK_ADDR,
+				   WINBOND_VCR_DUMMY_CLK_COUNT);
+	if (ret)
+		return ret;
+
+	ret = winbond_write_vcr_op(spinand, WINBOND_VCR_IO_MODE_ADDR,
+				   WINBOND_VCR_IO_MODE_OCTAL_DTR);
+	if (ret)
+		return ret;
+
+	/* Read flash ID to make sure the switch was successful. */
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x9f9f, 8),
+			   SPI_MEM_OP_NO_ADDR,
+			   SPI_MEM_OP_DUMMY_DTR(16, 8),
+			   SPI_MEM_OP_DATA_IN_DTR(SPINAND_MAX_ID_LEN,
+						  spinand->scratchbuf, 8));
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	if (memcmp(spinand->scratchbuf, spinand->id.data, SPINAND_MAX_ID_LEN))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int winbond_spinand_octal_dtr_disable(struct spinand_device *spinand)
+{
+	int ret;
+	struct spi_mem_op op =
+		SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x8181, 8),
+			   SPI_MEM_OP_ADDR_DTR(4, WINBOND_VCR_IO_MODE_ADDR, 8),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_OUT_DTR(2, spinand->scratchbuf, 8));
+
+	*spinand->scratchbuf = WINBOND_VCR_IO_MODE_SINGLE_STR;
+
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	ret = winbond_write_vcr_op(spinand, WINBOND_VCR_DUMMY_CLK_ADDR,
+				   WINBOND_VCR_DUMMY_CLK_DEFAULT);
+	if (ret)
+		return ret;
+
+	/* Read flash ID to make sure the switch was successful. */
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),
+			   SPI_MEM_OP_NO_ADDR,
+			   SPI_MEM_OP_DUMMY(1, 1),
+			   SPI_MEM_OP_DATA_IN(SPINAND_MAX_ID_LEN,
+					      spinand->scratchbuf, 1));
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	if (memcmp(spinand->scratchbuf, spinand->id.data, SPINAND_MAX_ID_LEN))
+		return -EINVAL;
+
+	return 0;
+}
+
 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
 	.init = winbond_spinand_init,
 };
-- 
2.25.1


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

* [PATCH v3 14/17] mtd: spinand: winbond: Add octal_dtr_enable/disable() in manufacturer_ops
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add implementation of octal_dtr_enable() and octal_dtr_disable()
manufacturer_ops for Winbond. To switch to Ocatl DTR mode, setting
programmable dummy cycles and SPI IO mode using the volatile
configuration register is required. To function at max 120MHz SPI clock
in Octal DTR mode, 12 programmable dummy clock cycle setting is
required. (Default number of dummy cycle are 8 clocks)

Set the programmable dummy cycle to 12 clocks, and SPI IO mode to
Octal DTR with Data Strobe in the VCR. Also, perform a READ ID
operation in Octal DTR SPI mode to ensure the switch was successful.
To disable Octal DTR mode, restore the VCR registers to their default
values and verify it using READ ID operation.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 85 ++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 3e0829f58350..c7478faf6cee 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -16,6 +16,16 @@
 
 #define WINBOND_CFG_BUF_READ		BIT(3)
 
+/* Octal DTR SPI mode (8D-8D-8D) with Data Strobe output*/
+#define WINBOND_VCR_IO_MODE_OCTAL_DTR	0xE7
+#define WINBOND_VCR_IO_MODE_SINGLE_STR	0xFF
+#define WINBOND_VCR_IO_MODE_ADDR	0x00
+
+/* Use 12 dummy clk cycles for using Octal DTR SPI at max 120MHZ */
+#define WINBOND_VCR_DUMMY_CLK_COUNT	12
+#define WINBOND_VCR_DUMMY_CLK_DEFAULT	0xFF
+#define WINBOND_VCR_DUMMY_CLK_ADDR	0x01
+
 static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
@@ -157,6 +167,81 @@ static int winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, u8 val)
 	return 0;
 }
 
+static int winbond_spinand_octal_dtr_enable(struct spinand_device *spinand)
+{
+	int ret;
+	struct spi_mem_op op;
+
+	ret = winbond_write_vcr_op(spinand, WINBOND_VCR_DUMMY_CLK_ADDR,
+				   WINBOND_VCR_DUMMY_CLK_COUNT);
+	if (ret)
+		return ret;
+
+	ret = winbond_write_vcr_op(spinand, WINBOND_VCR_IO_MODE_ADDR,
+				   WINBOND_VCR_IO_MODE_OCTAL_DTR);
+	if (ret)
+		return ret;
+
+	/* Read flash ID to make sure the switch was successful. */
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x9f9f, 8),
+			   SPI_MEM_OP_NO_ADDR,
+			   SPI_MEM_OP_DUMMY_DTR(16, 8),
+			   SPI_MEM_OP_DATA_IN_DTR(SPINAND_MAX_ID_LEN,
+						  spinand->scratchbuf, 8));
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	if (memcmp(spinand->scratchbuf, spinand->id.data, SPINAND_MAX_ID_LEN))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int winbond_spinand_octal_dtr_disable(struct spinand_device *spinand)
+{
+	int ret;
+	struct spi_mem_op op =
+		SPI_MEM_OP(SPI_MEM_OP_CMD_DTR(2, 0x8181, 8),
+			   SPI_MEM_OP_ADDR_DTR(4, WINBOND_VCR_IO_MODE_ADDR, 8),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_OUT_DTR(2, spinand->scratchbuf, 8));
+
+	*spinand->scratchbuf = WINBOND_VCR_IO_MODE_SINGLE_STR;
+
+	ret = spinand_write_enable_op(spinand);
+	if (ret)
+		return ret;
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	ret = winbond_write_vcr_op(spinand, WINBOND_VCR_DUMMY_CLK_ADDR,
+				   WINBOND_VCR_DUMMY_CLK_DEFAULT);
+	if (ret)
+		return ret;
+
+	/* Read flash ID to make sure the switch was successful. */
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),
+			   SPI_MEM_OP_NO_ADDR,
+			   SPI_MEM_OP_DUMMY(1, 1),
+			   SPI_MEM_OP_DATA_IN(SPINAND_MAX_ID_LEN,
+					      spinand->scratchbuf, 1));
+
+	ret = spi_mem_exec_op(spinand->spimem, &op);
+	if (ret)
+		return ret;
+
+	if (memcmp(spinand->scratchbuf, spinand->id.data, SPINAND_MAX_ID_LEN))
+		return -EINVAL;
+
+	return 0;
+}
+
 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
 	.init = winbond_spinand_init,
 };
-- 
2.25.1


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

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

* [PATCH v3 15/17] mtd: spianand: winbond: Add change_mode() manufacturer_ops
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add implementation of change_mode() for Winbond's manufacturer_ops,
that executes octal_dtr_enable() and octal_dtr_disable() according
to requested protocol.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index c7478faf6cee..d8eccb40c80f 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -242,8 +242,33 @@ static int winbond_spinand_octal_dtr_disable(struct spinand_device *spinand)
 	return 0;
 }
 
+static int winbond_change_spi_mode(struct spinand_device *spinand,
+				   const enum spinand_protocol protocol)
+{
+	if (spinand->protocol == protocol)
+		return 0;
+
+	switch (spinand->protocol) {
+	case SPINAND_1S_1S_1S:
+		if (protocol == SPINAND_8D_8D_8D)
+			return winbond_spinand_octal_dtr_enable(spinand);
+		break;
+
+	case SPINAND_8D_8D_8D:
+		if (protocol == SPINAND_1S_1S_1S)
+			return winbond_spinand_octal_dtr_disable(spinand);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
 	.init = winbond_spinand_init,
+	.change_mode = winbond_change_spi_mode,
 };
 
 const struct spinand_manufacturer winbond_spinand_manufacturer = {
-- 
2.25.1


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

* [PATCH v3 15/17] mtd: spianand: winbond: Add change_mode() manufacturer_ops
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Add implementation of change_mode() for Winbond's manufacturer_ops,
that executes octal_dtr_enable() and octal_dtr_disable() according
to requested protocol.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index c7478faf6cee..d8eccb40c80f 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -242,8 +242,33 @@ static int winbond_spinand_octal_dtr_disable(struct spinand_device *spinand)
 	return 0;
 }
 
+static int winbond_change_spi_mode(struct spinand_device *spinand,
+				   const enum spinand_protocol protocol)
+{
+	if (spinand->protocol == protocol)
+		return 0;
+
+	switch (spinand->protocol) {
+	case SPINAND_1S_1S_1S:
+		if (protocol == SPINAND_8D_8D_8D)
+			return winbond_spinand_octal_dtr_enable(spinand);
+		break;
+
+	case SPINAND_8D_8D_8D:
+		if (protocol == SPINAND_1S_1S_1S)
+			return winbond_spinand_octal_dtr_disable(spinand);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
 	.init = winbond_spinand_init,
+	.change_mode = winbond_change_spi_mode,
 };
 
 const struct spinand_manufacturer winbond_spinand_manufacturer = {
-- 
2.25.1


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

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

* [PATCH v3 16/17] mtd: spinand: winbond: Rename cache op_variants struct variable
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Till now, supported Winbond SPI NAND flashes had same supported
op_variants. W35N01JW introduces Octal DTR SPI IO mode, so now
different op_variants struct variables are required for different
Winbond flashes. Hence, rename and append the flash name in the
op_variants struct variable.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index d8eccb40c80f..5b943169120e 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -26,7 +26,7 @@
 #define WINBOND_VCR_DUMMY_CLK_DEFAULT	0xFF
 #define WINBOND_VCR_DUMMY_CLK_ADDR	0x01
 
-static SPINAND_OP_VARIANTS(read_cache_variants,
+static SPINAND_OP_VARIANTS(read_cache_variants_w25xxgv,
 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -34,11 +34,11 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
-static SPINAND_OP_VARIANTS(write_cache_variants,
+static SPINAND_OP_VARIANTS(write_cache_variants_w25xxgv,
 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
 
-static SPINAND_OP_VARIANTS(update_cache_variants,
+static SPINAND_OP_VARIANTS(update_cache_variants_w25xxgv,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
@@ -90,9 +90,9 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
 		     NAND_ECCREQ(1, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_w25xxgv,
+					      &write_cache_variants_w25xxgv,
+					      &update_cache_variants_w25xxgv),
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
@@ -100,9 +100,9 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(1, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_w25xxgv,
+					      &write_cache_variants_w25xxgv,
+					      &update_cache_variants_w25xxgv),
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
 };
-- 
2.25.1


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

* [PATCH v3 16/17] mtd: spinand: winbond: Rename cache op_variants struct variable
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Till now, supported Winbond SPI NAND flashes had same supported
op_variants. W35N01JW introduces Octal DTR SPI IO mode, so now
different op_variants struct variables are required for different
Winbond flashes. Hence, rename and append the flash name in the
op_variants struct variable.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index d8eccb40c80f..5b943169120e 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -26,7 +26,7 @@
 #define WINBOND_VCR_DUMMY_CLK_DEFAULT	0xFF
 #define WINBOND_VCR_DUMMY_CLK_ADDR	0x01
 
-static SPINAND_OP_VARIANTS(read_cache_variants,
+static SPINAND_OP_VARIANTS(read_cache_variants_w25xxgv,
 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -34,11 +34,11 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
-static SPINAND_OP_VARIANTS(write_cache_variants,
+static SPINAND_OP_VARIANTS(write_cache_variants_w25xxgv,
 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
 
-static SPINAND_OP_VARIANTS(update_cache_variants,
+static SPINAND_OP_VARIANTS(update_cache_variants_w25xxgv,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
@@ -90,9 +90,9 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
 		     NAND_ECCREQ(1, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_w25xxgv,
+					      &write_cache_variants_w25xxgv,
+					      &update_cache_variants_w25xxgv),
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
@@ -100,9 +100,9 @@ static const struct spinand_info winbond_spinand_table[] = {
 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
 		     NAND_ECCREQ(1, 512),
-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-					      &write_cache_variants,
-					      &update_cache_variants),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_w25xxgv,
+					      &write_cache_variants_w25xxgv,
+					      &update_cache_variants_w25xxgv),
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
 };
-- 
2.25.1


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

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

* [PATCH v3 17/17] mtd: spinand: winbond: Add support for Winbond W35N01JW SPI NAND flash
  2022-01-01  7:42 ` Apurva Nandan
@ 2022-01-01  7:42   ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Winbond W35N01JW is a SPI NAND flash supporting Octal DTR SPI protocol.
Add op_variants and ctrl_ops_variants for W35N01JW, thus adding all
required Octal DTR ops. Add W35N01JW's OOB layout functions for the
mtd_ooblayout_ops. Finally, add an entry for W35N01JW in spinand_info
table.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 71 ++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 5b943169120e..42fdb578f731 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -42,6 +42,37 @@ static SPINAND_OP_VARIANTS(update_cache_variants_w25xxgv,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
+static SPINAND_OP_VARIANTS(read_cache_variants_w35n01jw,
+		SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants_w35n01jw,
+		SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants_w35n01jw,
+		SPINAND_PROG_LOAD_OCTALIO_DTR(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static SPINAND_CTRL_OPS_VARIANTS(ctrl_ops_variants_w35n01jw,
+		SPINAND_CTRL_OPS(SPINAND_8D_8D_8D,
+				 SPINAND_RESET_OP_OCTAL_DTR,
+				 SPINAND_GET_FEATURE_OP_OCTAL_DTR(0, NULL),
+				 SPINAND_SET_FEATURE_OP_OCTAL_DTR(0, NULL),
+				 SPINAND_WR_EN_DIS_OP_OCTAL_DTR(true),
+				 SPINAND_BLK_ERASE_OP_OCTAL_DTR(0),
+				 SPINAND_PAGE_READ_OP_OCTAL_DTR(0),
+				 SPINAND_PROG_EXEC_OP_OCTAL_DTR(0)),
+		SPINAND_CTRL_OPS(SPINAND_1S_1S_1S,
+				 SPINAND_RESET_OP,
+				 SPINAND_GET_FEATURE_OP(0, NULL),
+				 SPINAND_SET_FEATURE_OP(0, NULL),
+				 SPINAND_WR_EN_DIS_OP(true),
+				 SPINAND_BLK_ERASE_OP(0),
+				 SPINAND_PAGE_READ_OP(0),
+				 SPINAND_PROG_EXEC_OP(0)));
+
 static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *region)
 {
@@ -66,11 +97,40 @@ static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
 	return 0;
 }
 
+static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 12;
+	region->length = 4;
+
+	return 0;
+}
+
+static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 2;
+	region->length = 10;
+
+	return 0;
+}
+
 static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
 	.ecc = w25m02gv_ooblayout_ecc,
 	.free = w25m02gv_ooblayout_free,
 };
 
+static const struct mtd_ooblayout_ops w35n01jw_ooblayout = {
+	.ecc = w35n01jw_ooblayout_ecc,
+	.free = w35n01jw_ooblayout_free,
+};
+
 static int w25m02gv_select_target(struct spinand_device *spinand,
 				  unsigned int target)
 {
@@ -105,6 +165,17 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &update_cache_variants_w25xxgv),
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+	SPINAND_INFO("W35N01JW",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
+		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
+		     NAND_ECCREQ(1, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_w35n01jw,
+					      &write_cache_variants_w35n01jw,
+					      &update_cache_variants_w35n01jw),
+		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
+		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
+		     SPINAND_INFO_CTRL_OPS_VARIANTS(&ctrl_ops_variants_w35n01jw)),
+
 };
 
 static int winbond_spinand_init(struct spinand_device *spinand)
-- 
2.25.1


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

* [PATCH v3 17/17] mtd: spinand: winbond: Add support for Winbond W35N01JW SPI NAND flash
@ 2022-01-01  7:42   ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-01-01  7:42 UTC (permalink / raw)
  To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Apurva Nandan, Patrice Chotard, Christophe Kerello,
	Boris Brezillon, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi
  Cc: p.yadav

Winbond W35N01JW is a SPI NAND flash supporting Octal DTR SPI protocol.
Add op_variants and ctrl_ops_variants for W35N01JW, thus adding all
required Octal DTR ops. Add W35N01JW's OOB layout functions for the
mtd_ooblayout_ops. Finally, add an entry for W35N01JW in spinand_info
table.

Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf

Signed-off-by: Apurva Nandan <a-nandan@ti.com>
---
 drivers/mtd/nand/spi/winbond.c | 71 ++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 5b943169120e..42fdb578f731 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -42,6 +42,37 @@ static SPINAND_OP_VARIANTS(update_cache_variants_w25xxgv,
 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
 
+static SPINAND_OP_VARIANTS(read_cache_variants_w35n01jw,
+		SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants_w35n01jw,
+		SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants_w35n01jw,
+		SPINAND_PROG_LOAD_OCTALIO_DTR(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static SPINAND_CTRL_OPS_VARIANTS(ctrl_ops_variants_w35n01jw,
+		SPINAND_CTRL_OPS(SPINAND_8D_8D_8D,
+				 SPINAND_RESET_OP_OCTAL_DTR,
+				 SPINAND_GET_FEATURE_OP_OCTAL_DTR(0, NULL),
+				 SPINAND_SET_FEATURE_OP_OCTAL_DTR(0, NULL),
+				 SPINAND_WR_EN_DIS_OP_OCTAL_DTR(true),
+				 SPINAND_BLK_ERASE_OP_OCTAL_DTR(0),
+				 SPINAND_PAGE_READ_OP_OCTAL_DTR(0),
+				 SPINAND_PROG_EXEC_OP_OCTAL_DTR(0)),
+		SPINAND_CTRL_OPS(SPINAND_1S_1S_1S,
+				 SPINAND_RESET_OP,
+				 SPINAND_GET_FEATURE_OP(0, NULL),
+				 SPINAND_SET_FEATURE_OP(0, NULL),
+				 SPINAND_WR_EN_DIS_OP(true),
+				 SPINAND_BLK_ERASE_OP(0),
+				 SPINAND_PAGE_READ_OP(0),
+				 SPINAND_PROG_EXEC_OP(0)));
+
 static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
 				  struct mtd_oob_region *region)
 {
@@ -66,11 +97,40 @@ static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
 	return 0;
 }
 
+static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 12;
+	region->length = 4;
+
+	return 0;
+}
+
+static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 2;
+	region->length = 10;
+
+	return 0;
+}
+
 static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
 	.ecc = w25m02gv_ooblayout_ecc,
 	.free = w25m02gv_ooblayout_free,
 };
 
+static const struct mtd_ooblayout_ops w35n01jw_ooblayout = {
+	.ecc = w35n01jw_ooblayout_ecc,
+	.free = w35n01jw_ooblayout_free,
+};
+
 static int w25m02gv_select_target(struct spinand_device *spinand,
 				  unsigned int target)
 {
@@ -105,6 +165,17 @@ static const struct spinand_info winbond_spinand_table[] = {
 					      &update_cache_variants_w25xxgv),
 		     0,
 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+	SPINAND_INFO("W35N01JW",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
+		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
+		     NAND_ECCREQ(1, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_w35n01jw,
+					      &write_cache_variants_w35n01jw,
+					      &update_cache_variants_w35n01jw),
+		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
+		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
+		     SPINAND_INFO_CTRL_OPS_VARIANTS(&ctrl_ops_variants_w35n01jw)),
+
 };
 
 static int winbond_spinand_init(struct spinand_device *spinand)
-- 
2.25.1


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

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

* Re: [PATCH v3 04/17] mtd: spinand: Rename 'op_templates' to 'data_ops'
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-03  9:48     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03  9:48 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:37 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Manufacturers have been deviating from the standard SPI operations for
> NAND flashes. There have been variations in non-page read/write
> instructions too. Additionally, operations, including non-page r/w ops,
> vary when flash is in different SPI mode, eg. Octal DTR.
> 
> To avoid live-patching in hot-paths or vendor-specific adjustment,
> it is better to have a set of operation templates and variants for
> non-page read/write operations as well. These would get initialized at
> the probe time or when flash changes modes. These would be called
> 'ctrl_ops'.
> 
> To make code better understandable, create two types of op templates
> which are: data_ops and ctrl_ops. Reason for having two different type
> of templates is the difference in their use cases i.e. it is possible
> to have ops of different protocol for read/write/update simulatneously
> in the data_ops, but all the ops in the ctrl_ops follow same protocol.
> 
> Rename op_templates to data_ops, and the ctrl_ops would be introduced
> in later commits.

Didn't read till the end, but I don't see any overlap between the
control and data operations in the first half of this series, so I'm
wondering if the split is actually necessary.

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

* Re: [PATCH v3 04/17] mtd: spinand: Rename 'op_templates' to 'data_ops'
@ 2022-01-03  9:48     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03  9:48 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:37 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Manufacturers have been deviating from the standard SPI operations for
> NAND flashes. There have been variations in non-page read/write
> instructions too. Additionally, operations, including non-page r/w ops,
> vary when flash is in different SPI mode, eg. Octal DTR.
> 
> To avoid live-patching in hot-paths or vendor-specific adjustment,
> it is better to have a set of operation templates and variants for
> non-page read/write operations as well. These would get initialized at
> the probe time or when flash changes modes. These would be called
> 'ctrl_ops'.
> 
> To make code better understandable, create two types of op templates
> which are: data_ops and ctrl_ops. Reason for having two different type
> of templates is the difference in their use cases i.e. it is possible
> to have ops of different protocol for read/write/update simulatneously
> in the data_ops, but all the ops in the ctrl_ops follow same protocol.
> 
> Rename op_templates to data_ops, and the ctrl_ops would be introduced
> in later commits.

Didn't read till the end, but I don't see any overlap between the
control and data operations in the first half of this series, so I'm
wondering if the split is actually necessary.

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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-03 10:01     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:01 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:38 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> 'ctrl_ops' are op templates for non-page read/write operations,
> which are: reset, get_feature, set_feature, write_enable, block_erase,
> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
> op templates for each of this op, as well as enum spinand_protocol
> denoting protocol of all these ops.
> 
> We require these new op templates because of deviation in standard
> SPINAND ops by manufacturers and also due to changes when there is a
> change in SPI protocol/mode. This prevents the core from live-patching
> and vendor-specific adjustments in ops.
> 
> Define 'ctrl_ops', add macros to initialize it and add it in
> spinand_device.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
> 
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 439d8ce40e1d..e5df6220ec1e 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>  			sizeof(struct spi_mem_op),			\
>  	}
>  
> +struct spinand_ctrl_ops {
> +	const struct {
> +		struct spi_mem_op reset;
> +		struct spi_mem_op get_feature;
> +		struct spi_mem_op set_feature;
> +		struct spi_mem_op write_enable;
> +		struct spi_mem_op block_erase;
> +		struct spi_mem_op page_read;
> +		struct spi_mem_op program_execute;
> +	} ops;
> +	const enum spinand_protocol protocol;

Do you really need that protocol field?

> +};
> +
> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
> +			 __write_enable, __block_erase, __page_read,		\
> +			 __program_execute)					\
> +	{									\
> +		.ops = {							\
> +			.reset = __reset,					\
> +			.get_feature = __get_feature,				\
> +			.set_feature = __set_feature,				\
> +			.write_enable = __write_enable,				\
> +			.block_erase = __block_erase,				\
> +			.page_read = __page_read,				\
> +			.program_execute = __program_execute,			\
> +		},								\
> +		.protocol = __protocol,						\
> +	}
> +
>  /**
>   * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>   *		      chip
> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>   * @data_ops.read_cache: read cache op template
>   * @data_ops.write_cache: write cache op template
>   * @data_ops.update_cache: update cache op template
> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
> + *	      non page-read/write ops.
>   * @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
> @@ -498,6 +529,8 @@ struct spinand_device {
>  		const struct spi_mem_op *update_cache;
>  	} data_ops;
>  
> +	const struct spinand_ctrl_ops *ctrl_ops;
> +

Okay, I had something slightly different in mind. First, I'd put all
templates in a struct:

struct spinand_op_templates {
	const struct spi_mem_op *read_cache;
	const struct spi_mem_op *write_cache;
	const struct spi_mem_op *update_cache;
	const struct spi_mem_op *reset;
	const struct spi_mem_op *get_feature;
	const struct spi_mem_op *set_feature;
	const struct spi_mem_op *write_enable;
	const struct spi_mem_op *block_erase;
	const struct spi_mem_op *page_load;
	const struct spi_mem_op *program_execute;
};

Then, at the spinand level, I'd define an array of templates:

enum spinand_protocol {
	SPINAND_1S_1S_1S,
	SPINAND_2S_2S_2S,
	SPINAND_4S_4S_4S,
	SPINAND_8S_8S_8S,
	SPINAND_8D_8D_8D,
	SPINAND_NUM_PROTOCOLS,
};

struct spinand_device {
	...
	enum spinand_protocol protocol;
	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
	...
};

This way, you can easily pick the right set of operations based
on the protocol/mode you're in:

#define spinand_get_op_template(spinand, opname) \
	((spinand)->op_templates[(spinand)->protocol]->opname)

static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
{
	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
	int ret;

	...
}

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-01-03 10:01     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:01 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:38 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> 'ctrl_ops' are op templates for non-page read/write operations,
> which are: reset, get_feature, set_feature, write_enable, block_erase,
> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
> op templates for each of this op, as well as enum spinand_protocol
> denoting protocol of all these ops.
> 
> We require these new op templates because of deviation in standard
> SPINAND ops by manufacturers and also due to changes when there is a
> change in SPI protocol/mode. This prevents the core from live-patching
> and vendor-specific adjustments in ops.
> 
> Define 'ctrl_ops', add macros to initialize it and add it in
> spinand_device.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
> 
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 439d8ce40e1d..e5df6220ec1e 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>  			sizeof(struct spi_mem_op),			\
>  	}
>  
> +struct spinand_ctrl_ops {
> +	const struct {
> +		struct spi_mem_op reset;
> +		struct spi_mem_op get_feature;
> +		struct spi_mem_op set_feature;
> +		struct spi_mem_op write_enable;
> +		struct spi_mem_op block_erase;
> +		struct spi_mem_op page_read;
> +		struct spi_mem_op program_execute;
> +	} ops;
> +	const enum spinand_protocol protocol;

Do you really need that protocol field?

> +};
> +
> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
> +			 __write_enable, __block_erase, __page_read,		\
> +			 __program_execute)					\
> +	{									\
> +		.ops = {							\
> +			.reset = __reset,					\
> +			.get_feature = __get_feature,				\
> +			.set_feature = __set_feature,				\
> +			.write_enable = __write_enable,				\
> +			.block_erase = __block_erase,				\
> +			.page_read = __page_read,				\
> +			.program_execute = __program_execute,			\
> +		},								\
> +		.protocol = __protocol,						\
> +	}
> +
>  /**
>   * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>   *		      chip
> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>   * @data_ops.read_cache: read cache op template
>   * @data_ops.write_cache: write cache op template
>   * @data_ops.update_cache: update cache op template
> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
> + *	      non page-read/write ops.
>   * @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
> @@ -498,6 +529,8 @@ struct spinand_device {
>  		const struct spi_mem_op *update_cache;
>  	} data_ops;
>  
> +	const struct spinand_ctrl_ops *ctrl_ops;
> +

Okay, I had something slightly different in mind. First, I'd put all
templates in a struct:

struct spinand_op_templates {
	const struct spi_mem_op *read_cache;
	const struct spi_mem_op *write_cache;
	const struct spi_mem_op *update_cache;
	const struct spi_mem_op *reset;
	const struct spi_mem_op *get_feature;
	const struct spi_mem_op *set_feature;
	const struct spi_mem_op *write_enable;
	const struct spi_mem_op *block_erase;
	const struct spi_mem_op *page_load;
	const struct spi_mem_op *program_execute;
};

Then, at the spinand level, I'd define an array of templates:

enum spinand_protocol {
	SPINAND_1S_1S_1S,
	SPINAND_2S_2S_2S,
	SPINAND_4S_4S_4S,
	SPINAND_8S_8S_8S,
	SPINAND_8D_8D_8D,
	SPINAND_NUM_PROTOCOLS,
};

struct spinand_device {
	...
	enum spinand_protocol protocol;
	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
	...
};

This way, you can easily pick the right set of operations based
on the protocol/mode you're in:

#define spinand_get_op_template(spinand, opname) \
	((spinand)->op_templates[(spinand)->protocol]->opname)

static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
{
	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
	int ret;

	...
}

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

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

* Re: [PATCH v3 03/17] mtd: spinand: Add enum spinand_protocol to indicate current SPI IO mode
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-03 10:05     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:05 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:36 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 69e06e741717..77927afcea0f 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -194,6 +194,18 @@
>  		   SPI_MEM_OP_NO_DUMMY,					\
>  		   SPI_MEM_OP_DATA_OUT_DTR(len, buf, 8))
>  
> +/**
> + * enum spinand_protocol - List of SPI protocols to denote the op protocol and
> + *			   SPI NAND flash IO modes.
> + */
> +enum spinand_protocol {
> +	SPINAND_1S_1S_1S,
> +	SPINAND_2S_2S_2S,
> +	SPINAND_4S_4S_4S,
> +	SPINAND_8S_8S_8S,
> +	SPINAND_8D_8D_8D,

I'd just name those SPINAND_PROTO_<width><S or D> since what really
matters is the command cycle.

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

* Re: [PATCH v3 03/17] mtd: spinand: Add enum spinand_protocol to indicate current SPI IO mode
@ 2022-01-03 10:05     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:05 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:36 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 69e06e741717..77927afcea0f 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -194,6 +194,18 @@
>  		   SPI_MEM_OP_NO_DUMMY,					\
>  		   SPI_MEM_OP_DATA_OUT_DTR(len, buf, 8))
>  
> +/**
> + * enum spinand_protocol - List of SPI protocols to denote the op protocol and
> + *			   SPI NAND flash IO modes.
> + */
> +enum spinand_protocol {
> +	SPINAND_1S_1S_1S,
> +	SPINAND_2S_2S_2S,
> +	SPINAND_4S_4S_4S,
> +	SPINAND_8S_8S_8S,
> +	SPINAND_8D_8D_8D,

I'd just name those SPINAND_PROTO_<width><S or D> since what really
matters is the command cycle.

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

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

* Re: [PATCH v3 11/17] mtd: spinand: Allow enabling/disabling Octal DTR mode in the core
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-03 10:14     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:14 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:44 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Enable Octal DTR SPI mode, i.e. 8D-8D-8D mode, if the SPI NAND flash
> device supports it. Mixed OSPI (1S-1S-8S & 1S-8S-8S), mixed DTR modes
> (1S-1D-8D), etc. aren't supported yet.
> 
> The method to switch to Octal DTR SPI mode may vary across
> manufacturers. For example, for Winbond, it is enabled by writing
> values to the volatile configuration register. So, let the
> manufacturer's code have their own implementation for switching to
> Octal DTR SPI mode.
> 
> Check for the SPI NAND device's support for Octal DTR mode using
> spinand flags, and if the data_ops and ctrl_ops are 8D-8D-8D, call
> change_mode() manufacturer op. If the SPI controller doesn't
> supports these modes, the selected data_ops and ctrl_ops will
> prevent switching to the Octal DTR mode. And finally update the
> spinand protocol and ctrl_ops on success. Similarly, for disabling
> Octal DTR mode, call change_mode(), and update protocol and ctrl_ops.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  drivers/mtd/nand/spi/core.c | 79 +++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h |  1 +
>  2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 1a602e4dd6bd..2fd08085db6f 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1067,6 +1067,81 @@ spinand_select_ctrl_ops_variant(struct spinand_device *spinand,
>  	return NULL;
>  }
>  
> +static bool spinand_op_is_octal_dtr(const struct spi_mem_op *op)
> +{
> +	return  op->cmd.buswidth == 8 && op->cmd.dtr &&
> +		op->addr.buswidth == 8 && op->addr.dtr &&
> +		op->data.buswidth == 8 && op->data.dtr;
> +}
> +
> +static int spinand_init_octal_dtr_enable(struct spinand_device *spinand)
> +{
> +	struct device *dev = &spinand->spimem->spi->dev;
> +	const struct spinand_ctrl_ops *octal_dtr_ctrl_ops;
> +	int ret;
> +
> +	if (!(spinand->flags & SPINAND_HAS_OCTAL_DTR_BIT))
> +		return 0;
> +
> +	if (!(spinand_op_is_octal_dtr(spinand->data_ops.read_cache) &&
> +	      spinand_op_is_octal_dtr(spinand->data_ops.write_cache) &&
> +	      spinand_op_is_octal_dtr(spinand->data_ops.update_cache)))
> +		return 0;
> +
> +	octal_dtr_ctrl_ops = spinand_select_ctrl_ops_variant(spinand,
> +					spinand->desc_entry->ctrl_ops_variants,
> +					SPINAND_8D_8D_8D);
> +
> +	if (!octal_dtr_ctrl_ops)
> +		return 0;
> +
> +	if (!spinand->manufacturer->ops->change_mode) {
> +		dev_dbg(dev,
> +			"Missing ->change_mode(), unable to switch mode\n");
> +		return -EINVAL;

Looks like something that's worth printing at the info level, and I
think returning EOPNOTSUPP would be more appropriate.

> +	}
> +
> +	ret = spinand->manufacturer->ops->change_mode(spinand,
> +						      SPINAND_8D_8D_8D);
> +	if (ret) {
> +		dev_err(dev,
> +			"Failed to enable Octal DTR SPI mode (err = %d)\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	spinand->protocol = SPINAND_8D_8D_8D;
> +	spinand->ctrl_ops = octal_dtr_ctrl_ops;
> +
> +	dev_dbg(dev,
> +		"%s SPI NAND switched to Octal DTR SPI (8D-8D-8D) mode\n",
> +		spinand->manufacturer->name);
> +	return 0;
> +}
> +
> +static int spinand_init_octal_dtr_disable(struct spinand_device *spinand)

This function is never used. I guess it should be called in the
suspend/shutdown path, at least.

> +{
> +	struct device *dev = &spinand->spimem->spi->dev;
> +	int ret;
> +
> +	if (!spinand->manufacturer->ops->change_mode)
> +		return -EINVAL;
> +
> +	ret = spinand->manufacturer->ops->change_mode(spinand,
> +						      SPINAND_1S_1S_1S);
> +
> +	if (ret) {
> +		dev_err(dev,
> +			"Failed to disable Octal DTR SPI mode (err = %d)\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	spinand->protocol = SPINAND_1S_1S_1S;
> +	spinand->ctrl_ops = &spinand_default_ctrl_ops;
> +	return 0;
> +}
> +
>  /**
>   * spinand_match_and_init() - Try to find a match between a device ID and an
>   *			      entry in a spinand_info table
> @@ -1203,6 +1278,10 @@ static int spinand_init_flash(struct spinand_device *spinand)
>  			break;
>  	}
>  
> +	ret = spinand_init_octal_dtr_enable(spinand);
> +	if (ret)
> +		return ret;
> +
>  	if (ret)
>  		spinand_manufacturer_cleanup(spinand);
>  
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index a8c071983a27..f12aa4516fab 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -417,6 +417,7 @@ struct spinand_ecc_info {
>  
>  #define SPINAND_HAS_QE_BIT		BIT(0)
>  #define SPINAND_HAS_CR_FEAT_BIT		BIT(1)
> +#define SPINAND_HAS_OCTAL_DTR_BIT	BIT(2)

Do we really need a new flag for this? Isn't the template op
initialization enough to reflect whether the NAND and controller can do
8DTR or not?

>  
>  /**
>   * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure


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

* Re: [PATCH v3 11/17] mtd: spinand: Allow enabling/disabling Octal DTR mode in the core
@ 2022-01-03 10:14     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:14 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:44 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Enable Octal DTR SPI mode, i.e. 8D-8D-8D mode, if the SPI NAND flash
> device supports it. Mixed OSPI (1S-1S-8S & 1S-8S-8S), mixed DTR modes
> (1S-1D-8D), etc. aren't supported yet.
> 
> The method to switch to Octal DTR SPI mode may vary across
> manufacturers. For example, for Winbond, it is enabled by writing
> values to the volatile configuration register. So, let the
> manufacturer's code have their own implementation for switching to
> Octal DTR SPI mode.
> 
> Check for the SPI NAND device's support for Octal DTR mode using
> spinand flags, and if the data_ops and ctrl_ops are 8D-8D-8D, call
> change_mode() manufacturer op. If the SPI controller doesn't
> supports these modes, the selected data_ops and ctrl_ops will
> prevent switching to the Octal DTR mode. And finally update the
> spinand protocol and ctrl_ops on success. Similarly, for disabling
> Octal DTR mode, call change_mode(), and update protocol and ctrl_ops.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  drivers/mtd/nand/spi/core.c | 79 +++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h |  1 +
>  2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 1a602e4dd6bd..2fd08085db6f 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1067,6 +1067,81 @@ spinand_select_ctrl_ops_variant(struct spinand_device *spinand,
>  	return NULL;
>  }
>  
> +static bool spinand_op_is_octal_dtr(const struct spi_mem_op *op)
> +{
> +	return  op->cmd.buswidth == 8 && op->cmd.dtr &&
> +		op->addr.buswidth == 8 && op->addr.dtr &&
> +		op->data.buswidth == 8 && op->data.dtr;
> +}
> +
> +static int spinand_init_octal_dtr_enable(struct spinand_device *spinand)
> +{
> +	struct device *dev = &spinand->spimem->spi->dev;
> +	const struct spinand_ctrl_ops *octal_dtr_ctrl_ops;
> +	int ret;
> +
> +	if (!(spinand->flags & SPINAND_HAS_OCTAL_DTR_BIT))
> +		return 0;
> +
> +	if (!(spinand_op_is_octal_dtr(spinand->data_ops.read_cache) &&
> +	      spinand_op_is_octal_dtr(spinand->data_ops.write_cache) &&
> +	      spinand_op_is_octal_dtr(spinand->data_ops.update_cache)))
> +		return 0;
> +
> +	octal_dtr_ctrl_ops = spinand_select_ctrl_ops_variant(spinand,
> +					spinand->desc_entry->ctrl_ops_variants,
> +					SPINAND_8D_8D_8D);
> +
> +	if (!octal_dtr_ctrl_ops)
> +		return 0;
> +
> +	if (!spinand->manufacturer->ops->change_mode) {
> +		dev_dbg(dev,
> +			"Missing ->change_mode(), unable to switch mode\n");
> +		return -EINVAL;

Looks like something that's worth printing at the info level, and I
think returning EOPNOTSUPP would be more appropriate.

> +	}
> +
> +	ret = spinand->manufacturer->ops->change_mode(spinand,
> +						      SPINAND_8D_8D_8D);
> +	if (ret) {
> +		dev_err(dev,
> +			"Failed to enable Octal DTR SPI mode (err = %d)\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	spinand->protocol = SPINAND_8D_8D_8D;
> +	spinand->ctrl_ops = octal_dtr_ctrl_ops;
> +
> +	dev_dbg(dev,
> +		"%s SPI NAND switched to Octal DTR SPI (8D-8D-8D) mode\n",
> +		spinand->manufacturer->name);
> +	return 0;
> +}
> +
> +static int spinand_init_octal_dtr_disable(struct spinand_device *spinand)

This function is never used. I guess it should be called in the
suspend/shutdown path, at least.

> +{
> +	struct device *dev = &spinand->spimem->spi->dev;
> +	int ret;
> +
> +	if (!spinand->manufacturer->ops->change_mode)
> +		return -EINVAL;
> +
> +	ret = spinand->manufacturer->ops->change_mode(spinand,
> +						      SPINAND_1S_1S_1S);
> +
> +	if (ret) {
> +		dev_err(dev,
> +			"Failed to disable Octal DTR SPI mode (err = %d)\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	spinand->protocol = SPINAND_1S_1S_1S;
> +	spinand->ctrl_ops = &spinand_default_ctrl_ops;
> +	return 0;
> +}
> +
>  /**
>   * spinand_match_and_init() - Try to find a match between a device ID and an
>   *			      entry in a spinand_info table
> @@ -1203,6 +1278,10 @@ static int spinand_init_flash(struct spinand_device *spinand)
>  			break;
>  	}
>  
> +	ret = spinand_init_octal_dtr_enable(spinand);
> +	if (ret)
> +		return ret;
> +
>  	if (ret)
>  		spinand_manufacturer_cleanup(spinand);
>  
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index a8c071983a27..f12aa4516fab 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -417,6 +417,7 @@ struct spinand_ecc_info {
>  
>  #define SPINAND_HAS_QE_BIT		BIT(0)
>  #define SPINAND_HAS_CR_FEAT_BIT		BIT(1)
> +#define SPINAND_HAS_OCTAL_DTR_BIT	BIT(2)

Do we really need a new flag for this? Isn't the template op
initialization enough to reflect whether the NAND and controller can do
8DTR or not?

>  
>  /**
>   * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure


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

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

* Re: [PATCH v3 12/17] mtd: spinand: Add mtd_suspend() to disable Octal DTR mode at suspend
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-03 10:17     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:17 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:45 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> The flash might or might not have gone a power-down during sleep.
> Hence, its SPI IO mode is unpredictable for the core at the time of
> resume. To ensure proper reinitialization during resume, disable the
> Octal DTR SPI IO mode and bring the flash to 1S-1S-1S mode when
> performing suspend using mtd_suspend().
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  drivers/mtd/nand/spi/core.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 2fd08085db6f..9d1c72634e5a 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1307,6 +1307,16 @@ 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);
> +
> +	if (spinand->ctrl_ops->protocol == SPINAND_8D_8D_8D)
> +		return spinand_init_octal_dtr_disable(spinand);

Ok, so you're calling it here. I'd re-order commmits so that DTR
support is added after the suspend hook is defined, even if this hook
does nothing at first. This way you don't have an unused warning in the
previous commit, and most importantly, you don't enter 8DTR before
you're sure things will be set back to 1S when entering suspend.

> +
> +	return 0;
> +}
> +
>  static int spinand_init(struct spinand_device *spinand)
>  {
>  	struct device *dev = &spinand->spimem->spi->dev;
> @@ -1381,6 +1391,7 @@ static int spinand_init(struct spinand_device *spinand)
>  	mtd->_erase = spinand_mtd_erase;
>  	mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
>  	mtd->_resume = spinand_mtd_resume;
> +	mtd->_suspend = spinand_mtd_suspend;
>  
>  	if (nand->ecc.engine) {
>  		ret = mtd_ooblayout_count_freebytes(mtd);


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

* Re: [PATCH v3 12/17] mtd: spinand: Add mtd_suspend() to disable Octal DTR mode at suspend
@ 2022-01-03 10:17     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:17 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:45 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> The flash might or might not have gone a power-down during sleep.
> Hence, its SPI IO mode is unpredictable for the core at the time of
> resume. To ensure proper reinitialization during resume, disable the
> Octal DTR SPI IO mode and bring the flash to 1S-1S-1S mode when
> performing suspend using mtd_suspend().
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  drivers/mtd/nand/spi/core.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 2fd08085db6f..9d1c72634e5a 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1307,6 +1307,16 @@ 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);
> +
> +	if (spinand->ctrl_ops->protocol == SPINAND_8D_8D_8D)
> +		return spinand_init_octal_dtr_disable(spinand);

Ok, so you're calling it here. I'd re-order commmits so that DTR
support is added after the suspend hook is defined, even if this hook
does nothing at first. This way you don't have an unused warning in the
previous commit, and most importantly, you don't enter 8DTR before
you're sure things will be set back to 1S when entering suspend.

> +
> +	return 0;
> +}
> +
>  static int spinand_init(struct spinand_device *spinand)
>  {
>  	struct device *dev = &spinand->spimem->spi->dev;
> @@ -1381,6 +1391,7 @@ static int spinand_init(struct spinand_device *spinand)
>  	mtd->_erase = spinand_mtd_erase;
>  	mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
>  	mtd->_resume = spinand_mtd_resume;
> +	mtd->_suspend = spinand_mtd_suspend;
>  
>  	if (nand->ecc.engine) {
>  		ret = mtd_ooblayout_count_freebytes(mtd);


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

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

* Re: [PATCH v3 15/17] mtd: spianand: winbond: Add change_mode() manufacturer_ops
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-03 10:27     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:27 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:48 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Add implementation of change_mode() for Winbond's manufacturer_ops,
> that executes octal_dtr_enable() and octal_dtr_disable() according
> to requested protocol.
> 
> Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  drivers/mtd/nand/spi/winbond.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
> index c7478faf6cee..d8eccb40c80f 100644
> --- a/drivers/mtd/nand/spi/winbond.c
> +++ b/drivers/mtd/nand/spi/winbond.c
> @@ -242,8 +242,33 @@ static int winbond_spinand_octal_dtr_disable(struct spinand_device *spinand)
>  	return 0;
>  }
>  
> +static int winbond_change_spi_mode(struct spinand_device *spinand,
> +				   const enum spinand_protocol protocol)
> +{
> +	if (spinand->protocol == protocol)
> +		return 0;
> +
> +	switch (spinand->protocol) {
> +	case SPINAND_1S_1S_1S:
> +		if (protocol == SPINAND_8D_8D_8D)
> +			return winbond_spinand_octal_dtr_enable(spinand);
> +		break;
> +
> +	case SPINAND_8D_8D_8D:
> +		if (protocol == SPINAND_1S_1S_1S)
> +			return winbond_spinand_octal_dtr_disable(spinand);
> +		break;
> +
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return -EOPNOTSUPP;

This version is slightly more concise:

	if (spinand->protocol == protocol)
		return 0;
	else if (spinand->protocol == SPINAND_1S && protocol ==	SPINAND_8D)
		return winbond_spinand_octal_dtr_enable(spinand);
	else if (spinand->protocol == SPINAND_8D && protocol ==	SPINAND_1S)
		return winbond_spinand_octal_dtr_disable(spinand);

	return -EOPNOTSUPP;

> +}
> +
>  static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
>  	.init = winbond_spinand_init,
> +	.change_mode = winbond_change_spi_mode,
>  };
>  
>  const struct spinand_manufacturer winbond_spinand_manufacturer = {


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

* Re: [PATCH v3 15/17] mtd: spianand: winbond: Add change_mode() manufacturer_ops
@ 2022-01-03 10:27     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:27 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:48 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Add implementation of change_mode() for Winbond's manufacturer_ops,
> that executes octal_dtr_enable() and octal_dtr_disable() according
> to requested protocol.
> 
> Datasheet: https://www.winbond.com/export/sites/winbond/datasheet/W35N01JW_Datasheet_Brief.pdf
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  drivers/mtd/nand/spi/winbond.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
> index c7478faf6cee..d8eccb40c80f 100644
> --- a/drivers/mtd/nand/spi/winbond.c
> +++ b/drivers/mtd/nand/spi/winbond.c
> @@ -242,8 +242,33 @@ static int winbond_spinand_octal_dtr_disable(struct spinand_device *spinand)
>  	return 0;
>  }
>  
> +static int winbond_change_spi_mode(struct spinand_device *spinand,
> +				   const enum spinand_protocol protocol)
> +{
> +	if (spinand->protocol == protocol)
> +		return 0;
> +
> +	switch (spinand->protocol) {
> +	case SPINAND_1S_1S_1S:
> +		if (protocol == SPINAND_8D_8D_8D)
> +			return winbond_spinand_octal_dtr_enable(spinand);
> +		break;
> +
> +	case SPINAND_8D_8D_8D:
> +		if (protocol == SPINAND_1S_1S_1S)
> +			return winbond_spinand_octal_dtr_disable(spinand);
> +		break;
> +
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return -EOPNOTSUPP;

This version is slightly more concise:

	if (spinand->protocol == protocol)
		return 0;
	else if (spinand->protocol == SPINAND_1S && protocol ==	SPINAND_8D)
		return winbond_spinand_octal_dtr_enable(spinand);
	else if (spinand->protocol == SPINAND_8D && protocol ==	SPINAND_1S)
		return winbond_spinand_octal_dtr_disable(spinand);

	return -EOPNOTSUPP;

> +}
> +
>  static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
>  	.init = winbond_spinand_init,
> +	.change_mode = winbond_change_spi_mode,
>  };
>  
>  const struct spinand_manufacturer winbond_spinand_manufacturer = {


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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-01-03 10:01     ` Boris Brezillon
@ 2022-01-03 10:36       ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:36 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Mon, 3 Jan 2022 11:01:07 +0100
Boris Brezillon <boris.brezillon@collabora.com> wrote:


> struct spinand_device {
> 	...
> 	enum spinand_protocol protocol;
> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];

My bad, it should be:

	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];

since those templates get populated dynamically at probe time based on
what the flash and the controller support.

> 	...
> };
> 

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-01-03 10:36       ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-03 10:36 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Mon, 3 Jan 2022 11:01:07 +0100
Boris Brezillon <boris.brezillon@collabora.com> wrote:


> struct spinand_device {
> 	...
> 	enum spinand_protocol protocol;
> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];

My bad, it should be:

	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];

since those templates get populated dynamically at probe time based on
what the flash and the controller support.

> 	...
> };
> 

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

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-04 14:52     ` Mark Brown
  -1 siblings, 0 replies; 76+ messages in thread
From: Mark Brown @ 2022-01-04 14:52 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Patrice Chotard, Christophe Kerello, Boris Brezillon,
	Daniel Palmer, Alexander Lobakin, linux-mtd, linux-kernel,
	linux-spi, p.yadav

[-- Attachment #1: Type: text/plain, Size: 374 bytes --]

On Sat, Jan 01, 2022 at 01:12:34PM +0530, Apurva Nandan wrote:
> Setting dtr field of spi_mem_op is useful when creating templates
> for DTR ops in spinand.h. Also, 2 bytes cmd phases are required when
> operating in Octal DTR SPI mode.

Are people OK with this?  It looks fine to me, if nobody objects I can
send it in the next merge window so it's there for the MTD bits.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
@ 2022-01-04 14:52     ` Mark Brown
  0 siblings, 0 replies; 76+ messages in thread
From: Mark Brown @ 2022-01-04 14:52 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Patrice Chotard, Christophe Kerello, Boris Brezillon,
	Daniel Palmer, Alexander Lobakin, linux-mtd, linux-kernel,
	linux-spi, p.yadav


[-- Attachment #1.1: Type: text/plain, Size: 374 bytes --]

On Sat, Jan 01, 2022 at 01:12:34PM +0530, Apurva Nandan wrote:
> Setting dtr field of spi_mem_op is useful when creating templates
> for DTR ops in spinand.h. Also, 2 bytes cmd phases are required when
> operating in Octal DTR SPI mode.

Are people OK with this?  It looks fine to me, if nobody objects I can
send it in the next merge window so it's there for the MTD bits.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 144 bytes --]

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

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-04 15:31     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-04 15:31 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:34 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Setting dtr field of spi_mem_op is useful when creating templates
> for DTR ops in spinand.h. Also, 2 bytes cmd phases are required when
> operating in Octal DTR SPI mode.
> 
> Create new templates for dtr mode cmd, address, dummy and data phase
> in spi_mem_op, which set the dtr field to 1 and also allow passing
> the nbytes for the cmd phase.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  include/linux/spi/spi-mem.h | 41 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 41 insertions(+)
> 
> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
> index 85e2ff7b840d..682378a9c600 100644
> --- a/include/linux/spi/spi-mem.h
> +++ b/include/linux/spi/spi-mem.h
> @@ -20,6 +20,14 @@
>  		.nbytes = 1,					\
>  	}
>  
> +#define SPI_MEM_OP_CMD_DTR(__nbytes, __opcode, __buswidth)	\
> +	{							\
> +		.nbytes = __nbytes,				\
> +		.opcode = __opcode,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)		\
>  	{							\
>  		.nbytes = __nbytes,				\
> @@ -27,6 +35,14 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_ADDR_DTR(__nbytes, __val, __buswidth)	\
> +	{							\
> +		.nbytes = __nbytes,				\
> +		.val = __val,					\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_NO_ADDR	{ }
>  
>  #define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\
> @@ -35,6 +51,13 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_DUMMY_DTR(__nbytes, __buswidth)		\
> +	{							\
> +		.nbytes = __nbytes,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_NO_DUMMY	{ }
>  
>  #define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)		\
> @@ -45,6 +68,15 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_DATA_IN_DTR(__nbytes, __buf, __buswidth)	\
> +	{							\
> +		.dir = SPI_MEM_DATA_IN,				\
> +		.nbytes = __nbytes,				\
> +		.buf.in = __buf,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)	\
>  	{							\
>  		.dir = SPI_MEM_DATA_OUT,			\
> @@ -53,6 +85,15 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_DATA_OUT_DTR(__nbytes, __buf, __buswidth)	\
> +	{							\
> +		.dir = SPI_MEM_DATA_OUT,			\
> +		.nbytes = __nbytes,				\
> +		.buf.out = __buf,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_NO_DATA	{ }
>  
>  /**

How about:

diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 85e2ff7b840d..9a8d42803026 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -13,44 +13,59 @@
 
 #include <linux/spi/spi.h>
 
-#define SPI_MEM_OP_CMD(__opcode, __buswidth)                   \
+#define SPI_MEM_OP_DTR .dtr = 1
+
+#define SPI_MEM_OP_CMD(__opcode, __buswidth, ...)              \
        {                                                       \
                .buswidth = __buswidth,                         \
                .opcode = __opcode,                             \
                .nbytes = 1,                                    \
+               __VA_ARGS__                                     \
        }
 
-#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)           \
+#define SPI_MEM_OP_EXT_CMD(__nbytes, __opcode, __buswidth, ...)        \
+       {                                                       \
+               .buswidth = __buswidth,                         \
+               .opcode = __opcode,                             \
+               .nbytes = __nbytes,                             \
+               __VA_ARGS__                                     \
+       }
+
+#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth, ...)      \
        {                                                       \
                .nbytes = __nbytes,                             \
                .val = __val,                                   \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
 #define SPI_MEM_OP_NO_ADDR     { }
 
-#define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)                 \
+#define SPI_MEM_OP_DUMMY(__nbytes, __buswidth, ...)            \
        {                                                       \
                .nbytes = __nbytes,                             \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
 #define SPI_MEM_OP_NO_DUMMY    { }
 
-#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)                \
+#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth, ...)   \
        {                                                       \
                .dir = SPI_MEM_DATA_IN,                         \
                .nbytes = __nbytes,                             \
                .buf.in = __buf,                                \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
-#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)       \
+#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth, ...)  \
        {                                                       \
                .dir = SPI_MEM_DATA_OUT,                        \
                .nbytes = __nbytes,                             \
                .buf.out = __buf,                               \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
 #define SPI_MEM_OP_NO_DATA     { }

and you get to define a DTR op like that:

	struct spi_mem_op op =
		SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1234, 8, SPI_MEM_OP_DTR),
			   SPI_MEM_OP_ADDR(4, 0xdeadbeef, 8, SPI_MEM_OP_DTR),
			   SPI_MEM_OP_DATA_OUT(128, buf, 8, SPI_MEM_OP_DTR));

This also means we can extend the struct without having to define new macros.

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
@ 2022-01-04 15:31     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-04 15:31 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:34 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Setting dtr field of spi_mem_op is useful when creating templates
> for DTR ops in spinand.h. Also, 2 bytes cmd phases are required when
> operating in Octal DTR SPI mode.
> 
> Create new templates for dtr mode cmd, address, dummy and data phase
> in spi_mem_op, which set the dtr field to 1 and also allow passing
> the nbytes for the cmd phase.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  include/linux/spi/spi-mem.h | 41 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 41 insertions(+)
> 
> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
> index 85e2ff7b840d..682378a9c600 100644
> --- a/include/linux/spi/spi-mem.h
> +++ b/include/linux/spi/spi-mem.h
> @@ -20,6 +20,14 @@
>  		.nbytes = 1,					\
>  	}
>  
> +#define SPI_MEM_OP_CMD_DTR(__nbytes, __opcode, __buswidth)	\
> +	{							\
> +		.nbytes = __nbytes,				\
> +		.opcode = __opcode,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)		\
>  	{							\
>  		.nbytes = __nbytes,				\
> @@ -27,6 +35,14 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_ADDR_DTR(__nbytes, __val, __buswidth)	\
> +	{							\
> +		.nbytes = __nbytes,				\
> +		.val = __val,					\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_NO_ADDR	{ }
>  
>  #define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\
> @@ -35,6 +51,13 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_DUMMY_DTR(__nbytes, __buswidth)		\
> +	{							\
> +		.nbytes = __nbytes,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_NO_DUMMY	{ }
>  
>  #define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)		\
> @@ -45,6 +68,15 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_DATA_IN_DTR(__nbytes, __buf, __buswidth)	\
> +	{							\
> +		.dir = SPI_MEM_DATA_IN,				\
> +		.nbytes = __nbytes,				\
> +		.buf.in = __buf,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)	\
>  	{							\
>  		.dir = SPI_MEM_DATA_OUT,			\
> @@ -53,6 +85,15 @@
>  		.buswidth = __buswidth,				\
>  	}
>  
> +#define SPI_MEM_OP_DATA_OUT_DTR(__nbytes, __buf, __buswidth)	\
> +	{							\
> +		.dir = SPI_MEM_DATA_OUT,			\
> +		.nbytes = __nbytes,				\
> +		.buf.out = __buf,				\
> +		.buswidth = __buswidth,				\
> +		.dtr = 1,					\
> +	}
> +
>  #define SPI_MEM_OP_NO_DATA	{ }
>  
>  /**

How about:

diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 85e2ff7b840d..9a8d42803026 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -13,44 +13,59 @@
 
 #include <linux/spi/spi.h>
 
-#define SPI_MEM_OP_CMD(__opcode, __buswidth)                   \
+#define SPI_MEM_OP_DTR .dtr = 1
+
+#define SPI_MEM_OP_CMD(__opcode, __buswidth, ...)              \
        {                                                       \
                .buswidth = __buswidth,                         \
                .opcode = __opcode,                             \
                .nbytes = 1,                                    \
+               __VA_ARGS__                                     \
        }
 
-#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)           \
+#define SPI_MEM_OP_EXT_CMD(__nbytes, __opcode, __buswidth, ...)        \
+       {                                                       \
+               .buswidth = __buswidth,                         \
+               .opcode = __opcode,                             \
+               .nbytes = __nbytes,                             \
+               __VA_ARGS__                                     \
+       }
+
+#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth, ...)      \
        {                                                       \
                .nbytes = __nbytes,                             \
                .val = __val,                                   \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
 #define SPI_MEM_OP_NO_ADDR     { }
 
-#define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)                 \
+#define SPI_MEM_OP_DUMMY(__nbytes, __buswidth, ...)            \
        {                                                       \
                .nbytes = __nbytes,                             \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
 #define SPI_MEM_OP_NO_DUMMY    { }
 
-#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)                \
+#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth, ...)   \
        {                                                       \
                .dir = SPI_MEM_DATA_IN,                         \
                .nbytes = __nbytes,                             \
                .buf.in = __buf,                                \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
-#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)       \
+#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth, ...)  \
        {                                                       \
                .dir = SPI_MEM_DATA_OUT,                        \
                .nbytes = __nbytes,                             \
                .buf.out = __buf,                               \
                .buswidth = __buswidth,                         \
+               __VA_ARGS__                                     \
        }
 
 #define SPI_MEM_OP_NO_DATA     { }

and you get to define a DTR op like that:

	struct spi_mem_op op =
		SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1234, 8, SPI_MEM_OP_DTR),
			   SPI_MEM_OP_ADDR(4, 0xdeadbeef, 8, SPI_MEM_OP_DTR),
			   SPI_MEM_OP_DATA_OUT(128, buf, 8, SPI_MEM_OP_DTR));

This also means we can extend the struct without having to define new macros.

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

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  2022-01-04 15:31     ` Boris Brezillon
@ 2022-01-05  5:50       ` Pratyush Yadav
  -1 siblings, 0 replies; 76+ messages in thread
From: Pratyush Yadav @ 2022-01-05  5:50 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Apurva Nandan, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Mark Brown, Patrice Chotard,
	Christophe Kerello, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi

On 04/01/22 04:31PM, Boris Brezillon wrote:
> and you get to define a DTR op like that:
> 
> 	struct spi_mem_op op =
> 		SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1234, 8, SPI_MEM_OP_DTR),
> 			   SPI_MEM_OP_ADDR(4, 0xdeadbeef, 8, SPI_MEM_OP_DTR),
> 			   SPI_MEM_OP_DATA_OUT(128, buf, 8, SPI_MEM_OP_DTR));
> 
> This also means we can extend the struct without having to define new macros.

I like this. It would also let us easily mix-and-match the ecc parameter 
that Miquel is adding.

-- 
Regards,
Pratyush Yadav
Texas Instruments Inc.

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
@ 2022-01-05  5:50       ` Pratyush Yadav
  0 siblings, 0 replies; 76+ messages in thread
From: Pratyush Yadav @ 2022-01-05  5:50 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Apurva Nandan, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Mark Brown, Patrice Chotard,
	Christophe Kerello, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi

On 04/01/22 04:31PM, Boris Brezillon wrote:
> and you get to define a DTR op like that:
> 
> 	struct spi_mem_op op =
> 		SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1234, 8, SPI_MEM_OP_DTR),
> 			   SPI_MEM_OP_ADDR(4, 0xdeadbeef, 8, SPI_MEM_OP_DTR),
> 			   SPI_MEM_OP_DATA_OUT(128, buf, 8, SPI_MEM_OP_DTR));
> 
> This also means we can extend the struct without having to define new macros.

I like this. It would also let us easily mix-and-match the ecc parameter 
that Miquel is adding.

-- 
Regards,
Pratyush Yadav
Texas Instruments Inc.

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

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  2022-01-05  5:50       ` Pratyush Yadav
@ 2022-01-05  7:36         ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-05  7:36 UTC (permalink / raw)
  To: Pratyush Yadav
  Cc: Apurva Nandan, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Mark Brown, Patrice Chotard,
	Christophe Kerello, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi

On Wed, 5 Jan 2022 11:20:55 +0530
Pratyush Yadav <p.yadav@ti.com> wrote:

> On 04/01/22 04:31PM, Boris Brezillon wrote:
> > and you get to define a DTR op like that:
> > 
> > 	struct spi_mem_op op =
> > 		SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1234, 8, SPI_MEM_OP_DTR),
> > 			   SPI_MEM_OP_ADDR(4, 0xdeadbeef, 8, SPI_MEM_OP_DTR),
> > 			   SPI_MEM_OP_DATA_OUT(128, buf, 8, SPI_MEM_OP_DTR));
> > 
> > This also means we can extend the struct without having to define new macros.  
> 
> I like this. It would also let us easily mix-and-match the ecc parameter 
> that Miquel is adding.
> 

In practice, I doubt you'll ever set the ecc bit when declaring the op,
it's more a modification you do afterwards if ECC needs to be enabled,
but who knows...

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
@ 2022-01-05  7:36         ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-05  7:36 UTC (permalink / raw)
  To: Pratyush Yadav
  Cc: Apurva Nandan, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Mark Brown, Patrice Chotard,
	Christophe Kerello, Daniel Palmer, Alexander Lobakin, linux-mtd,
	linux-kernel, linux-spi

On Wed, 5 Jan 2022 11:20:55 +0530
Pratyush Yadav <p.yadav@ti.com> wrote:

> On 04/01/22 04:31PM, Boris Brezillon wrote:
> > and you get to define a DTR op like that:
> > 
> > 	struct spi_mem_op op =
> > 		SPI_MEM_OP(SPI_MEM_OP_EXT_CMD(2, 0x1234, 8, SPI_MEM_OP_DTR),
> > 			   SPI_MEM_OP_ADDR(4, 0xdeadbeef, 8, SPI_MEM_OP_DTR),
> > 			   SPI_MEM_OP_DATA_OUT(128, buf, 8, SPI_MEM_OP_DTR));
> > 
> > This also means we can extend the struct without having to define new macros.  
> 
> I like this. It would also let us easily mix-and-match the ecc parameter 
> that Miquel is adding.
> 

In practice, I doubt you'll ever set the ecc bit when declaring the op,
it's more a modification you do afterwards if ECC needs to be enabled,
but who knows...

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

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
  2022-01-04 15:31     ` Boris Brezillon
@ 2022-01-05  8:24       ` Tudor.Ambarus
  -1 siblings, 0 replies; 76+ messages in thread
From: Tudor.Ambarus @ 2022-01-05  8:24 UTC (permalink / raw)
  To: boris.brezillon, a-nandan
  Cc: miquel.raynal, richard, vigneshr, broonie, patrice.chotard,
	christophe.kerello, daniel, alobakin, linux-mtd, linux-kernel,
	linux-spi, p.yadav

On 1/4/22 5:31 PM, Boris Brezillon wrote:
> -#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)                \
> +#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth, ...)   \
>         {                                                       \
>                 .dir = SPI_MEM_DATA_IN,                         \
>                 .nbytes = __nbytes,                             \
>                 .buf.in = __buf,                                \
>                 .buswidth = __buswidth,                         \
> +               __VA_ARGS__                                     \
>         }
> 
> -#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)       \
> +#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth, ...)  \
>         {                                                       \
>                 .dir = SPI_MEM_DATA_OUT,                        \
>                 .nbytes = __nbytes,                             \
>                 .buf.out = __buf,                               \
>                 .buswidth = __buswidth,                         \
> +               __VA_ARGS__                                   

I like it too. This also comes in handy when we'll have to differentiate
between register and memory accesses.

Cheers,
ta

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

* Re: [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase
@ 2022-01-05  8:24       ` Tudor.Ambarus
  0 siblings, 0 replies; 76+ messages in thread
From: Tudor.Ambarus @ 2022-01-05  8:24 UTC (permalink / raw)
  To: boris.brezillon, a-nandan
  Cc: miquel.raynal, richard, vigneshr, broonie, patrice.chotard,
	christophe.kerello, daniel, alobakin, linux-mtd, linux-kernel,
	linux-spi, p.yadav

On 1/4/22 5:31 PM, Boris Brezillon wrote:
> -#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)                \
> +#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth, ...)   \
>         {                                                       \
>                 .dir = SPI_MEM_DATA_IN,                         \
>                 .nbytes = __nbytes,                             \
>                 .buf.in = __buf,                                \
>                 .buswidth = __buswidth,                         \
> +               __VA_ARGS__                                     \
>         }
> 
> -#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)       \
> +#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth, ...)  \
>         {                                                       \
>                 .dir = SPI_MEM_DATA_OUT,                        \
>                 .nbytes = __nbytes,                             \
>                 .buf.out = __buf,                               \
>                 .buswidth = __buswidth,                         \
> +               __VA_ARGS__                                   

I like it too. This also comes in handy when we'll have to differentiate
between register and memory accesses.

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

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

* Re: [PATCH v3 09/17] mtd: spinand: Add change_mode() in manufacturer_ops
  2022-01-01  7:42   ` Apurva Nandan
@ 2022-01-05  9:52     ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-05  9:52 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:42 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Introduce change_mode() manufacturer_op to let the vendor provide the
> implementation of switching of SPI IO modes.
> 
> The method to switch to different SPI IO mode may vary across
> manufacturers. For example, for Winbond, Octal DTR is enabled by
> writing values to the volatile configuration register. So, let the
> manufacturer's code have their own implementation for switching to
> any given SPI IO mode. Manufacturer's code need to take care, if
> the requested protocol change is allowed/needed and how to apply
> it.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  include/linux/mtd/spinand.h | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 5dae0649f2fb..ad924271a248 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -298,6 +298,7 @@ struct spinand_devid {
>  /**
>   * struct manufacurer_ops - SPI NAND manufacturer specific operations
>   * @init: initialize a SPI NAND device
> + * @change_mode: switch the SPI NAND flash to a specific SPI protocol
>   * @cleanup: cleanup a SPI NAND device
>   *
>   * Each SPI NAND manufacturer driver should implement this interface so that
> @@ -305,6 +306,8 @@ struct spinand_devid {
>   */
>  struct spinand_manufacturer_ops {
>  	int (*init)(struct spinand_device *spinand);
> +	int (*change_mode)(struct spinand_device *spinand,
> +			   const enum spinand_protocol protocol);

Protocol or mode? Pick one and stick to it. Given you already use
protocol elsewhere, maybe s/select_mode/select_protocol/.

>  	void (*cleanup)(struct spinand_device *spinand);
>  };
>  


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

* Re: [PATCH v3 09/17] mtd: spinand: Add change_mode() in manufacturer_ops
@ 2022-01-05  9:52     ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-01-05  9:52 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Sat, 1 Jan 2022 13:12:42 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Introduce change_mode() manufacturer_op to let the vendor provide the
> implementation of switching of SPI IO modes.
> 
> The method to switch to different SPI IO mode may vary across
> manufacturers. For example, for Winbond, Octal DTR is enabled by
> writing values to the volatile configuration register. So, let the
> manufacturer's code have their own implementation for switching to
> any given SPI IO mode. Manufacturer's code need to take care, if
> the requested protocol change is allowed/needed and how to apply
> it.
> 
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> ---
>  include/linux/mtd/spinand.h | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 5dae0649f2fb..ad924271a248 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -298,6 +298,7 @@ struct spinand_devid {
>  /**
>   * struct manufacurer_ops - SPI NAND manufacturer specific operations
>   * @init: initialize a SPI NAND device
> + * @change_mode: switch the SPI NAND flash to a specific SPI protocol
>   * @cleanup: cleanup a SPI NAND device
>   *
>   * Each SPI NAND manufacturer driver should implement this interface so that
> @@ -305,6 +306,8 @@ struct spinand_devid {
>   */
>  struct spinand_manufacturer_ops {
>  	int (*init)(struct spinand_device *spinand);
> +	int (*change_mode)(struct spinand_device *spinand,
> +			   const enum spinand_protocol protocol);

Protocol or mode? Pick one and stick to it. Given you already use
protocol elsewhere, maybe s/select_mode/select_protocol/.

>  	void (*cleanup)(struct spinand_device *spinand);
>  };
>  


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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-01-03 10:01     ` Boris Brezillon
@ 2022-02-15 15:33       ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-02-15 15:33 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Boris,

On 03/01/22 15:31, Boris Brezillon wrote:
> On Sat, 1 Jan 2022 13:12:38 +0530
> Apurva Nandan <a-nandan@ti.com> wrote:
>
>> 'ctrl_ops' are op templates for non-page read/write operations,
>> which are: reset, get_feature, set_feature, write_enable, block_erase,
>> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
>> op templates for each of this op, as well as enum spinand_protocol
>> denoting protocol of all these ops.
>>
>> We require these new op templates because of deviation in standard
>> SPINAND ops by manufacturers and also due to changes when there is a
>> change in SPI protocol/mode. This prevents the core from live-patching
>> and vendor-specific adjustments in ops.
>>
>> Define 'ctrl_ops', add macros to initialize it and add it in
>> spinand_device.
>>
>> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
>> ---
>>   include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>>   1 file changed, 33 insertions(+)
>>
>> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
>> index 439d8ce40e1d..e5df6220ec1e 100644
>> --- a/include/linux/mtd/spinand.h
>> +++ b/include/linux/mtd/spinand.h
>> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>>   			sizeof(struct spi_mem_op),			\
>>   	}
>>   
>> +struct spinand_ctrl_ops {
>> +	const struct {
>> +		struct spi_mem_op reset;
>> +		struct spi_mem_op get_feature;
>> +		struct spi_mem_op set_feature;
>> +		struct spi_mem_op write_enable;
>> +		struct spi_mem_op block_erase;
>> +		struct spi_mem_op page_read;
>> +		struct spi_mem_op program_execute;
>> +	} ops;
>> +	const enum spinand_protocol protocol;
> Do you really need that protocol field?
>
>> +};
>> +
>> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
>> +			 __write_enable, __block_erase, __page_read,		\
>> +			 __program_execute)					\
>> +	{									\
>> +		.ops = {							\
>> +			.reset = __reset,					\
>> +			.get_feature = __get_feature,				\
>> +			.set_feature = __set_feature,				\
>> +			.write_enable = __write_enable,				\
>> +			.block_erase = __block_erase,				\
>> +			.page_read = __page_read,				\
>> +			.program_execute = __program_execute,			\
>> +		},								\
>> +		.protocol = __protocol,						\
>> +	}
>> +
>>   /**
>>    * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>>    *		      chip
>> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>>    * @data_ops.read_cache: read cache op template
>>    * @data_ops.write_cache: write cache op template
>>    * @data_ops.update_cache: update cache op template
>> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
>> + *	      non page-read/write ops.
>>    * @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
>> @@ -498,6 +529,8 @@ struct spinand_device {
>>   		const struct spi_mem_op *update_cache;
>>   	} data_ops;
>>   
>> +	const struct spinand_ctrl_ops *ctrl_ops;
>> +
> Okay, I had something slightly different in mind. First, I'd put all
> templates in a struct:
>
> struct spinand_op_templates {
> 	const struct spi_mem_op *read_cache;
> 	const struct spi_mem_op *write_cache;
> 	const struct spi_mem_op *update_cache;
> 	const struct spi_mem_op *reset;
> 	const struct spi_mem_op *get_feature;
> 	const struct spi_mem_op *set_feature;
> 	const struct spi_mem_op *write_enable;
> 	const struct spi_mem_op *block_erase;
> 	const struct spi_mem_op *page_load;
> 	const struct spi_mem_op *program_execute;
> };
>
> Then, at the spinand level, I'd define an array of templates:
>
> enum spinand_protocol {
> 	SPINAND_1S_1S_1S,
> 	SPINAND_2S_2S_2S,
> 	SPINAND_4S_4S_4S,
> 	SPINAND_8S_8S_8S,
> 	SPINAND_8D_8D_8D,
> 	SPINAND_NUM_PROTOCOLS,
> };
>
> struct spinand_device {
> 	...
> 	enum spinand_protocol protocol;
> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
> 	...
> };
>
> This way, you can easily pick the right set of operations based
> on the protocol/mode you're in:
>
> #define spinand_get_op_template(spinand, opname) \
> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>
> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
> {
> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
> 	int ret;
>
> 	...
> }

I find a couple of issues with this  method,

1. read_cache, write_cache, update_cache op templates don't fit well 
with the other non-data ops, as
these data ops are used to create a dirmap, and that can be done only 
once at probe time. Hence, there
is a different mechanism of selecting of data ops and non-data ops. 
Hence, this division in the op templates
struct as data_ops and ctrl_ops is required. Currently, the core only 
supports using a single protocol for
data ops, chosen at the time of probing.

2. If we use this single op_templates struct, I can't think of any good 
way to initialize these in the
manufacturers driver (winbond.c), refer to 17th patch in this series. 
Could you please suggest a macro
implementation also for winbond.c with the suggested op_templates struct.

Thanks,
Apurva Nandan


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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-02-15 15:33       ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-02-15 15:33 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Boris,

On 03/01/22 15:31, Boris Brezillon wrote:
> On Sat, 1 Jan 2022 13:12:38 +0530
> Apurva Nandan <a-nandan@ti.com> wrote:
>
>> 'ctrl_ops' are op templates for non-page read/write operations,
>> which are: reset, get_feature, set_feature, write_enable, block_erase,
>> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
>> op templates for each of this op, as well as enum spinand_protocol
>> denoting protocol of all these ops.
>>
>> We require these new op templates because of deviation in standard
>> SPINAND ops by manufacturers and also due to changes when there is a
>> change in SPI protocol/mode. This prevents the core from live-patching
>> and vendor-specific adjustments in ops.
>>
>> Define 'ctrl_ops', add macros to initialize it and add it in
>> spinand_device.
>>
>> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
>> ---
>>   include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>>   1 file changed, 33 insertions(+)
>>
>> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
>> index 439d8ce40e1d..e5df6220ec1e 100644
>> --- a/include/linux/mtd/spinand.h
>> +++ b/include/linux/mtd/spinand.h
>> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>>   			sizeof(struct spi_mem_op),			\
>>   	}
>>   
>> +struct spinand_ctrl_ops {
>> +	const struct {
>> +		struct spi_mem_op reset;
>> +		struct spi_mem_op get_feature;
>> +		struct spi_mem_op set_feature;
>> +		struct spi_mem_op write_enable;
>> +		struct spi_mem_op block_erase;
>> +		struct spi_mem_op page_read;
>> +		struct spi_mem_op program_execute;
>> +	} ops;
>> +	const enum spinand_protocol protocol;
> Do you really need that protocol field?
>
>> +};
>> +
>> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
>> +			 __write_enable, __block_erase, __page_read,		\
>> +			 __program_execute)					\
>> +	{									\
>> +		.ops = {							\
>> +			.reset = __reset,					\
>> +			.get_feature = __get_feature,				\
>> +			.set_feature = __set_feature,				\
>> +			.write_enable = __write_enable,				\
>> +			.block_erase = __block_erase,				\
>> +			.page_read = __page_read,				\
>> +			.program_execute = __program_execute,			\
>> +		},								\
>> +		.protocol = __protocol,						\
>> +	}
>> +
>>   /**
>>    * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>>    *		      chip
>> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>>    * @data_ops.read_cache: read cache op template
>>    * @data_ops.write_cache: write cache op template
>>    * @data_ops.update_cache: update cache op template
>> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
>> + *	      non page-read/write ops.
>>    * @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
>> @@ -498,6 +529,8 @@ struct spinand_device {
>>   		const struct spi_mem_op *update_cache;
>>   	} data_ops;
>>   
>> +	const struct spinand_ctrl_ops *ctrl_ops;
>> +
> Okay, I had something slightly different in mind. First, I'd put all
> templates in a struct:
>
> struct spinand_op_templates {
> 	const struct spi_mem_op *read_cache;
> 	const struct spi_mem_op *write_cache;
> 	const struct spi_mem_op *update_cache;
> 	const struct spi_mem_op *reset;
> 	const struct spi_mem_op *get_feature;
> 	const struct spi_mem_op *set_feature;
> 	const struct spi_mem_op *write_enable;
> 	const struct spi_mem_op *block_erase;
> 	const struct spi_mem_op *page_load;
> 	const struct spi_mem_op *program_execute;
> };
>
> Then, at the spinand level, I'd define an array of templates:
>
> enum spinand_protocol {
> 	SPINAND_1S_1S_1S,
> 	SPINAND_2S_2S_2S,
> 	SPINAND_4S_4S_4S,
> 	SPINAND_8S_8S_8S,
> 	SPINAND_8D_8D_8D,
> 	SPINAND_NUM_PROTOCOLS,
> };
>
> struct spinand_device {
> 	...
> 	enum spinand_protocol protocol;
> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
> 	...
> };
>
> This way, you can easily pick the right set of operations based
> on the protocol/mode you're in:
>
> #define spinand_get_op_template(spinand, opname) \
> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>
> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
> {
> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
> 	int ret;
>
> 	...
> }

I find a couple of issues with this  method,

1. read_cache, write_cache, update_cache op templates don't fit well 
with the other non-data ops, as
these data ops are used to create a dirmap, and that can be done only 
once at probe time. Hence, there
is a different mechanism of selecting of data ops and non-data ops. 
Hence, this division in the op templates
struct as data_ops and ctrl_ops is required. Currently, the core only 
supports using a single protocol for
data ops, chosen at the time of probing.

2. If we use this single op_templates struct, I can't think of any good 
way to initialize these in the
manufacturers driver (winbond.c), refer to 17th patch in this series. 
Could you please suggest a macro
implementation also for winbond.c with the suggested op_templates struct.

Thanks,
Apurva Nandan


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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-02-15 15:33       ` Apurva Nandan
@ 2022-02-15 17:37         ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-02-15 17:37 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Apurva,

On Tue, 15 Feb 2022 21:03:52 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Hi Boris,
> 
> On 03/01/22 15:31, Boris Brezillon wrote:
> > On Sat, 1 Jan 2022 13:12:38 +0530
> > Apurva Nandan <a-nandan@ti.com> wrote:
> >  
> >> 'ctrl_ops' are op templates for non-page read/write operations,
> >> which are: reset, get_feature, set_feature, write_enable, block_erase,
> >> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
> >> op templates for each of this op, as well as enum spinand_protocol
> >> denoting protocol of all these ops.
> >>
> >> We require these new op templates because of deviation in standard
> >> SPINAND ops by manufacturers and also due to changes when there is a
> >> change in SPI protocol/mode. This prevents the core from live-patching
> >> and vendor-specific adjustments in ops.
> >>
> >> Define 'ctrl_ops', add macros to initialize it and add it in
> >> spinand_device.
> >>
> >> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> >> ---
> >>   include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
> >>   1 file changed, 33 insertions(+)
> >>
> >> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> >> index 439d8ce40e1d..e5df6220ec1e 100644
> >> --- a/include/linux/mtd/spinand.h
> >> +++ b/include/linux/mtd/spinand.h
> >> @@ -356,6 +356,35 @@ struct spinand_op_variants {
> >>   			sizeof(struct spi_mem_op),			\
> >>   	}
> >>   
> >> +struct spinand_ctrl_ops {
> >> +	const struct {
> >> +		struct spi_mem_op reset;
> >> +		struct spi_mem_op get_feature;
> >> +		struct spi_mem_op set_feature;
> >> +		struct spi_mem_op write_enable;
> >> +		struct spi_mem_op block_erase;
> >> +		struct spi_mem_op page_read;
> >> +		struct spi_mem_op program_execute;
> >> +	} ops;
> >> +	const enum spinand_protocol protocol;  
> > Do you really need that protocol field?
> >  
> >> +};
> >> +
> >> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
> >> +			 __write_enable, __block_erase, __page_read,		\
> >> +			 __program_execute)					\
> >> +	{									\
> >> +		.ops = {							\
> >> +			.reset = __reset,					\
> >> +			.get_feature = __get_feature,				\
> >> +			.set_feature = __set_feature,				\
> >> +			.write_enable = __write_enable,				\
> >> +			.block_erase = __block_erase,				\
> >> +			.page_read = __page_read,				\
> >> +			.program_execute = __program_execute,			\
> >> +		},								\
> >> +		.protocol = __protocol,						\
> >> +	}
> >> +
> >>   /**
> >>    * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
> >>    *		      chip
> >> @@ -468,6 +497,8 @@ struct spinand_dirmap {
> >>    * @data_ops.read_cache: read cache op template
> >>    * @data_ops.write_cache: write cache op template
> >>    * @data_ops.update_cache: update cache op template
> >> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
> >> + *	      non page-read/write ops.
> >>    * @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
> >> @@ -498,6 +529,8 @@ struct spinand_device {
> >>   		const struct spi_mem_op *update_cache;
> >>   	} data_ops;
> >>   
> >> +	const struct spinand_ctrl_ops *ctrl_ops;
> >> +  
> > Okay, I had something slightly different in mind. First, I'd put all
> > templates in a struct:
> >
> > struct spinand_op_templates {
> > 	const struct spi_mem_op *read_cache;
> > 	const struct spi_mem_op *write_cache;
> > 	const struct spi_mem_op *update_cache;
> > 	const struct spi_mem_op *reset;
> > 	const struct spi_mem_op *get_feature;
> > 	const struct spi_mem_op *set_feature;
> > 	const struct spi_mem_op *write_enable;
> > 	const struct spi_mem_op *block_erase;
> > 	const struct spi_mem_op *page_load;
> > 	const struct spi_mem_op *program_execute;
> > };
> >
> > Then, at the spinand level, I'd define an array of templates:
> >
> > enum spinand_protocol {
> > 	SPINAND_1S_1S_1S,
> > 	SPINAND_2S_2S_2S,
> > 	SPINAND_4S_4S_4S,
> > 	SPINAND_8S_8S_8S,
> > 	SPINAND_8D_8D_8D,
> > 	SPINAND_NUM_PROTOCOLS,
> > };
> >
> > struct spinand_device {
> > 	...
> > 	enum spinand_protocol protocol;
> > 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];

It should probably be

	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];

with the spinand_op_templates struct defined as:

struct spinand_op_templates {
 	struct spi_mem_op read_cache;
 	struct spi_mem_op write_cache;
 	struct spi_mem_op update_cache;
 	struct spi_mem_op reset;
 	struct spi_mem_op get_feature;
 	struct spi_mem_op set_feature;
 	struct spi_mem_op write_enable;
 	struct spi_mem_op block_erase;
 	struct spi_mem_op page_load;
 	struct spi_mem_op program_execute;
};

so the NAND framework can populate these ops.

Or maybe even better, define an enum that contains all the ops:

enum spinand_op_id {
	SPI_NAND_OP_READ_CACHE,
	SPI_NAND_OP_WRITE_CACHE,
	SPI_NAND_OP_UPDATE_CACHE,
	SPI_NAND_OP_RESET,
...
	SPI_NAND_NUM_OPS,
};

struct spinand_device {
	...
 	enum spinand_protocol protocol;
 	struct spi_mem_op op_templates[SPINAND_NUM_PROTOCOLS][SPI_NAND_NUM_OPS];
	...
};

> >
> > This way, you can easily pick the right set of operations based
> > on the protocol/mode you're in:
> >
> > #define spinand_get_op_template(spinand, opname) \
> > 	((spinand)->op_templates[(spinand)->protocol]->opname)
> >
> > static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
> > {
> > 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
> > 	int ret;
> >
> > 	...
> > }  
> 
> I find a couple of issues with this  method,
> 
> 1. read_cache, write_cache, update_cache op templates don't fit well 
> with the other non-data ops, as
> these data ops are used to create a dirmap, and that can be done only 
> once at probe time. Hence, there
> is a different mechanism of selecting of data ops and non-data ops. 

Not sure I see why this is a problem. You can populate data-ops for all
modes, and pick the one that provides the best perfs when you create
the dirmap (which should really be at the end of the probe, if it's not
already).

> Hence, this division in the op templates
> struct as data_ops and ctrl_ops is required. Currently, the core only 
> supports using a single protocol for
> data ops, chosen at the time of probing.

Again, I don't see why you need to differentiate the control and data
ops when populating this table. Those are just operations the NAND
supports, and the data operations is just a subset.

> 
> 2. If we use this single op_templates struct, I can't think of any good 
> way to initialize these in the
> manufacturers driver (winbond.c), refer to 17th patch in this series. 
> Could you please suggest a macro
> implementation also for winbond.c with the suggested op_templates struct.

First replace the op_variants field by something more generic:

struct spinand_info {
...
	const struct spinand_op_variants **ops_variants;
...
};

#define SPINAND_OP_VARIANTS(_id, ...) \
	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }

#define SPINAND_OPS_VARIANTS(name, ...)
	const struct spinand_op_variants name[]{
		__VA_ARGS__,
	};

#define SPINAND_INFO_OPS_VARIANTS(defs)
	.ops_variants = defs

...

static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
		SPINAND_OP_VARIANTS(READ_CACHE,
			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
			...)),
		SPINAND_OP_VARIANTS(WRITE_CACHE,
			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
		...
		SPINAND_OP_VARIANTS(RESET,
			SPINAND_RESET_OP_OCTAL_DTR,
			SPINAND_RESET_OP,
		...
		);
...


	SPINAND_INFO("W35N01JW",
		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
		     NAND_ECCREQ(1, 512),
		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
		     SPINAND_INFO_OPS_VARIANTS(&w35n01jw_ops_variants)),

You also need to adjust spinand_match_and_init() to account for this
new layout and put each template op in the right subset based on
op.cmd.width and op.cmd.dtr.

Regards,

Boris

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-02-15 17:37         ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-02-15 17:37 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Apurva,

On Tue, 15 Feb 2022 21:03:52 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> Hi Boris,
> 
> On 03/01/22 15:31, Boris Brezillon wrote:
> > On Sat, 1 Jan 2022 13:12:38 +0530
> > Apurva Nandan <a-nandan@ti.com> wrote:
> >  
> >> 'ctrl_ops' are op templates for non-page read/write operations,
> >> which are: reset, get_feature, set_feature, write_enable, block_erase,
> >> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
> >> op templates for each of this op, as well as enum spinand_protocol
> >> denoting protocol of all these ops.
> >>
> >> We require these new op templates because of deviation in standard
> >> SPINAND ops by manufacturers and also due to changes when there is a
> >> change in SPI protocol/mode. This prevents the core from live-patching
> >> and vendor-specific adjustments in ops.
> >>
> >> Define 'ctrl_ops', add macros to initialize it and add it in
> >> spinand_device.
> >>
> >> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> >> ---
> >>   include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
> >>   1 file changed, 33 insertions(+)
> >>
> >> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> >> index 439d8ce40e1d..e5df6220ec1e 100644
> >> --- a/include/linux/mtd/spinand.h
> >> +++ b/include/linux/mtd/spinand.h
> >> @@ -356,6 +356,35 @@ struct spinand_op_variants {
> >>   			sizeof(struct spi_mem_op),			\
> >>   	}
> >>   
> >> +struct spinand_ctrl_ops {
> >> +	const struct {
> >> +		struct spi_mem_op reset;
> >> +		struct spi_mem_op get_feature;
> >> +		struct spi_mem_op set_feature;
> >> +		struct spi_mem_op write_enable;
> >> +		struct spi_mem_op block_erase;
> >> +		struct spi_mem_op page_read;
> >> +		struct spi_mem_op program_execute;
> >> +	} ops;
> >> +	const enum spinand_protocol protocol;  
> > Do you really need that protocol field?
> >  
> >> +};
> >> +
> >> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
> >> +			 __write_enable, __block_erase, __page_read,		\
> >> +			 __program_execute)					\
> >> +	{									\
> >> +		.ops = {							\
> >> +			.reset = __reset,					\
> >> +			.get_feature = __get_feature,				\
> >> +			.set_feature = __set_feature,				\
> >> +			.write_enable = __write_enable,				\
> >> +			.block_erase = __block_erase,				\
> >> +			.page_read = __page_read,				\
> >> +			.program_execute = __program_execute,			\
> >> +		},								\
> >> +		.protocol = __protocol,						\
> >> +	}
> >> +
> >>   /**
> >>    * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
> >>    *		      chip
> >> @@ -468,6 +497,8 @@ struct spinand_dirmap {
> >>    * @data_ops.read_cache: read cache op template
> >>    * @data_ops.write_cache: write cache op template
> >>    * @data_ops.update_cache: update cache op template
> >> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
> >> + *	      non page-read/write ops.
> >>    * @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
> >> @@ -498,6 +529,8 @@ struct spinand_device {
> >>   		const struct spi_mem_op *update_cache;
> >>   	} data_ops;
> >>   
> >> +	const struct spinand_ctrl_ops *ctrl_ops;
> >> +  
> > Okay, I had something slightly different in mind. First, I'd put all
> > templates in a struct:
> >
> > struct spinand_op_templates {
> > 	const struct spi_mem_op *read_cache;
> > 	const struct spi_mem_op *write_cache;
> > 	const struct spi_mem_op *update_cache;
> > 	const struct spi_mem_op *reset;
> > 	const struct spi_mem_op *get_feature;
> > 	const struct spi_mem_op *set_feature;
> > 	const struct spi_mem_op *write_enable;
> > 	const struct spi_mem_op *block_erase;
> > 	const struct spi_mem_op *page_load;
> > 	const struct spi_mem_op *program_execute;
> > };
> >
> > Then, at the spinand level, I'd define an array of templates:
> >
> > enum spinand_protocol {
> > 	SPINAND_1S_1S_1S,
> > 	SPINAND_2S_2S_2S,
> > 	SPINAND_4S_4S_4S,
> > 	SPINAND_8S_8S_8S,
> > 	SPINAND_8D_8D_8D,
> > 	SPINAND_NUM_PROTOCOLS,
> > };
> >
> > struct spinand_device {
> > 	...
> > 	enum spinand_protocol protocol;
> > 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];

It should probably be

	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];

with the spinand_op_templates struct defined as:

struct spinand_op_templates {
 	struct spi_mem_op read_cache;
 	struct spi_mem_op write_cache;
 	struct spi_mem_op update_cache;
 	struct spi_mem_op reset;
 	struct spi_mem_op get_feature;
 	struct spi_mem_op set_feature;
 	struct spi_mem_op write_enable;
 	struct spi_mem_op block_erase;
 	struct spi_mem_op page_load;
 	struct spi_mem_op program_execute;
};

so the NAND framework can populate these ops.

Or maybe even better, define an enum that contains all the ops:

enum spinand_op_id {
	SPI_NAND_OP_READ_CACHE,
	SPI_NAND_OP_WRITE_CACHE,
	SPI_NAND_OP_UPDATE_CACHE,
	SPI_NAND_OP_RESET,
...
	SPI_NAND_NUM_OPS,
};

struct spinand_device {
	...
 	enum spinand_protocol protocol;
 	struct spi_mem_op op_templates[SPINAND_NUM_PROTOCOLS][SPI_NAND_NUM_OPS];
	...
};

> >
> > This way, you can easily pick the right set of operations based
> > on the protocol/mode you're in:
> >
> > #define spinand_get_op_template(spinand, opname) \
> > 	((spinand)->op_templates[(spinand)->protocol]->opname)
> >
> > static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
> > {
> > 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
> > 	int ret;
> >
> > 	...
> > }  
> 
> I find a couple of issues with this  method,
> 
> 1. read_cache, write_cache, update_cache op templates don't fit well 
> with the other non-data ops, as
> these data ops are used to create a dirmap, and that can be done only 
> once at probe time. Hence, there
> is a different mechanism of selecting of data ops and non-data ops. 

Not sure I see why this is a problem. You can populate data-ops for all
modes, and pick the one that provides the best perfs when you create
the dirmap (which should really be at the end of the probe, if it's not
already).

> Hence, this division in the op templates
> struct as data_ops and ctrl_ops is required. Currently, the core only 
> supports using a single protocol for
> data ops, chosen at the time of probing.

Again, I don't see why you need to differentiate the control and data
ops when populating this table. Those are just operations the NAND
supports, and the data operations is just a subset.

> 
> 2. If we use this single op_templates struct, I can't think of any good 
> way to initialize these in the
> manufacturers driver (winbond.c), refer to 17th patch in this series. 
> Could you please suggest a macro
> implementation also for winbond.c with the suggested op_templates struct.

First replace the op_variants field by something more generic:

struct spinand_info {
...
	const struct spinand_op_variants **ops_variants;
...
};

#define SPINAND_OP_VARIANTS(_id, ...) \
	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }

#define SPINAND_OPS_VARIANTS(name, ...)
	const struct spinand_op_variants name[]{
		__VA_ARGS__,
	};

#define SPINAND_INFO_OPS_VARIANTS(defs)
	.ops_variants = defs

...

static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
		SPINAND_OP_VARIANTS(READ_CACHE,
			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
			...)),
		SPINAND_OP_VARIANTS(WRITE_CACHE,
			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
		...
		SPINAND_OP_VARIANTS(RESET,
			SPINAND_RESET_OP_OCTAL_DTR,
			SPINAND_RESET_OP,
		...
		);
...


	SPINAND_INFO("W35N01JW",
		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
		     NAND_ECCREQ(1, 512),
		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
		     SPINAND_INFO_OPS_VARIANTS(&w35n01jw_ops_variants)),

You also need to adjust spinand_match_and_init() to account for this
new layout and put each template op in the right subset based on
op.cmd.width and op.cmd.dtr.

Regards,

Boris

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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-02-15 17:37         ` Boris Brezillon
@ 2022-03-02 15:30           ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-03-02 15:30 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Boris,

On 15/02/22 23:07, Boris Brezillon wrote:
> Hi Apurva,
>
> On Tue, 15 Feb 2022 21:03:52 +0530
> Apurva Nandan<a-nandan@ti.com>  wrote:
>
>> Hi Boris,
>>
>> On 03/01/22 15:31, Boris Brezillon wrote:
>>> On Sat, 1 Jan 2022 13:12:38 +0530
>>> Apurva Nandan<a-nandan@ti.com>  wrote:
>>>   
>>>> 'ctrl_ops' are op templates for non-page read/write operations,
>>>> which are: reset, get_feature, set_feature, write_enable, block_erase,
>>>> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
>>>> op templates for each of this op, as well as enum spinand_protocol
>>>> denoting protocol of all these ops.
>>>>
>>>> We require these new op templates because of deviation in standard
>>>> SPINAND ops by manufacturers and also due to changes when there is a
>>>> change in SPI protocol/mode. This prevents the core from live-patching
>>>> and vendor-specific adjustments in ops.
>>>>
>>>> Define 'ctrl_ops', add macros to initialize it and add it in
>>>> spinand_device.
>>>>
>>>> Signed-off-by: Apurva Nandan<a-nandan@ti.com>
>>>> ---
>>>>    include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>>>>    1 file changed, 33 insertions(+)
>>>>
>>>> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
>>>> index 439d8ce40e1d..e5df6220ec1e 100644
>>>> --- a/include/linux/mtd/spinand.h
>>>> +++ b/include/linux/mtd/spinand.h
>>>> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>>>>    			sizeof(struct spi_mem_op),			\
>>>>    	}
>>>>    
>>>> +struct spinand_ctrl_ops {
>>>> +	const struct {
>>>> +		struct spi_mem_op reset;
>>>> +		struct spi_mem_op get_feature;
>>>> +		struct spi_mem_op set_feature;
>>>> +		struct spi_mem_op write_enable;
>>>> +		struct spi_mem_op block_erase;
>>>> +		struct spi_mem_op page_read;
>>>> +		struct spi_mem_op program_execute;
>>>> +	} ops;
>>>> +	const enum spinand_protocol protocol;
>>> Do you really need that protocol field?
>>>   
>>>> +};
>>>> +
>>>> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
>>>> +			 __write_enable, __block_erase, __page_read,		\
>>>> +			 __program_execute)					\
>>>> +	{									\
>>>> +		.ops = {							\
>>>> +			.reset = __reset,					\
>>>> +			.get_feature = __get_feature,				\
>>>> +			.set_feature = __set_feature,				\
>>>> +			.write_enable = __write_enable,				\
>>>> +			.block_erase = __block_erase,				\
>>>> +			.page_read = __page_read,				\
>>>> +			.program_execute = __program_execute,			\
>>>> +		},								\
>>>> +		.protocol = __protocol,						\
>>>> +	}
>>>> +
>>>>    /**
>>>>     * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>>>>     *		      chip
>>>> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>>>>     * @data_ops.read_cache: read cache op template
>>>>     * @data_ops.write_cache: write cache op template
>>>>     * @data_ops.update_cache: update cache op template
>>>> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
>>>> + *	      non page-read/write ops.
>>>>     * @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
>>>> @@ -498,6 +529,8 @@ struct spinand_device {
>>>>    		const struct spi_mem_op *update_cache;
>>>>    	} data_ops;
>>>>    
>>>> +	const struct spinand_ctrl_ops *ctrl_ops;
>>>> +
>>> Okay, I had something slightly different in mind. First, I'd put all
>>> templates in a struct:
>>>
>>> struct spinand_op_templates {
>>> 	const struct spi_mem_op *read_cache;
>>> 	const struct spi_mem_op *write_cache;
>>> 	const struct spi_mem_op *update_cache;
>>> 	const struct spi_mem_op *reset;
>>> 	const struct spi_mem_op *get_feature;
>>> 	const struct spi_mem_op *set_feature;
>>> 	const struct spi_mem_op *write_enable;
>>> 	const struct spi_mem_op *block_erase;
>>> 	const struct spi_mem_op *page_load;
>>> 	const struct spi_mem_op *program_execute;
>>> };
>>>
>>> Then, at the spinand level, I'd define an array of templates:
>>>
>>> enum spinand_protocol {
>>> 	SPINAND_1S_1S_1S,
>>> 	SPINAND_2S_2S_2S,
>>> 	SPINAND_4S_4S_4S,
>>> 	SPINAND_8S_8S_8S,
>>> 	SPINAND_8D_8D_8D,
>>> 	SPINAND_NUM_PROTOCOLS,
>>> };
>>>
>>> struct spinand_device {
>>> 	...
>>> 	enum spinand_protocol protocol;
>>> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
> It should probably be
>
> 	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];
>
> with the spinand_op_templates struct defined as:
>
> struct spinand_op_templates {
>   	struct spi_mem_op read_cache;
>   	struct spi_mem_op write_cache;
>   	struct spi_mem_op update_cache;
>   	struct spi_mem_op reset;
>   	struct spi_mem_op get_feature;
>   	struct spi_mem_op set_feature;
>   	struct spi_mem_op write_enable;
>   	struct spi_mem_op block_erase;
>   	struct spi_mem_op page_load;
>   	struct spi_mem_op program_execute;
> };
>
> so the NAND framework can populate these ops.
>
> Or maybe even better, define an enum that contains all the ops:
>
> enum spinand_op_id {
> 	SPI_NAND_OP_READ_CACHE,
> 	SPI_NAND_OP_WRITE_CACHE,
> 	SPI_NAND_OP_UPDATE_CACHE,
> 	SPI_NAND_OP_RESET,
> ...
> 	SPI_NAND_NUM_OPS,
> };
>
> struct spinand_device {
> 	...
>   	enum spinand_protocol protocol;
>   	struct spi_mem_op op_templates[SPINAND_NUM_PROTOCOLS][SPI_NAND_NUM_OPS];
> 	...
> };
>
>>> This way, you can easily pick the right set of operations based
>>> on the protocol/mode you're in:
>>>
>>> #define spinand_get_op_template(spinand, opname) \
>>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>>>
>>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
>>> {
>>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
>>> 	int ret;
>>>
>>> 	...
>>> }
>> I find a couple of issues with this  method,
>>
>> 1. read_cache, write_cache, update_cache op templates don't fit well
>> with the other non-data ops, as
>> these data ops are used to create a dirmap, and that can be done only
>> once at probe time. Hence, there
>> is a different mechanism of selecting of data ops and non-data ops.
> Not sure I see why this is a problem. You can populate data-ops for all
> modes, and pick the one that provides the best perfs when you create
> the dirmap (which should really be at the end of the probe, if it's not
> already).
>
>> Hence, this division in the op templates
>> struct as data_ops and ctrl_ops is required. Currently, the core only
>> supports using a single protocol for
>> data ops, chosen at the time of probing.
> Again, I don't see why you need to differentiate the control and data
> ops when populating this table. Those are just operations the NAND
> supports, and the data operations is just a subset.
>
>> 2. If we use this single op_templates struct, I can't think of any good
>> way to initialize these in the
>> manufacturers driver (winbond.c), refer to 17th patch in this series.
>> Could you please suggest a macro
>> implementation also for winbond.c with the suggested op_templates struct.
> First replace the op_variants field by something more generic:
>
> struct spinand_info {
> ...
> 	const struct spinand_op_variants **ops_variants;
> ...
> };
>
> #define SPINAND_OP_VARIANTS(_id, ...) \
> 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
>
> #define SPINAND_OPS_VARIANTS(name, ...)
> 	const struct spinand_op_variants name[]{
> 		__VA_ARGS__,
> 	};
>
> #define SPINAND_INFO_OPS_VARIANTS(defs)
> 	.ops_variants = defs
>
> ...
>
> static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
> 		SPINAND_OP_VARIANTS(READ_CACHE,
> 			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
> 			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> 			...)),
> 		SPINAND_OP_VARIANTS(WRITE_CACHE,
> 			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
> 			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
> 		...
> 		SPINAND_OP_VARIANTS(RESET,
> 			SPINAND_RESET_OP_OCTAL_DTR,
> 			SPINAND_RESET_OP,
> 		...
> 		);
> ...

I find a issue with this implementation, please give corrective suggestions:

In type of op variant listing, there is no way to specify the protocol 
of the op in the variants struct itself.
     - This will lead to filtering/sorting/searching of ops for finding 
the protocols in the spinand core
     while in spinand_match_and_init(), which I don't feel is a good way 
for protocol based op categorization.
     - This would also lead to complexities in cases of mixed mode 
operations.
     - In addition, we can't simply choose the first supported protocol 
in each op id, as some ops have
     intendependency of protocol with other ops. This is because 
non-data ops (like reset, block erase..)
     cannot be in different protocols at same time, so it would make 
sense to have some form of protocol
     based arrangement while listing them.

> 	SPINAND_INFO("W35N01JW",
> 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
> 		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
> 		     NAND_ECCREQ(1, 512),
> 		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
> 		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
> 		     SPINAND_INFO_OPS_VARIANTS(&w35n01jw_ops_variants)),
>
> You also need to adjust spinand_match_and_init() to account for this
> new layout and put each template op in the right subset based on
> op.cmd.width and op.cmd.dtr.
>
> Regards,
>
> Boris

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-03-02 15:30           ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-03-02 15:30 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Boris,

On 15/02/22 23:07, Boris Brezillon wrote:
> Hi Apurva,
>
> On Tue, 15 Feb 2022 21:03:52 +0530
> Apurva Nandan<a-nandan@ti.com>  wrote:
>
>> Hi Boris,
>>
>> On 03/01/22 15:31, Boris Brezillon wrote:
>>> On Sat, 1 Jan 2022 13:12:38 +0530
>>> Apurva Nandan<a-nandan@ti.com>  wrote:
>>>   
>>>> 'ctrl_ops' are op templates for non-page read/write operations,
>>>> which are: reset, get_feature, set_feature, write_enable, block_erase,
>>>> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
>>>> op templates for each of this op, as well as enum spinand_protocol
>>>> denoting protocol of all these ops.
>>>>
>>>> We require these new op templates because of deviation in standard
>>>> SPINAND ops by manufacturers and also due to changes when there is a
>>>> change in SPI protocol/mode. This prevents the core from live-patching
>>>> and vendor-specific adjustments in ops.
>>>>
>>>> Define 'ctrl_ops', add macros to initialize it and add it in
>>>> spinand_device.
>>>>
>>>> Signed-off-by: Apurva Nandan<a-nandan@ti.com>
>>>> ---
>>>>    include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>>>>    1 file changed, 33 insertions(+)
>>>>
>>>> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
>>>> index 439d8ce40e1d..e5df6220ec1e 100644
>>>> --- a/include/linux/mtd/spinand.h
>>>> +++ b/include/linux/mtd/spinand.h
>>>> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>>>>    			sizeof(struct spi_mem_op),			\
>>>>    	}
>>>>    
>>>> +struct spinand_ctrl_ops {
>>>> +	const struct {
>>>> +		struct spi_mem_op reset;
>>>> +		struct spi_mem_op get_feature;
>>>> +		struct spi_mem_op set_feature;
>>>> +		struct spi_mem_op write_enable;
>>>> +		struct spi_mem_op block_erase;
>>>> +		struct spi_mem_op page_read;
>>>> +		struct spi_mem_op program_execute;
>>>> +	} ops;
>>>> +	const enum spinand_protocol protocol;
>>> Do you really need that protocol field?
>>>   
>>>> +};
>>>> +
>>>> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
>>>> +			 __write_enable, __block_erase, __page_read,		\
>>>> +			 __program_execute)					\
>>>> +	{									\
>>>> +		.ops = {							\
>>>> +			.reset = __reset,					\
>>>> +			.get_feature = __get_feature,				\
>>>> +			.set_feature = __set_feature,				\
>>>> +			.write_enable = __write_enable,				\
>>>> +			.block_erase = __block_erase,				\
>>>> +			.page_read = __page_read,				\
>>>> +			.program_execute = __program_execute,			\
>>>> +		},								\
>>>> +		.protocol = __protocol,						\
>>>> +	}
>>>> +
>>>>    /**
>>>>     * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>>>>     *		      chip
>>>> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>>>>     * @data_ops.read_cache: read cache op template
>>>>     * @data_ops.write_cache: write cache op template
>>>>     * @data_ops.update_cache: update cache op template
>>>> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
>>>> + *	      non page-read/write ops.
>>>>     * @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
>>>> @@ -498,6 +529,8 @@ struct spinand_device {
>>>>    		const struct spi_mem_op *update_cache;
>>>>    	} data_ops;
>>>>    
>>>> +	const struct spinand_ctrl_ops *ctrl_ops;
>>>> +
>>> Okay, I had something slightly different in mind. First, I'd put all
>>> templates in a struct:
>>>
>>> struct spinand_op_templates {
>>> 	const struct spi_mem_op *read_cache;
>>> 	const struct spi_mem_op *write_cache;
>>> 	const struct spi_mem_op *update_cache;
>>> 	const struct spi_mem_op *reset;
>>> 	const struct spi_mem_op *get_feature;
>>> 	const struct spi_mem_op *set_feature;
>>> 	const struct spi_mem_op *write_enable;
>>> 	const struct spi_mem_op *block_erase;
>>> 	const struct spi_mem_op *page_load;
>>> 	const struct spi_mem_op *program_execute;
>>> };
>>>
>>> Then, at the spinand level, I'd define an array of templates:
>>>
>>> enum spinand_protocol {
>>> 	SPINAND_1S_1S_1S,
>>> 	SPINAND_2S_2S_2S,
>>> 	SPINAND_4S_4S_4S,
>>> 	SPINAND_8S_8S_8S,
>>> 	SPINAND_8D_8D_8D,
>>> 	SPINAND_NUM_PROTOCOLS,
>>> };
>>>
>>> struct spinand_device {
>>> 	...
>>> 	enum spinand_protocol protocol;
>>> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
> It should probably be
>
> 	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];
>
> with the spinand_op_templates struct defined as:
>
> struct spinand_op_templates {
>   	struct spi_mem_op read_cache;
>   	struct spi_mem_op write_cache;
>   	struct spi_mem_op update_cache;
>   	struct spi_mem_op reset;
>   	struct spi_mem_op get_feature;
>   	struct spi_mem_op set_feature;
>   	struct spi_mem_op write_enable;
>   	struct spi_mem_op block_erase;
>   	struct spi_mem_op page_load;
>   	struct spi_mem_op program_execute;
> };
>
> so the NAND framework can populate these ops.
>
> Or maybe even better, define an enum that contains all the ops:
>
> enum spinand_op_id {
> 	SPI_NAND_OP_READ_CACHE,
> 	SPI_NAND_OP_WRITE_CACHE,
> 	SPI_NAND_OP_UPDATE_CACHE,
> 	SPI_NAND_OP_RESET,
> ...
> 	SPI_NAND_NUM_OPS,
> };
>
> struct spinand_device {
> 	...
>   	enum spinand_protocol protocol;
>   	struct spi_mem_op op_templates[SPINAND_NUM_PROTOCOLS][SPI_NAND_NUM_OPS];
> 	...
> };
>
>>> This way, you can easily pick the right set of operations based
>>> on the protocol/mode you're in:
>>>
>>> #define spinand_get_op_template(spinand, opname) \
>>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>>>
>>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
>>> {
>>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
>>> 	int ret;
>>>
>>> 	...
>>> }
>> I find a couple of issues with this  method,
>>
>> 1. read_cache, write_cache, update_cache op templates don't fit well
>> with the other non-data ops, as
>> these data ops are used to create a dirmap, and that can be done only
>> once at probe time. Hence, there
>> is a different mechanism of selecting of data ops and non-data ops.
> Not sure I see why this is a problem. You can populate data-ops for all
> modes, and pick the one that provides the best perfs when you create
> the dirmap (which should really be at the end of the probe, if it's not
> already).
>
>> Hence, this division in the op templates
>> struct as data_ops and ctrl_ops is required. Currently, the core only
>> supports using a single protocol for
>> data ops, chosen at the time of probing.
> Again, I don't see why you need to differentiate the control and data
> ops when populating this table. Those are just operations the NAND
> supports, and the data operations is just a subset.
>
>> 2. If we use this single op_templates struct, I can't think of any good
>> way to initialize these in the
>> manufacturers driver (winbond.c), refer to 17th patch in this series.
>> Could you please suggest a macro
>> implementation also for winbond.c with the suggested op_templates struct.
> First replace the op_variants field by something more generic:
>
> struct spinand_info {
> ...
> 	const struct spinand_op_variants **ops_variants;
> ...
> };
>
> #define SPINAND_OP_VARIANTS(_id, ...) \
> 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
>
> #define SPINAND_OPS_VARIANTS(name, ...)
> 	const struct spinand_op_variants name[]{
> 		__VA_ARGS__,
> 	};
>
> #define SPINAND_INFO_OPS_VARIANTS(defs)
> 	.ops_variants = defs
>
> ...
>
> static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
> 		SPINAND_OP_VARIANTS(READ_CACHE,
> 			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
> 			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> 			...)),
> 		SPINAND_OP_VARIANTS(WRITE_CACHE,
> 			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
> 			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
> 		...
> 		SPINAND_OP_VARIANTS(RESET,
> 			SPINAND_RESET_OP_OCTAL_DTR,
> 			SPINAND_RESET_OP,
> 		...
> 		);
> ...

I find a issue with this implementation, please give corrective suggestions:

In type of op variant listing, there is no way to specify the protocol 
of the op in the variants struct itself.
     - This will lead to filtering/sorting/searching of ops for finding 
the protocols in the spinand core
     while in spinand_match_and_init(), which I don't feel is a good way 
for protocol based op categorization.
     - This would also lead to complexities in cases of mixed mode 
operations.
     - In addition, we can't simply choose the first supported protocol 
in each op id, as some ops have
     intendependency of protocol with other ops. This is because 
non-data ops (like reset, block erase..)
     cannot be in different protocols at same time, so it would make 
sense to have some form of protocol
     based arrangement while listing them.

> 	SPINAND_INFO("W35N01JW",
> 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
> 		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
> 		     NAND_ECCREQ(1, 512),
> 		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
> 		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
> 		     SPINAND_INFO_OPS_VARIANTS(&w35n01jw_ops_variants)),
>
> You also need to adjust spinand_match_and_init() to account for this
> new layout and put each template op in the right subset based on
> op.cmd.width and op.cmd.dtr.
>
> Regards,
>
> Boris

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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-03-02 15:30           ` Apurva Nandan
@ 2022-03-02 20:05             ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-03-02 20:05 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Wed, 2 Mar 2022 21:00:55 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> >> 1. read_cache, write_cache, update_cache op templates don't fit well
> >> with the other non-data ops, as
> >> these data ops are used to create a dirmap, and that can be done only
> >> once at probe time. Hence, there
> >> is a different mechanism of selecting of data ops and non-data ops.  
> > Not sure I see why this is a problem. You can populate data-ops for all
> > modes, and pick the one that provides the best perfs when you create
> > the dirmap (which should really be at the end of the probe, if it's not
> > already).
> >  
> >> Hence, this division in the op templates
> >> struct as data_ops and ctrl_ops is required. Currently, the core only
> >> supports using a single protocol for
> >> data ops, chosen at the time of probing.  
> > Again, I don't see why you need to differentiate the control and data
> > ops when populating this table. Those are just operations the NAND
> > supports, and the data operations is just a subset.
> >  
> >> 2. If we use this single op_templates struct, I can't think of any good
> >> way to initialize these in the
> >> manufacturers driver (winbond.c), refer to 17th patch in this series.
> >> Could you please suggest a macro
> >> implementation also for winbond.c with the suggested op_templates struct.  
> > First replace the op_variants field by something more generic:
> >
> > struct spinand_info {
> > ...
> > 	const struct spinand_op_variants **ops_variants;
> > ...
> > };
> >
> > #define SPINAND_OP_VARIANTS(_id, ...) \
> > 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
> >
> > #define SPINAND_OPS_VARIANTS(name, ...)
> > 	const struct spinand_op_variants name[]{
> > 		__VA_ARGS__,
> > 	};
> >
> > #define SPINAND_INFO_OPS_VARIANTS(defs)
> > 	.ops_variants = defs
> >
> > ...
> >
> > static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
> > 		SPINAND_OP_VARIANTS(READ_CACHE,
> > 			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
> > 			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> > 			...)),
> > 		SPINAND_OP_VARIANTS(WRITE_CACHE,
> > 			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
> > 			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
> > 		...
> > 		SPINAND_OP_VARIANTS(RESET,
> > 			SPINAND_RESET_OP_OCTAL_DTR,
> > 			SPINAND_RESET_OP,
> > 		...
> > 		);
> > ...  
> 
> I find a issue with this implementation, please give corrective suggestions:
> 
> In type of op variant listing, there is no way to specify the protocol 
> of the op in the variants struct itself.
>      - This will lead to filtering/sorting/searching of ops for finding 
> the protocols in the spinand core
>      while in spinand_match_and_init(), which I don't feel is a good way 
> for protocol based op categorization.

You'll have to go over all those operations to check which ones are
supported by the controller anyway. And it's not like the
classification is complicated since the cmd bus-width+DTR seems to be
the discriminant, and it's stored directly in the operation template.

>      - This would also lead to complexities in cases of mixed mode 
> operations.

Not sure what you mean by mixed mode. Are you referring to something
like 1S-8D-8D? IIUC, all we care about is the mode used for the cmd
cycle. I don't think there are commands to switch between stateless
(1S-x[S,D]-x[S,D]) modes (assuming 1S-xD-xD is a thing).

>      - In addition, we can't simply choose the first supported protocol 
> in each op id, as some ops have
>      intendependency of protocol with other ops. This is because 
> non-data ops (like reset, block erase..)
>      cannot be in different protocols at same time, so it would make 
> sense to have some form of protocol
>      based arrangement while listing them.

I'm not suggesting to choose the first supported operation and use it
unconditionally, but instead choose one operation per stateful mode
(1S, 2S, 4S, ..., 8D) and use the appropriate template depending on
the mode the flash is currently in.


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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-03-02 20:05             ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-03-02 20:05 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Wed, 2 Mar 2022 21:00:55 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> >> 1. read_cache, write_cache, update_cache op templates don't fit well
> >> with the other non-data ops, as
> >> these data ops are used to create a dirmap, and that can be done only
> >> once at probe time. Hence, there
> >> is a different mechanism of selecting of data ops and non-data ops.  
> > Not sure I see why this is a problem. You can populate data-ops for all
> > modes, and pick the one that provides the best perfs when you create
> > the dirmap (which should really be at the end of the probe, if it's not
> > already).
> >  
> >> Hence, this division in the op templates
> >> struct as data_ops and ctrl_ops is required. Currently, the core only
> >> supports using a single protocol for
> >> data ops, chosen at the time of probing.  
> > Again, I don't see why you need to differentiate the control and data
> > ops when populating this table. Those are just operations the NAND
> > supports, and the data operations is just a subset.
> >  
> >> 2. If we use this single op_templates struct, I can't think of any good
> >> way to initialize these in the
> >> manufacturers driver (winbond.c), refer to 17th patch in this series.
> >> Could you please suggest a macro
> >> implementation also for winbond.c with the suggested op_templates struct.  
> > First replace the op_variants field by something more generic:
> >
> > struct spinand_info {
> > ...
> > 	const struct spinand_op_variants **ops_variants;
> > ...
> > };
> >
> > #define SPINAND_OP_VARIANTS(_id, ...) \
> > 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
> >
> > #define SPINAND_OPS_VARIANTS(name, ...)
> > 	const struct spinand_op_variants name[]{
> > 		__VA_ARGS__,
> > 	};
> >
> > #define SPINAND_INFO_OPS_VARIANTS(defs)
> > 	.ops_variants = defs
> >
> > ...
> >
> > static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
> > 		SPINAND_OP_VARIANTS(READ_CACHE,
> > 			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
> > 			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> > 			...)),
> > 		SPINAND_OP_VARIANTS(WRITE_CACHE,
> > 			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
> > 			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
> > 		...
> > 		SPINAND_OP_VARIANTS(RESET,
> > 			SPINAND_RESET_OP_OCTAL_DTR,
> > 			SPINAND_RESET_OP,
> > 		...
> > 		);
> > ...  
> 
> I find a issue with this implementation, please give corrective suggestions:
> 
> In type of op variant listing, there is no way to specify the protocol 
> of the op in the variants struct itself.
>      - This will lead to filtering/sorting/searching of ops for finding 
> the protocols in the spinand core
>      while in spinand_match_and_init(), which I don't feel is a good way 
> for protocol based op categorization.

You'll have to go over all those operations to check which ones are
supported by the controller anyway. And it's not like the
classification is complicated since the cmd bus-width+DTR seems to be
the discriminant, and it's stored directly in the operation template.

>      - This would also lead to complexities in cases of mixed mode 
> operations.

Not sure what you mean by mixed mode. Are you referring to something
like 1S-8D-8D? IIUC, all we care about is the mode used for the cmd
cycle. I don't think there are commands to switch between stateless
(1S-x[S,D]-x[S,D]) modes (assuming 1S-xD-xD is a thing).

>      - In addition, we can't simply choose the first supported protocol 
> in each op id, as some ops have
>      intendependency of protocol with other ops. This is because 
> non-data ops (like reset, block erase..)
>      cannot be in different protocols at same time, so it would make 
> sense to have some form of protocol
>      based arrangement while listing them.

I'm not suggesting to choose the first supported operation and use it
unconditionally, but instead choose one operation per stateful mode
(1S, 2S, 4S, ..., 8D) and use the appropriate template depending on
the mode the flash is currently in.


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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-02-15 17:37         ` Boris Brezillon
@ 2022-03-10  7:57           ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-03-10  7:57 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Boris,

On 15/02/22 23:07, Boris Brezillon wrote:
> Hi Apurva,
>
> On Tue, 15 Feb 2022 21:03:52 +0530
> Apurva Nandan <a-nandan@ti.com> wrote:
>
>> Hi Boris,
>>
>> On 03/01/22 15:31, Boris Brezillon wrote:
>>> On Sat, 1 Jan 2022 13:12:38 +0530
>>> Apurva Nandan <a-nandan@ti.com> wrote:
>>>   
>>>> 'ctrl_ops' are op templates for non-page read/write operations,
>>>> which are: reset, get_feature, set_feature, write_enable, block_erase,
>>>> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
>>>> op templates for each of this op, as well as enum spinand_protocol
>>>> denoting protocol of all these ops.
>>>>
>>>> We require these new op templates because of deviation in standard
>>>> SPINAND ops by manufacturers and also due to changes when there is a
>>>> change in SPI protocol/mode. This prevents the core from live-patching
>>>> and vendor-specific adjustments in ops.
>>>>
>>>> Define 'ctrl_ops', add macros to initialize it and add it in
>>>> spinand_device.
>>>>
>>>> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
>>>> ---
>>>>    include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>>>>    1 file changed, 33 insertions(+)
>>>>
>>>> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
>>>> index 439d8ce40e1d..e5df6220ec1e 100644
>>>> --- a/include/linux/mtd/spinand.h
>>>> +++ b/include/linux/mtd/spinand.h
>>>> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>>>>    			sizeof(struct spi_mem_op),			\
>>>>    	}
>>>>    
>>>> +struct spinand_ctrl_ops {
>>>> +	const struct {
>>>> +		struct spi_mem_op reset;
>>>> +		struct spi_mem_op get_feature;
>>>> +		struct spi_mem_op set_feature;
>>>> +		struct spi_mem_op write_enable;
>>>> +		struct spi_mem_op block_erase;
>>>> +		struct spi_mem_op page_read;
>>>> +		struct spi_mem_op program_execute;
>>>> +	} ops;
>>>> +	const enum spinand_protocol protocol;
>>> Do you really need that protocol field?
>>>   
>>>> +};
>>>> +
>>>> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
>>>> +			 __write_enable, __block_erase, __page_read,		\
>>>> +			 __program_execute)					\
>>>> +	{									\
>>>> +		.ops = {							\
>>>> +			.reset = __reset,					\
>>>> +			.get_feature = __get_feature,				\
>>>> +			.set_feature = __set_feature,				\
>>>> +			.write_enable = __write_enable,				\
>>>> +			.block_erase = __block_erase,				\
>>>> +			.page_read = __page_read,				\
>>>> +			.program_execute = __program_execute,			\
>>>> +		},								\
>>>> +		.protocol = __protocol,						\
>>>> +	}
>>>> +
>>>>    /**
>>>>     * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>>>>     *		      chip
>>>> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>>>>     * @data_ops.read_cache: read cache op template
>>>>     * @data_ops.write_cache: write cache op template
>>>>     * @data_ops.update_cache: update cache op template
>>>> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
>>>> + *	      non page-read/write ops.
>>>>     * @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
>>>> @@ -498,6 +529,8 @@ struct spinand_device {
>>>>    		const struct spi_mem_op *update_cache;
>>>>    	} data_ops;
>>>>    
>>>> +	const struct spinand_ctrl_ops *ctrl_ops;
>>>> +
>>> Okay, I had something slightly different in mind. First, I'd put all
>>> templates in a struct:
>>>
>>> struct spinand_op_templates {
>>> 	const struct spi_mem_op *read_cache;
>>> 	const struct spi_mem_op *write_cache;
>>> 	const struct spi_mem_op *update_cache;
>>> 	const struct spi_mem_op *reset;
>>> 	const struct spi_mem_op *get_feature;
>>> 	const struct spi_mem_op *set_feature;
>>> 	const struct spi_mem_op *write_enable;
>>> 	const struct spi_mem_op *block_erase;
>>> 	const struct spi_mem_op *page_load;
>>> 	const struct spi_mem_op *program_execute;
>>> };
>>>
>>> Then, at the spinand level, I'd define an array of templates:
>>>
>>> enum spinand_protocol {
>>> 	SPINAND_1S_1S_1S,
>>> 	SPINAND_2S_2S_2S,
>>> 	SPINAND_4S_4S_4S,
>>> 	SPINAND_8S_8S_8S,
>>> 	SPINAND_8D_8D_8D,
>>> 	SPINAND_NUM_PROTOCOLS,
>>> };
>>>
>>> struct spinand_device {
>>> 	...
>>> 	enum spinand_protocol protocol;
>>> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
> It should probably be
>
> 	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];
>
> with the spinand_op_templates struct defined as:
>
> struct spinand_op_templates {
>   	struct spi_mem_op read_cache;
>   	struct spi_mem_op write_cache;
>   	struct spi_mem_op update_cache;
>   	struct spi_mem_op reset;
>   	struct spi_mem_op get_feature;
>   	struct spi_mem_op set_feature;
>   	struct spi_mem_op write_enable;
>   	struct spi_mem_op block_erase;
>   	struct spi_mem_op page_load;
>   	struct spi_mem_op program_execute;
> };
>
> so the NAND framework can populate these ops.
>
> Or maybe even better, define an enum that contains all the ops:
>
> enum spinand_op_id {
> 	SPI_NAND_OP_READ_CACHE,
> 	SPI_NAND_OP_WRITE_CACHE,
> 	SPI_NAND_OP_UPDATE_CACHE,
> 	SPI_NAND_OP_RESET,
> ...
> 	SPI_NAND_NUM_OPS,
> };
>
> struct spinand_device {
> 	...
>   	enum spinand_protocol protocol;
>   	struct spi_mem_op op_templates[SPINAND_NUM_PROTOCOLS][SPI_NAND_NUM_OPS];
> 	...
> };
>
>>> This way, you can easily pick the right set of operations based
>>> on the protocol/mode you're in:
>>>
>>> #define spinand_get_op_template(spinand, opname) \
>>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>>>
>>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
>>> {
>>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
>>> 	int ret;
>>>
>>> 	...
>>> }
>> I find a couple of issues with this  method,
>>
>> 1. read_cache, write_cache, update_cache op templates don't fit well
>> with the other non-data ops, as
>> these data ops are used to create a dirmap, and that can be done only
>> once at probe time. Hence, there
>> is a different mechanism of selecting of data ops and non-data ops.
> Not sure I see why this is a problem. You can populate data-ops for all
> modes, and pick the one that provides the best perfs when you create
> the dirmap (which should really be at the end of the probe, if it's not
> already).
>
>> Hence, this division in the op templates
>> struct as data_ops and ctrl_ops is required. Currently, the core only
>> supports using a single protocol for
>> data ops, chosen at the time of probing.
> Again, I don't see why you need to differentiate the control and data
> ops when populating this table. Those are just operations the NAND
> supports, and the data operations is just a subset.
>
>> 2. If we use this single op_templates struct, I can't think of any good
>> way to initialize these in the
>> manufacturers driver (winbond.c), refer to 17th patch in this series.
>> Could you please suggest a macro
>> implementation also for winbond.c with the suggested op_templates struct.
> First replace the op_variants field by something more generic:
>
> struct spinand_info {
> ...
> 	const struct spinand_op_variants **ops_variants;
> ...
> };
>
> #define SPINAND_OP_VARIANTS(_id, ...) \
> 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
>
> #define SPINAND_OPS_VARIANTS(name, ...)
> 	const struct spinand_op_variants name[]{
> 		__VA_ARGS__,
> 	};
>
> #define SPINAND_INFO_OPS_VARIANTS(defs)
> 	.ops_variants = defs

If we modify these macros, it would require other spinand vendor drivers 
to change (toshiba, micron, etc).
The older macros suit them well, should we go about changing them to 
this new macro (will require re-testing all of them),
or can we keep them unchanged and have new set of macros with different 
name (please give suggestion for it) for op variants.

>
> ...
>
> static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
> 		SPINAND_OP_VARIANTS(READ_CACHE,
> 			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
> 			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> 			...)),
> 		SPINAND_OP_VARIANTS(WRITE_CACHE,
> 			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
> 			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
> 		...
> 		SPINAND_OP_VARIANTS(RESET,
> 			SPINAND_RESET_OP_OCTAL_DTR,
> 			SPINAND_RESET_OP,
> 		...
> 		);
> ...
>
>
> 	SPINAND_INFO("W35N01JW",
> 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
> 		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
> 		     NAND_ECCREQ(1, 512),
> 		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
> 		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
> 		     SPINAND_INFO_OPS_VARIANTS(&w35n01jw_ops_variants)),
>
> You also need to adjust spinand_match_and_init() to account for this
> new layout and put each template op in the right subset based on
> op.cmd.width and op.cmd.dtr.
>
> Regards,
>
> Boris

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-03-10  7:57           ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-03-10  7:57 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

Hi Boris,

On 15/02/22 23:07, Boris Brezillon wrote:
> Hi Apurva,
>
> On Tue, 15 Feb 2022 21:03:52 +0530
> Apurva Nandan <a-nandan@ti.com> wrote:
>
>> Hi Boris,
>>
>> On 03/01/22 15:31, Boris Brezillon wrote:
>>> On Sat, 1 Jan 2022 13:12:38 +0530
>>> Apurva Nandan <a-nandan@ti.com> wrote:
>>>   
>>>> 'ctrl_ops' are op templates for non-page read/write operations,
>>>> which are: reset, get_feature, set_feature, write_enable, block_erase,
>>>> page_read and program_execute ops. The 'ctrl_ops' struct contains in it
>>>> op templates for each of this op, as well as enum spinand_protocol
>>>> denoting protocol of all these ops.
>>>>
>>>> We require these new op templates because of deviation in standard
>>>> SPINAND ops by manufacturers and also due to changes when there is a
>>>> change in SPI protocol/mode. This prevents the core from live-patching
>>>> and vendor-specific adjustments in ops.
>>>>
>>>> Define 'ctrl_ops', add macros to initialize it and add it in
>>>> spinand_device.
>>>>
>>>> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
>>>> ---
>>>>    include/linux/mtd/spinand.h | 33 +++++++++++++++++++++++++++++++++
>>>>    1 file changed, 33 insertions(+)
>>>>
>>>> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
>>>> index 439d8ce40e1d..e5df6220ec1e 100644
>>>> --- a/include/linux/mtd/spinand.h
>>>> +++ b/include/linux/mtd/spinand.h
>>>> @@ -356,6 +356,35 @@ struct spinand_op_variants {
>>>>    			sizeof(struct spi_mem_op),			\
>>>>    	}
>>>>    
>>>> +struct spinand_ctrl_ops {
>>>> +	const struct {
>>>> +		struct spi_mem_op reset;
>>>> +		struct spi_mem_op get_feature;
>>>> +		struct spi_mem_op set_feature;
>>>> +		struct spi_mem_op write_enable;
>>>> +		struct spi_mem_op block_erase;
>>>> +		struct spi_mem_op page_read;
>>>> +		struct spi_mem_op program_execute;
>>>> +	} ops;
>>>> +	const enum spinand_protocol protocol;
>>> Do you really need that protocol field?
>>>   
>>>> +};
>>>> +
>>>> +#define SPINAND_CTRL_OPS(__protocol, __reset, __get_feature, __set_feature,	\
>>>> +			 __write_enable, __block_erase, __page_read,		\
>>>> +			 __program_execute)					\
>>>> +	{									\
>>>> +		.ops = {							\
>>>> +			.reset = __reset,					\
>>>> +			.get_feature = __get_feature,				\
>>>> +			.set_feature = __set_feature,				\
>>>> +			.write_enable = __write_enable,				\
>>>> +			.block_erase = __block_erase,				\
>>>> +			.page_read = __page_read,				\
>>>> +			.program_execute = __program_execute,			\
>>>> +		},								\
>>>> +		.protocol = __protocol,						\
>>>> +	}
>>>> +
>>>>    /**
>>>>     * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
>>>>     *		      chip
>>>> @@ -468,6 +497,8 @@ struct spinand_dirmap {
>>>>     * @data_ops.read_cache: read cache op template
>>>>     * @data_ops.write_cache: write cache op template
>>>>     * @data_ops.update_cache: update cache op template
>>>> + * @ctrl_ops: various SPI mem op templates for handling the flash device, i.e.
>>>> + *	      non page-read/write ops.
>>>>     * @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
>>>> @@ -498,6 +529,8 @@ struct spinand_device {
>>>>    		const struct spi_mem_op *update_cache;
>>>>    	} data_ops;
>>>>    
>>>> +	const struct spinand_ctrl_ops *ctrl_ops;
>>>> +
>>> Okay, I had something slightly different in mind. First, I'd put all
>>> templates in a struct:
>>>
>>> struct spinand_op_templates {
>>> 	const struct spi_mem_op *read_cache;
>>> 	const struct spi_mem_op *write_cache;
>>> 	const struct spi_mem_op *update_cache;
>>> 	const struct spi_mem_op *reset;
>>> 	const struct spi_mem_op *get_feature;
>>> 	const struct spi_mem_op *set_feature;
>>> 	const struct spi_mem_op *write_enable;
>>> 	const struct spi_mem_op *block_erase;
>>> 	const struct spi_mem_op *page_load;
>>> 	const struct spi_mem_op *program_execute;
>>> };
>>>
>>> Then, at the spinand level, I'd define an array of templates:
>>>
>>> enum spinand_protocol {
>>> 	SPINAND_1S_1S_1S,
>>> 	SPINAND_2S_2S_2S,
>>> 	SPINAND_4S_4S_4S,
>>> 	SPINAND_8S_8S_8S,
>>> 	SPINAND_8D_8D_8D,
>>> 	SPINAND_NUM_PROTOCOLS,
>>> };
>>>
>>> struct spinand_device {
>>> 	...
>>> 	enum spinand_protocol protocol;
>>> 	const struct spinand_op_templates *op_templates[SPINAND_NUM_PROTOCOLS];
> It should probably be
>
> 	struct spinand_op_templates op_templates[SPINAND_NUM_PROTOCOLS];
>
> with the spinand_op_templates struct defined as:
>
> struct spinand_op_templates {
>   	struct spi_mem_op read_cache;
>   	struct spi_mem_op write_cache;
>   	struct spi_mem_op update_cache;
>   	struct spi_mem_op reset;
>   	struct spi_mem_op get_feature;
>   	struct spi_mem_op set_feature;
>   	struct spi_mem_op write_enable;
>   	struct spi_mem_op block_erase;
>   	struct spi_mem_op page_load;
>   	struct spi_mem_op program_execute;
> };
>
> so the NAND framework can populate these ops.
>
> Or maybe even better, define an enum that contains all the ops:
>
> enum spinand_op_id {
> 	SPI_NAND_OP_READ_CACHE,
> 	SPI_NAND_OP_WRITE_CACHE,
> 	SPI_NAND_OP_UPDATE_CACHE,
> 	SPI_NAND_OP_RESET,
> ...
> 	SPI_NAND_NUM_OPS,
> };
>
> struct spinand_device {
> 	...
>   	enum spinand_protocol protocol;
>   	struct spi_mem_op op_templates[SPINAND_NUM_PROTOCOLS][SPI_NAND_NUM_OPS];
> 	...
> };
>
>>> This way, you can easily pick the right set of operations based
>>> on the protocol/mode you're in:
>>>
>>> #define spinand_get_op_template(spinand, opname) \
>>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>>>
>>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
>>> {
>>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
>>> 	int ret;
>>>
>>> 	...
>>> }
>> I find a couple of issues with this  method,
>>
>> 1. read_cache, write_cache, update_cache op templates don't fit well
>> with the other non-data ops, as
>> these data ops are used to create a dirmap, and that can be done only
>> once at probe time. Hence, there
>> is a different mechanism of selecting of data ops and non-data ops.
> Not sure I see why this is a problem. You can populate data-ops for all
> modes, and pick the one that provides the best perfs when you create
> the dirmap (which should really be at the end of the probe, if it's not
> already).
>
>> Hence, this division in the op templates
>> struct as data_ops and ctrl_ops is required. Currently, the core only
>> supports using a single protocol for
>> data ops, chosen at the time of probing.
> Again, I don't see why you need to differentiate the control and data
> ops when populating this table. Those are just operations the NAND
> supports, and the data operations is just a subset.
>
>> 2. If we use this single op_templates struct, I can't think of any good
>> way to initialize these in the
>> manufacturers driver (winbond.c), refer to 17th patch in this series.
>> Could you please suggest a macro
>> implementation also for winbond.c with the suggested op_templates struct.
> First replace the op_variants field by something more generic:
>
> struct spinand_info {
> ...
> 	const struct spinand_op_variants **ops_variants;
> ...
> };
>
> #define SPINAND_OP_VARIANTS(_id, ...) \
> 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
>
> #define SPINAND_OPS_VARIANTS(name, ...)
> 	const struct spinand_op_variants name[]{
> 		__VA_ARGS__,
> 	};
>
> #define SPINAND_INFO_OPS_VARIANTS(defs)
> 	.ops_variants = defs

If we modify these macros, it would require other spinand vendor drivers 
to change (toshiba, micron, etc).
The older macros suit them well, should we go about changing them to 
this new macro (will require re-testing all of them),
or can we keep them unchanged and have new set of macros with different 
name (please give suggestion for it) for op variants.

>
> ...
>
> static SPINAND_OPS_VARIANTS(w35n01jw_ops_variants,
> 		SPINAND_OP_VARIANTS(READ_CACHE,
> 			SPINAND_PAGE_READ_FROM_CACHE_OCTALIO_DTR_OP(0, 24, NULL, 0),
> 			SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
> 			...)),
> 		SPINAND_OP_VARIANTS(WRITE_CACHE,
> 			SPINAND_PROG_LOAD_OCTALIO_DTR(true, 0, NULL, 0),
> 			SPINAND_PROG_LOAD(true, 0, NULL, 0)),
> 		...
> 		SPINAND_OP_VARIANTS(RESET,
> 			SPINAND_RESET_OP_OCTAL_DTR,
> 			SPINAND_RESET_OP,
> 		...
> 		);
> ...
>
>
> 	SPINAND_INFO("W35N01JW",
> 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc),
> 		     NAND_MEMORG(1, 4096, 128, 64, 512, 20, 1, 1, 1),
> 		     NAND_ECCREQ(1, 512),
> 		     SPINAND_HAS_OCTAL_DTR_BIT | SPINAND_HAS_CR_FEAT_BIT,
> 		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
> 		     SPINAND_INFO_OPS_VARIANTS(&w35n01jw_ops_variants)),
>
> You also need to adjust spinand_match_and_init() to account for this
> new layout and put each template op in the right subset based on
> op.cmd.width and op.cmd.dtr.
>
> Regards,
>
> Boris

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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-03-10  7:57           ` Apurva Nandan
@ 2022-03-10  8:40             ` Boris Brezillon
  -1 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-03-10  8:40 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Thu, 10 Mar 2022 13:27:06 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> >>> This way, you can easily pick the right set of operations based
> >>> on the protocol/mode you're in:
> >>>
> >>> #define spinand_get_op_template(spinand, opname) \
> >>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
> >>>
> >>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
> >>> {
> >>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
> >>> 	int ret;
> >>>
> >>> 	...
> >>> }  
> >> I find a couple of issues with this  method,
> >>
> >> 1. read_cache, write_cache, update_cache op templates don't fit well
> >> with the other non-data ops, as
> >> these data ops are used to create a dirmap, and that can be done only
> >> once at probe time. Hence, there
> >> is a different mechanism of selecting of data ops and non-data ops.  
> > Not sure I see why this is a problem. You can populate data-ops for all
> > modes, and pick the one that provides the best perfs when you create
> > the dirmap (which should really be at the end of the probe, if it's not
> > already).
> >  
> >> Hence, this division in the op templates
> >> struct as data_ops and ctrl_ops is required. Currently, the core only
> >> supports using a single protocol for
> >> data ops, chosen at the time of probing.  
> > Again, I don't see why you need to differentiate the control and data
> > ops when populating this table. Those are just operations the NAND
> > supports, and the data operations is just a subset.
> >  
> >> 2. If we use this single op_templates struct, I can't think of any good
> >> way to initialize these in the
> >> manufacturers driver (winbond.c), refer to 17th patch in this series.
> >> Could you please suggest a macro
> >> implementation also for winbond.c with the suggested op_templates struct.  
> > First replace the op_variants field by something more generic:
> >
> > struct spinand_info {
> > ...
> > 	const struct spinand_op_variants **ops_variants;
> > ...
> > };
> >
> > #define SPINAND_OP_VARIANTS(_id, ...) \
> > 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
> >
> > #define SPINAND_OPS_VARIANTS(name, ...)
> > 	const struct spinand_op_variants name[]{
> > 		__VA_ARGS__,
> > 	};
> >
> > #define SPINAND_INFO_OPS_VARIANTS(defs)
> > 	.ops_variants = defs  
> 
> If we modify these macros, it would require other spinand vendor drivers 
> to change (toshiba, micron, etc).
> The older macros suit them well, should we go about changing them to 
> this new macro (will require re-testing all of them),
> or can we keep them unchanged and have new set of macros with different 
> name (please give suggestion for it) for op variants.

I'd rather have everything converted to the new approach (we don't want
2 ways of describing the same thing), and I'm not sure you can make the
old macros map to the new solution, so I fear you'll have to patch all
vendors. This being said, I'm fine providing simple wrappers if that
helps, but I don't see how they'd make the description simpler/more
compact to be honest.

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-03-10  8:40             ` Boris Brezillon
  0 siblings, 0 replies; 76+ messages in thread
From: Boris Brezillon @ 2022-03-10  8:40 UTC (permalink / raw)
  To: Apurva Nandan
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav

On Thu, 10 Mar 2022 13:27:06 +0530
Apurva Nandan <a-nandan@ti.com> wrote:

> >>> This way, you can easily pick the right set of operations based
> >>> on the protocol/mode you're in:
> >>>
> >>> #define spinand_get_op_template(spinand, opname) \
> >>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
> >>>
> >>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
> >>> {
> >>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
> >>> 	int ret;
> >>>
> >>> 	...
> >>> }  
> >> I find a couple of issues with this  method,
> >>
> >> 1. read_cache, write_cache, update_cache op templates don't fit well
> >> with the other non-data ops, as
> >> these data ops are used to create a dirmap, and that can be done only
> >> once at probe time. Hence, there
> >> is a different mechanism of selecting of data ops and non-data ops.  
> > Not sure I see why this is a problem. You can populate data-ops for all
> > modes, and pick the one that provides the best perfs when you create
> > the dirmap (which should really be at the end of the probe, if it's not
> > already).
> >  
> >> Hence, this division in the op templates
> >> struct as data_ops and ctrl_ops is required. Currently, the core only
> >> supports using a single protocol for
> >> data ops, chosen at the time of probing.  
> > Again, I don't see why you need to differentiate the control and data
> > ops when populating this table. Those are just operations the NAND
> > supports, and the data operations is just a subset.
> >  
> >> 2. If we use this single op_templates struct, I can't think of any good
> >> way to initialize these in the
> >> manufacturers driver (winbond.c), refer to 17th patch in this series.
> >> Could you please suggest a macro
> >> implementation also for winbond.c with the suggested op_templates struct.  
> > First replace the op_variants field by something more generic:
> >
> > struct spinand_info {
> > ...
> > 	const struct spinand_op_variants **ops_variants;
> > ...
> > };
> >
> > #define SPINAND_OP_VARIANTS(_id, ...) \
> > 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
> >
> > #define SPINAND_OPS_VARIANTS(name, ...)
> > 	const struct spinand_op_variants name[]{
> > 		__VA_ARGS__,
> > 	};
> >
> > #define SPINAND_INFO_OPS_VARIANTS(defs)
> > 	.ops_variants = defs  
> 
> If we modify these macros, it would require other spinand vendor drivers 
> to change (toshiba, micron, etc).
> The older macros suit them well, should we go about changing them to 
> this new macro (will require re-testing all of them),
> or can we keep them unchanged and have new set of macros with different 
> name (please give suggestion for it) for op variants.

I'd rather have everything converted to the new approach (we don't want
2 ways of describing the same thing), and I'm not sure you can make the
old macros map to the new solution, so I fear you'll have to patch all
vendors. This being said, I'm fine providing simple wrappers if that
helps, but I don't see how they'd make the description simpler/more
compact to be honest.

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

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
  2022-03-10  8:40             ` Boris Brezillon
@ 2022-03-14 11:47               ` Apurva Nandan
  -1 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-03-14 11:47 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav


On 10/03/22 14:10, Boris Brezillon wrote:
> On Thu, 10 Mar 2022 13:27:06 +0530
> Apurva Nandan <a-nandan@ti.com> wrote:
>
>>>>> This way, you can easily pick the right set of operations based
>>>>> on the protocol/mode you're in:
>>>>>
>>>>> #define spinand_get_op_template(spinand, opname) \
>>>>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>>>>>
>>>>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
>>>>> {
>>>>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
>>>>> 	int ret;
>>>>>
>>>>> 	...
>>>>> }
>>>> I find a couple of issues with this  method,
>>>>
>>>> 1. read_cache, write_cache, update_cache op templates don't fit well
>>>> with the other non-data ops, as
>>>> these data ops are used to create a dirmap, and that can be done only
>>>> once at probe time. Hence, there
>>>> is a different mechanism of selecting of data ops and non-data ops.
>>> Not sure I see why this is a problem. You can populate data-ops for all
>>> modes, and pick the one that provides the best perfs when you create
>>> the dirmap (which should really be at the end of the probe, if it's not
>>> already).
>>>   
>>>> Hence, this division in the op templates
>>>> struct as data_ops and ctrl_ops is required. Currently, the core only
>>>> supports using a single protocol for
>>>> data ops, chosen at the time of probing.
>>> Again, I don't see why you need to differentiate the control and data
>>> ops when populating this table. Those are just operations the NAND
>>> supports, and the data operations is just a subset.
>>>   
>>>> 2. If we use this single op_templates struct, I can't think of any good
>>>> way to initialize these in the
>>>> manufacturers driver (winbond.c), refer to 17th patch in this series.
>>>> Could you please suggest a macro
>>>> implementation also for winbond.c with the suggested op_templates struct.
>>> First replace the op_variants field by something more generic:
>>>
>>> struct spinand_info {
>>> ...
>>> 	const struct spinand_op_variants **ops_variants;
>>> ...
>>> };
>>>
>>> #define SPINAND_OP_VARIANTS(_id, ...) \
>>> 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
>>>
>>> #define SPINAND_OPS_VARIANTS(name, ...)
>>> 	const struct spinand_op_variants name[]{
>>> 		__VA_ARGS__,
>>> 	};
>>>
>>> #define SPINAND_INFO_OPS_VARIANTS(defs)
>>> 	.ops_variants = defs
>> If we modify these macros, it would require other spinand vendor drivers
>> to change (toshiba, micron, etc).
>> The older macros suit them well, should we go about changing them to
>> this new macro (will require re-testing all of them),
>> or can we keep them unchanged and have new set of macros with different
>> name (please give suggestion for it) for op variants.
> I'd rather have everything converted to the new approach (we don't want
> 2 ways of describing the same thing), and I'm not sure you can make the
> old macros map to the new solution, so I fear you'll have to patch all
> vendors. This being said, I'm fine providing simple wrappers if that
> helps, but I don't see how they'd make the description simpler/more
> compact to be honest.
Okay, I will convert all of the vendor drivers, but please note I don't 
have any way to test the changes on all the flashes.

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

* Re: [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates
@ 2022-03-14 11:47               ` Apurva Nandan
  0 siblings, 0 replies; 76+ messages in thread
From: Apurva Nandan @ 2022-03-14 11:47 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Mark Brown, Patrice Chotard, Christophe Kerello, Daniel Palmer,
	Alexander Lobakin, linux-mtd, linux-kernel, linux-spi, p.yadav


On 10/03/22 14:10, Boris Brezillon wrote:
> On Thu, 10 Mar 2022 13:27:06 +0530
> Apurva Nandan <a-nandan@ti.com> wrote:
>
>>>>> This way, you can easily pick the right set of operations based
>>>>> on the protocol/mode you're in:
>>>>>
>>>>> #define spinand_get_op_template(spinand, opname) \
>>>>> 	((spinand)->op_templates[(spinand)->protocol]->opname)
>>>>>
>>>>> static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
>>>>> {
>>>>> 	struct spi_mem_op op = *spinand_get_op_template(spinand, get_feature);
>>>>> 	int ret;
>>>>>
>>>>> 	...
>>>>> }
>>>> I find a couple of issues with this  method,
>>>>
>>>> 1. read_cache, write_cache, update_cache op templates don't fit well
>>>> with the other non-data ops, as
>>>> these data ops are used to create a dirmap, and that can be done only
>>>> once at probe time. Hence, there
>>>> is a different mechanism of selecting of data ops and non-data ops.
>>> Not sure I see why this is a problem. You can populate data-ops for all
>>> modes, and pick the one that provides the best perfs when you create
>>> the dirmap (which should really be at the end of the probe, if it's not
>>> already).
>>>   
>>>> Hence, this division in the op templates
>>>> struct as data_ops and ctrl_ops is required. Currently, the core only
>>>> supports using a single protocol for
>>>> data ops, chosen at the time of probing.
>>> Again, I don't see why you need to differentiate the control and data
>>> ops when populating this table. Those are just operations the NAND
>>> supports, and the data operations is just a subset.
>>>   
>>>> 2. If we use this single op_templates struct, I can't think of any good
>>>> way to initialize these in the
>>>> manufacturers driver (winbond.c), refer to 17th patch in this series.
>>>> Could you please suggest a macro
>>>> implementation also for winbond.c with the suggested op_templates struct.
>>> First replace the op_variants field by something more generic:
>>>
>>> struct spinand_info {
>>> ...
>>> 	const struct spinand_op_variants **ops_variants;
>>> ...
>>> };
>>>
>>> #define SPINAND_OP_VARIANTS(_id, ...) \
>>> 	[SPI_NAND_OP_ ## _id] = { __VA_ARGS__ }
>>>
>>> #define SPINAND_OPS_VARIANTS(name, ...)
>>> 	const struct spinand_op_variants name[]{
>>> 		__VA_ARGS__,
>>> 	};
>>>
>>> #define SPINAND_INFO_OPS_VARIANTS(defs)
>>> 	.ops_variants = defs
>> If we modify these macros, it would require other spinand vendor drivers
>> to change (toshiba, micron, etc).
>> The older macros suit them well, should we go about changing them to
>> this new macro (will require re-testing all of them),
>> or can we keep them unchanged and have new set of macros with different
>> name (please give suggestion for it) for op variants.
> I'd rather have everything converted to the new approach (we don't want
> 2 ways of describing the same thing), and I'm not sure you can make the
> old macros map to the new solution, so I fear you'll have to patch all
> vendors. This being said, I'm fine providing simple wrappers if that
> helps, but I don't see how they'd make the description simpler/more
> compact to be honest.
Okay, I will convert all of the vendor drivers, but please note I don't 
have any way to test the changes on all the flashes.

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

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

end of thread, other threads:[~2022-03-14 11:48 UTC | newest]

Thread overview: 76+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-01  7:42 [PATCH v3 00/17] mtd: spinand: Add Octal DTR SPI (8D-8D-8D) mode support Apurva Nandan
2022-01-01  7:42 ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 01/17] spi: spi-mem: Add DTR templates for cmd, address, dummy and data phase Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-04 14:52   ` Mark Brown
2022-01-04 14:52     ` Mark Brown
2022-01-04 15:31   ` Boris Brezillon
2022-01-04 15:31     ` Boris Brezillon
2022-01-05  5:50     ` Pratyush Yadav
2022-01-05  5:50       ` Pratyush Yadav
2022-01-05  7:36       ` Boris Brezillon
2022-01-05  7:36         ` Boris Brezillon
2022-01-05  8:24     ` Tudor.Ambarus
2022-01-05  8:24       ` Tudor.Ambarus
2022-01-01  7:42 ` [PATCH v3 02/17] mtd: spinand: Define macros for Octal DTR ops Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 03/17] mtd: spinand: Add enum spinand_protocol to indicate current SPI IO mode Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-03 10:05   ` Boris Brezillon
2022-01-03 10:05     ` Boris Brezillon
2022-01-01  7:42 ` [PATCH v3 04/17] mtd: spinand: Rename 'op_templates' to 'data_ops' Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-03  9:48   ` Boris Brezillon
2022-01-03  9:48     ` Boris Brezillon
2022-01-01  7:42 ` [PATCH v3 05/17] mtd: spinand: Define ctrl_ops for non-page read/write op templates Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-03 10:01   ` Boris Brezillon
2022-01-03 10:01     ` Boris Brezillon
2022-01-03 10:36     ` Boris Brezillon
2022-01-03 10:36       ` Boris Brezillon
2022-02-15 15:33     ` Apurva Nandan
2022-02-15 15:33       ` Apurva Nandan
2022-02-15 17:37       ` Boris Brezillon
2022-02-15 17:37         ` Boris Brezillon
2022-03-02 15:30         ` Apurva Nandan
2022-03-02 15:30           ` Apurva Nandan
2022-03-02 20:05           ` Boris Brezillon
2022-03-02 20:05             ` Boris Brezillon
2022-03-10  7:57         ` Apurva Nandan
2022-03-10  7:57           ` Apurva Nandan
2022-03-10  8:40           ` Boris Brezillon
2022-03-10  8:40             ` Boris Brezillon
2022-03-14 11:47             ` Apurva Nandan
2022-03-14 11:47               ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 06/17] mtd: spinand: Define default ctrl_ops in the core Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 07/17] mtd: spinand: Switch from op macros usage to 'ctrl_ops' " Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 08/17] mtd: spinand: Add support for manufacturer-based ctrl_ops variations Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 09/17] mtd: spinand: Add change_mode() in manufacturer_ops Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-05  9:52   ` Boris Brezillon
2022-01-05  9:52     ` Boris Brezillon
2022-01-01  7:42 ` [PATCH v3 10/17] mtd: spinand: Add pointer to probed flash's spinand_info Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 11/17] mtd: spinand: Allow enabling/disabling Octal DTR mode in the core Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-03 10:14   ` Boris Brezillon
2022-01-03 10:14     ` Boris Brezillon
2022-01-01  7:42 ` [PATCH v3 12/17] mtd: spinand: Add mtd_suspend() to disable Octal DTR mode at suspend Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-03 10:17   ` Boris Brezillon
2022-01-03 10:17     ` Boris Brezillon
2022-01-01  7:42 ` [PATCH v3 13/17] mtd: spinand: winbond: Add support for write volatile configuration register op Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 14/17] mtd: spinand: winbond: Add octal_dtr_enable/disable() in manufacturer_ops Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 15/17] mtd: spianand: winbond: Add change_mode() manufacturer_ops Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-03 10:27   ` Boris Brezillon
2022-01-03 10:27     ` Boris Brezillon
2022-01-01  7:42 ` [PATCH v3 16/17] mtd: spinand: winbond: Rename cache op_variants struct variable Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan
2022-01-01  7:42 ` [PATCH v3 17/17] mtd: spinand: winbond: Add support for Winbond W35N01JW SPI NAND flash Apurva Nandan
2022-01-01  7:42   ` Apurva Nandan

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