Skip to contentSkip to conversation

sf: fix support of QSPI memories and controllers

PATCH New Cyrille Pitchen 6 participants 36 messages Mar 15, 2016 – Mar 21, 2016

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover sf: fix support of QSPI memories and controllers

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()
sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

 arch/arm/mach-at91/include/mach/clk.h |   5 +
 drivers/mtd/spi/Kconfig               |  18 +-
 drivers/mtd/spi/Makefile              |   2 +
 drivers/mtd/spi/atmel_qspi_flash.c    | 432 ++++++++++++++++++++
 drivers/mtd/spi/sf-uclass.c           |  11 +
 drivers/mtd/spi/sf_internal.h         | 115 ++++--
 drivers/mtd/spi/sf_micron.c           | 222 ++++++++++
 drivers/mtd/spi/sf_params.c           |  32 +-
 drivers/mtd/spi/sf_probe.c            |  46 ++-
 drivers/mtd/spi/spi_flash.c           | 744 +++++++++++++++++++++-------------
 drivers/spi/Kconfig                   |   9 +
 drivers/spi/Makefile                  |   1 +
 drivers/spi/atmel_qspi.c              | 150 +++++++
 drivers/spi/atmel_qspi.h              | 145 +++++++
 include/spi_flash.h                   | 105 +++++
 15 files changed, 1701 insertions(+), 336 deletions(-)
 create mode 100644 drivers/mtd/spi/atmel_qspi_flash.c
 create mode 100644 drivers/mtd/spi/sf_micron.c
 create mode 100644 drivers/spi/atmel_qspi.c
 create mode 100644 drivers/spi/atmel_qspi.h
Signature · 1 line
1.8.2.2
#1 lore raw

PATCH 1/18 Revert "sf: Fix quad bit set for micron devices"

This reverts commit c56ae7519f141523ba1248b22b5b5169b21772fe.

Once the 'Quad Enable' bit is cleared in their Enhanced Volatile Configuration Register (EVCR), Micron memories expect ALL commands to use the SPI 4-4-4 protocol. Commands using SPI 1-y-z protocols are no longer accepted.

Within the reverted commit, the write_evcr() function is implemented using the spi_flash_write_common(), which is a shortcut for the
[ spi_flash_cmd_write_enable(), spi_flash_cmd_write(), spi_flash_cmd_wait_ready() ] sequence.

Since the internal state of the Micron memory has been changed when the spi_flash_cmd_write() function completes, the later call of the spi_flash_cmd_wait_ready() function fails.

Indeed the SPI controller driver is not aware of the SPI protocol switch.

Further patches will fix the support of Micron QSPI memories.

---
 drivers/mtd/spi/sf_internal.h |  3 ---
 drivers/mtd/spi/spi_flash.c   | 62 ++-----------------------------------------
 2 files changed, 2 insertions(+), 63 deletions(-)
drivers/mtd/spi/sf_internal.h +0 -3
index 007a5a085caf..7418c76b272c 100644
@@ -77,7 +77,6 @@ enum spi_nor_option_flags {
 #define CMD_WRITE_DISABLE		0x04
 #define CMD_WRITE_ENABLE		0x06
 #define CMD_QUAD_PAGE_PROGRAM		0x32
-#define CMD_WRITE_EVCR			0x61
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW		0x03
@@ -91,7 +90,6 @@ enum spi_nor_option_flags {
 #define CMD_READ_STATUS1		0x35
 #define CMD_READ_CONFIG			0x35
 #define CMD_FLAG_STATUS			0x70
-#define CMD_READ_EVCR			0x65
 
 /* Bank addr access commands */
 #ifdef CONFIG_SPI_FLASH_BAR
@@ -106,7 +104,6 @@ enum spi_nor_option_flags {
 #define STATUS_QEB_WINSPAN		BIT(1)
 #define STATUS_QEB_MXIC			BIT(6)
 #define STATUS_PEC			BIT(7)
-#define STATUS_QEB_MICRON		BIT(7)
 #define SR_BP0				BIT(2)  /* Block protect 0 */
 #define SR_BP1				BIT(3)  /* Block protect 1 */
 #define SR_BP2				BIT(4)  /* Block protect 2 */
drivers/mtd/spi/spi_flash.c +2 -60

80 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#2 lore raw

PATCH 2/18 sf: call spi_claim_bus() and spi_release_bus() only once per read, write or erase

In reply to Cyrille Pitchen

There is no need to claim/release the SPI bus for each command sent to the memory when performing read, write or erase operations. Now we claim the SPI bus once for all at the very beginning of these operations then we release it just before exiting.

---
 drivers/mtd/spi/sf_internal.h |  5 +---
 drivers/mtd/spi/spi_flash.c   | 68 +++++++++++++++++++++++++------------------
 2 files changed, 40 insertions(+), 33 deletions(-)
drivers/mtd/spi/sf_internal.h +1 -4
index 7418c76b272c..dd8152721fe1 100644
@@ -192,11 +192,9 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
 
 /*
  * Used for spi_flash write operation
- * - SPI claim
  * - spi_flash_cmd_write_enable
  * - spi_flash_cmd_write
  * - spi_flash_cmd_wait_ready
- * - SPI release
  */
 int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 		size_t cmd_len, const void *buf, size_t buf_len);
@@ -210,8 +208,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		size_t len, const void *buf);
 
 /*
- * Same as spi_flash_cmd_read() except it also claims/releases the SPI
- * bus. Used as common part of the ->read() operation.
+ * Same as spi_flash_cmd_read(). Used as common part of the ->read() operation.
  */
 int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
 		size_t cmd_len, void *data, size_t data_len);
drivers/mtd/spi/spi_flash.c +39 -29

170 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#3 lore raw

PATCH 3/18 sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()

In reply to Cyrille Pitchen

Since spi_claim_bus() and spi_release_bus() are now called outside spi_flash_read_common(), this latest function is just a useless alias for spi_flash_cmd_read(). So we remove it.

---
 drivers/mtd/spi/sf_internal.h |  6 ------
 drivers/mtd/spi/spi_flash.c   | 30 +++++++++---------------------
 2 files changed, 9 insertions(+), 27 deletions(-)
drivers/mtd/spi/sf_internal.h +0 -6
index dd8152721fe1..96c9255cb03d 100644
@@ -207,12 +207,6 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		size_t len, const void *buf);
 
-/*
- * Same as spi_flash_cmd_read(). Used as common part of the ->read() operation.
- */
-int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
-		size_t cmd_len, void *data, size_t data_len);
-
 /* Flash read operation, support all possible read commands */
 int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		size_t len, void *data);
drivers/mtd/spi/spi_flash.c +9 -21
index 740ecd44473a..b1ebc65f37d7 100644
@@ -32,11 +32,12 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
 
 static int read_sr(struct spi_flash *flash, u8 *rs)
 {
+	struct spi_slave *spi = flash->spi;
 	int ret;
 	u8 cmd;
 
 	cmd = CMD_READ_STATUS;
-	ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
+	ret = spi_flash_cmd_read(spi, &cmd, 1, rs, 1);
 	if (ret < 0) {
 		debug("SF: fail to read status register\n");
 		return ret;
@@ -47,10 +48,11 @@ static int read_sr(struct spi_flash *flash, u8 *rs)
 
 static int read_fsr(struct spi_flash *flash, u8 *fsr)
 {
+	struct spi_slave *spi = flash->spi;
 	int ret;
 	const u8 cmd = CMD_FLAG_STATUS;
 
-	ret = spi_flash_read_common(flash, &cmd, 1, fsr, 1);
+	ret = spi_flash_cmd_read(spi, &cmd, 1, fsr, 1);
 	if (ret < 0) {
 		debug("SF: fail to read flag status register\n");
 		return ret;
@@ -77,11 +79,12 @@ static int write_sr(struct spi_flash *flash, u8 ws)
 #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
 static int read_cr(struct spi_flash *flash, u8 *rc)
 {
+	struct spi_slave *spi = flash->spi;
 	int ret;
 	u8 cmd;
 
 	cmd = CMD_READ_CONFIG;
-	ret = spi_flash_read_common(flash, &cmd, 1, rc, 1);
+	ret = spi_flash_cmd_read(spi, &cmd, 1, rc, 1);
 	if (ret < 0) {
 		debug("SF: fail to read config register\n");
 		return ret;
@@ -136,6 +139,7 @@ bar_end:
 
 static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
 {
+	struct spi_slave *spi = flash->spi;
 	u8 curr_bank = 0;
 	int ret;
 
@@ -152,8 +156,7 @@ static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
 		flash->bank_write_cmd = CMD_EXTNADDR_WREAR;
 	}
 
-	ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
-				    &curr_bank, 1);
+	ret = spi_flash_cmd_read(spi, &flash->bank_read_cmd, 1, &curr_bank, 1);
 	if (ret) {
 		debug("SF: fail to read bank addr register\n");
 		return ret;
@@ -414,21 +417,6 @@ release:
 	return ret;
 }
 
-int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
-		size_t cmd_len, void *data, size_t data_len)
-{
-	struct spi_slave *spi = flash->spi;
-	int ret;
-
-	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
-	if (ret < 0) {
-		debug("SF: read cmd failed\n");
-		return ret;
-	}
-
-	return ret;
-}
-
 /*
  * TODO: remove the weak after all the other spi_flash_copy_mmap
  * implementations removed from drivers
@@ -496,7 +484,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 
 		spi_flash_addr(read_addr, cmd);
 
-		ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
+		ret = spi_flash_cmd_read(spi, cmd, cmdsz, data, read_len);
 		if (ret < 0) {
 			debug("SF: read failed\n");
 			break;
Signature · 1 line
1.8.2.2
#4 lore raw

PATCH 4/18 sf: remove spi_flash_write_common()

In reply to Cyrille Pitchen

This patch prepares the split of memory versus internal registers SPI commands.

---
 drivers/mtd/spi/sf_internal.h |  8 +++---
 drivers/mtd/spi/spi_flash.c   | 62 ++++++++++++++++++++++++++-----------------
 2 files changed, 42 insertions(+), 28 deletions(-)
drivers/mtd/spi/sf_internal.h +4 -4
index 96c9255cb03d..25fc5a112d92 100644
@@ -191,13 +191,13 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
 }
 
 /*
- * Used for spi_flash write operation
+ * Used for spi_flash register update operation
  * - spi_flash_cmd_write_enable
- * - spi_flash_cmd_write
+ * - write new register value
  * - spi_flash_cmd_wait_ready
  */
-int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
-		size_t cmd_len, const void *buf, size_t buf_len);
+int spi_flash_update_reg(struct spi_flash *flash, u8 opcode, size_t len,
+			 const void *buf);
 
 /*
  * Flash write operation, support all possible write commands.
drivers/mtd/spi/spi_flash.c +38 -24

152 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#5 lore raw

PATCH 5/18 sf: export spi_flash_wait_ready() function

In reply to Cyrille Pitchen

This patch exports a new function so future drivers can use it.

---
 drivers/mtd/spi/sf_internal.h | 3 +++
 drivers/mtd/spi/spi_flash.c   | 7 ++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/mtd/spi/sf_internal.h +3 -0
index 25fc5a112d92..e2a4449dbf40 100644
@@ -190,6 +190,9 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
 	return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
 }
 
+/* Wait for Busy/Write in Progress flag to be cleared */
+int spi_flash_wait_ready(struct spi_flash *flash);
+
 /*
  * Used for spi_flash register update operation
  * - spi_flash_cmd_write_enable
drivers/mtd/spi/spi_flash.c +6 -1
index e43e74fd95cd..6f30ff6f8d7c 100644
@@ -249,6 +249,11 @@ static int spi_flash_cmd_wait_ready(struct spi_flash *flash,
 	return -ETIMEDOUT;
 }
 
+int spi_flash_wait_ready(struct spi_flash *flash)
+{
+	return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+}
+
 int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
 			 size_t len, const void *buf)
 {
@@ -267,7 +272,7 @@ int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
 		return ret;
 	}
 
-	ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+	ret = spi_flash_wait_ready(flash);
 	if (ret < 0) {
 		debug("SF: write register timed out\n");
 		return ret;
Signature · 1 line
1.8.2.2
#6 lore raw

PATCH 6/18 sf: share erase generic algorithm

In reply to Cyrille Pitchen

This patch splits the generic algorithm to erase pages/sectors from the actual implementation which is specific to each UCLASS_SPI_FLASH driver.

For now, the sf_probe.c driver is the only instance of this driver class using this generic algorithm but other driver instances are to come. This patch will ease their implementation.

Please note that the sf_dataflash.c driver has its own implementation of the .erase hook (of the struct dm_spi_flash_ops) which is not compatible with this generic algorithm. This is why we can't simply change the prototype of .erase hook and create a spi_flash_erase() wrapper.

---
 drivers/mtd/spi/sf_internal.h |  4 ++++
 drivers/mtd/spi/spi_flash.c   | 28 +++++++++++++++++++---------
 2 files changed, 23 insertions(+), 9 deletions(-)
drivers/mtd/spi/sf_internal.h +4 -0
index e2a4449dbf40..3c6bac3464f8 100644
@@ -169,6 +169,10 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
 /* Flash erase(sectors) operation, support all possible erase commands */
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len);
 
+typedef int (*spi_flash_erase_fn)(struct spi_flash *, u32);
+int spi_flash_erase_alg(struct spi_flash *flash, u32 offset, size_t len,
+			spi_flash_erase_fn erase_fn);
+
 /* Lock stmicro spi flash region */
 int stm_lock(struct spi_flash *flash, u32 ofs, size_t len);
 
drivers/mtd/spi/spi_flash.c +19 -9
index 6f30ff6f8d7c..20b8c31c09e0 100644
@@ -281,11 +281,11 @@ int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
 	return 0;
 }
 
-int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+int spi_flash_erase_alg(struct spi_flash *flash, u32 offset, size_t len,
+			spi_flash_erase_fn erase_fn)
 {
 	struct spi_slave *spi = flash->spi;
 	u32 erase_size, erase_addr;
-	u8 cmd[SPI_FLASH_CMD_LEN];
 	int ret = -1;
 
 	erase_size = flash->erase_size;
@@ -309,7 +309,6 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		}
 	}
 
-	cmd[0] = flash->erase_cmd;
 	while (len) {
 		erase_addr = offset;
 
@@ -328,12 +327,8 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 			break;
 		}
 
-		spi_flash_addr(erase_addr, cmd);
-
-		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
-		      cmd[2], cmd[3], erase_addr);
-
-		ret = spi_flash_cmd_write(spi, cmd, sizeof(cmd), NULL, 0);
+		debug("SF: erase %2x %06x\n", flash->erase_cmd, erase_addr);
+		ret = erase_fn(flash, erase_addr);
 		if (ret < 0) {
 			debug("SF: erase failed\n");
 			break;
@@ -356,6 +351,21 @@ release:
 	return ret;
 }
 
+static int spi_flash_erase_impl(struct spi_flash *flash, u32 offset)
+{
+	struct spi_slave *spi = flash->spi;
+	u8 cmd[SPI_FLASH_CMD_LEN];
+
+	cmd[0] = flash->erase_cmd;
+	spi_flash_addr(offset, cmd);
+	return spi_flash_cmd_write(spi, cmd, sizeof(cmd), NULL, 0);
+}
+
+int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+{
+	return spi_flash_erase_alg(flash, offset, len, spi_flash_erase_impl);
+}
+
 int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		size_t len, const void *buf)
 {
Signature · 1 line
1.8.2.2
#7 lore raw

PATCH 7/18 sf: share write generic algorithm

In reply to Cyrille Pitchen

This patch splits the generic algorithm to write data from the actual implementation which is specific to each UCLASS_SPI_FLASH driver.

For now, the sf_probe.c driver is the only instance of this driver class using this generic algorithm but other driver instances are to come. This patch will ease their implementation.

Please note that the sf_dataflash.c driver has its own implementation of the .write hook (of the struct dm_spi_flash_ops) which is not compatible with this generic algorithm. This is why we can't simply change the prototype of .write hook and create a spi_flash_write() wrapper.

---
 drivers/mtd/spi/sf_internal.h |  5 +++++
 drivers/mtd/spi/spi_flash.c   | 34 ++++++++++++++++++++++++----------
 2 files changed, 29 insertions(+), 10 deletions(-)
drivers/mtd/spi/sf_internal.h +5 -0
index 3c6bac3464f8..592c23cd4ce1 100644
@@ -214,6 +214,11 @@ int spi_flash_update_reg(struct spi_flash *flash, u8 opcode, size_t len,
 int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		size_t len, const void *buf);
 
+typedef int (*spi_flash_write_fn)(struct spi_flash *, u32, size_t,
+				  const void *);
+int spi_flash_write_alg(struct spi_flash *flash, u32 offset, size_t len,
+			const void *buf, spi_flash_write_fn write_fn);
+
 /* Flash read operation, support all possible read commands */
 int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		size_t len, void *data);
drivers/mtd/spi/spi_flash.c +24 -10
index 20b8c31c09e0..3c8224c2b084 100644
@@ -366,14 +366,13 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 	return spi_flash_erase_alg(flash, offset, len, spi_flash_erase_impl);
 }
 
-int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
-		size_t len, const void *buf)
+int spi_flash_write_alg(struct spi_flash *flash, u32 offset, size_t len,
+			const void *buf, spi_flash_write_fn write_fn)
 {
 	struct spi_slave *spi = flash->spi;
 	unsigned long byte_addr, page_size;
 	u32 write_addr;
 	size_t chunk_len, actual;
-	u8 cmd[SPI_FLASH_CMD_LEN];
 	int ret = -1;
 
 	page_size = flash->page_size;
@@ -393,7 +392,6 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		}
 	}
 
-	cmd[0] = flash->write_cmd;
 	for (actual = 0; actual < len; actual += chunk_len) {
 		write_addr = offset;
 
@@ -419,13 +417,10 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 			break;
 		}
 
-		spi_flash_addr(write_addr, cmd);
-
-		debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
-		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
+		debug("SF: 0x%p => cmd = { 0x%02x 0x%06x } chunk_len = %zu\n",
+		      buf + actual, flash->write_cmd, write_addr, chunk_len);
 
-		ret = spi_flash_cmd_write(spi, cmd, sizeof(cmd),
-					  buf + actual, chunk_len);
+		ret = write_fn(flash, write_addr, chunk_len, buf + actual);
 		if (ret < 0) {
 			debug("SF: write failed\n");
 			break;
@@ -446,6 +441,25 @@ release:
 	return ret;
 }
 
+static int spi_flash_write_impl(struct spi_flash *flash, u32 offset,
+				size_t len, const void *buf)
+{
+	struct spi_slave *spi = flash->spi;
+	u8 cmd[SPI_FLASH_CMD_LEN];
+	size_t cmdsz = sizeof(cmd);
+
+	cmd[0] = flash->write_cmd;
+	spi_flash_addr(offset, cmd);
+	return spi_flash_cmd_write(spi, cmd, cmdsz, buf, len);
+}
+
+int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
+			    size_t len, const void *buf)
+{
+	return spi_flash_write_alg(flash, offset, len, buf,
+				   spi_flash_write_impl);
+}
+
 /*
  * TODO: remove the weak after all the other spi_flash_copy_mmap
  * implementations removed from drivers
Signature · 1 line
1.8.2.2
#8 lore raw

PATCH 8/18 sf: share read generic algorithm

In reply to Cyrille Pitchen

This patch splits the generic algorithm to read data from the actual implementation which is specific to each UCLASS_SPI_FLASH driver.

For now, the sf_probe.c driver is the only instance of this driver class using this generic algorithm but other driver instances are to come. This patch will ease their implementation.

Please note that the sf_dataflash.c driver has its own implementation of the .read hook (of the struct dm_spi_flash_ops) which is not compatible with this generic algorithm. This is why we can't simply change the prototype of .read hook and create a spi_flash_read() wrapper.

---
 drivers/mtd/spi/sf_internal.h |  4 ++++
 drivers/mtd/spi/spi_flash.c   | 48 ++++++++++++++++++++++++++++---------------
 2 files changed, 35 insertions(+), 17 deletions(-)
drivers/mtd/spi/sf_internal.h +4 -0
index 592c23cd4ce1..569863a31684 100644
@@ -223,6 +223,10 @@ int spi_flash_write_alg(struct spi_flash *flash, u32 offset, size_t len,
 int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		size_t len, void *data);
 
+typedef int (*spi_flash_read_fn)(struct spi_flash *, u32, size_t, void *);
+int spi_flash_read_alg(struct spi_flash *flash, u32 offset, size_t len,
+		void *data, spi_flash_read_fn read_fn);
+
 #ifdef CONFIG_SPI_FLASH_MTD
 int spi_flash_mtd_register(struct spi_flash *flash);
 void spi_flash_mtd_unregister(void);
drivers/mtd/spi/spi_flash.c +31 -17

80 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#9 lore raw

PATCH 9/18 sf: add hooks to handle register read and write operations

In reply to Cyrille Pitchen

This patch finalizes the split of internal register and memory data SPI commands. Indeed some (Q)SPI controllers such as the Atmel QSPI controller need to make the difference between register read/write SPI commands and data read/write/erase SPI commands.

It follows an interface close to the one used by the spi-nor.c driver in Linux:

- read_reg:   read out the register
- write_reg:  write data to the register
- read:       read data from the SPI flash
- write:      write data into the SPI flash
- erase:      erase sectors of the SPI flash
---
 drivers/mtd/spi/sf-uclass.c   | 11 +++++++
 drivers/mtd/spi/sf_internal.h | 13 ++++++--
 drivers/mtd/spi/sf_probe.c    | 18 +++++++++++
 drivers/mtd/spi/spi_flash.c   | 70 ++++++++++++++++++++++++-------------------
 include/spi_flash.h           | 58 +++++++++++++++++++++++++++++++++++
 5 files changed, 137 insertions(+), 33 deletions(-)
drivers/mtd/spi/sf-uclass.c +11 -0
index 19de964e6121..ebae9b1edb15 100644
@@ -13,6 +13,17 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+int spi_flash_read_reg_dm(struct udevice *dev, u8 opcode, size_t len, void *buf)
+{
+	return sf_get_ops(dev)->read_reg(dev, opcode, len, buf);
+}
+
+int spi_flash_write_reg_dm(struct udevice *dev, u8 opcode, size_t len,
+			   const void *buf)
+{
+	return sf_get_ops(dev)->write_reg(dev, opcode, len, buf);
+}
+
 int spi_flash_read_dm(struct udevice *dev, u32 offset, size_t len, void *buf)
 {
 	return sf_get_ops(dev)->read(dev, offset, len, buf);
drivers/mtd/spi/sf_internal.h +11 -2
index 569863a31684..15a5fa9c2afd 100644
@@ -12,6 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/compiler.h>
+#include <spi_flash.h>
 
 /* Dual SPI flash memories - see SPI_COMM_DUAL_... */
 enum spi_dual_flash {
@@ -185,13 +186,13 @@ int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len);
 /* Enable writing on the SPI flash */
 static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
 {
-	return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0);
+	return spi_flash_write_reg(flash, CMD_WRITE_ENABLE, 0, NULL);
 }
 
 /* Disable writing on the SPI flash */
 static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
 {
-	return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
+	return spi_flash_write_reg(flash, CMD_WRITE_DISABLE, 0, NULL);
 }
 
 /* Wait for Busy/Write in Progress flag to be cleared */
@@ -206,6 +207,10 @@ int spi_flash_wait_ready(struct spi_flash *flash);
 int spi_flash_update_reg(struct spi_flash *flash, u8 opcode, size_t len,
 			 const void *buf);
 
+/* Flash write register operation */
+int spi_flash_cmd_write_reg_ops(struct spi_flash *flash, u8 opcode, size_t len,
+				const void *buf);
+
 /*
  * Flash write operation, support all possible write commands.
  * Write the requested data out breaking it up into multiple write
@@ -219,6 +224,10 @@ typedef int (*spi_flash_write_fn)(struct spi_flash *, u32, size_t,
 int spi_flash_write_alg(struct spi_flash *flash, u32 offset, size_t len,
 			const void *buf, spi_flash_write_fn write_fn);
 
+/* Flash read register operation */
+int spi_flash_cmd_read_reg_ops(struct spi_flash *flash, u8 opcode, size_t len,
+			       void *buf);
+
 /* Flash read operation, support all possible read commands */
 int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		size_t len, void *data);
drivers/mtd/spi/sf_probe.c +18 -0
index 7b296378d2be..fbd7d4740b51 100644
@@ -111,6 +111,22 @@ void spi_flash_free(struct spi_flash *flash)
 
 #else /* defined CONFIG_DM_SPI_FLASH */
 
+static int spi_flash_std_read_reg(struct udevice *dev, u8 opcode, size_t len,
+				  void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_cmd_read_reg_ops(flash, opcode, len, buf);
+}
+
+static int spi_flash_std_write_reg(struct udevice *dev, u8 opcode, size_t len,
+				   const void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_cmd_write_reg_ops(flash, opcode, len, buf);
+}
+
 static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
 			      void *buf)
 {
@@ -157,6 +173,8 @@ static int spi_flash_std_probe(struct udevice *dev)
 }
 
 static const struct dm_spi_flash_ops spi_flash_std_ops = {
+	.read_reg = spi_flash_std_read_reg,
+	.write_reg = spi_flash_std_write_reg,
 	.read = spi_flash_std_read,
 	.write = spi_flash_std_write,
 	.erase = spi_flash_std_erase,
drivers/mtd/spi/spi_flash.c +39 -31

143 lines not on this page · raw message

include/spi_flash.h +58 -0

94 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#10 lore raw

PATCH 10/18 sf: move support of SST flash into generic spi_flash_write_alg()

In reply to Cyrille Pitchen

This patch makes the support of SST flashes available to all UCLASS_SPI_FLASH drivers, not only the sf_probe.c one.

---
 drivers/mtd/spi/sf_internal.h |  8 ++---
 drivers/mtd/spi/sf_probe.c    |  9 -----
 drivers/mtd/spi/spi_flash.c   | 76 +++++++++++++++++++++++--------------------
 3 files changed, 43 insertions(+), 50 deletions(-)
drivers/mtd/spi/sf_internal.h +2 -6
index 15a5fa9c2afd..c5966fb37ac8 100644
@@ -51,7 +51,8 @@ enum {
 
 enum spi_nor_option_flags {
 	SNOR_F_SST_WR		= BIT(0),
-	SNOR_F_USE_FSR		= BIT(1),
+	SNOR_F_SST_WR_2ND	= BIT(1),
+	SNOR_F_USE_FSR		= BIT(2),
 };
 
 #define SPI_FLASH_3B_ADDR_LEN		3
@@ -118,11 +119,6 @@ enum spi_nor_option_flags {
 #ifdef CONFIG_SPI_FLASH_SST
 # define CMD_SST_BP		0x02    /* Byte Program */
 # define CMD_SST_AAI_WP		0xAD	/* Auto Address Incr Word Program */
-
-int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
-		const void *buf);
-int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
-		const void *buf);
 #endif
 
 /**
drivers/mtd/spi/sf_probe.c +0 -9
index fbd7d4740b51..837535fdb7a5 100644
@@ -140,15 +140,6 @@ static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
 {
 	struct spi_flash *flash = dev_get_uclass_priv(dev);
 
-#if defined(CONFIG_SPI_FLASH_SST)
-	if (flash->flags & SNOR_F_SST_WR) {
-		if (flash->spi->mode & SPI_TX_BYTE)
-			return sst_write_bp(flash, offset, len, buf);
-		else
-			return sst_write_wp(flash, offset, len, buf);
-	}
-#endif
-
 	return spi_flash_cmd_write_ops(flash, offset, len, buf);
 }
 
drivers/mtd/spi/spi_flash.c +41 -35

171 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#11 lore raw

PATCH 11/18 sf: fix selection of supported READ commands for QSPI memories

In reply to Cyrille Pitchen

It looks odd to compute a logical AND between the e_rd_cmd field of struct spi_flash_params and the mode_rx field of struct spi_slave.

Indeed, these two fields don't use the same range of values. mode_rx is limited to SPI_RX_{SLOW, FAST, DUAL, QUAD}. Even completed with the SPI_TX_{DUAL, QUAD} flags from the mode field, this is not enough to find out whether the SPI controller driver supports Fast Read 4-4-4 (Micron, Macronix, Winbond) commands.
With only the SPI_RX_QUAD and the SPI_TX_QUAD, how to make the difference between Fast Read 1-4-4 and Fast Read 4-4-4 ?

On the other hand, the e_rd_cmd field already provides a more accurate knowledge of the Fast Read commands supported by the SPI flash memory.

Then this patch provides a safe convertion from mode_rx + mode values into e_rd_cmd values to be used by the sf_probe.c driver: this driver never try using the Fast Read 4-4-4 command.
Other drivers will provide an exhaustive list of supported Fast Read commands.

Hence a more accurate op code is chosen according to both the SPI flash memory and the SPI controller capabilities.

Please note that we cannot simply extend the SPI_TX_* and SPI_RX_* flags of the struct spi_slave since they are set according DT properties shared with Linux: spi-tx-bus-width and spi-rx-bus-width.

These two DT properties don't allow us to make the difference between the SPI 1-4-4 and SPI 4-4-4 protocols.

---
 drivers/mtd/spi/sf_internal.h | 14 +++++++++++---
 drivers/mtd/spi/sf_params.c   | 32 ++++++++++++++++----------------
 drivers/mtd/spi/sf_probe.c    | 19 ++++++++++++++++++-
 drivers/mtd/spi/spi_flash.c   |  9 ++++++---
 4 files changed, 51 insertions(+), 23 deletions(-)
drivers/mtd/spi/sf_internal.h +11 -3
index c5966fb37ac8..8b8521369e4e 100644
@@ -29,12 +29,19 @@ enum spi_read_cmds {
 	QUAD_OUTPUT_FAST	= BIT(3),
 	DUAL_IO_FAST		= BIT(4),
 	QUAD_IO_FAST		= BIT(5),
+	DUAL_CMD_FAST		= BIT(6),
+	QUAD_CMD_FAST		= BIT(7),
 };
 
 /* Normal - Extended - Full command set */
 #define RD_NORM		(ARRAY_SLOW | ARRAY_FAST)
-#define RD_EXTN		(RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
-#define RD_FULL		(RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+#define RD_EXTN		(RD_NORM | DUAL_OUTPUT_FAST)
+#define RD_DUAL		(RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+#define RD_DCMD		(RD_DUAL | DUAL_CMD_FAST)
+#define RD_QUAD		(RD_NORM | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+#define RD_QCMD		(RD_QUAD | QUAD_CMD_FAST)
+#define RD_FULL		(RD_DUAL | RD_QUAD)
+#define RD_FCMD		(RD_DCMD | RD_QCMD)
 
 /* sf param flags */
 enum {
@@ -240,6 +247,7 @@ void spi_flash_mtd_unregister(void);
 /**
  * spi_flash_scan - scan the SPI FLASH
  * @flash:	the spi flash structure
+ * @e_rd_cmd:	Enum list for read commands supported by the SPI controller
  *
  * The drivers can use this fuction to scan the SPI FLASH.
  * In the scanning, it will try to get all the necessary information to
@@ -247,6 +255,6 @@ void spi_flash_mtd_unregister(void);
  *
  * Return: 0 for success, others for failure.
  */
-int spi_flash_scan(struct spi_flash *flash);
+int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd);
 
 #endif /* _SF_INTERNAL_H_ */
drivers/mtd/spi/sf_params.c +16 -16
index 4f37e33eb068..d3103dbc8742 100644
@@ -47,10 +47,10 @@ const struct spi_flash_params spi_flash_params_table[] = {
 	{"MX25L1605D",	   0xc22015, 0x0,	64 * 1024,    32, RD_NORM,			  0},
 	{"MX25L3205D",	   0xc22016, 0x0,	64 * 1024,    64, RD_NORM,			  0},
 	{"MX25L6405D",	   0xc22017, 0x0,	64 * 1024,   128, RD_NORM,			  0},
-	{"MX25L12805",	   0xc22018, 0x0,	64 * 1024,   256, RD_FULL,		     WR_QPP},
-	{"MX25L25635F",	   0xc22019, 0x0,	64 * 1024,   512, RD_FULL,		     WR_QPP},
-	{"MX25L51235F",	   0xc2201a, 0x0,	64 * 1024,  1024, RD_FULL,		     WR_QPP},
-	{"MX25L12855E",	   0xc22618, 0x0,	64 * 1024,   256, RD_FULL,		     WR_QPP},
+	{"MX25L12805",	   0xc22018, 0x0,	64 * 1024,   256, RD_QCMD,		     WR_QPP},
+	{"MX25L25635F",	   0xc22019, 0x0,	64 * 1024,   512, RD_QCMD,		     WR_QPP},
+	{"MX25L51235F",	   0xc2201a, 0x0,	64 * 1024,  1024, RD_QCMD,		     WR_QPP},
+	{"MX25L12855E",	   0xc22618, 0x0,	64 * 1024,   256, RD_QCMD,		     WR_QPP},
 #endif
 #ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */
 	{"S25FL008A",	   0x010213, 0x0,	64 * 1024,    16, RD_NORM,			  0},
@@ -83,18 +83,18 @@ const struct spi_flash_params spi_flash_params_table[] = {
 	{"M25P64",	   0x202017, 0x0,       64 * 1024,   128, RD_NORM,			  0},
 	{"M25P128",	   0x202018, 0x0,      256 * 1024,    64, RD_NORM,			  0},
 	{"M25PX64",	   0x207117, 0x0,       64 * 1024,   128, RD_NORM,		    SECT_4K},
-	{"N25Q32",	   0x20ba16, 0x0,       64 * 1024,    64, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q32A",	   0x20bb16, 0x0,       64 * 1024,    64, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q64",	   0x20ba17, 0x0,       64 * 1024,   128, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q64A",	   0x20bb17, 0x0,       64 * 1024,   128, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q128",	   0x20ba18, 0x0,       64 * 1024,   256, RD_FULL,		     WR_QPP},
-	{"N25Q128A",	   0x20bb18, 0x0,       64 * 1024,   256, RD_FULL,		     WR_QPP},
-	{"N25Q256",	   0x20ba19, 0x0,       64 * 1024,   512, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q256A",	   0x20bb19, 0x0,       64 * 1024,   512, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q512",	   0x20ba20, 0x0,       64 * 1024,  1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
-	{"N25Q512A",	   0x20bb20, 0x0,       64 * 1024,  1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
-	{"N25Q1024",	   0x20ba21, 0x0,       64 * 1024,  2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
-	{"N25Q1024A",	   0x20bb21, 0x0,       64 * 1024,  2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q32",	   0x20ba16, 0x0,       64 * 1024,    64, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q32A",	   0x20bb16, 0x0,       64 * 1024,    64, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q64",	   0x20ba17, 0x0,       64 * 1024,   128, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q64A",	   0x20bb17, 0x0,       64 * 1024,   128, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q128",	   0x20ba18, 0x0,       64 * 1024,   256, RD_FCMD,		     WR_QPP},
+	{"N25Q128A",	   0x20bb18, 0x0,       64 * 1024,   256, RD_FCMD,		     WR_QPP},
+	{"N25Q256",	   0x20ba19, 0x0,       64 * 1024,   512, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q256A",	   0x20bb19, 0x0,       64 * 1024,   512, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q512",	   0x20ba20, 0x0,       64 * 1024,  1024, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q512A",	   0x20bb20, 0x0,       64 * 1024,  1024, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q1024",	   0x20ba21, 0x0,       64 * 1024,  2048, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q1024A",	   0x20bb21, 0x0,       64 * 1024,  2048, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
 #endif
 #ifdef CONFIG_SPI_FLASH_SST		/* SST */
 	{"SST25VF040B",	   0xbf258d, 0x0,	64 * 1024,     8, RD_NORM,          SECT_4K | SST_WR},
drivers/mtd/spi/sf_probe.c +18 -1
index 837535fdb7a5..8a0345bc1994 100644
@@ -26,6 +26,7 @@
 static int spi_flash_probe_slave(struct spi_flash *flash)
 {
 	struct spi_slave *spi = flash->spi;
+	u8 mode_rx, e_rd_cmd;
 	int ret;
 
 	/* Setup spi_slave */
@@ -34,6 +35,22 @@ static int spi_flash_probe_slave(struct spi_flash *flash)
 		return -ENODEV;
 	}
 
+	/* Convert SPI mode_rx and mode to SPI flash read commands */
+	mode_rx = spi->mode_rx;
+	if (mode_rx & SPI_RX_QUAD) {
+		e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_QUAD)
+			e_rd_cmd |= QUAD_IO_FAST;
+	} else if (mode_rx & SPI_RX_DUAL) {
+		e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_DUAL)
+			e_rd_cmd |= DUAL_IO_FAST;
+	} else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+		e_rd_cmd = ARRAY_SLOW;
+	} else {
+		e_rd_cmd = RD_NORM;
+	}
+
 	/* Claim spi bus */
 	ret = spi_claim_bus(spi);
 	if (ret) {
@@ -41,7 +58,7 @@ static int spi_flash_probe_slave(struct spi_flash *flash)
 		return ret;
 	}
 
-	ret = spi_flash_scan(flash);
+	ret = spi_flash_scan(flash, e_rd_cmd);
 	if (ret)
 		goto err_read_id;
 
drivers/mtd/spi/spi_flash.c +6 -3
index 7f5341a87c07..5ba148bd3626 100644
@@ -987,7 +987,7 @@ int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
 }
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
-int spi_flash_scan(struct spi_flash *flash)
+int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 {
 	struct spi_slave *spi = flash->spi;
 	const struct spi_flash_params *params;
@@ -1000,7 +1000,10 @@ int spi_flash_scan(struct spi_flash *flash)
 		CMD_READ_DUAL_OUTPUT_FAST,
 		CMD_READ_QUAD_OUTPUT_FAST,
 		CMD_READ_DUAL_IO_FAST,
-		CMD_READ_QUAD_IO_FAST };
+		CMD_READ_QUAD_IO_FAST,
+		CMD_READ_DUAL_IO_FAST,	/* same op code as for DUAL_IO_FAST */
+		CMD_READ_QUAD_IO_FAST,	/* same op code as for QUAD_IO_FAST */
+	};
 
 	/* Assign spi_flash ops */
 #ifndef CONFIG_DM_SPI_FLASH
@@ -1115,7 +1118,7 @@ int spi_flash_scan(struct spi_flash *flash)
 	flash->sector_size = flash->erase_size;
 
 	/* Look for the fastest read cmd */
-	cmd = fls(params->e_rd_cmd & spi->mode_rx);
+	cmd = fls(params->e_rd_cmd & e_rd_cmd);
 	if (cmd) {
 		cmd = spi_read_cmds_array[cmd - 1];
 		flash->read_cmd = cmd;
Signature · 1 line
1.8.2.2
#12 lore raw

PATCH 12/18 sf: fix detection of QSPI memories when they boot in Quad or Dual mode

In reply to Cyrille Pitchen

The quad (or dual) mode of a SPI flash memory may be enabled at boot time by non-volatile bits in some setting register. Also such a mode may have already been enabled at early stage by some boot loader.

Hence, we should not guess the SPI flash memory is always configured for the regular SPI 1-1-1 protocol.

Micron and Macronix memories, once their Quad (or dual for Micron) mode enabled, no longer process the regular JEDEC Read ID (0x9f) command but instead reply to a new command: JEDEC Read ID Multiple I/O (0xaf). Besides, in Quad mode both memory manufacturers expect ALL commands to use the SPI 4-4-4 protocol. For Micron memories, enabling their Dual mode implies to use the SPI 2-2-2 protocol for ALL commands.

Winbond memories, once their Quad mode enabled, expect ALL commands to use the SPI 4-4-4 protocol. Unlike Micron and Macronix memories, they still reply to the regular JEDEC Read ID (0x9f) command but not the JEDEC Read ID Multiple I/O (0x9f) command.

---
 drivers/mtd/spi/sf_internal.h |  1 +
 drivers/mtd/spi/spi_flash.c   | 90 +++++++++++++++++++++++++++++++++----------
 include/spi_flash.h           | 45 ++++++++++++++++++++++
 3 files changed, 116 insertions(+), 20 deletions(-)
drivers/mtd/spi/sf_internal.h +1 -0
index 8b8521369e4e..26d359707d5b 100644
@@ -99,6 +99,7 @@ enum spi_nor_option_flags {
 #define CMD_READ_STATUS1		0x35
 #define CMD_READ_CONFIG			0x35
 #define CMD_FLAG_STATUS			0x70
+#define CMD_READ_ID_MIO			0xaf
 
 /* Bank addr access commands */
 #ifdef CONFIG_SPI_FLASH_BAR
drivers/mtd/spi/spi_flash.c +70 -20

112 lines not on this page · raw message

include/spi_flash.h +45 -0

63 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#13 lore raw

PATCH 13/18 sf: add helper function to set the number of dummy bytes

In reply to Cyrille Pitchen

This patch adds a helper function to ease the conversion between a number of dummy clock cycles and number of bytes.

Actually this number of bytes depends on both the number of dummy clock cycles and SPI protocol used by (Fast) Read commands.

This new function is exported so it can be used by other drivers.

---
 drivers/mtd/spi/sf_internal.h |  6 ++++++
 drivers/mtd/spi/spi_flash.c   | 11 +++++++++++
 2 files changed, 17 insertions(+)
drivers/mtd/spi/sf_internal.h +6 -0
index 26d359707d5b..86a0276f8518 100644
@@ -240,6 +240,12 @@ typedef int (*spi_flash_read_fn)(struct spi_flash *, u32, size_t, void *);
 int spi_flash_read_alg(struct spi_flash *flash, u32 offset, size_t len,
 		void *data, spi_flash_read_fn read_fn);
 
+/*
+ * Helper function to compute the number of dummy bytes from both the number
+ * of dummy cycles and the SPI protocol used for (Fast) Read operations.
+ */
+int spi_flash_set_dummy_byte(struct spi_flash *flash, u8 num_dummy_cycles);
+
 #ifdef CONFIG_SPI_FLASH_MTD
 int spi_flash_mtd_register(struct spi_flash *flash);
 void spi_flash_mtd_unregister(void);
drivers/mtd/spi/spi_flash.c +11 -0
index 5d641bbb8301..01a073d81eb9 100644
@@ -882,6 +882,17 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len)
 }
 #endif
 
+int spi_flash_set_dummy_byte(struct spi_flash *flash, u8 num_dummy_cycles)
+{
+	u8 dummy_bits = num_dummy_cycles;
+
+	dummy_bits *= SPI_FLASH_PROTO_ADR_FROM_PROTO(flash->read_proto);
+	if (dummy_bits & 0x7)
+		return -EINVAL;
+
+	flash->dummy_byte = dummy_bits >> 3;
+	return 0;
+}
 
 #ifdef CONFIG_SPI_FLASH_MACRONIX
 static int macronix_quad_enable(struct spi_flash *flash)
Signature · 1 line
1.8.2.2
#14 lore raw

PATCH 14/18 sf: add 4byte address opcodes

In reply to Cyrille Pitchen

This patch provides an alternative to support memory >16MiB (>128Mib). Indeed using the Base Address Register changes the internal state of the SPI flash memory. However some early boot loaders expect to access the first memory bank of the SPI flash. Then when another bank has been selected, those boot loader will fail to read the right data.

Using 4byte address opcodes doesn't change the internal state of the SPI flash memory but sill allows to access data above 16MiB.

---
 drivers/mtd/spi/Kconfig       | 18 ++++++++-
 drivers/mtd/spi/sf_internal.h | 17 +++++++-
 drivers/mtd/spi/spi_flash.c   | 93 +++++++++++++++++++++++++++++++++++++------
 include/spi_flash.h           |  2 +
 4 files changed, 114 insertions(+), 16 deletions(-)
drivers/mtd/spi/Kconfig +17 -1
index 3f7433cbc214..999c3176adee 100644
@@ -34,14 +34,30 @@ config SPI_FLASH
 
 	  If unsure, say N
 
+config SPI_FLASH_ABOVE_16MB
+	bool "Support of >16MB memories"
+	depends on SPI_FLASH
+	default n
+
+choice
+	prompt "Select >16MB method"
+	depends on SPI_FLASH_ABOVE_16MB
+
 config SPI_FLASH_BAR
 	bool "SPI flash Bank/Extended address register support"
-	depends on SPI_FLASH
 	help
 	  Enable the SPI flash Bank/Extended address register support.
 	  Bank/Extended address registers are used to access the flash
 	  which has size > 16MiB in 3-byte addressing.
 
+config SPI_FLASH_4B_OPCODES
+	bool "4-byte address op codes support"
+	help
+	  Replace regular 3-byte address op codes by thier 4-byte address
+	  version when the size of the memory if greater than 16MB.
+
+endchoice
+
 if SPI_FLASH
 
 config SPI_FLASH_ATMEL
drivers/mtd/spi/sf_internal.h +15 -2
index 86a0276f8518..a98c011218ce 100644
@@ -62,8 +62,8 @@ enum spi_nor_option_flags {
 	SNOR_F_USE_FSR		= BIT(2),
 };
 
-#define SPI_FLASH_3B_ADDR_LEN		3
-#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN)
+#define SPI_FLASH_4B_ADDR_LEN		4
+#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_4B_ADDR_LEN)
 #define SPI_FLASH_16MB_BOUN		0x1000000
 
 /* CFI Manufacture ID's */
@@ -79,6 +79,9 @@ enum spi_nor_option_flags {
 #define CMD_ERASE_32K			0x52
 #define CMD_ERASE_CHIP			0xc7
 #define CMD_ERASE_64K			0xd8
+#define CMD_ERASE_4K_4B			0x21
+#define CMD_ERASE_32K_4B		0x5c
+#define CMD_ERASE_64K_4B		0xdc
 
 /* Write commands */
 #define CMD_WRITE_STATUS		0x01
@@ -86,6 +89,10 @@ enum spi_nor_option_flags {
 #define CMD_WRITE_DISABLE		0x04
 #define CMD_WRITE_ENABLE		0x06
 #define CMD_QUAD_PAGE_PROGRAM		0x32
+#define CMD_QUAD_PAGE_PROGRAM_MXIC	0x38
+#define CMD_PAGE_PROGRAM_4B		0x12
+#define CMD_QUAD_PAGE_PROGRAM_4B	0x34
+#define CMD_QUAD_PAGE_PROGRAM_MXIC_4B	0x3e
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW		0x03
@@ -94,6 +101,12 @@ enum spi_nor_option_flags {
 #define CMD_READ_DUAL_IO_FAST		0xbb
 #define CMD_READ_QUAD_OUTPUT_FAST	0x6b
 #define CMD_READ_QUAD_IO_FAST		0xeb
+#define CMD_READ_ARRAY_SLOW_4B		0x13
+#define CMD_READ_ARRAY_FAST_4B		0x0c
+#define CMD_READ_DUAL_OUTPUT_FAST_4B	0x3c
+#define CMD_READ_DUAL_IO_FAST_4B	0xbc
+#define CMD_READ_QUAD_OUTPUT_FAST_4B	0x6c
+#define CMD_READ_QUAD_IO_FAST_4B	0xec
 #define CMD_READ_ID			0x9f
 #define CMD_READ_STATUS			0x05
 #define CMD_READ_STATUS1		0x35
drivers/mtd/spi/spi_flash.c +80 -13

147 lines not on this page · raw message

include/spi_flash.h +2 -0
index 945cc07ee8b2..5db06e5133f3 100644
@@ -88,6 +88,7 @@ enum spi_flash_protocol {
  * @read_proto		SPI protocol to be used by &read ops
  * @write_proto		SPI protocol to be used by &write ops
  * @erase_proto		SPI protocol to be used by &erase ops
+ * @addr_width		Number of address bytes (typically 3 or 4)
  * @memory_map:		Address of read-only SPI flash access
  * @flash_lock:		lock a region of the SPI Flash
  * @flash_unlock:	unlock a region of the SPI Flash
@@ -117,6 +118,7 @@ struct spi_flash {
 	u32 page_size;
 	u32 sector_size;
 	u32 erase_size;
+	u32 addr_width;
 #ifdef CONFIG_SPI_FLASH_BAR
 	u8 bank_read_cmd;
 	u8 bank_write_cmd;
Signature · 1 line
1.8.2.2
#15 lore raw

PATCH v2 14/18 sf: add 4byte address opcodes

This patch provides an alternative to support memory >16MiB (>128Mib). Indeed using the Base Address Register changes the internal state of the SPI flash memory. However some early boot loaders expect to access the first memory bank of the SPI flash. Then when another bank has been selected, those boot loader will fail to read the right data.

Using 4byte address opcodes doesn't change the internal state of the SPI flash memory but sill allows to access data above 16MiB.

---

ChangeLog:

v1 -> v2:
- add missing entry for PAGE PROGRAM op code

 drivers/mtd/spi/Kconfig       | 18 ++++++++-
 drivers/mtd/spi/sf_internal.h | 17 +++++++-
 drivers/mtd/spi/spi_flash.c   | 94 +++++++++++++++++++++++++++++++++++++------
 include/spi_flash.h           |  2 +
 4 files changed, 115 insertions(+), 16 deletions(-)
drivers/mtd/spi/Kconfig +17 -1
index 3f7433cbc214..999c3176adee 100644
@@ -34,14 +34,30 @@ config SPI_FLASH
 
 	  If unsure, say N
 
+config SPI_FLASH_ABOVE_16MB
+	bool "Support of >16MB memories"
+	depends on SPI_FLASH
+	default n
+
+choice
+	prompt "Select >16MB method"
+	depends on SPI_FLASH_ABOVE_16MB
+
 config SPI_FLASH_BAR
 	bool "SPI flash Bank/Extended address register support"
-	depends on SPI_FLASH
 	help
 	  Enable the SPI flash Bank/Extended address register support.
 	  Bank/Extended address registers are used to access the flash
 	  which has size > 16MiB in 3-byte addressing.
 
+config SPI_FLASH_4B_OPCODES
+	bool "4-byte address op codes support"
+	help
+	  Replace regular 3-byte address op codes by thier 4-byte address
+	  version when the size of the memory if greater than 16MB.
+
+endchoice
+
 if SPI_FLASH
 
 config SPI_FLASH_ATMEL
drivers/mtd/spi/sf_internal.h +15 -2
index 86a0276f8518..a98c011218ce 100644
@@ -62,8 +62,8 @@ enum spi_nor_option_flags {
 	SNOR_F_USE_FSR		= BIT(2),
 };
 
-#define SPI_FLASH_3B_ADDR_LEN		3
-#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN)
+#define SPI_FLASH_4B_ADDR_LEN		4
+#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_4B_ADDR_LEN)
 #define SPI_FLASH_16MB_BOUN		0x1000000
 
 /* CFI Manufacture ID's */
@@ -79,6 +79,9 @@ enum spi_nor_option_flags {
 #define CMD_ERASE_32K			0x52
 #define CMD_ERASE_CHIP			0xc7
 #define CMD_ERASE_64K			0xd8
+#define CMD_ERASE_4K_4B			0x21
+#define CMD_ERASE_32K_4B		0x5c
+#define CMD_ERASE_64K_4B		0xdc
 
 /* Write commands */
 #define CMD_WRITE_STATUS		0x01
@@ -86,6 +89,10 @@ enum spi_nor_option_flags {
 #define CMD_WRITE_DISABLE		0x04
 #define CMD_WRITE_ENABLE		0x06
 #define CMD_QUAD_PAGE_PROGRAM		0x32
+#define CMD_QUAD_PAGE_PROGRAM_MXIC	0x38
+#define CMD_PAGE_PROGRAM_4B		0x12
+#define CMD_QUAD_PAGE_PROGRAM_4B	0x34
+#define CMD_QUAD_PAGE_PROGRAM_MXIC_4B	0x3e
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW		0x03
@@ -94,6 +101,12 @@ enum spi_nor_option_flags {
 #define CMD_READ_DUAL_IO_FAST		0xbb
 #define CMD_READ_QUAD_OUTPUT_FAST	0x6b
 #define CMD_READ_QUAD_IO_FAST		0xeb
+#define CMD_READ_ARRAY_SLOW_4B		0x13
+#define CMD_READ_ARRAY_FAST_4B		0x0c
+#define CMD_READ_DUAL_OUTPUT_FAST_4B	0x3c
+#define CMD_READ_DUAL_IO_FAST_4B	0xbc
+#define CMD_READ_QUAD_OUTPUT_FAST_4B	0x6c
+#define CMD_READ_QUAD_IO_FAST_4B	0xec
 #define CMD_READ_ID			0x9f
 #define CMD_READ_STATUS			0x05
 #define CMD_READ_STATUS1		0x35
drivers/mtd/spi/spi_flash.c +81 -13

148 lines not on this page · raw message

include/spi_flash.h +2 -0
index 945cc07ee8b2..5db06e5133f3 100644
@@ -88,6 +88,7 @@ enum spi_flash_protocol {
  * @read_proto		SPI protocol to be used by &read ops
  * @write_proto		SPI protocol to be used by &write ops
  * @erase_proto		SPI protocol to be used by &erase ops
+ * @addr_width		Number of address bytes (typically 3 or 4)
  * @memory_map:		Address of read-only SPI flash access
  * @flash_lock:		lock a region of the SPI Flash
  * @flash_unlock:	unlock a region of the SPI Flash
@@ -117,6 +118,7 @@ struct spi_flash {
 	u32 page_size;
 	u32 sector_size;
 	u32 erase_size;
+	u32 addr_width;
 #ifdef CONFIG_SPI_FLASH_BAR
 	u8 bank_read_cmd;
 	u8 bank_write_cmd;
Signature · 1 line
1.8.2.2
#16 lore raw

PATCH 15/18 sf: prepare next fixes to support of QSPI memories by manufacturer

In reply to Cyrille Pitchen

This is just a transitional patch to add manufacturer dedicated support for QSPI memories.

Indeed, using Quad SPI protocols is slighty more complicated than simply enabling the Quad I/O or QPI mode. We should also take care about the number of dummy cycles. For instance, some Spansion QSPI memories use a factory default value of 6 dummy cycles.

Besides we have to care about the mode cycles: special kind of dummy cycles which make the SPI flash memory enter/leaver its Continuous Read/ Enhanced Performance mode. This mode is actually used by XIP operations but not relevant in the MTD layer. However we should prevent the SPI flash memory from entering Continuous Read mode by mistake. Depending on the manufacturer, it can be done by using the right Fast Read op code (Winbond) or by updating a dedicated bit in one configuration register (Micron).

Also the QSPI manufacturers don't support the exact same SPI protocols for Fast Read operations. We need to provide a mean to tune SPI protocols and the op codes by manufacturer.

For all these reasons, future patches are to come to add QSPI support by manufacturer. Till then, the legacy code is still used as a fallback implementation.

---
 drivers/mtd/spi/spi_flash.c | 155 ++++++++++++++++++++++++++++----------------
 1 file changed, 99 insertions(+), 56 deletions(-)
drivers/mtd/spi/spi_flash.c +99 -56
index b4a44e25f190..50250491d228 100644
@@ -1033,6 +1033,98 @@ static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
 	}
 }
 
+/* Transitional function to be removed */
+static int spi_flash_setup_deprecated(struct spi_flash *flash,
+				      const struct spi_flash_params *params,
+				      int best_match)
+{
+	struct spi_slave *spi = flash->spi;
+	u8 idcode0 = params->jedec >> 16;
+	u8 cmd;
+	int ret;
+	static u8 spi_read_cmds_array[] = {
+		CMD_READ_ARRAY_SLOW,
+		CMD_READ_ARRAY_FAST,
+		CMD_READ_DUAL_OUTPUT_FAST,
+		CMD_READ_QUAD_OUTPUT_FAST,
+		CMD_READ_DUAL_IO_FAST,
+		CMD_READ_QUAD_IO_FAST,
+		CMD_READ_DUAL_IO_FAST,	/* same op code as for DUAL_IO_FAST */
+		CMD_READ_QUAD_IO_FAST,	/* same op code as for QUAD_IO_FAST */
+	};
+
+	/* Look for the fastest read cmd */
+	if (best_match) {
+		cmd = spi_read_cmds_array[best_match - 1];
+		flash->read_cmd = cmd;
+	} else {
+		/* Go for default supported read cmd */
+		flash->read_cmd = CMD_READ_ARRAY_FAST;
+	}
+
+	/* Not require to look for fastest only two write cmds yet */
+	if (params->flags & WR_QPP && spi->mode & SPI_TX_QUAD)
+		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+	else
+		/* Go for default supported write cmd */
+		flash->write_cmd = CMD_PAGE_PROGRAM;
+
+	/* Set the quad enable bit - only for quad commands */
+	if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
+	    (flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
+	    (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
+		ret = set_quad_mode(flash, idcode0);
+		if (ret) {
+			debug("SF: Fail to set QEB for %02x\n", idcode0);
+			return -EINVAL;
+		}
+	}
+
+	/* Read dummy_byte: dummy byte is determined based on the
+	 * dummy cycles of a particular command.
+	 * Fast commands - dummy_byte = dummy_cycles/8
+	 * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8
+	 * For I/O commands except cmd[0] everything goes on no.of lines
+	 * based on particular command but incase of fast commands except
+	 * data all go on single line irrespective of command.
+	 */
+	switch (flash->read_cmd) {
+	case CMD_READ_QUAD_IO_FAST:
+		flash->dummy_byte = 2;
+		break;
+	case CMD_READ_ARRAY_SLOW:
+		flash->dummy_byte = 0;
+		break;
+	default:
+		flash->dummy_byte = 1;
+	}
+
+	return 0;
+}
+
+static int spi_flash_setup(struct spi_flash *flash,
+			   const struct spi_flash_params *params,
+			   u8 e_rd_cmd)
+{
+	int match = fls(params->e_rd_cmd & e_rd_cmd);
+
+	/*
+	 * The (Fast) Read and Page Program opcodes to be used depends on the
+	 * manufacturer.
+	 */
+	switch (params->jedec >> 16) {
+		/*
+		 * TODO: Manufacturer dedicated setup will be added HERE by
+		 * further patches.
+		 */
+
+	default:
+		return spi_flash_setup_deprecated(flash, params, match);
+	}
+
+	return 0;
+}
+
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
 {
@@ -1090,18 +1182,8 @@ int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 	const struct spi_flash_params *params;
 	const struct spi_flash_read_id_config *cfg;
 	u16 jedec, ext_jedec;
-	u8 cmd, idcode[5];
+	u8 idcode[5];
 	int ret;
-	static u8 spi_read_cmds_array[] = {
-		CMD_READ_ARRAY_SLOW,
-		CMD_READ_ARRAY_FAST,
-		CMD_READ_DUAL_OUTPUT_FAST,
-		CMD_READ_QUAD_OUTPUT_FAST,
-		CMD_READ_DUAL_IO_FAST,
-		CMD_READ_QUAD_IO_FAST,
-		CMD_READ_DUAL_IO_FAST,	/* same op code as for DUAL_IO_FAST */
-		CMD_READ_QUAD_IO_FAST,	/* same op code as for QUAD_IO_FAST */
-	};
 
 	/* Assign spi_flash ops */
 #ifndef CONFIG_DM_SPI_FLASH
@@ -1238,52 +1320,13 @@ int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 	/* Now erase size becomes valid sector size */
 	flash->sector_size = flash->erase_size;
 
-	/* Look for the fastest read cmd */
-	cmd = fls(params->e_rd_cmd & e_rd_cmd);
-	if (cmd) {
-		cmd = spi_read_cmds_array[cmd - 1];
-		flash->read_cmd = cmd;
-	} else {
-		/* Go for default supported read cmd */
-		flash->read_cmd = CMD_READ_ARRAY_FAST;
-	}
-
-	/* Not require to look for fastest only two write cmds yet */
-	if (params->flags & WR_QPP && spi->mode & SPI_TX_QUAD)
-		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
-	else
-		/* Go for default supported write cmd */
-		flash->write_cmd = CMD_PAGE_PROGRAM;
-
-	/* Set the quad enable bit - only for quad commands */
-	if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
-	    (flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
-	    (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
-		ret = set_quad_mode(flash, idcode[0]);
-		if (ret) {
-			debug("SF: Fail to set QEB for %02x\n", idcode[0]);
-			return -EINVAL;
-		}
-	}
-
-	/* Read dummy_byte: dummy byte is determined based on the
-	 * dummy cycles of a particular command.
-	 * Fast commands - dummy_byte = dummy_cycles/8
-	 * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8
-	 * For I/O commands except cmd[0] everything goes on no.of lines
-	 * based on particular command but incase of fast commands except
-	 * data all go on single line irrespective of command.
+	/*
+	 * Setup (Fast) Read & Page Program opcode and protocols.
+	 * Also set the right number of dummy/mode cycles.
 	 */
-	switch (flash->read_cmd) {
-	case CMD_READ_QUAD_IO_FAST:
-		flash->dummy_byte = 2;
-		break;
-	case CMD_READ_ARRAY_SLOW:
-		flash->dummy_byte = 0;
-		break;
-	default:
-		flash->dummy_byte = 1;
-	}
+	ret = spi_flash_setup(flash, params, e_rd_cmd);
+	if (ret < 0)
+		return ret;
 
 #ifdef CONFIG_SPI_FLASH_STMICRO
 	if (params->flags & E_FSR)
Signature · 1 line
1.8.2.2
#17 lore raw

PATCH 16/18 sf: fix support of Micron memories

In reply to Cyrille Pitchen

This patch provides support of Micron QSPI memories.

---
 drivers/mtd/spi/Makefile      |   1 +
 drivers/mtd/spi/sf_internal.h |  24 +++++
 drivers/mtd/spi/sf_micron.c   | 222 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/spi_flash.c   |  13 +--
 4 files changed, 251 insertions(+), 9 deletions(-)
 create mode 100644 drivers/mtd/spi/sf_micron.c
drivers/mtd/spi/Makefile +1 -0
index c665836f9560..90266d619ddf 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o
 endif
 
 obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o sf_params.o sf.o
+obj-$(CONFIG_SPI_FLASH_STMICRO) += sf_micron.o
 obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
 obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
 obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
drivers/mtd/spi/sf_internal.h +24 -0
index a98c011218ce..afee8b69ca6b 100644
@@ -142,6 +142,24 @@ enum spi_nor_option_flags {
 # define CMD_SST_AAI_WP		0xAD	/* Auto Address Incr Word Program */
 #endif
 
+/* Micron specific */
+#ifdef CONFIG_SPI_FLASH_STMICRO
+
+/* Volatile Configuration Register (VCR) */
+#define CMD_MICRON_WR_VCR	0x81
+#define CMD_MICRON_RD_VCR	0x85
+#define MICRON_VCR_XIP		BIT(3)
+#define MICRON_VCR_DUMMIES	0xf0
+#define MICRON_VCR_DUMMIES_(x)	(((x) << 4) & MICRON_VCR_DUMMIES)
+
+/* Enhanced Volatile Configuraiton Register (EVCR) */
+#define CMD_MICRON_WR_EVCR	0x61
+#define CMD_MICRON_RD_EVCR	0x65
+#define MICRON_EVCR_QUAD_DIS	BIT(7)
+#define MICRON_EVCR_DUAL_DIS	BIT(6)
+#endif
+
+
 /**
  * struct spi_flash_params - SPI/QSPI flash device params structure
  *
@@ -264,6 +282,12 @@ int spi_flash_mtd_register(struct spi_flash *flash);
 void spi_flash_mtd_unregister(void);
 #endif
 
+#ifdef CONFIG_SPI_FLASH_STMICRO
+int spi_flash_setup_micron(struct spi_flash *flash,
+			   const struct spi_flash_params *params,
+			   int best_match);
+#endif
+
 /**
  * spi_flash_scan - scan the SPI FLASH
  * @flash:	the spi flash structure
drivers/mtd/spi/sf_micron.c new file +222 -0

222 lines not on this page · raw message

drivers/mtd/spi/spi_flash.c +4 -9
index 50250491d228..922afc811a0b 100644
@@ -1022,11 +1022,6 @@ static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
 	case SPI_FLASH_CFI_MFR_WINBOND:
 		return spansion_quad_enable(flash);
 #endif
-#ifdef CONFIG_SPI_FLASH_STMICRO
-	case SPI_FLASH_CFI_MFR_STMICRO:
-		debug("SF: QEB is volatile for %02x flash\n", idcode0);
-		return 0;
-#endif
 	default:
 		printf("SF: Need set QEB func for %02x flash\n", idcode0);
 		return -1;
@@ -1113,10 +1108,10 @@ static int spi_flash_setup(struct spi_flash *flash,
 	 * manufacturer.
 	 */
 	switch (params->jedec >> 16) {
-		/*
-		 * TODO: Manufacturer dedicated setup will be added HERE by
-		 * further patches.
-		 */
+#ifdef CONFIG_SPI_FLASH_STMICRO
+	case SPI_FLASH_CFI_MFR_STMICRO:
+		return spi_flash_setup_micron(flash, params, match);
+#endif
 
 	default:
 		return spi_flash_setup_deprecated(flash, params, match);
Signature · 1 line
1.8.2.2
#18 lore raw

PATCH 17/18 ARM: at91: clock: add function to get QSPI clocks

In reply to Cyrille Pitchen

Add the new get_qpsi_clk_rate() function which will be needed by the future Atmel QSPI controller driver.

---
 arch/arm/mach-at91/include/mach/clk.h | 5 +++++
 1 file changed, 5 insertions(+)
arch/arm/mach-at91/include/mach/clk.h +5 -0
index 8577c74b47b7..aba7656e72f7 100644
@@ -99,6 +99,11 @@ static inline unsigned long get_spi_clk_rate(unsigned int dev_id)
 		return get_mck_clk_rate();
 }
 
+static inline unsigned long get_qspi_clk_rate(unsigned int dev_id)
+{
+	return get_mck_clk_rate();
+}
+
 static inline unsigned long get_twi_clk_rate(unsigned int dev_id)
 {
 	if (get_h32mxdiv())
Signature · 1 line
1.8.2.2
#19 lore raw

PATCH 18/18 sf: add driver for Atmel QSPI controller

In reply to Cyrille Pitchen

This patch adds support of the Atmel QSPI controller.

---
 drivers/mtd/spi/Makefile           |   1 +
 drivers/mtd/spi/atmel_qspi_flash.c | 432 +++++++++++++++++++++++++++++++++++++
 drivers/spi/Kconfig                |   9 +
 drivers/spi/Makefile               |   1 +
 drivers/spi/atmel_qspi.c           | 150 +++++++++++++
 drivers/spi/atmel_qspi.h           | 145 +++++++++++++
 6 files changed, 738 insertions(+)
 create mode 100644 drivers/mtd/spi/atmel_qspi_flash.c
 create mode 100644 drivers/spi/atmel_qspi.c
 create mode 100644 drivers/spi/atmel_qspi.h
drivers/mtd/spi/Makefile +1 -0
index 90266d619ddf..207e1d556f3f 100644
@@ -17,3 +17,4 @@ obj-$(CONFIG_SPI_FLASH_STMICRO) += sf_micron.o
 obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
 obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
 obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
+obj-$(CONFIG_ATMEL_QSPI) += atmel_qspi_flash.o
drivers/mtd/spi/atmel_qspi_flash.c new file +432 -0

432 lines not on this page · raw message

drivers/spi/Kconfig +9 -0
index f0258f84afeb..d478c5d953c6 100644
@@ -23,6 +23,15 @@ config ALTERA_SPI
 	  IP core. Please find details on the "Embedded Peripherals IP
 	  User Guide" of Altera.
 
+config ATMEL_QSPI
+	bool "Atmel QSPI driver"
+	depends on ARCH_AT91
+	select SPI_FLASH
+	select DM_SPI_FLASH
+	help
+	  Enable the Ateml Quad-SPI (QSPI) driver. This driver can only be
+	  used to access SPI NOR flashes.
+
 config CADENCE_QSPI
 	bool "Cadence QSPI driver"
 	help
drivers/spi/Makefile +1 -0
index 3eca7456d6a6..eb3bd95f5ee7 100644
@@ -18,6 +18,7 @@ endif
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
 obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
 obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
+obj-$(CONFIG_ATMEL_QSPI) += atmel_qspi.o
 obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
 obj-$(CONFIG_BFIN_SPI) += bfin_spi.o
 obj-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
drivers/spi/atmel_qspi.c new file +150 -0

150 lines not on this page · raw message

drivers/spi/atmel_qspi.h new file +145 -0

145 lines not on this page · raw message

Signature · 1 line
1.8.2.2
#20 lore raw

cover sf: fix support of QSPI memories and controllers

In reply to Cyrille Pitchen
Quoted 26 lines · Cyrille Pitchen

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1]
http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

#21 lore raw

cover sf: fix support of QSPI memories and controllers

Quoted 36 lines · Jagan Teki
Quoted 26 lines · Cyrille Pitchen

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 6 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1]
http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

The patchset seems to be in a sensible shape to me, so maybe we should do it the other way around -- get this in and have you rebase your V6(?) patchset on top of it -- since clearly your patchset will take some more time to ripe.

Signature · 2 lines
Best regards,
Marek Vasut
#22 lore raw

cover sf: fix support of QSPI memories and controllers

In reply to Jagan Teki

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 36 lines · Cyrille Pitchen
Quoted 26 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 4 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few comments:

Globally I see the new code attend to match the spi-nor framework from Linux. OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit to add support to Micron QSPI memories was reverted since it didn't work alone. In his reply, Brian agreed the code was not tested and should not have been merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol change at the QSPI memory side. This applies to Micron memories when they enter their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the .read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command op code. Indeed, taking the Micron case as un example, the very same 0xeb op code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles (if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to during Fast Read operations to make the memory enter/leaver its Continuous Read mode. Once is Continuous Read mode, the op code byte is no longer sent, it is implicit and the command actually starts from the address cycles. This mode is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by updating the relevant bit in some configuration register (e.g. setting the XIP bit in Micron Volatile Configuration Register) or by choosing the right op code (e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not already enabled. This not always true, some early bootloarders, such as the sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities, the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4 protocols. Maybe some SPI controllers support the first protocol but not the latest. It could be good to add another argument to spi_nor_scan() providing an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI memory and select the proper protocol, this new argument should use the same range of values as the .flash_read field in the struct spi_nor_info used to describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

	/* Convert SPI mode_rx and mode to SPI flash read commands */

+ mode_rx = spi->mode_rx;
+ if (mode_rx & SPI_RX_QUAD) {
+ e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+ if (spi->mode & SPI_TX_QUAD)
+ e_rd_cmd |= QUAD_IO_FAST;
+ } else if (mode_rx & SPI_RX_DUAL) {
+ e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+ if (spi->mode & SPI_TX_DUAL)
+ e_rd_cmd |= DUAL_IO_FAST;
+ } else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+ e_rd_cmd = ARRAY_SLOW;
+ } else {
+ e_rd_cmd = RD_NORM;
+ }
+
[...]
- ret = spi_flash_scan(flash);
+ ret = spi_flash_scan(flash, e_rd_cmd);

I've spent a lot of time working on the QSPI memory topic so I can tell you that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support, please let me know.

Best regards,

Cyrille

[1] http://lists.infradead.org/pipermail/linux-mtd/2016-February/065371.html

#23 lore raw

cover sf: fix support of QSPI memories and controllers

Quoted 151 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 36 lines · Cyrille Pitchen
Quoted 26 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 4 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few comments:

Globally I see the new code attend to match the spi-nor framework from Linux. OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit to add support to Micron QSPI memories was reverted since it didn't work alone. In his reply, Brian agreed the code was not tested and should not have been merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol change at the QSPI memory side. This applies to Micron memories when they enter their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the .read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command op code. Indeed, taking the Micron case as un example, the very same 0xeb op code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles (if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to during Fast Read operations to make the memory enter/leaver its Continuous Read mode. Once is Continuous Read mode, the op code byte is no longer sent, it is implicit and the command actually starts from the address cycles. This mode is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by updating the relevant bit in some configuration register (e.g. setting the XIP bit in Micron Volatile Configuration Register) or by choosing the right op code (e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not already enabled. This not always true, some early bootloarders, such as the sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities, the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4 protocols. Maybe some SPI controllers support the first protocol but not the latest. It could be good to add another argument to spi_nor_scan() providing an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI memory and select the proper protocol, this new argument should use the same range of values as the .flash_read field in the struct spi_nor_info used to describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

	/* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+	mode_rx = spi->mode_rx;
+	if (mode_rx & SPI_RX_QUAD) {
+		e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_QUAD)
+			e_rd_cmd |= QUAD_IO_FAST;
+	} else if (mode_rx & SPI_RX_DUAL) {
+		e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_DUAL)
+			e_rd_cmd |= DUAL_IO_FAST;
+	} else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+		e_rd_cmd = ARRAY_SLOW;
+	} else {
+		e_rd_cmd = RD_NORM;
+	}
+
[...]
-	ret = spi_flash_scan(flash);
+	ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 4 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support, please let me know.

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

Signature · 1 line
Jagan
#24 lore raw

cover sf: fix support of QSPI memories and controllers

Hello Jagan,

Quoted 163 lines · Jagan Teki
Quoted 151 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 36 lines · Cyrille Pitchen
Quoted 26 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 4 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few comments:

Globally I see the new code attend to match the spi-nor framework from Linux. OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit to add support to Micron QSPI memories was reverted since it didn't work alone. In his reply, Brian agreed the code was not tested and should not have been merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol change at the QSPI memory side. This applies to Micron memories when they enter their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the .read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command op code. Indeed, taking the Micron case as un example, the very same 0xeb op code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles (if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to during Fast Read operations to make the memory enter/leaver its Continuous Read mode. Once is Continuous Read mode, the op code byte is no longer sent, it is implicit and the command actually starts from the address cycles. This mode is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by updating the relevant bit in some configuration register (e.g. setting the XIP bit in Micron Volatile Configuration Register) or by choosing the right op code (e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not already enabled. This not always true, some early bootloarders, such as the sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities, the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4 protocols. Maybe some SPI controllers support the first protocol but not the latest. It could be good to add another argument to spi_nor_scan() providing an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI memory and select the proper protocol, this new argument should use the same range of values as the .flash_read field in the struct spi_nor_info used to describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

	/* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+	mode_rx = spi->mode_rx;
+	if (mode_rx & SPI_RX_QUAD) {
+		e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_QUAD)
+			e_rd_cmd |= QUAD_IO_FAST;
+	} else if (mode_rx & SPI_RX_DUAL) {
+		e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_DUAL)
+			e_rd_cmd |= DUAL_IO_FAST;
+	} else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+		e_rd_cmd = ARRAY_SLOW;
+	} else {
+		e_rd_cmd = RD_NORM;
+	}
+
[...]
-	ret = spi_flash_scan(flash);
+	ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 4 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support, please let me know.

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

Quoted 2 lines

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

If I understand Cyrille's post correctly, it is not about better tuning, it is about fixing existing issues, right? I mean, Cyrille is talking about situations where the code will be not simply slow, but plain wrong, correct?

If so, and since it appears Cyrills's patch series are bug fixes which the framework would not properly work if it did not integrate them anyway, I would agree with Marek that it makes more sense applying Cyrille's patches first.

Quoted 2 lines
Signature · 1 line
Jagan

Amicalement,

Signature · 1 line
Albert.
#25 lore raw

cover sf: fix support of QSPI memories and controllers

Hi Albert,

Quoted 175 lines · Albert ARIBAUD

Hello Jagan,

Quoted 163 lines · Jagan Teki
Quoted 151 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 36 lines · Cyrille Pitchen
Quoted 26 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 4 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few comments:

Globally I see the new code attend to match the spi-nor framework from Linux. OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit to add support to Micron QSPI memories was reverted since it didn't work alone. In his reply, Brian agreed the code was not tested and should not have been merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol change at the QSPI memory side. This applies to Micron memories when they enter their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the

    .read_mmap() also.

- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command op code. Indeed, taking the Micron case as un example, the very same 0xeb op code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles (if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to during Fast Read operations to make the memory enter/leaver its Continuous Read mode. Once is Continuous Read mode, the op code byte is no longer sent, it is implicit and the command actually starts from the address cycles. This mode is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by updating the relevant bit in some configuration register (e.g. setting the XIP bit in Micron Volatile Configuration Register) or by choosing the right op code (e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not already enabled. This not always true, some early bootloarders, such as the sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities, the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4 protocols. Maybe some SPI controllers support the first protocol but not the latest. It could be good to add another argument to spi_nor_scan() providing an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI memory and select the proper protocol, this new argument should use the same range of values as the .flash_read field in the struct spi_nor_info used to describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

	/* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+	mode_rx = spi->mode_rx;
+	if (mode_rx & SPI_RX_QUAD) {
+		e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_QUAD)
+			e_rd_cmd |= QUAD_IO_FAST;
+	} else if (mode_rx & SPI_RX_DUAL) {
+		e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_DUAL)
+			e_rd_cmd |= DUAL_IO_FAST;
+	} else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+		e_rd_cmd = ARRAY_SLOW;
+	} else {
+		e_rd_cmd = RD_NORM;
+	}
+
[...]
-	ret = spi_flash_scan(flash);
+	ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 4 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support, please let me know.

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

Quoted 2 lines

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

If I understand Cyrille's post correctly, it is not about better tuning, it is about fixing existing issues, right? I mean, Cyrille is talking about situations where the code will be not simply slow, but plain wrong, correct?

Quoted 4 lines

If so, and since it appears Cyrills's patch series are bug fixes which the framework would not properly work if it did not integrate them anyway, I would agree with Marek that it makes more sense applying Cyrille's patches first.

OK, if these are bug fixes then what is the issue on working on top of spi-nor? and more over this series is on ML just now and need a proper review as well and will take some time too. I have planned spi-nor series for this release better work on this series - thanks!

Signature · 1 line
Jagan
#26 lore raw

cover sf: fix support of QSPI memories and controllers

Hello Jagan,

Quoted 178 lines · Jagan Teki

Hi Albert,

Quoted 175 lines · Albert ARIBAUD

Hello Jagan,

Quoted 163 lines · Jagan Teki
Quoted 151 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 36 lines · Cyrille Pitchen
Quoted 26 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 4 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few comments:

Globally I see the new code attend to match the spi-nor framework from Linux. OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit to add support to Micron QSPI memories was reverted since it didn't work alone. In his reply, Brian agreed the code was not tested and should not have been merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol change at the QSPI memory side. This applies to Micron memories when they enter their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the

    .read_mmap() also.

- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command op code. Indeed, taking the Micron case as un example, the very same 0xeb op code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles (if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to during Fast Read operations to make the memory enter/leaver its Continuous Read mode. Once is Continuous Read mode, the op code byte is no longer sent, it is implicit and the command actually starts from the address cycles. This mode is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by updating the relevant bit in some configuration register (e.g. setting the XIP bit in Micron Volatile Configuration Register) or by choosing the right op code (e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not already enabled. This not always true, some early bootloarders, such as the sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities, the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4 protocols. Maybe some SPI controllers support the first protocol but not the latest. It could be good to add another argument to spi_nor_scan() providing an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI memory and select the proper protocol, this new argument should use the same range of values as the .flash_read field in the struct spi_nor_info used to describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

	/* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+	mode_rx = spi->mode_rx;
+	if (mode_rx & SPI_RX_QUAD) {
+		e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_QUAD)
+			e_rd_cmd |= QUAD_IO_FAST;
+	} else if (mode_rx & SPI_RX_DUAL) {
+		e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_DUAL)
+			e_rd_cmd |= DUAL_IO_FAST;
+	} else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+		e_rd_cmd = ARRAY_SLOW;
+	} else {
+		e_rd_cmd = RD_NORM;
+	}
+
[...]
-	ret = spi_flash_scan(flash);
+	ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 4 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support, please let me know.

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

Quoted 2 lines

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

If I understand Cyrille's post correctly, it is not about better tuning, it is about fixing existing issues, right? I mean, Cyrille is talking about situations where the code will be not simply slow, but plain wrong, correct?

Quoted 7 lines
Quoted 4 lines

If so, and since it appears Cyrills's patch series are bug fixes which the framework would not properly work if it did not integrate them anyway, I would agree with Marek that it makes more sense applying Cyrille's patches first.

OK, if these are bug fixes then what is the issue on working on top of spi-nor?

I believe you said spi-nor is not going to be submitted again until a couple of weeks, and then there will be a review period; that may not fit 2016.05. Cyrille's fixes could go out of the review phase before spi-nor does, and possibly even be ready for 2016.05.

Quoted 2 lines

and more over this series is on ML just now and need a proper review as well and will take some time too.

Yes, but non-structural bugfixes are easier and quicker to test than structural changes (which btw won't be entirely testable until the bug fixes are applied IIUC).

Quoted 2 lines

I have planned spi-nor
series for this release better work on this series - thanks!

But if spi-nor is released in 2016.05 without Cyrille's patches, there will be known bugs unfixed, right?

Quoted 2 lines
Signature · 1 line
Jagan

Amicalement,

Signature · 1 line
Albert.
#27 lore raw

cover sf: fix support of QSPI memories and controllers

In reply to Jagan Teki

Le 16/03/2016 15:14, Jagan Teki a ?crit :

Quoted 152 lines · Cyrille Pitchen
Quoted 151 lines

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 36 lines · Cyrille Pitchen
Quoted 26 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()

Quoted 8 lines

sf: fix selection of supported READ commands for QSPI memories
sf: fix detection of QSPI memories when they boot in Quad or Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 4 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few comments:

Globally I see the new code attend to match the spi-nor framework from Linux. OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit to add support to Micron QSPI memories was reverted since it didn't work alone. In his reply, Brian agreed the code was not tested and should not have been merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol change at the QSPI memory side. This applies to Micron memories when they enter their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the .read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command op code. Indeed, taking the Micron case as un example, the very same 0xeb op code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles (if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to during Fast Read operations to make the memory enter/leaver its Continuous Read mode. Once is Continuous Read mode, the op code byte is no longer sent, it is implicit and the command actually starts from the address cycles. This mode is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by updating the relevant bit in some configuration register (e.g. setting the XIP bit in Micron Volatile Configuration Register) or by choosing the right op code (e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not already enabled. This not always true, some early bootloarders, such as the sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities, the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4 protocols. Maybe some SPI controllers support the first protocol but not the latest. It could be good to add another argument to spi_nor_scan() providing an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI memory and select the proper protocol, this new argument should use the same range of values as the .flash_read field in the struct spi_nor_info used to describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

    /* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+    mode_rx = spi->mode_rx;
+    if (mode_rx & SPI_RX_QUAD) {
+        e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_QUAD)
+            e_rd_cmd |= QUAD_IO_FAST;
+    } else if (mode_rx & SPI_RX_DUAL) {
+        e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_DUAL)
+            e_rd_cmd |= DUAL_IO_FAST;
+    } else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+        e_rd_cmd = ARRAY_SLOW;
+    } else {
+        e_rd_cmd = RD_NORM;
+    }
+
[...]
-    ret = spi_flash_scan(flash);
+    ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 9 lines
Quoted 4 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support, please let me know.

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

OK, no problem!

I will just send the additional patches I used to test with the sama5d2 xplained board.
They are not related with the spi_flash/spi-nor framework itself but they are part of a WIP update of the sama5d2_xplained board support. If some people need those patches to unblock their own developments using QSPI memories on sama5d2 SoCs, all the material will be available :)

Best regards,

Cyrille

#28 lore raw

PATCH 1/4 rework board config files

---
 board/atmel/sama5d2_xplained/Kconfig            | 14 ++++++++++++++
 board/atmel/sama5d2_xplained/sama5d2_xplained.c | 14 +++++++++-----
 drivers/mmc/Kconfig                             |  6 ++++++
 include/configs/at91-sama5_common.h             | 10 ++++++++++
 include/configs/sama5d2_xplained.h              | 15 ++-------------
 5 files changed, 41 insertions(+), 18 deletions(-)
board/atmel/sama5d2_xplained/Kconfig +14 -0
index 55712e97454b..d4106b90f599 100644
@@ -12,4 +12,18 @@ config SYS_SOC
 config SYS_CONFIG_NAME
 	default "sama5d2_xplained"
 
+config ATMEL_SPI0
+	bool "SPI0"
+	default y
+
+config ATMEL_SDHCI0
+	bool "SDHCI0"
+	select ATMEL_SDHCI
+	default y
+
+config ATMEL_SDHCI1
+	bool "SDHCI1"
+	select ATMEL_SDHCI
+	default y
+
 endif
board/atmel/sama5d2_xplained/sama5d2_xplained.c +9 -5
index 10edf28a9bd6..4dd83e5e991f 100644
@@ -25,6 +25,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_DM_SPI
 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 {
 	return bus == 0 && cs == 0;
@@ -39,7 +40,9 @@ void spi_cs_deactivate(struct spi_slave *slave)
 {
 	atmel_pio4_set_pio_output(AT91_PIO_PORTA, 17, 1);
 }
+#endif
 
+#ifdef CONFIG_ATMEL_SPI0
 static void board_spi0_hw_init(void)
 {
 	atmel_pio4_set_a_periph(AT91_PIO_PORTA, 14, 0);
@@ -50,6 +53,7 @@ static void board_spi0_hw_init(void)
 
 	at91_periph_clk_enable(ATMEL_ID_SPI0);
 }
+#endif
 
 static void board_usb_hw_init(void)
 {
@@ -157,6 +161,7 @@ static void board_gmac_hw_init(void)
 	at91_periph_clk_enable(ATMEL_ID_GMAC);
 }
 
+#ifdef CONFIG_ATMEL_SDHCI0
 static void board_sdhci0_hw_init(void)
 {
 	atmel_pio4_set_a_periph(AT91_PIO_PORTA, 0, 0);	/* SDMMC0_CK */
@@ -176,7 +181,9 @@ static void board_sdhci0_hw_init(void)
 	at91_enable_periph_generated_clk(ATMEL_ID_SDMMC0,
 					 GCK_CSS_PLLA_CLK, 1);
 }
+#endif
 
+#ifdef CONFIG_ATMEL_SDHCI1
 static void board_sdhci1_hw_init(void)
 {
 	atmel_pio4_set_e_periph(AT91_PIO_PORTA, 18, 0);	/* SDMMC1_DAT0 */
@@ -192,6 +199,7 @@ static void board_sdhci1_hw_init(void)
 	at91_enable_periph_generated_clk(ATMEL_ID_SDMMC1,
 					 GCK_CSS_PLLA_CLK, 1);
 }
+#endif
 
 int board_mmc_init(bd_t *bis)
 {
@@ -230,17 +238,15 @@ int board_init(void)
 	/* address of boot parameters */
 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
 
-#ifdef CONFIG_ATMEL_SPI
+#ifdef CONFIG_ATMEL_SPI0
 	board_spi0_hw_init();
 #endif
-#ifdef CONFIG_ATMEL_SDHCI
 #ifdef CONFIG_ATMEL_SDHCI0
 	board_sdhci0_hw_init();
 #endif
 #ifdef CONFIG_ATMEL_SDHCI1
 	board_sdhci1_hw_init();
 #endif
-#endif
 #ifdef CONFIG_MACB
 	board_gmac_hw_init();
 #endif
@@ -289,14 +295,12 @@ void spl_board_init(void)
 #ifdef CONFIG_SYS_USE_SERIALFLASH
 	board_spi0_hw_init();
 #endif
-#ifdef CONFIG_ATMEL_SDHCI
 #ifdef CONFIG_ATMEL_SDHCI0
 	board_sdhci0_hw_init();
 #endif
 #ifdef CONFIG_ATMEL_SDHCI1
 	board_sdhci1_hw_init();
 #endif
-#endif
 }
 
 static void ddrc_conf(struct atmel_mpddrc_config *ddrc)
drivers/mmc/Kconfig +6 -0
index dc8532fe9373..b3d085119ac8 100644
@@ -49,4 +49,10 @@ config MMC_UNIPHIER
 	help
 	  This selects support for the SD/MMC Host Controller on UniPhier SoCs.
 
+config ATMEL_SDHCI
+	bool "Atmel SD Host Controller Interface"
+	depends on ARCH_AT91
+	help
+	  This enables support for the Atmel SD/eMMC controller
+
 endmenu
include/configs/at91-sama5_common.h +10 -0
index 6525b5c3701e..0297fd781dc6 100644
@@ -104,6 +104,16 @@
 					"sf read 0x21000000 0x60000 0xc000; "	\
 					"sf read 0x22000000 0x6c000 0x394000; "	\
 					"bootz 0x22000000 - 0x21000000"
+#elif CONFIG_SYS_USE_QSPIFLASH
+/* u-boot env in QSPI flash, by default is bus 0 and cs 0  */
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_OFFSET		0x10000
+#define CONFIG_ENV_SIZE			0x10000
+#define CONFIG_ENV_SECT_SIZE		0x10000
+#define CONFIG_BOOTCOMMAND		"sf probe 0; "                          \
+					"sf read 0x21000000 0x60000 0x10000; "  \
+					"sf read 0x22000000 0x70000 0x500000; " \
+					"bootz 0x22000000 - 0x21000000"
 #endif
 
 #endif
include/configs/sama5d2_xplained.h +2 -13
index 272257ea0edd..3391a0ea5b45 100644
@@ -16,6 +16,8 @@
 #include "at91-sama5_common.h"
 
 /* serial console */
+#undef CONFIG_BAUDRATE
+#define CONFIG_BAUDRATE			57600
 #define CONFIG_ATMEL_USART
 #define CONFIG_USART_BASE		ATMEL_BASE_UART1
 #define CONFIG_USART_ID			ATMEL_ID_UART1
@@ -37,16 +39,6 @@
 #undef CONFIG_AT91_GPIO
 #define CONFIG_ATMEL_PIO4
 
-/* SerialFlash */
-#ifdef CONFIG_CMD_SF
-#define CONFIG_ATMEL_SPI
-#define CONFIG_ATMEL_SPI0
-#define CONFIG_SPI_FLASH_ATMEL
-#define CONFIG_SF_DEFAULT_BUS		0
-#define CONFIG_SF_DEFAULT_CS		0
-#define CONFIG_SF_DEFAULT_SPEED		30000000
-#endif
-
 /* NAND flash */
 #undef CONFIG_CMD_NAND
 
@@ -57,9 +49,6 @@
 #define CONFIG_MMC
 #define CONFIG_GENERIC_MMC
 #define CONFIG_SDHCI
-#define CONFIG_ATMEL_SDHCI
-#define CONFIG_ATMEL_SDHCI0
-#define CONFIG_ATMEL_SDHCI1
 #define CONFIG_SUPPORT_EMMC_BOOT
 #endif
 
Signature · 1 line
1.8.2.2
#29 lore raw

PATCH 2/4 sama5d2_xplained: add support of QSPI controllers

---
 board/atmel/sama5d2_xplained/Kconfig            |  6 ++++++
 board/atmel/sama5d2_xplained/sama5d2_xplained.c | 18 ++++++++++++++++++
 2 files changed, 24 insertions(+)
board/atmel/sama5d2_xplained/Kconfig +6 -0
index d4106b90f599..1659a2043b04 100644
@@ -26,4 +26,10 @@ config ATMEL_SDHCI1
 	select ATMEL_SDHCI
 	default y
 
+config ATMEL_QSPI0
+	bool "QSPI0"
+	select DM_SPI
+	select ATMEL_QSPI
+	default n
+
 endif
board/atmel/sama5d2_xplained/sama5d2_xplained.c +18 -0
index 4dd83e5e991f..6d4c2da99bc3 100644
@@ -55,6 +55,21 @@ static void board_spi0_hw_init(void)
 }
 #endif
 
+#ifdef CONFIG_ATMEL_QSPI0
+static void board_qspi0_hw_init(void)
+{
+	/* QSPI0 - ioset 3 */
+	atmel_pio4_set_f_periph(AT91_PIO_PORTA, 22, 0);	/* SCK */
+	atmel_pio4_set_f_periph(AT91_PIO_PORTA, 23, 0); /* CS */
+	atmel_pio4_set_f_periph(AT91_PIO_PORTA, 24, 1); /* IO0 */
+	atmel_pio4_set_f_periph(AT91_PIO_PORTA, 25, 1); /* IO1 */
+	atmel_pio4_set_f_periph(AT91_PIO_PORTA, 26, 1); /* IO2 */
+	atmel_pio4_set_f_periph(AT91_PIO_PORTA, 27, 1); /* IO3 */
+
+	at91_periph_clk_enable(ATMEL_ID_QSPI0);
+}
+#endif
+
 static void board_usb_hw_init(void)
 {
 	atmel_pio4_set_pio_output(AT91_PIO_PORTB, 10, 1);
@@ -241,6 +256,9 @@ int board_init(void)
 #ifdef CONFIG_ATMEL_SPI0
 	board_spi0_hw_init();
 #endif
+#ifdef CONFIG_ATMEL_QSPI0
+	board_qspi0_hw_init();
+#endif
 #ifdef CONFIG_ATMEL_SDHCI0
 	board_sdhci0_hw_init();
 #endif
Signature · 1 line
1.8.2.2
#30 lore raw

PATCH 3/4 dts: add dts file for Atmel sama5d2 xplained board

In reply to Cyrille Pitchen
---
 arch/arm/dts/Makefile                  |  3 +++
 arch/arm/dts/at91-sama5d2_xplained.dts | 33 +++++++++++++++++++++++++++++++++
 arch/arm/dts/sama5d2.dtsi              | 19 +++++++++++++++++++
 3 files changed, 55 insertions(+)
 create mode 100644 arch/arm/dts/at91-sama5d2_xplained.dts
 create mode 100644 arch/arm/dts/sama5d2.dtsi
arch/arm/dts/Makefile +3 -0
index 578038be21f9..97521f16aac4 100644
@@ -207,6 +207,9 @@ dtb-$(CONFIG_SOC_KEYSTONE) += k2hk-evm.dtb \
 	k2e-evm.dtb \
 	k2g-evm.dtb
 
+dtb-$(CONFIG_ARCH_AT91) += \
+	at91-sama5d2_xplained.dtb
+
 targets += $(dtb-y)
 
 # Add any required device tree compiler flags here
arch/arm/dts/at91-sama5d2_xplained.dts new file +33 -0
new file mode 100644
index 000000000000..2394f6bd4249
@@ -0,0 +1,33 @@
+/dts-v1/;
+#include "sama5d2.dtsi"
+
+/ {
+	model = "Atmel SAMA5D2 Xplained";
+	compatible = "atmel,sama5d2-xplained", "atmel,sama5d2", "atmel,sama5";
+
+	chosen {
+		stdout-path = "serial0";
+	};
+};
+
+&qspi0 {
+	status = "okay";
+
+	flash at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "atmel,sama5d2-qspi-flash";
+		reg = <0>;
+		spi-max-frequency = <83000000>;
+
+		partition at 00000000 {
+			label = "boot";
+			reg = <0x00000000 0x00c00000>;
+		};
+
+		partition at 00c00000 {
+			label = "rootfs";
+			reg = <0x00c00000 0x00000000>;
+		};
+	};
+};
arch/arm/dts/sama5d2.dtsi new file +19 -0
new file mode 100644
index 000000000000..dccc66cccb88
@@ -0,0 +1,19 @@
+#include "skeleton.dtsi"
+
+/ {
+	model = "Atmel SAMA5D2 family SoC";
+	compatible = "atmel,sama5d2";
+
+	aliases {
+		spi0 = &qspi0;
+	};
+
+	qspi0: spi at f0020000 {
+		compatible = "atmel,sama5d2-qspi";
+		reg = <0xf0020000 0x100>, <0xd0000000 0x08000000>;
+		reg-names = "qspi_base", "qspi_mmap";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+};
\ No newline at end of file
Signature · 1 line
1.8.2.2
#31 lore raw

PATCH 4/4 sf: fix sf probe

In reply to Cyrille Pitchen

This patch fixes the "sf probe" command. The very first SPI flash probe passes, for instance when u-boot tries to read its environment settings from a (Q)SPI memory but next "sf probe" commands fail because the flash memory node is unbound from the SPI controller children nodes.

---
 cmd/sf.c | 1 -
 1 file changed, 1 deletion(-)
cmd/sf.c +0 -1
index 42862d9d921a..5a666bbe9491 100644
@@ -123,7 +123,6 @@ static int do_spi_flash_probe(int argc, char * const argv[])
 	ret = spi_find_bus_and_cs(bus, cs, &bus_dev, &new);
 	if (!ret) {
 		device_remove(new);
-		device_unbind(new);
 	}
 	flash = NULL;
 	ret = spi_flash_probe_bus_cs(bus, cs, speed, mode, &new);
Signature · 1 line
1.8.2.2
#32 lore raw

cover sf: fix support of QSPI memories and controllers

In reply to Jagan Teki

Hi All,

please excuse the late reply to this thread. But I'm very interested in QSPI, as one of my customers uses Micron QSPI NOR and really wants to take full advantage of the device (quad access) to speed up the overall boot process. This is on SoCFPGA btw.

Please allow me a few comments below.

Quoted 197 lines · Jagan Teki
Quoted 196 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 38 lines · Cyrille Pitchen
Quoted 28 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a
memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()
sf: fix selection of supported READ commands for QSPI memories

Quoted 8 lines

sf: fix detection of QSPI memories when they boot in Quad or
Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 8 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1]
http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few
comments:

Globally I see the new code attend to match the spi-nor framework from Linux.
OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit
to add support to Micron QSPI memories was reverted since it didn't work alone.
In his reply, Brian agreed the code was not tested and should not have been
merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol
change at the QSPI memory side. This applies to Micron memories when they enter
their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y
protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI
mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the
.read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command
op code. Indeed, taking the Micron case as un example, the very same 0xeb op
code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or
with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles
(if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output
command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we
don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to
during Fast Read operations to make the memory enter/leaver its Continuous Read
mode. Once is Continuous Read mode, the op code byte is no longer sent, it is
implicit and the command actually starts from the address cycles. This mode
is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by
updating the relevant bit in some configuration register (e.g. setting the XIP
bit in Micron Volatile Configuration Register) or by choosing the right op code
(e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can
be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about
the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI
memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not
already enabled. This not always true, some early bootloarders, such as the
sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from
the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command
in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities,
the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4
protocols. Maybe some SPI controllers support the first protocol but not the
latest. It could be good to add another argument to spi_nor_scan() providing
an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI
memory and select the proper protocol, this new argument should use the same
range of values as the .flash_read field in the struct spi_nor_info used to
describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes
into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

    /* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+    mode_rx = spi->mode_rx;
+    if (mode_rx & SPI_RX_QUAD) {
+        e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_QUAD)
+            e_rd_cmd |= QUAD_IO_FAST;
+    } else if (mode_rx & SPI_RX_DUAL) {
+        e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_DUAL)
+            e_rd_cmd |= DUAL_IO_FAST;
+    } else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+        e_rd_cmd = ARRAY_SLOW;
+    } else {
+        e_rd_cmd = RD_NORM;
+    }
+
[...]
-    ret = spi_flash_scan(flash);
+    ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 6 lines
Quoted 6 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you
that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support,
please let me know.

Thanks Cyrille, for this very detailed and good explanation. This is really appreciated. And I really hope that Jagan will get back to your generous offer, to assist with any such QSPI NOR related problems. I'll definitely remember this and might bug you at some time... ;)

Quoted 8 lines

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

Jagan, what is the current plan here? I have to admit that I didn't check closely on your SPI-NOR work lately, sorry. So I can't really comment with a profound deep knowledge. But from what I read in Cyrille's patchset and explanation above, his patchset fixes some issues and brings us also more in line with the (upcoming) Linux framework. So I would really love to see this integrated into mainline quickly. Allowing a broader test basis on multiple platforms. Will it be a big task for Cyrille to rebase his patchset on top of your patches? Can you perhaps assist Cyrille with this? Or would it perhaps make sense to postpone your patchset and integrate Cyrille's first instead?

Cyrille, if Jagans rework goes in first, do you already have a plan on when to rebase your patchset on top of this? Or do you see some "show-stoppers" here?

Comments welcome.

Thanks,
Stefan

#33 lore raw

cover sf: fix support of QSPI memories and controllers

Hi Stefan,

Le 18/03/2016 14:48, Stefan Roese a ?crit :

Quoted 240 lines

Hi All,

please excuse the late reply to this thread. But I'm very interested in QSPI, as one of my customers uses Micron QSPI NOR and really wants to take full advantage of the device (quad access) to speed up the overall boot process. This is on SoCFPGA btw.

Please allow me a few comments below.

Quoted 197 lines · Jagan Teki
Quoted 196 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 38 lines · Cyrille Pitchen
Quoted 28 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a
memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()
sf: fix selection of supported READ commands for QSPI memories

Quoted 8 lines

sf: fix detection of QSPI memories when they boot in Quad or
Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 8 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1]
http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few
comments:

Globally I see the new code attend to match the spi-nor framework from Linux.
OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit
to add support to Micron QSPI memories was reverted since it didn't work alone.
In his reply, Brian agreed the code was not tested and should not have been
merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol
change at the QSPI memory side. This applies to Micron memories when they enter
their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y
protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI
mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the
.read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command
op code. Indeed, taking the Micron case as un example, the very same 0xeb op
code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or
with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles
(if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output
command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we
don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to
during Fast Read operations to make the memory enter/leaver its Continuous Read
mode. Once is Continuous Read mode, the op code byte is no longer sent, it is
implicit and the command actually starts from the address cycles. This mode
is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by
updating the relevant bit in some configuration register (e.g. setting the XIP
bit in Micron Volatile Configuration Register) or by choosing the right op code
(e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can
be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about
the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI
memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not
already enabled. This not always true, some early bootloarders, such as the
sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from
the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command
in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities,
the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4
protocols. Maybe some SPI controllers support the first protocol but not the
latest. It could be good to add another argument to spi_nor_scan() providing
an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI
memory and select the proper protocol, this new argument should use the same
range of values as the .flash_read field in the struct spi_nor_info used to
describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes
into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

    /* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+    mode_rx = spi->mode_rx;
+    if (mode_rx & SPI_RX_QUAD) {
+        e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_QUAD)
+            e_rd_cmd |= QUAD_IO_FAST;
+    } else if (mode_rx & SPI_RX_DUAL) {
+        e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_DUAL)
+            e_rd_cmd |= DUAL_IO_FAST;
+    } else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+        e_rd_cmd = ARRAY_SLOW;
+    } else {
+        e_rd_cmd = RD_NORM;
+    }
+
[...]
-    ret = spi_flash_scan(flash);
+    ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 6 lines
Quoted 6 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you
that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support,
please let me know.

Thanks Cyrille, for this very detailed and good explanation. This is really appreciated. And I really hope that Jagan will get back to your generous offer, to assist with any such QSPI NOR related problems. I'll definitely remember this and might bug you at some time... ;)

Quoted 8 lines

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

Jagan, what is the current plan here? I have to admit that I didn't check closely on your SPI-NOR work lately, sorry. So I can't really comment with a profound deep knowledge. But from what I read in Cyrille's patchset and explanation above, his patchset fixes some issues and brings us also more in line with the (upcoming) Linux framework. So I would really love to see this integrated into mainline quickly. Allowing a broader test basis on multiple platforms. Will it be a big task for Cyrille to rebase his patchset on top of your patches? Can you perhaps assist Cyrille with this? Or would it perhaps make sense to postpone your patchset and integrate Cyrille's first instead?

Quoted 4 lines

Cyrille, if Jagans rework goes in first, do you already have a plan on when to rebase your patchset on top of this? Or do you see some "show-stoppers" here?

Well if I need to rebase my patchset, for sure I will wait for Jagan's rework to be completed and accepted first. I don't think it would be efficient to rebase the QSPI series on the fly before the rework is totally stabilized.

One of the commit message from u-boot-spi.git can sum up the global rework:
"sf: Drop entire spi-flash framework" [1]

Indeed all files from drivers/mtd/spi are deleted, the next commits replace them by new files in the spi-nor folder. These new files are almost some "copy/paste" of drivers/mtd/spi-nor files from Linux.

OK, why not but it also implies that I can't simply rebase my patchset. Since the all files are different it means I have to write a new series of patches from scratch. As I said, I won't start such a work before the new framework is totally accepted and integrated in next releases of u-boot.

I don't say using the Linux code as a reference is a bad idea, indeed there are good things in the spi-nor framework to be taken. For instance, in my own series I added .read_reg() and .write_reg() hooks the same way as done in the Linux source.
I just warn developers that currently the Linux code misses some stuff to support QSPI memories efficiently. As an example, spi_nor_scan() fails to read the JEDEC ID if the QSPI memory is already in QPI mode (Micron, Macronix, Winbond, ...).
This issue didn't exist with regular SPI NOR flash memories as they are almost "stateless" as compared to QSPI memories. SPI memories always use a single protocol, SPI 1-1-1 with MISO and MOSI I/O lines, for all commands. On the other hand, QSPI memories are much complex: you have to deal with many different protocols and find a way to guess the current internal state of the QSPI memory before sending commands to it.

So, this is why I've send all the material I have in the case other developers are blocked and need support for QSPI memories in u-boot.

Best regards,

Cyrille

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=commit;h=7ae4605cd2b3484be9e61874c8323226b42bb9ba

Quoted 6 lines

Comments welcome.

Thanks,
Stefan

#34 lore raw

cover sf: fix support of QSPI memories and controllers

Hi Cyrille,

Quoted 253 lines · Cyrille Pitchen

Hi Stefan,

Le 18/03/2016 14:48, Stefan Roese a ?crit :

Quoted 240 lines

Hi All,

please excuse the late reply to this thread. But I'm very interested in QSPI, as one of my customers uses Micron QSPI NOR and really wants to take full advantage of the device (quad access) to speed up the overall boot process. This is on SoCFPGA btw.

Please allow me a few comments below.

Quoted 197 lines · Jagan Teki
Quoted 196 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 38 lines · Cyrille Pitchen
Quoted 28 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a
memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()
sf: fix selection of supported READ commands for QSPI memories

Quoted 8 lines

sf: fix detection of QSPI memories when they boot in Quad or
Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 8 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1]
http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few
comments:

Globally I see the new code attend to match the spi-nor framework from Linux.
OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit
to add support to Micron QSPI memories was reverted since it didn't work alone.
In his reply, Brian agreed the code was not tested and should not have been
merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol
change at the QSPI memory side. This applies to Micron memories when they enter
their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y
protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI
mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the
.read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command
op code. Indeed, taking the Micron case as un example, the very same 0xeb op
code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or
with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles
(if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output
command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we
don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to
during Fast Read operations to make the memory enter/leaver its Continuous Read
mode. Once is Continuous Read mode, the op code byte is no longer sent, it is
implicit and the command actually starts from the address cycles. This mode
is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by
updating the relevant bit in some configuration register (e.g. setting the XIP
bit in Micron Volatile Configuration Register) or by choosing the right op code
(e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can
be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about
the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI
memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not
already enabled. This not always true, some early bootloarders, such as the
sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from
the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command
in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities,
the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4
protocols. Maybe some SPI controllers support the first protocol but not the
latest. It could be good to add another argument to spi_nor_scan() providing
an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI
memory and select the proper protocol, this new argument should use the same
range of values as the .flash_read field in the struct spi_nor_info used to
describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes
into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

    /* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+    mode_rx = spi->mode_rx;
+    if (mode_rx & SPI_RX_QUAD) {
+        e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_QUAD)
+            e_rd_cmd |= QUAD_IO_FAST;
+    } else if (mode_rx & SPI_RX_DUAL) {
+        e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_DUAL)
+            e_rd_cmd |= DUAL_IO_FAST;
+    } else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+        e_rd_cmd = ARRAY_SLOW;
+    } else {
+        e_rd_cmd = RD_NORM;
+    }
+
[...]
-    ret = spi_flash_scan(flash);
+    ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 6 lines
Quoted 6 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you
that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support,
please let me know.

Thanks Cyrille, for this very detailed and good explanation. This is really appreciated. And I really hope that Jagan will get back to your generous offer, to assist with any such QSPI NOR related problems. I'll definitely remember this and might bug you at some time... ;)

Quoted 8 lines

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

Jagan, what is the current plan here? I have to admit that I didn't check closely on your SPI-NOR work lately, sorry. So I can't really comment with a profound deep knowledge. But from what I read in Cyrille's patchset and explanation above, his patchset fixes some issues and brings us also more in line with the (upcoming) Linux framework. So I would really love to see this integrated into mainline quickly. Allowing a broader test basis on multiple platforms. Will it be a big task for Cyrille to rebase his patchset on top of your patches? Can you perhaps assist Cyrille with this? Or would it perhaps make sense to postpone your patchset and integrate Cyrille's first instead?

Quoted 4 lines

Cyrille, if Jagans rework goes in first, do you already have a plan on when to rebase your patchset on top of this? Or do you see some "show-stoppers" here?

Well if I need to rebase my patchset, for sure I will wait for Jagan's rework to be completed and accepted first. I don't think it would be efficient to rebase the QSPI series on the fly before the rework is totally stabilized.

Quoted 6 lines

One of the commit message from u-boot-spi.git can sum up the global rework:
"sf: Drop entire spi-flash framework" [1]

Indeed all files from drivers/mtd/spi are deleted, the next commits replace them by new files in the spi-nor folder. These new files are almost some "copy/paste" of drivers/mtd/spi-nor files from Linux.

Yeah.. the idea of using Linux spi-nor is like u-boot also facing similar issue where Linux facing like spi drivers became more flash centric, and it's not totally same design as Linux. We took the idea from Linux and have MTD driver model on top of it. The whole idea to add this is to follow the u-boot driver model principle and if the stack look some how similar to Linux then the development is as faster as, when
compared to maintain separate thread of development - this is very legacy story I have been saying on this on ML for year back.

And did you find any issues with this spi-nor series?

Quoted 6 lines

OK, why not but it also implies that I can't simply rebase my patchset. Since the all files are different it means I have to write a new series of patches from scratch. As I said, I won't start such a work before the new framework is totally accepted and integrated in next releases of u-boot.

Quoted 14 lines

I don't say using the Linux code as a reference is a bad idea, indeed there are good things in the spi-nor framework to be taken. For instance, in my own series I added .read_reg() and .write_reg() hooks the same way as done in the Linux source.
I just warn developers that currently the Linux code misses some stuff to support QSPI memories efficiently. As an example, spi_nor_scan() fails to read the JEDEC ID if the QSPI memory is already in QPI mode (Micron, Macronix, Winbond, ...).
This issue didn't exist with regular SPI NOR flash memories as they are almost "stateless" as compared to QSPI memories. SPI memories always use a single protocol, SPI 1-1-1 with MISO and MOSI I/O lines, for all commands. On the other hand, QSPI memories are much complex: you have to deal with many different protocols and find a way to guess the current internal state of the QSPI memory before sending commands to it.

OK, I understand that you sent separate patches, are these patches fix this issue?

https://patchwork.ozlabs.org/patch/598527/
https://patchwork.ozlabs.org/patch/598528/
https://patchwork.ozlabs.org/patch/598530/
https://patchwork.ozlabs.org/patch/598532/

If so, then I will start reviewing these and will push these changes first and will rebase spi-nor on top of this.

thanks!

Signature · 1 line
Jagan.
#35 lore raw

cover sf: fix support of QSPI memories and controllers

Hi Jagan,

Le 21/03/2016 10:07, Jagan Teki a ?crit :

Quoted 273 lines

Hi Cyrille,

Quoted 253 lines · Cyrille Pitchen

Hi Stefan,

Le 18/03/2016 14:48, Stefan Roese a ?crit :

Quoted 240 lines

Hi All,

please excuse the late reply to this thread. But I'm very interested in QSPI, as one of my customers uses Micron QSPI NOR and really wants to take full advantage of the device (quad access) to speed up the overall boot process. This is on SoCFPGA btw.

Please allow me a few comments below.

Quoted 197 lines · Jagan Teki
Quoted 196 lines · Cyrille Pitchen

Le 15/03/2016 19:21, Jagan Teki a ?crit :

Quoted 38 lines · Cyrille Pitchen
Quoted 28 lines

Hi all,

This series of patches fixes and extend the support of QSPI memories in the SPI flash framework. The updates are split into many parts to make it easier to understand and review but they should be considered as a whole.

This was tested on a Atmel sama5d2 xplained board with a Micron n25q128a
memory.

Best regards,

Cyrille

Cyrille Pitchen (18):
Revert "sf: Fix quad bit set for micron devices"
sf: call spi_claim_bus() and spi_release_bus() only once per read,
write or erase
sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
sf: remove spi_flash_write_common()
sf: export spi_flash_wait_ready() function
sf: share erase generic algorithm
sf: share write generic algorithm
sf: share read generic algorithm
sf: add hooks to handle register read and write operations
sf: move support of SST flash into generic spi_flash_write_alg()
sf: fix selection of supported READ commands for QSPI memories

Quoted 8 lines

sf: fix detection of QSPI memories when they boot in Quad or
Dual mode
sf: add helper function to set the number of dummy bytes
sf: add 4byte address opcodes
sf: prepare next fixes to support of QSPI memories by manufacturer
sf: fix support of Micron memories
ARM: at91: clock: add function to get QSPI clocks
sf: add driver for Atmel QSPI controller

Quoted 8 lines

Appreciate for the work, we're working on spi-nor framework[1] planning to push in couple of weeks. Will let you know once it merged so that you can add your changes on top of that.

[1]
http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-next

Hi Jagan,

I've started to have a look on your branch. I hope it's not to late for few
comments:

Globally I see the new code attend to match the spi-nor framework from Linux.
OK that's fine but please note the current spi-nor framework in Linux has incomplete and sometime not working support of QSPI memories.

First, after a discussion with Brian and Bean on linux-mtd [1], Bean's commit
to add support to Micron QSPI memories was reverted since it didn't work alone.
In his reply, Brian agreed the code was not tested and should not have been
merged.

This highlights a more general issue: currently, there is no mean for the spi-nor framework to notify the SPI controller driver about a SPI protocol
change at the QSPI memory side. This applies to Micron memories when they enter
their Quad I/O mode. If so, ALL commands, even JEDEC Read ID, Read Status Register, ..., MUST use the SPI 4-4-4 protocol. Commands sent using SPI 1-x-y
protocols are no longer decoded properly.
This also applies to Macronix and Winbond memories if they enter their QPI
mode, which is the equivalent of Micron Quad I/O mode.
This is why I've suggested to add 4 new fields in the struct spi_nor:
- .reg_proto: the SPI protocol to be used by .read_reg() and .write_reg() hooks.
- .read_proto: the SPI protocol to be used by the .read() hooks, maybe by the
.read_mmap() also.
- .write_proto: the SPI protocol to be used by the .write() hooks
- .erase_proto: the SPI protocol to be used by the .erase() hooks.

(Q)SPI controller drivers cannot guess the protocol to be used from the command
op code. Indeed, taking the Micron case as un example, the very same 0xeb op
code may be used with the SPI 1-4-4 protocol (Micron Extended SPI mode) or
with the SPI 4-4-4 protocol (Micron Quad I/O mode).

Also just some words about the naming of SPI x-y-z protocols:
- x refers to the number of I/O lines used to send the op code byte
- y is the number of I/O lines used to send the address, mode/dummy cycles
(if these cycles exist for the command op code)
- z is the number of I/O lines used to send/receive data (if needed)

So the SNOR_OP_READ_1_1_2_IO macro for the Fast Read Dual I/O command (as opposed to the macro SNOR_OP_READ_1_1_2 macro for the Fast Read Dual Output
command) doesn't make sense: it should be named SNOR_OP_READ_1_2_2.

Then about the value used for the dummy cycles, it's not always true that we
don't care about initializing them. Depending on the configuration of the memory, some special dummy cycles, sometime called mode cycles, are used to
during Fast Read operations to make the memory enter/leaver its Continuous Read
mode. Once is Continuous Read mode, the op code byte is no longer sent, it is
implicit and the command actually starts from the address cycles. This mode
is mostly used for XIP applications hence is not relevant for mtd usage. However we should take care not to enter this Continuous Mode by mistake. Depending on the memory manufacturer, the Continuous Mode can be disabled by
updating the relevant bit in some configuration register (e.g. setting the XIP
bit in Micron Volatile Configuration Register) or by choosing the right op code
(e.g. for Winbond memories in QPI mode, both the 0x0b and 0xeb op codes can
be used for Fast Read 4-4-4 operation but only the 0xeb op code cares about
the dummy cycle value to enter/leave the Continuous Read mode). Some Spansion memories use 6 dummy cycles for Fast Read 1-4-4 command as factory default, not 8.

Besides when sending a regular JEDEC Read ID (0x9f) command to probe the (Q)SPI
memory, the current spi-nor framework assumes the Quad I/O or QPI mode is not
already enabled. This not always true, some early bootloarders, such as the
sama5d2 ROM Code, enables the Micron Quad I/O mode when configured to boot from
the QSPI memory. If so, the QSPI memory no longer replies to the 0x9f command
in SPI 1-1-1 protocol but instead to the 0xaf command in SPI 4-4-4 protocol.

Finally, about the proper way to describe the SPI controller capabilities,
the SPI_TX_{DUAL, QUAD} and SPI_RX_{DUAL, QUAD} mode flags are set in the SPI framework based on the "spi-rx-bus-width" and "spi-tx-bus-width" DT properties already used in Linux.
This is not enough to make the difference between the SPI 1-4-4 and SPI 4-4-4
protocols. Maybe some SPI controllers support the first protocol but not the
latest. It could be good to add another argument to spi_nor_scan() providing
an exhaustive list of SPI protocols supported by the SPI controller. Then to match this list with the list of SPI protocols supported by the SPI
memory and select the proper protocol, this new argument should use the same
range of values as the .flash_read field in the struct spi_nor_info used to
describe the SPI memories.

For backward compatibility, the m25p80 driver could then convert the SPI modes
into spi-nor read modes. Please have a look at patch 11 of my series; the chunk related to spi_flash_probe_slave() in sf_probe.c:

    /* Convert SPI mode_rx and mode to SPI flash read commands */
(quoted diff) +16 -1
+    mode_rx = spi->mode_rx;
+    if (mode_rx & SPI_RX_QUAD) {
+        e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_QUAD)
+            e_rd_cmd |= QUAD_IO_FAST;
+    } else if (mode_rx & SPI_RX_DUAL) {
+        e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+        if (spi->mode & SPI_TX_DUAL)
+            e_rd_cmd |= DUAL_IO_FAST;
+    } else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+        e_rd_cmd = ARRAY_SLOW;
+    } else {
+        e_rd_cmd = RD_NORM;
+    }
+
[...]
-    ret = spi_flash_scan(flash);
+    ret = spi_flash_scan(flash, e_rd_cmd);
Quoted 6 lines
Quoted 6 lines

I've spent a lot of time working on the QSPI memory topic so I can tell you
that there are many other traps to avoid!
If I can help you on this topic during your rework of the SPI NOR support,
please let me know.

Thanks Cyrille, for this very detailed and good explanation. This is really appreciated. And I really hope that Jagan will get back to your generous offer, to assist with any such QSPI NOR related problems. I'll definitely remember this and might bug you at some time... ;)

Quoted 8 lines

I understand your points, thanks for that and anyway this spi-nor work is a starting point for both syncing with Linux as well with new feature or for better tunning. And more over I started this work in 2014 end and it's been reviewing over and over and we finally landed up with MTD driver model.

So, please wait for sometime until this gets merged we definitely work together for better tunning, thanks!

Jagan, what is the current plan here? I have to admit that I didn't check closely on your SPI-NOR work lately, sorry. So I can't really comment with a profound deep knowledge. But from what I read in Cyrille's patchset and explanation above, his patchset fixes some issues and brings us also more in line with the (upcoming) Linux framework. So I would really love to see this integrated into mainline quickly. Allowing a broader test basis on multiple platforms. Will it be a big task for Cyrille to rebase his patchset on top of your patches? Can you perhaps assist Cyrille with this? Or would it perhaps make sense to postpone your patchset and integrate Cyrille's first instead?

Quoted 4 lines

Cyrille, if Jagans rework goes in first, do you already have a plan on when to rebase your patchset on top of this? Or do you see some "show-stoppers" here?

Well if I need to rebase my patchset, for sure I will wait for Jagan's rework to be completed and accepted first. I don't think it would be efficient to rebase the QSPI series on the fly before the rework is totally stabilized.

Quoted 6 lines

One of the commit message from u-boot-spi.git can sum up the global rework:
"sf: Drop entire spi-flash framework" [1]

Indeed all files from drivers/mtd/spi are deleted, the next commits replace them by new files in the spi-nor folder. These new files are almost some "copy/paste" of drivers/mtd/spi-nor files from Linux.

Yeah.. the idea of using Linux spi-nor is like u-boot also facing similar issue where Linux facing like spi drivers became more flash centric, and it's not totally same design as Linux. We took the idea from Linux and have MTD driver model on top of it. The whole idea to add this is to follow the u-boot driver model principle and if the stack look some how similar to Linux then the development is as faster as, when
compared to maintain separate thread of development - this is very legacy story I have been saying on this on ML for year back.

Quoted 2 lines

And did you find any issues with this spi-nor series?

Well, the spi-nor series is based on Linux code, which already lacks support of QSPI memories.

Moreover, the Linux version of m25p80.c uses the tx_nbits and rx_bits fields of the struct spi_transfer to tell the SPI controller driver about the number of I/O lines to be used to send or receive the command bytes. However there is no equivalent mechanism with the u-boot version which relies on calls of spi_write_then_read(). The u-boot version has no mean to support SPI protocols other than SPI 1-1-1 and the SPI controller drivers should not try to guess the SPI protocol from the op code.

Also be aware that the design chosen by the Linux m25p80 driver, that is to say the use of spi_sync_transfer() or spi_sync(), is not suited to all hardware QSPI controllers. For instance the Atmel QSPI controller expects separated inputs for the command op code, the address, the dummy cycles and the data.

spi_write_then_read() calls spi_xfer() twice: the first time to send the op code, address and dummy cycles then the second time to send the data. How can a SPI controller driver make the difference between the two calls if it should decode the input buffer to extract the op code, the address then the dummy cycles on the first call but send raw data for the second call?

In addition, maybe it could be better to call spi_claim_bus() / spi_release_bus() once for all at the beginning / end of spi_nor_read(), spi_nor_erase() and spi_nor_write() instead of calling them for each register read/write operation. I would avoid so many calls.

About the support the 16MiB memories, I see that commit 795c078c4563 ("mtd: spi-nor: Add 4-byte addressing") copies the Linux version except for the special case of Spansion memories which uses the dedicated 4byte address op codes for Fast Read, Page Program and Sector Erase.
Please note that entering the 4byte address mode, like set_4byte() does, changes the internal state of the SPI memory which has side effects: if a CPU reset occurs and if early bootloaders don't support this address mode, sending only 3 address bytes inside Fast Read commands, they fail reading from the SPI memory. That's why I've sent a patch to implement an alternative (thus optional) method to support >16MiB memories by converting the 3byte address op codes to their associated 4byte version:

0x02 -> 0x12  Page Program
0x03 -> 0x13  Read
0x0b -> 0x0c  Fast Read
0x6b -> 0x6c  Fast Read Quad Output 1-1-4
0xd8 -> 0xdc  Sector Erase

...

Quoted 21 lines
Quoted 6 lines

OK, why not but it also implies that I can't simply rebase my patchset. Since the all files are different it means I have to write a new series of patches from scratch. As I said, I won't start such a work before the new framework is totally accepted and integrated in next releases of u-boot.

Quoted 14 lines

I don't say using the Linux code as a reference is a bad idea, indeed there are good things in the spi-nor framework to be taken. For instance, in my own series I added .read_reg() and .write_reg() hooks the same way as done in the Linux source.
I just warn developers that currently the Linux code misses some stuff to support QSPI memories efficiently. As an example, spi_nor_scan() fails to read the JEDEC ID if the QSPI memory is already in QPI mode (Micron, Macronix, Winbond, ...).
This issue didn't exist with regular SPI NOR flash memories as they are almost "stateless" as compared to QSPI memories. SPI memories always use a single protocol, SPI 1-1-1 with MISO and MOSI I/O lines, for all commands. On the other hand, QSPI memories are much complex: you have to deal with many different protocols and find a way to guess the current internal state of the QSPI memory before sending commands to it.

Quoted 6 lines

OK, I understand that you sent separate patches, are these patches fix this issue?

https://patchwork.ozlabs.org/patch/598527/
https://patchwork.ozlabs.org/patch/598528/
https://patchwork.ozlabs.org/patch/598530/

Those 3 patches only deal with support of the sama5d2 xplained board. They prepare the migration to the DM model and DT support since the Atmel QSPI controller driver uses the DM model. One of them also configures the pin muxing as needed to use the QSPI controller.

They are Work In Progress and not related with the mtd sub-system. I only provide them to unblock some customers who are waiting for support of QSPI memories in u-boot on sama5d2 SoCs.

Quoted 1 line

https://patchwork.ozlabs.org/patch/598532/

I guess this last one is not related with the mtd sub-system itself. It fixes an issue I found using the "sf probe" command. However it might need some review because I don't understand why the "device_unbind(new)" call was there at first so maybe I miss something. I guess there was a good reason to add this call and I want to avoid introducing regression.

Quoted 6 lines

If so, then I will start reviewing these and will push these changes first and will rebase spi-nor on top of this.

thanks!

Best regards,

Cyrille