All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
@ 2016-03-15 18:12 Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 01/18] Revert "sf: Fix quad bit set for micron devices" Cyrille Pitchen
                   ` (18 more replies)
  0 siblings, 19 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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

-- 
1.8.2.2

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

* [U-Boot] [PATCH 01/18] Revert "sf: Fix quad bit set for micron devices"
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 02/18] sf: call spi_claim_bus() and spi_release_bus() only once per read, write or erase Cyrille Pitchen
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  3 ---
 drivers/mtd/spi/spi_flash.c   | 62 ++-----------------------------------------
 2 files changed, 2 insertions(+), 63 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 007a5a085caf..7418c76b272c 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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 */
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 44d9e9ba0105..e52728da9a09 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -112,37 +112,6 @@ static int write_cr(struct spi_flash *flash, u8 wc)
 }
 #endif
 
-#ifdef CONFIG_SPI_FLASH_STMICRO
-static int read_evcr(struct spi_flash *flash, u8 *evcr)
-{
-	int ret;
-	const u8 cmd = CMD_READ_EVCR;
-
-	ret = spi_flash_read_common(flash, &cmd, 1, evcr, 1);
-	if (ret < 0) {
-		debug("SF: error reading EVCR\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static int write_evcr(struct spi_flash *flash, u8 evcr)
-{
-	u8 cmd;
-	int ret;
-
-	cmd = CMD_WRITE_EVCR;
-	ret = spi_flash_write_common(flash, &cmd, 1, &evcr, 1);
-	if (ret < 0) {
-		debug("SF: error while writing EVCR register\n");
-		return ret;
-	}
-
-	return 0;
-}
-#endif
-
 #ifdef CONFIG_SPI_FLASH_BAR
 static int spi_flash_write_bar(struct spi_flash *flash, u32 offset)
 {
@@ -895,34 +864,6 @@ static int spansion_quad_enable(struct spi_flash *flash)
 }
 #endif
 
-#ifdef CONFIG_SPI_FLASH_STMICRO
-static int micron_quad_enable(struct spi_flash *flash)
-{
-	u8 qeb_status;
-	int ret;
-
-	ret = read_evcr(flash, &qeb_status);
-	if (ret < 0)
-		return ret;
-
-	if (!(qeb_status & STATUS_QEB_MICRON))
-		return 0;
-
-	ret = write_evcr(flash, qeb_status & ~STATUS_QEB_MICRON);
-	if (ret < 0)
-		return ret;
-
-	/* read EVCR and check it */
-	ret = read_evcr(flash, &qeb_status);
-	if (!(ret >= 0 && !(qeb_status & STATUS_QEB_MICRON))) {
-		printf("SF: Micron EVCR Quad bit not clear\n");
-		return -EINVAL;
-	}
-
-	return ret;
-}
-#endif
-
 static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
 {
 	switch (idcode0) {
@@ -937,7 +878,8 @@ static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
 #endif
 #ifdef CONFIG_SPI_FLASH_STMICRO
 	case SPI_FLASH_CFI_MFR_STMICRO:
-		return micron_quad_enable(flash);
+		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);
-- 
1.8.2.2

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

* [U-Boot] [PATCH 02/18] sf: call spi_claim_bus() and spi_release_bus() only once per read, write or erase
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 01/18] Revert "sf: Fix quad bit set for micron devices" Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 03/18] sf: replace spi_flash_read_common() calls by spi_flash_cmd_read() Cyrille Pitchen
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  5 +---
 drivers/mtd/spi/spi_flash.c   | 68 +++++++++++++++++++++++++------------------
 2 files changed, 40 insertions(+), 33 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 7418c76b272c..dd8152721fe1 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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);
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index e52728da9a09..740ecd44473a 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -261,12 +261,6 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 	if (buf == NULL)
 		timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
 
-	ret = spi_claim_bus(spi);
-	if (ret) {
-		debug("SF: unable to claim SPI bus\n");
-		return ret;
-	}
-
 	ret = spi_flash_cmd_write_enable(flash);
 	if (ret < 0) {
 		debug("SF: enabling write failed\n");
@@ -287,13 +281,12 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 		return ret;
 	}
 
-	spi_release_bus(spi);
-
 	return ret;
 }
 
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 {
+	struct spi_slave *spi = flash->spi;
 	u32 erase_size, erase_addr;
 	u8 cmd[SPI_FLASH_CMD_LEN];
 	int ret = -1;
@@ -304,11 +297,18 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		return -1;
 	}
 
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("SF: unable to claim SPI bus\n");
+		return ret;
+	}
+
 	if (flash->flash_is_locked) {
 		if (flash->flash_is_locked(flash, offset, len) > 0) {
 			printf("offset 0x%x is protected and cannot be erased\n",
 			       offset);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto release;
 		}
 	}
 
@@ -323,7 +323,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 #ifdef CONFIG_SPI_FLASH_BAR
 		ret = spi_flash_write_bar(flash, erase_addr);
 		if (ret < 0)
-			return ret;
+			break;
 #endif
 		spi_flash_addr(erase_addr, cmd);
 
@@ -340,6 +340,9 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		len -= erase_size;
 	}
 
+release:
+	spi_release_bus(spi);
+
 	return ret;
 }
 
@@ -355,11 +358,18 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 
 	page_size = flash->page_size;
 
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("SF: unable to claim SPI bus\n");
+		return ret;
+	}
+
 	if (flash->flash_is_locked) {
 		if (flash->flash_is_locked(flash, offset, len) > 0) {
 			printf("offset 0x%x is protected and cannot be written\n",
 			       offset);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto release;
 		}
 	}
 
@@ -374,7 +384,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 #ifdef CONFIG_SPI_FLASH_BAR
 		ret = spi_flash_write_bar(flash, write_addr);
 		if (ret < 0)
-			return ret;
+			break;
 #endif
 		byte_addr = offset % page_size;
 		chunk_len = min(len - actual, (size_t)(page_size - byte_addr));
@@ -398,6 +408,9 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		offset += chunk_len;
 	}
 
+release:
+	spi_release_bus(spi);
+
 	return ret;
 }
 
@@ -407,20 +420,12 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
 	struct spi_slave *spi = flash->spi;
 	int ret;
 
-	ret = spi_claim_bus(spi);
-	if (ret) {
-		debug("SF: unable to claim SPI bus\n");
-		return ret;
-	}
-
 	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
 	if (ret < 0) {
 		debug("SF: read cmd failed\n");
 		return ret;
 	}
 
-	spi_release_bus(spi);
-
 	return ret;
 }
 
@@ -446,25 +451,26 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 	int bank_sel = 0;
 	int ret = -1;
 
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("SF: unable to claim SPI bus\n");
+		return ret;
+	}
+
 	/* Handle memory-mapped SPI */
 	if (flash->memory_map) {
-		ret = spi_claim_bus(spi);
-		if (ret) {
-			debug("SF: unable to claim SPI bus\n");
-			return ret;
-		}
 		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP);
 		spi_flash_copy_mmap(data, flash->memory_map + offset, len);
 		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
-		spi_release_bus(spi);
-		return 0;
+		goto release;
 	}
 
 	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
 	cmd = calloc(1, cmdsz);
 	if (!cmd) {
 		debug("SF: Failed to allocate cmd\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto release;
 	}
 
 	cmd[0] = flash->read_cmd;
@@ -478,7 +484,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 #ifdef CONFIG_SPI_FLASH_BAR
 		ret = spi_flash_write_bar(flash, read_addr);
 		if (ret < 0)
-			return ret;
+			break;
 		bank_sel = flash->bank_curr;
 #endif
 		remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
@@ -502,6 +508,10 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 	}
 
 	free(cmd);
+
+release:
+	spi_release_bus(spi);
+
 	return ret;
 }
 
-- 
1.8.2.2

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

* [U-Boot] [PATCH 03/18] sf: replace spi_flash_read_common() calls by spi_flash_cmd_read()
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 01/18] Revert "sf: Fix quad bit set for micron devices" Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 02/18] sf: call spi_claim_bus() and spi_release_bus() only once per read, write or erase Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 04/18] sf: remove spi_flash_write_common() Cyrille Pitchen
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  6 ------
 drivers/mtd/spi/spi_flash.c   | 30 +++++++++---------------------
 2 files changed, 9 insertions(+), 27 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index dd8152721fe1..96c9255cb03d 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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);
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 740ecd44473a..b1ebc65f37d7 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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;
-- 
1.8.2.2

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

* [U-Boot] [PATCH 04/18] sf: remove spi_flash_write_common()
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (2 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 03/18] sf: replace spi_flash_read_common() calls by spi_flash_cmd_read() Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 05/18] sf: export spi_flash_wait_ready() function Cyrille Pitchen
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  8 +++---
 drivers/mtd/spi/spi_flash.c   | 62 ++++++++++++++++++++++++++-----------------
 2 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 96c9255cb03d..25fc5a112d92 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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.
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index b1ebc65f37d7..e43e74fd95cd 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -63,11 +63,9 @@ static int read_fsr(struct spi_flash *flash, u8 *fsr)
 
 static int write_sr(struct spi_flash *flash, u8 ws)
 {
-	u8 cmd;
 	int ret;
 
-	cmd = CMD_WRITE_STATUS;
-	ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1);
+	ret = spi_flash_update_reg(flash, CMD_WRITE_STATUS, 1, &ws);
 	if (ret < 0) {
 		debug("SF: fail to write status register\n");
 		return ret;
@@ -96,16 +94,14 @@ static int read_cr(struct spi_flash *flash, u8 *rc)
 static int write_cr(struct spi_flash *flash, u8 wc)
 {
 	u8 data[2];
-	u8 cmd;
 	int ret;
 
 	ret = read_sr(flash, &data[0]);
 	if (ret < 0)
 		return ret;
 
-	cmd = CMD_WRITE_STATUS;
 	data[1] = wc;
-	ret = spi_flash_write_common(flash, &cmd, 1, &data, 2);
+	ret = spi_flash_update_reg(flash, CMD_WRITE_STATUS, 2, data);
 	if (ret) {
 		debug("SF: fail to write config register\n");
 		return ret;
@@ -118,15 +114,14 @@ static int write_cr(struct spi_flash *flash, u8 wc)
 #ifdef CONFIG_SPI_FLASH_BAR
 static int spi_flash_write_bar(struct spi_flash *flash, u32 offset)
 {
-	u8 cmd, bank_sel;
+	u8 bank_sel;
 	int ret;
 
 	bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift);
 	if (bank_sel == flash->bank_curr)
 		goto bar_end;
 
-	cmd = flash->bank_write_cmd;
-	ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
+	ret = spi_flash_update_reg(flash, flash->bank_write_cmd, 1, &bank_sel);
 	if (ret < 0) {
 		debug("SF: fail to write bank register\n");
 		return ret;
@@ -254,37 +249,31 @@ static int spi_flash_cmd_wait_ready(struct spi_flash *flash,
 	return -ETIMEDOUT;
 }
 
-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)
 {
 	struct spi_slave *spi = flash->spi;
-	unsigned long timeout = SPI_FLASH_PROG_TIMEOUT;
 	int ret;
 
-	if (buf == NULL)
-		timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
-
 	ret = spi_flash_cmd_write_enable(flash);
 	if (ret < 0) {
 		debug("SF: enabling write failed\n");
 		return ret;
 	}
 
-	ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len);
+	ret = spi_flash_cmd_write(spi, &opcode, 1, buf, len);
 	if (ret < 0) {
 		debug("SF: write cmd failed\n");
 		return ret;
 	}
 
-	ret = spi_flash_cmd_wait_ready(flash, timeout);
+	ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
 	if (ret < 0) {
-		debug("SF: write %s timed out\n",
-		      timeout == SPI_FLASH_PROG_TIMEOUT ?
-			"program" : "page erase");
+		debug("SF: write register timed out\n");
 		return ret;
 	}
 
-	return ret;
+	return 0;
 }
 
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
@@ -328,17 +317,30 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		if (ret < 0)
 			break;
 #endif
+		ret = spi_flash_cmd_write_enable(flash);
+		if (ret < 0) {
+			debug("SF: enabling write failed\n");
+			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_write_common(flash, cmd, sizeof(cmd), NULL, 0);
+		ret = spi_flash_cmd_write(spi, cmd, sizeof(cmd), NULL, 0);
 		if (ret < 0) {
 			debug("SF: erase failed\n");
 			break;
 		}
 
+		ret = spi_flash_cmd_wait_ready(flash,
+					       SPI_FLASH_PAGE_ERASE_TIMEOUT);
+		if (ret < 0) {
+			debug("SF: write page erase timed out\n");
+			break;
+		}
+
 		offset += erase_size;
 		len -= erase_size;
 	}
@@ -396,18 +398,30 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 			chunk_len = min(chunk_len,
 					(size_t)spi->max_write_size);
 
+		ret = spi_flash_cmd_write_enable(flash);
+		if (ret < 0) {
+			debug("SF: enabling write failed\n");
+			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);
 
-		ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
-					buf + actual, chunk_len);
+		ret = spi_flash_cmd_write(spi, cmd, sizeof(cmd),
+					  buf + actual, chunk_len);
 		if (ret < 0) {
 			debug("SF: write failed\n");
 			break;
 		}
 
+		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+		if (ret < 0) {
+			debug("SF: write program timed out\n");
+			break;
+		}
+
 		offset += chunk_len;
 	}
 
-- 
1.8.2.2

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

* [U-Boot] [PATCH 05/18] sf: export spi_flash_wait_ready() function
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (3 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 04/18] sf: remove spi_flash_write_common() Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 06/18] sf: share erase generic algorithm Cyrille Pitchen
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h | 3 +++
 drivers/mtd/spi/spi_flash.c   | 7 ++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 25fc5a112d92..e2a4449dbf40 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index e43e74fd95cd..6f30ff6f8d7c 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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;
-- 
1.8.2.2

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

* [U-Boot] [PATCH 06/18] sf: share erase generic algorithm
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (4 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 05/18] sf: export spi_flash_wait_ready() function Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 07/18] sf: share write " Cyrille Pitchen
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  4 ++++
 drivers/mtd/spi/spi_flash.c   | 28 +++++++++++++++++++---------
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index e2a4449dbf40..3c6bac3464f8 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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);
 
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 6f30ff6f8d7c..20b8c31c09e0 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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)
 {
-- 
1.8.2.2

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

* [U-Boot] [PATCH 07/18] sf: share write generic algorithm
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (5 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 06/18] sf: share erase generic algorithm Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 08/18] sf: share read " Cyrille Pitchen
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  5 +++++
 drivers/mtd/spi/spi_flash.c   | 34 ++++++++++++++++++++++++----------
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 3c6bac3464f8..592c23cd4ce1 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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);
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 20b8c31c09e0..3c8224c2b084 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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
-- 
1.8.2.2

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

* [U-Boot] [PATCH 08/18] sf: share read generic algorithm
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (6 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 07/18] sf: share write " Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 09/18] sf: add hooks to handle register read and write operations Cyrille Pitchen
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  4 ++++
 drivers/mtd/spi/spi_flash.c   | 48 ++++++++++++++++++++++++++++---------------
 2 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 592c23cd4ce1..569863a31684 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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);
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 3c8224c2b084..4be99ea0b424 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -473,11 +473,10 @@ void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len)
 	memcpy(data, offset, len);
 }
 
-int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
-		size_t len, void *data)
+int spi_flash_read_alg(struct spi_flash *flash, u32 offset, size_t len,
+		       void *data, spi_flash_read_fn read_fn)
 {
 	struct spi_slave *spi = flash->spi;
-	u8 *cmd, cmdsz;
 	u32 remain_len, read_len, read_addr;
 	int bank_sel = 0;
 	int ret = -1;
@@ -496,15 +495,6 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		goto release;
 	}
 
-	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
-	cmd = calloc(1, cmdsz);
-	if (!cmd) {
-		debug("SF: Failed to allocate cmd\n");
-		ret = -ENOMEM;
-		goto release;
-	}
-
-	cmd[0] = flash->read_cmd;
 	while (len) {
 		read_addr = offset;
 
@@ -525,9 +515,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		else
 			read_len = remain_len;
 
-		spi_flash_addr(read_addr, cmd);
-
-		ret = spi_flash_cmd_read(spi, cmd, cmdsz, data, read_len);
+		ret = read_fn(flash, read_addr, read_len, data);
 		if (ret < 0) {
 			debug("SF: read failed\n");
 			break;
@@ -538,14 +526,40 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		data += read_len;
 	}
 
-	free(cmd);
-
 release:
 	spi_release_bus(spi);
 
 	return ret;
 }
 
+static int spi_flash_read_impl(struct spi_flash *flash, u32 offset,
+			       size_t len, void *buf)
+{
+	struct spi_slave *spi = flash->spi;
+	u8 *cmd;
+	size_t cmdsz;
+	int ret;
+
+	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+	cmd = calloc(1, cmdsz);
+	if (!cmd) {
+		debug("SF: Failed to allocate cmd\n");
+		return -ENOMEM;
+	}
+
+	cmd[0] = flash->read_cmd;
+	spi_flash_addr(offset, cmd);
+	ret = spi_flash_cmd_read(spi, cmd, cmdsz, buf, len);
+	free(cmd);
+	return ret;
+}
+
+int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+		size_t len, void *buf)
+{
+	return spi_flash_read_alg(flash, offset, len, buf, spi_flash_read_impl);
+}
+
 #ifdef CONFIG_SPI_FLASH_SST
 static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
 {
-- 
1.8.2.2

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

* [U-Boot] [PATCH 09/18] sf: add hooks to handle register read and write operations
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (7 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 08/18] sf: share read " Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 10/18] sf: move support of SST flash into generic spi_flash_write_alg() Cyrille Pitchen
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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(-)

diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index 19de964e6121..ebae9b1edb15 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -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);
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 569863a31684..15a5fa9c2afd 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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);
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 7b296378d2be..fbd7d4740b51 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -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,
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 4be99ea0b424..4f269eacc591 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -32,12 +32,9 @@ 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_cmd_read(spi, &cmd, 1, rs, 1);
+	ret = spi_flash_read_reg(flash, CMD_READ_STATUS, 1, rs);
 	if (ret < 0) {
 		debug("SF: fail to read status register\n");
 		return ret;
@@ -48,11 +45,9 @@ 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_cmd_read(spi, &cmd, 1, fsr, 1);
+	ret = spi_flash_read_reg(flash, CMD_FLAG_STATUS, 1, fsr);
 	if (ret < 0) {
 		debug("SF: fail to read flag status register\n");
 		return ret;
@@ -77,12 +72,9 @@ 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_cmd_read(spi, &cmd, 1, rc, 1);
+	ret = spi_flash_read_reg(flash, CMD_READ_CONFIG, 1, rc);
 	if (ret < 0) {
 		debug("SF: fail to read config register\n");
 		return ret;
@@ -134,7 +126,6 @@ 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;
 
@@ -151,7 +142,7 @@ static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
 		flash->bank_write_cmd = CMD_EXTNADDR_WREAR;
 	}
 
-	ret = spi_flash_cmd_read(spi, &flash->bank_read_cmd, 1, &curr_bank, 1);
+	ret = spi_flash_read_reg(flash, flash->bank_read_cmd, &curr_bank, 1);
 	if (ret) {
 		debug("SF: fail to read bank addr register\n");
 		return ret;
@@ -257,7 +248,6 @@ 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)
 {
-	struct spi_slave *spi = flash->spi;
 	int ret;
 
 	ret = spi_flash_cmd_write_enable(flash);
@@ -266,7 +256,7 @@ int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
 		return ret;
 	}
 
-	ret = spi_flash_cmd_write(spi, &opcode, 1, buf, len);
+	ret = spi_flash_write_reg(flash, opcode, len, buf);
 	if (ret < 0) {
 		debug("SF: write cmd failed\n");
 		return ret;
@@ -281,6 +271,14 @@ int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
 	return 0;
 }
 
+int spi_flash_cmd_write_reg_ops(struct spi_flash *flash, u8 opcode, size_t len,
+				const void *buf)
+{
+	struct spi_slave *spi = flash->spi;
+
+	return spi_flash_cmd_write(spi, &opcode, 1, buf, len);
+}
+
 int spi_flash_erase_alg(struct spi_flash *flash, u32 offset, size_t len,
 			spi_flash_erase_fn erase_fn)
 {
@@ -460,6 +458,14 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 				   spi_flash_write_impl);
 }
 
+int spi_flash_cmd_read_reg_ops(struct spi_flash *flash, u8 opcode,
+			       size_t len, void *buf)
+{
+	struct spi_slave *spi = flash->spi;
+
+	return spi_flash_cmd_read(spi, &opcode, 1, buf, len);
+}
+
 /*
  * TODO: remove the weak after all the other spi_flash_copy_mmap
  * implementations removed from drivers
@@ -982,8 +988,25 @@ int spi_flash_scan(struct spi_flash *flash)
 		CMD_READ_DUAL_IO_FAST,
 		CMD_READ_QUAD_IO_FAST };
 
+	/* Assign spi_flash ops */
+#ifndef CONFIG_DM_SPI_FLASH
+	flash->read_reg = spi_flash_cmd_read_reg_ops;
+	flash->write_reg = spi_flash_cmd_write_reg_ops;
+	flash->write = spi_flash_cmd_write_ops;
+#if defined(CONFIG_SPI_FLASH_SST)
+	if (flash->flags & SNOR_F_SST_WR) {
+		if (spi->mode & SPI_TX_BYTE)
+			flash->write = sst_write_bp;
+		else
+			flash->write = sst_write_wp;
+	}
+#endif
+	flash->erase = spi_flash_cmd_erase_ops;
+	flash->read = spi_flash_cmd_read_ops;
+#endif
+
 	/* Read the ID codes */
-	ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
+	ret = spi_flash_read_reg(flash, CMD_READ_ID, sizeof(idcode), idcode);
 	if (ret) {
 		printf("SF: Failed to get idcodes\n");
 		return ret;
@@ -1032,21 +1055,6 @@ int spi_flash_scan(struct spi_flash *flash)
 	if (params->flags & SST_WR)
 		flash->flags |= SNOR_F_SST_WR;
 
-	/* Assign spi_flash ops */
-#ifndef CONFIG_DM_SPI_FLASH
-	flash->write = spi_flash_cmd_write_ops;
-#if defined(CONFIG_SPI_FLASH_SST)
-	if (flash->flags & SNOR_F_SST_WR) {
-		if (spi->mode & SPI_TX_BYTE)
-			flash->write = sst_write_bp;
-		else
-			flash->write = sst_write_wp;
-	}
-#endif
-	flash->erase = spi_flash_cmd_erase_ops;
-	flash->read = spi_flash_cmd_read_ops;
-#endif
-
 	/* lock hooks are flash specific - assign them based on idcode0 */
 	switch (idcode[0]) {
 #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
diff --git a/include/spi_flash.h b/include/spi_flash.h
index d0ce9e721ad0..31d11e55571d 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -52,6 +52,9 @@ struct spi_slave;
  * @flash_lock:		lock a region of the SPI Flash
  * @flash_unlock:	unlock a region of the SPI Flash
  * @flash_is_locked:	check if a region of the SPI Flash is completely locked
+ * @read_reg:		Flash read_reg ops: Send cmd to read len bytes into buf
+ * @write_reg:		Flash write_reg ops: Send cmd to write len bytes from
+ *			buf
  * @read:		Flash read ops: Read len bytes at offset into buf
  *			Supported cmds: Fast Array Read
  * @write:		Flash write ops: Write len bytes from buf into offset
@@ -101,6 +104,10 @@ struct spi_flash {
 	 * if required, perhaps with a way of scanning through the list to
 	 * find the driver that matches the device.
 	 */
+	int (*read_reg)(struct spi_flash *flash, u8 opcode, size_t len,
+			void *buf);
+	int (*write_reg)(struct spi_flash *flash, u8 opcode, size_t len,
+			 const void *buf);
 	int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
 	int (*write)(struct spi_flash *flash, u32 offset, size_t len,
 			const void *buf);
@@ -109,6 +116,9 @@ struct spi_flash {
 };
 
 struct dm_spi_flash_ops {
+	int (*read_reg)(struct udevice *dev, u8 opcode, size_t len, void *buf);
+	int (*write_reg)(struct udevice *dev, u8 opcode, size_t len,
+			 const void *buf);
 	int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf);
 	int (*write)(struct udevice *dev, u32 offset, size_t len,
 		     const void *buf);
@@ -120,6 +130,30 @@ struct dm_spi_flash_ops {
 
 #ifdef CONFIG_DM_SPI_FLASH
 /**
+ * spi_flash_read_reg_dm() - Send register command and read data result
+ *
+ * @dev:	SPI flash device
+ * @opcode:	Register command op code
+ * @len:	Number of bytes to read as register command output
+ * @buf:	Buffer to fill with the register command output
+ * @return 0 if OK, -ve on error
+ */
+int spi_flash_read_reg_dm(struct udevice *dev, u8 opcode, size_t len,
+			  void *buf);
+
+/**
+ * spi_flash_write_reg_dm() - Send register command with data
+ *
+ * @dev:	SPI flash device
+ * @opcode:	Register command op code
+ * @len:	Number of bytes to write as register command input
+ * @buf:	Buffer filled with the register command input
+ * @return 0 if OK, -ve on error
+ */
+int spi_flash_write_reg_dm(struct udevice *dev, u8 opcode, size_t len,
+			   const void *buf);
+
+/**
  * spi_flash_read_dm() - Read data from SPI flash
  *
  * @dev:	SPI flash device
@@ -165,6 +199,18 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 /* Compatibility function - this is the old U-Boot API */
 void spi_flash_free(struct spi_flash *flash);
 
+static inline int spi_flash_read_reg(struct spi_flash *flash, u8 opcode,
+				     size_t len, void *buf)
+{
+	return spi_flash_read_reg_dm(flash->dev, opcode, len, buf);
+}
+
+static inline int spi_flash_write_reg(struct spi_flash *flash, u8 opcode,
+				      size_t len, const void *buf)
+{
+	return spi_flash_write_reg_dm(flash->dev, opcode, len, buf);
+}
+
 static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
 				 size_t len, void *buf)
 {
@@ -208,6 +254,18 @@ struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
 
 void spi_flash_free(struct spi_flash *flash);
 
+static inline int spi_flash_read_reg(struct spi_flash *flash, u8 opcode,
+				     size_t len, void *buf)
+{
+	return flash->read_reg(flash, opcode, len, buf);
+}
+
+static inline int spi_flash_write_reg(struct spi_flash *flash, u8 opcode,
+				      size_t len, const void *buf)
+{
+	return flash->write_reg(flash, opcode, len, buf);
+}
+
 static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
 		size_t len, void *buf)
 {
-- 
1.8.2.2

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

* [U-Boot] [PATCH 10/18] sf: move support of SST flash into generic spi_flash_write_alg()
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (8 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 09/18] sf: add hooks to handle register read and write operations Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 11/18] sf: fix selection of supported READ commands for QSPI memories Cyrille Pitchen
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 15a5fa9c2afd..c5966fb37ac8 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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
 
 /**
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index fbd7d4740b51..837535fdb7a5 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -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);
 }
 
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 4f269eacc591..7f5341a87c07 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -364,6 +364,14 @@ 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);
 }
 
+#if defined(CONFIG_SPI_FLASH_SST)
+static int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
+			const void *buf, spi_flash_write_fn write_fn);
+
+static int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
+			const void *buf, spi_flash_write_fn write_fn);
+#endif
+
 int spi_flash_write_alg(struct spi_flash *flash, u32 offset, size_t len,
 			const void *buf, spi_flash_write_fn write_fn)
 {
@@ -373,6 +381,15 @@ int spi_flash_write_alg(struct spi_flash *flash, u32 offset, size_t len,
 	size_t chunk_len, actual;
 	int ret = -1;
 
+#if defined(CONFIG_SPI_FLASH_SST)
+	if (flash->flags & SNOR_F_SST_WR) {
+		if (spi->mode & SPI_TX_BYTE)
+			return sst_write_bp(flash, offset, len, buf, write_fn);
+		else
+			return sst_write_wp(flash, offset, len, buf, write_fn);
+	}
+#endif
+
 	page_size = flash->page_size;
 
 	ret = spi_claim_bus(spi);
@@ -448,6 +465,10 @@ static int spi_flash_write_impl(struct spi_flash *flash, u32 offset,
 
 	cmd[0] = flash->write_cmd;
 	spi_flash_addr(offset, cmd);
+#ifdef CONFIG_SPI_FLASH_SST
+	if (flash->flags & SNOR_F_SST_WR_2ND)
+		cmdsz = 1;
+#endif
 	return spi_flash_cmd_write(spi, cmd, cmdsz, buf, len);
 }
 
@@ -567,38 +588,33 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 }
 
 #ifdef CONFIG_SPI_FLASH_SST
-static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
+static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf,
+			  spi_flash_write_fn write_fn)
 {
 	struct spi_slave *spi = flash->spi;
 	int ret;
-	u8 cmd[4] = {
-		CMD_SST_BP,
-		offset >> 16,
-		offset >> 8,
-		offset,
-	};
 
+	flash->write_cmd = CMD_SST_BP;
 	debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
-	      spi_w8r8(spi, CMD_READ_STATUS), buf, cmd[0], offset);
+	      spi_w8r8(spi, CMD_READ_STATUS), buf, flash->write_cmd, offset);
 
 	ret = spi_flash_cmd_write_enable(flash);
 	if (ret)
 		return ret;
 
-	ret = spi_flash_cmd_write(spi, cmd, sizeof(cmd), buf, 1);
+	ret = write_fn(flash, offset, 1, buf);
 	if (ret)
 		return ret;
 
 	return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
 }
 
-int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
-		const void *buf)
+static int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
+			const void *buf, spi_flash_write_fn write_fn)
 {
 	struct spi_slave *spi = flash->spi;
-	size_t actual, cmd_len;
+	size_t actual;
 	int ret;
-	u8 cmd[4];
 
 	ret = spi_claim_bus(spi);
 	if (ret) {
@@ -606,10 +622,12 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 		return ret;
 	}
 
+	flash->flags &= ~SNOR_F_SST_WR_2ND;
+
 	/* If the data is not word aligned, write out leading single byte */
 	actual = offset % 2;
 	if (actual) {
-		ret = sst_byte_write(flash, offset, buf);
+		ret = sst_byte_write(flash, offset, buf, write_fn);
 		if (ret)
 			goto done;
 	}
@@ -619,19 +637,14 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 	if (ret)
 		goto done;
 
-	cmd_len = 4;
-	cmd[0] = CMD_SST_AAI_WP;
-	cmd[1] = offset >> 16;
-	cmd[2] = offset >> 8;
-	cmd[3] = offset;
+	flash->write_cmd = CMD_SST_AAI_WP;
 
 	for (; actual < len - 1; actual += 2) {
 		debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
 		      spi_w8r8(spi, CMD_READ_STATUS), buf + actual,
-		      cmd[0], offset);
+		      flash->write_cmd, offset);
 
-		ret = spi_flash_cmd_write(spi, cmd, cmd_len,
-					buf + actual, 2);
+		ret = write_fn(flash, offset, 2, buf + actual);
 		if (ret) {
 			debug("SF: sst word program failed\n");
 			break;
@@ -641,16 +654,17 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 		if (ret)
 			break;
 
-		cmd_len = 1;
+		flash->flags |= SNOR_F_SST_WR_2ND;
 		offset += 2;
 	}
+	flash->flags &= ~SNOR_F_SST_WR_2ND;
 
 	if (!ret)
 		ret = spi_flash_cmd_write_disable(flash);
 
 	/* If there is a single trailing byte, write it out */
 	if (!ret && actual != len)
-		ret = sst_byte_write(flash, offset, buf + actual);
+		ret = sst_byte_write(flash, offset, buf + actual, write_fn);
 
  done:
 	debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
@@ -660,8 +674,8 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 	return ret;
 }
 
-int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
-		const void *buf)
+static int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
+			const void *buf, spi_flash_write_fn write_fn)
 {
 	struct spi_slave *spi = flash->spi;
 	size_t actual;
@@ -674,7 +688,7 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
 	}
 
 	for (actual = 0; actual < len; actual++) {
-		ret = sst_byte_write(flash, offset, buf + actual);
+		ret = sst_byte_write(flash, offset, buf + actual, write_fn);
 		if (ret) {
 			debug("SF: sst byte program failed\n");
 			break;
@@ -993,14 +1007,6 @@ int spi_flash_scan(struct spi_flash *flash)
 	flash->read_reg = spi_flash_cmd_read_reg_ops;
 	flash->write_reg = spi_flash_cmd_write_reg_ops;
 	flash->write = spi_flash_cmd_write_ops;
-#if defined(CONFIG_SPI_FLASH_SST)
-	if (flash->flags & SNOR_F_SST_WR) {
-		if (spi->mode & SPI_TX_BYTE)
-			flash->write = sst_write_bp;
-		else
-			flash->write = sst_write_wp;
-	}
-#endif
 	flash->erase = spi_flash_cmd_erase_ops;
 	flash->read = spi_flash_cmd_read_ops;
 #endif
-- 
1.8.2.2

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

* [U-Boot] [PATCH 11/18] sf: fix selection of supported READ commands for QSPI memories
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (9 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 10/18] sf: move support of SST flash into generic spi_flash_write_alg() Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 12/18] sf: fix detection of QSPI memories when they boot in Quad or Dual mode Cyrille Pitchen
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index c5966fb37ac8..8b8521369e4e 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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_ */
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
index 4f37e33eb068..d3103dbc8742 100644
--- a/drivers/mtd/spi/sf_params.c
+++ b/drivers/mtd/spi/sf_params.c
@@ -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},
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 837535fdb7a5..8a0345bc1994 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -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;
 
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 7f5341a87c07..5ba148bd3626 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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;
-- 
1.8.2.2

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

* [U-Boot] [PATCH 12/18] sf: fix detection of QSPI memories when they boot in Quad or Dual mode
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (10 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 11/18] sf: fix selection of supported READ commands for QSPI memories Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 13/18] sf: add helper function to set the number of dummy bytes Cyrille Pitchen
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 8b8521369e4e..26d359707d5b 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 5ba148bd3626..5d641bbb8301 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -987,10 +987,37 @@ int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
 }
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
+struct spi_flash_read_id_config {
+	enum spi_flash_protocol	proto;
+	u8			e_rd_cmd;
+	u8			cmd;
+	int			idlen;
+};
+
+static const struct spi_flash_read_id_config configs[] = {
+	/* Regular JEDEC Read ID (MUST be first, always tested) */
+	{SPI_FLASH_PROTO_1_1_1, (ARRAY_SLOW | ARRAY_FAST), CMD_READ_ID, 5},
+#if defined(CONFIG_SPI_FLASH_WINBOND)
+	/* Winbond QPI mode */
+	{SPI_FLASH_PROTO_4_4_4, QUAD_CMD_FAST, CMD_READ_ID, 5},
+#endif
+#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_MACRONIX)
+	/* Micron Quad mode & Macronix QPI mode */
+	{SPI_FLASH_PROTO_4_4_4, QUAD_CMD_FAST, CMD_READ_ID_MIO, 3},
+#endif
+#if defined(CONFIG_SPI_FLASH_STMICRO)
+	/* Micron Dual mode */
+	{SPI_FLASH_PROTO_2_2_2, DUAL_CMD_FAST, CMD_READ_ID_MIO, 3},
+#endif
+	/* Sentinel */
+	{SPI_FLASH_PROTO_1_1_1, 0, 0, 0},
+};
+
 int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 {
 	struct spi_slave *spi = flash->spi;
 	const struct spi_flash_params *params;
+	const struct spi_flash_read_id_config *cfg;
 	u16 jedec, ext_jedec;
 	u8 cmd, idcode[5];
 	int ret;
@@ -1014,32 +1041,55 @@ int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 	flash->read = spi_flash_cmd_read_ops;
 #endif
 
-	/* Read the ID codes */
-	ret = spi_flash_read_reg(flash, CMD_READ_ID, sizeof(idcode), idcode);
-	if (ret) {
-		printf("SF: Failed to get idcodes\n");
-		return ret;
-	}
+	/*
+	 * Check whether the SPI NOR memory has already been configured (at
+	 * reset of by some bootloader) to use a protocol other than SPI 1-1-1.
+	 */
+	params = NULL;
+	jedec = 0;
+	ext_jedec = 0;
+	for (cfg = configs; cfg->e_rd_cmd; ++cfg) {
+		/* Only try protocols supported by the SPI controller */
+		if (cfg != configs && !(e_rd_cmd & cfg->e_rd_cmd))
+			continue;
+
+		/* Set this protocol for all commands */
+		flash->reg_proto = cfg->proto;
+		flash->read_proto = cfg->proto;
+		flash->write_proto = cfg->proto;
+		flash->erase_proto = cfg->proto;
+
+		/* Read the ID codes */
+		memset(idcode, 0, sizeof(idcode));
+		ret = spi_flash_read_reg(flash, cfg->cmd, cfg->idlen, idcode);
+		if (ret) {
+			printf("SF: Failed to get idcodes\n");
+			return -EINVAL;
+		}
 
 #ifdef DEBUG
-	printf("SF: Got idcodes\n");
-	print_buffer(0, idcode, 1, sizeof(idcode), 0);
+		printf("SF: Got idcodes\n");
+		print_buffer(0, idcode, 1, sizeof(idcode), 0);
 #endif
 
-	jedec = idcode[1] << 8 | idcode[2];
-	ext_jedec = idcode[3] << 8 | idcode[4];
-
-	/* Validate params from spi_flash_params table */
-	params = spi_flash_params_table;
-	for (; params->name != NULL; params++) {
-		if ((params->jedec >> 16) == idcode[0]) {
-			if ((params->jedec & 0xFFFF) == jedec) {
-				if (params->ext_jedec == 0)
-					break;
-				else if (params->ext_jedec == ext_jedec)
-					break;
+		jedec = idcode[1] << 8 | idcode[2];
+		ext_jedec = idcode[3] << 8 | idcode[4];
+
+		/* Validate params from spi_flash_params table */
+		params = spi_flash_params_table;
+		for (; params->name != NULL; params++) {
+			if ((params->jedec >> 16) == idcode[0]) {
+				if ((params->jedec & 0xFFFF) == jedec) {
+					if (params->ext_jedec == 0)
+						break;
+					else if (params->ext_jedec == ext_jedec)
+						break;
+				}
 			}
 		}
+
+		if (params->name)
+			break;
 	}
 
 	if (!params->name) {
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 31d11e55571d..945cc07ee8b2 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -28,6 +28,42 @@
 
 struct spi_slave;
 
+#define SPI_FLASH_PROTO_CMD_OFF	8
+#define SPI_FLASH_PROTO_CMD_MASK	GENMASK(11, 8)
+#define SPI_FLASH_PROTO_CMD_TO_PROTO(cmd) \
+	(((cmd) << SPI_FLASH_PROTO_CMD_OFF) & SPI_FLASH_PROTO_CMD_MASK)
+#define SPI_FLASH_PROTO_CMD_FROM_PROTO(proto) \
+	((((u32)(proto)) & SPI_FLASH_PROTO_CMD_MASK) >> SPI_FLASH_PROTO_CMD_OFF)
+
+#define SPI_FLASH_PROTO_ADR_OFF	4
+#define SPI_FLASH_PROTO_ADR_MASK	GENMASK(7, 4)
+#define SPI_FLASH_PROTO_ADR_TO_PROTO(adr) \
+	(((adr) << SPI_FLASH_PROTO_ADR_OFF) & SPI_FLASH_PROTO_ADR_MASK)
+#define SPI_FLASH_PROTO_ADR_FROM_PROTO(proto) \
+	((((u32)(proto)) & SPI_FLASH_PROTO_ADR_MASK) >> SPI_FLASH_PROTO_ADR_OFF)
+
+#define SPI_FLASH_PROTO_DAT_OFF	0
+#define SPI_FLASH_PROTO_DAT_MASK	GENMASK(3, 0)
+#define SPI_FLASH_PROTO_DAT_TO_PROTO(dat) \
+	(((dat) << SPI_FLASH_PROTO_DAT_OFF) & SPI_FLASH_PROTO_DAT_MASK)
+#define SPI_FLASH_PROTO_DAT_FROM_PROTO(proto) \
+	((((u32)(proto)) & SPI_FLASH_PROTO_DAT_MASK) >> SPI_FLASH_PROTO_DAT_OFF)
+
+#define SPI_FLASH_PROTO(cmd, adr, dat)	     \
+	(SPI_FLASH_PROTO_CMD_TO_PROTO(cmd) | \
+	 SPI_FLASH_PROTO_ADR_TO_PROTO(adr) | \
+	 SPI_FLASH_PROTO_DAT_TO_PROTO(dat))
+
+enum spi_flash_protocol {
+	SPI_FLASH_PROTO_1_1_1 = SPI_FLASH_PROTO(1, 1, 1), /* SPI */
+	SPI_FLASH_PROTO_1_1_2 = SPI_FLASH_PROTO(1, 1, 2), /* Dual Output */
+	SPI_FLASH_PROTO_1_1_4 = SPI_FLASH_PROTO(1, 1, 4), /* Quad Output */
+	SPI_FLASH_PROTO_1_2_2 = SPI_FLASH_PROTO(1, 2, 2), /* Dual IO */
+	SPI_FLASH_PROTO_1_4_4 = SPI_FLASH_PROTO(1, 4, 4), /* Quad IO */
+	SPI_FLASH_PROTO_2_2_2 = SPI_FLASH_PROTO(2, 2, 2), /* Dual Command */
+	SPI_FLASH_PROTO_4_4_4 = SPI_FLASH_PROTO(4, 4, 4), /* Quad Command */
+};
+
 /**
  * struct spi_flash - SPI flash structure
  *
@@ -48,6 +84,10 @@ struct spi_slave;
  * @read_cmd:		Read cmd - Array Fast, Extn read and quad read.
  * @write_cmd:		Write cmd - page and quad program.
  * @dummy_byte:		Dummy cycles for read operation.
+ * @reg_proto		SPI protocol to be used by &read_reg and &write_reg ops
+ * @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
  * @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
@@ -87,6 +127,11 @@ struct spi_flash {
 	u8 write_cmd;
 	u8 dummy_byte;
 
+	enum spi_flash_protocol reg_proto;
+	enum spi_flash_protocol read_proto;
+	enum spi_flash_protocol write_proto;
+	enum spi_flash_protocol erase_proto;
+
 	void *memory_map;
 
 	int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len);
-- 
1.8.2.2

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

* [U-Boot] [PATCH 13/18] sf: add helper function to set the number of dummy bytes
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (11 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 12/18] sf: fix detection of QSPI memories when they boot in Quad or Dual mode Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 14/18] sf: add 4byte address opcodes Cyrille Pitchen
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h |  6 ++++++
 drivers/mtd/spi/spi_flash.c   | 11 +++++++++++
 2 files changed, 17 insertions(+)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 26d359707d5b..86a0276f8518 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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);
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 5d641bbb8301..01a073d81eb9 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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)
-- 
1.8.2.2

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

* [U-Boot] [PATCH 14/18] sf: add 4byte address opcodes
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (12 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 13/18] sf: add helper function to set the number of dummy bytes Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-21  8:58   ` [U-Boot] [PATCH 14/18 v2] " Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 15/18] sf: prepare next fixes to support of QSPI memories by manufacturer Cyrille Pitchen
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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(-)

diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 3f7433cbc214..999c3176adee 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -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
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 86a0276f8518..a98c011218ce 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 01a073d81eb9..b4a44e25f190 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -22,12 +22,15 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static void spi_flash_addr(u32 addr, u8 *cmd)
+static void spi_flash_addr(const struct spi_flash *flash, u32 addr, u8 *cmd)
 {
+	u8 shift = flash->addr_width * 8;
+
 	/* cmd[0] is actual command */
-	cmd[1] = addr >> 16;
-	cmd[2] = addr >> 8;
-	cmd[3] = addr >> 0;
+	cmd[1] = addr >> (shift -  8);
+	cmd[2] = addr >> (shift - 16);
+	cmd[3] = addr >> (shift - 24);
+	cmd[4] = addr >> (shift - 32);
 }
 
 static int read_sr(struct spi_flash *flash, u8 *rs)
@@ -154,6 +157,62 @@ bar_end:
 }
 #endif
 
+#ifdef CONFIG_SPI_FLASH_4B_OPCODES
+struct address_entry {
+	u8	src_opcode;
+	u8	dst_opcode;
+};
+
+static u8 spi_flash_convert_opcode(u8 opcode,
+				   const struct address_entry *entries,
+				   size_t num_entries)
+{
+	int b, e;
+
+	b = 0;
+	e = num_entries - 1;
+	while (b <= e) {
+		int m = (b + e) >> 1;
+		const struct address_entry *entry = &entries[m];
+
+		if (opcode == entry->src_opcode)
+			return entry->dst_opcode;
+
+		if (opcode < entry->src_opcode)
+			e = m - 1;
+		else
+			b = m + 1;
+	}
+
+	/* No convertion found */
+	return opcode;
+}
+
+static u8 spi_flash_3to4_opcode(u8 opcode)
+{
+	/* MUST be sorted by 3byte opcode */
+#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
+	static const struct address_entry spi_flash_3to4_table[] = {
+		ENTRY_3TO4(CMD_READ_ARRAY_SLOW),	/* 0x03 */
+		ENTRY_3TO4(CMD_READ_ARRAY_FAST),	/* 0x0b */
+		ENTRY_3TO4(CMD_ERASE_4K),		/* 0x20 */
+		ENTRY_3TO4(CMD_QUAD_PAGE_PROGRAM),	/* 0x32 */
+		ENTRY_3TO4(CMD_QUAD_PAGE_PROGRAM_MXIC),	/* 0x38 */
+		ENTRY_3TO4(CMD_READ_DUAL_OUTPUT_FAST),	/* 0x3b */
+		ENTRY_3TO4(CMD_ERASE_32K),		/* 0x52 */
+		ENTRY_3TO4(CMD_READ_QUAD_OUTPUT_FAST),	/* 0x6b */
+		ENTRY_3TO4(CMD_READ_DUAL_IO_FAST),	/* 0xbb */
+		ENTRY_3TO4(CMD_ERASE_64K),		/* 0xd8 */
+		ENTRY_3TO4(CMD_READ_QUAD_IO_FAST),	/* 0xeb */
+	};
+#undef ENTRY_3TO4
+
+	return spi_flash_convert_opcode(opcode,
+					spi_flash_3to4_table,
+					ARRAY_SIZE(spi_flash_3to4_table));
+}
+#endif /* CONFIG_SPI_FLASH_4B_OPCODES */
+
 #ifdef CONFIG_SF_DUAL_FLASH
 static void spi_flash_dual(struct spi_flash *flash, u32 *addr)
 {
@@ -353,10 +412,11 @@ static int spi_flash_erase_impl(struct spi_flash *flash, u32 offset)
 {
 	struct spi_slave *spi = flash->spi;
 	u8 cmd[SPI_FLASH_CMD_LEN];
+	size_t cmdsz = 1 + flash->addr_width;
 
 	cmd[0] = flash->erase_cmd;
-	spi_flash_addr(offset, cmd);
-	return spi_flash_cmd_write(spi, cmd, sizeof(cmd), NULL, 0);
+	spi_flash_addr(flash, offset, cmd);
+	return spi_flash_cmd_write(spi, cmd, cmdsz, NULL, 0);
 }
 
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
@@ -461,10 +521,10 @@ static int spi_flash_write_impl(struct spi_flash *flash, u32 offset,
 {
 	struct spi_slave *spi = flash->spi;
 	u8 cmd[SPI_FLASH_CMD_LEN];
-	size_t cmdsz = sizeof(cmd);
+	size_t cmdsz = 1 + flash->addr_width;
 
 	cmd[0] = flash->write_cmd;
-	spi_flash_addr(offset, cmd);
+	spi_flash_addr(flash, offset, cmd);
 #ifdef CONFIG_SPI_FLASH_SST
 	if (flash->flags & SNOR_F_SST_WR_2ND)
 		cmdsz = 1;
@@ -567,7 +627,7 @@ static int spi_flash_read_impl(struct spi_flash *flash, u32 offset,
 	size_t cmdsz;
 	int ret;
 
-	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+	cmdsz = 1 + flash->addr_width + flash->dummy_byte;
 	cmd = calloc(1, cmdsz);
 	if (!cmd) {
 		debug("SF: Failed to allocate cmd\n");
@@ -575,7 +635,7 @@ static int spi_flash_read_impl(struct spi_flash *flash, u32 offset,
 	}
 
 	cmd[0] = flash->read_cmd;
-	spi_flash_addr(offset, cmd);
+	spi_flash_addr(flash, offset, cmd);
 	ret = spi_flash_cmd_read(spi, cmd, cmdsz, buf, len);
 	free(cmd);
 	return ret;
@@ -1255,15 +1315,22 @@ int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 	puts("\n");
 #endif
 
-#ifndef CONFIG_SPI_FLASH_BAR
+	/* Set number of bytes for address and convert opcodes if needed */
+	flash->addr_width = 3;
 	if (((flash->dual_flash == SF_SINGLE_FLASH) &&
 	     (flash->size > SPI_FLASH_16MB_BOUN)) ||
 	     ((flash->dual_flash > SF_SINGLE_FLASH) &&
 	     (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
+#if defined(CONFIG_SPI_FLASH_4B_OPCODES)
+		flash->addr_width = 4;
+		flash->read_cmd  = spi_flash_3to4_opcode(flash->read_cmd);
+		flash->write_cmd = spi_flash_3to4_opcode(flash->write_cmd);
+		flash->erase_cmd = spi_flash_3to4_opcode(flash->erase_cmd);
+#elif !defined(CONFIG_SPI_FLASH_BAR)
 		puts("SF: Warning - Only lower 16MiB accessible,");
-		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
-	}
+		puts(" Full access #define CONFIG_SPI_FLASH_ABOVE_16MB\n");
 #endif
+	}
 
 	return ret;
 }
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 945cc07ee8b2..5db06e5133f3 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -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;
-- 
1.8.2.2

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

* [U-Boot] [PATCH 15/18] sf: prepare next fixes to support of QSPI memories by manufacturer
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (13 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 14/18] sf: add 4byte address opcodes Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 16/18] sf: fix support of Micron memories Cyrille Pitchen
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/spi_flash.c | 155 ++++++++++++++++++++++++++++----------------
 1 file changed, 99 insertions(+), 56 deletions(-)

diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index b4a44e25f190..50250491d228 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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)
-- 
1.8.2.2

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

* [U-Boot] [PATCH 16/18] sf: fix support of Micron memories
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (14 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 15/18] sf: prepare next fixes to support of QSPI memories by manufacturer Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 17/18] ARM: at91: clock: add function to get QSPI clocks Cyrille Pitchen
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

This patch provides support of Micron QSPI memories.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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

diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index c665836f9560..90266d619ddf 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -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
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index a98c011218ce..afee8b69ca6b 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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
diff --git a/drivers/mtd/spi/sf_micron.c b/drivers/mtd/spi/sf_micron.c
new file mode 100644
index 000000000000..b399b6ff52fe
--- /dev/null
+++ b/drivers/mtd/spi/sf_micron.c
@@ -0,0 +1,222 @@
+/*
+ * Micron SPI NOR flash support
+ *
+ * Copyright (C) 2016 Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include "sf_internal.h"
+
+static int spi_flash_micron_set_dummy_cycles(struct spi_flash *flash,
+					     u8 num_dummy_cycles)
+{
+	u8 vcr, mask, value;
+	int ret;
+
+	/* Set the number of dummy cycles and disable XIP */
+	mask = (MICRON_VCR_DUMMIES | MICRON_VCR_XIP);
+	value = MICRON_VCR_DUMMIES_(num_dummy_cycles) | MICRON_VCR_XIP;
+
+	/* Check current VCR value */
+	ret = spi_flash_read_reg(flash, CMD_MICRON_RD_VCR, 1, &vcr);
+	if (ret)
+		goto end;
+
+	if ((vcr & mask) == value)
+		goto end;
+
+	/* VCR update is needed */
+	vcr = (vcr & ~mask) | value;
+	ret = spi_flash_update_reg(flash, CMD_MICRON_WR_VCR, 1, &vcr);
+	if (ret)
+		goto end;
+
+	/* Verify update */
+	ret = spi_flash_read_reg(flash, CMD_MICRON_RD_VCR, 1, &vcr);
+	if (ret)
+		goto end;
+
+	if ((vcr & mask) != value)
+		ret = -EIO;
+
+end:
+	if (ret)
+		printf("SF: failed to set the dummy cycles on Micron memory!\n");
+
+	return ret;
+}
+
+static int spi_flash_micron_set_protocol(struct spi_flash *flash,
+					 enum spi_flash_protocol proto,
+					 u8 mask, u8 value)
+{
+	u8 evcr;
+	int ret;
+
+	/* Check current EVCR value */
+	ret = spi_flash_read_reg(flash, CMD_MICRON_RD_EVCR, 1, &evcr);
+	if (ret)
+		goto end;
+
+	if ((evcr & mask) == value)
+		goto end;
+
+	/* EVCR update is needed */
+	ret = spi_flash_cmd_write_enable(flash);
+	if (ret)
+		goto end;
+
+	evcr = (evcr & ~mask) | value;
+	ret = spi_flash_write_reg(flash, CMD_MICRON_WR_EVCR, 1, &evcr);
+	if (ret)
+		goto end;
+
+	/*
+	 * Don't forget to update the protocol HERE otherwise next commands
+	 * will fail.
+	 */
+	flash->reg_proto = proto;
+
+	/* Wait for ready status */
+	ret = spi_flash_wait_ready(flash);
+	if (ret)
+		goto end;
+
+	/* Verify update */
+	ret = spi_flash_read_reg(flash, CMD_MICRON_RD_EVCR, 1, &evcr);
+	if (ret)
+		goto end;
+
+	if ((evcr & mask) != value)
+		ret = -EIO;
+
+end:
+	if (ret) {
+		printf("SF: failed to set I/O mode on Micron memory!\n");
+		return ret;
+	}
+
+	flash->read_proto = proto;
+	flash->write_proto = proto;
+	flash->erase_proto = proto;
+	return 0;
+}
+
+static inline int spi_flash_micron_set_ext_spi_mode(struct spi_flash *flash)
+{
+	enum spi_flash_protocol proto = SPI_FLASH_PROTO_1_1_1;
+	u8 mask = (MICRON_EVCR_QUAD_DIS | MICRON_EVCR_DUAL_DIS);
+	u8 value = mask;
+
+	return spi_flash_micron_set_protocol(flash, proto, mask, value);
+}
+
+static inline int spi_flash_micron_set_dual_mode(struct spi_flash *flash)
+{
+	enum spi_flash_protocol proto = SPI_FLASH_PROTO_2_2_2;
+	u8 mask = (MICRON_EVCR_QUAD_DIS | MICRON_EVCR_DUAL_DIS);
+	u8 value = MICRON_EVCR_QUAD_DIS;
+
+	return spi_flash_micron_set_protocol(flash, proto, mask, value);
+}
+
+static inline int spi_flash_micron_set_quad_mode(struct spi_flash *flash)
+{
+	enum spi_flash_protocol proto = SPI_FLASH_PROTO_4_4_4;
+	u8 mask = MICRON_EVCR_QUAD_DIS;
+	u8 value = 0;
+
+	return spi_flash_micron_set_protocol(flash, proto, mask, value);
+}
+
+int spi_flash_setup_micron(struct spi_flash *flash,
+			   const struct spi_flash_params *params,
+			   int best_match)
+{
+	u16 read_cmd = best_match ? (1 << (best_match - 1)) : ARRAY_FAST;
+	u8 dummy_cycles = (read_cmd == ARRAY_SLOW) ? 0 : 8;
+	int ret = 0;
+
+	/* Configure (Fast) Read operations */
+	switch (read_cmd) {
+	case QUAD_CMD_FAST:
+		if (flash->reg_proto != SPI_FLASH_PROTO_4_4_4)
+			ret = spi_flash_micron_set_quad_mode(flash);
+		flash->read_cmd = CMD_READ_QUAD_IO_FAST;
+		break;
+
+	case QUAD_IO_FAST:
+		if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+			ret = spi_flash_micron_set_ext_spi_mode(flash);
+		flash->read_proto = SPI_FLASH_PROTO_1_4_4;
+		flash->read_cmd = CMD_READ_QUAD_IO_FAST;
+		break;
+
+	case QUAD_OUTPUT_FAST:
+		if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+			ret = spi_flash_micron_set_ext_spi_mode(flash);
+		flash->read_proto = SPI_FLASH_PROTO_1_1_4;
+		flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST;
+		break;
+
+	case DUAL_CMD_FAST:
+		if (flash->reg_proto != SPI_FLASH_PROTO_2_2_2)
+			ret = spi_flash_micron_set_dual_mode(flash);
+		flash->read_cmd = CMD_READ_DUAL_IO_FAST;
+		break;
+
+	case DUAL_IO_FAST:
+		if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+			ret = spi_flash_micron_set_ext_spi_mode(flash);
+		flash->read_proto = SPI_FLASH_PROTO_1_2_2;
+		flash->read_cmd = CMD_READ_DUAL_IO_FAST;
+		break;
+
+	case DUAL_OUTPUT_FAST:
+		if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+			ret = spi_flash_micron_set_ext_spi_mode(flash);
+		flash->read_proto = SPI_FLASH_PROTO_1_1_2;
+		flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST;
+		break;
+
+	case ARRAY_FAST:
+		flash->read_proto = SPI_FLASH_PROTO_1_1_1;
+		flash->read_cmd = CMD_READ_ARRAY_FAST;
+		break;
+
+	case ARRAY_SLOW:
+		flash->read_proto = SPI_FLASH_PROTO_1_1_1;
+		flash->read_cmd = CMD_READ_ARRAY_SLOW;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	/* Configure Page Program operations */
+	if (flash->write_proto == SPI_FLASH_PROTO_4_4_4 ||
+	    flash->write_proto == SPI_FLASH_PROTO_2_2_2) {
+		flash->write_cmd = CMD_PAGE_PROGRAM;
+	} else if ((flash->spi->mode & SPI_TX_QUAD) &&
+		   (params->flags & WR_QPP)) {
+		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+		flash->write_proto = SPI_FLASH_PROTO_1_1_4;
+	} else {
+		flash->write_cmd = CMD_PAGE_PROGRAM;
+		flash->write_proto = SPI_FLASH_PROTO_1_1_1;
+	}
+
+	/* Set number of dummy cycles for Fast Read operations */
+	if (params->e_rd_cmd & (QUAD_CMD_FAST | DUAL_CMD_FAST))
+		ret = spi_flash_micron_set_dummy_cycles(flash, dummy_cycles);
+	return ret ? : spi_flash_set_dummy_byte(flash, dummy_cycles);
+}
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 50250491d228..922afc811a0b 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -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);
-- 
1.8.2.2

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

* [U-Boot] [PATCH 17/18] ARM: at91: clock: add function to get QSPI clocks
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (15 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 16/18] sf: fix support of Micron memories Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:12 ` [U-Boot] [PATCH 18/18] sf: add driver for Atmel QSPI controller Cyrille Pitchen
  2016-03-15 18:21 ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Jagan Teki
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

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

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 arch/arm/mach-at91/include/mach/clk.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/mach-at91/include/mach/clk.h b/arch/arm/mach-at91/include/mach/clk.h
index 8577c74b47b7..aba7656e72f7 100644
--- a/arch/arm/mach-at91/include/mach/clk.h
+++ b/arch/arm/mach-at91/include/mach/clk.h
@@ -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())
-- 
1.8.2.2

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

* [U-Boot] [PATCH 18/18] sf: add driver for Atmel QSPI controller
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (16 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 17/18] ARM: at91: clock: add function to get QSPI clocks Cyrille Pitchen
@ 2016-03-15 18:12 ` Cyrille Pitchen
  2016-03-15 18:21 ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Jagan Teki
  18 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-15 18:12 UTC (permalink / raw)
  To: u-boot

This patch adds support of the Atmel QSPI controller.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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

diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 90266d619ddf..207e1d556f3f 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -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
diff --git a/drivers/mtd/spi/atmel_qspi_flash.c b/drivers/mtd/spi/atmel_qspi_flash.c
new file mode 100644
index 000000000000..97f85ae2e30c
--- /dev/null
+++ b/drivers/mtd/spi/atmel_qspi_flash.c
@@ -0,0 +1,432 @@
+#include <common.h>
+#include <errno.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include "sf_internal.h"
+#include "../../spi/atmel_qspi.h"
+
+struct atmel_qspi_command {
+	union {
+		struct {
+			unsigned int	instruction:1;
+			unsigned int	address:3;
+			unsigned int	mode:1;
+			unsigned int	dummy:1;
+			unsigned int	data:1;
+			unsigned int	reserved:25;
+		}		bits;
+		unsigned int	word;
+	}			enable;
+	unsigned char		instruction;
+	unsigned char		mode;
+	unsigned char		num_mode_cycles;
+	unsigned char		num_dummy_cycles;
+	unsigned int		address;
+
+	size_t			buf_len;
+	const void		*tx_buf;
+	void			*rx_buf;
+
+	enum spi_flash_protocol	protocol;
+	u32			ifr_tfrtype;
+};
+
+
+static void atmel_qspi_memcpy_fromio(void *dst, unsigned long src, size_t len)
+{
+	u8 *d = (u8 *)dst;
+
+	while (len--) {
+		*d++ = readb(src);
+		src++;
+	}
+}
+
+static void atmel_qspi_memcpy_toio(unsigned long dst, const void *src,
+				   size_t len)
+{
+	const u8 *s = (const u8 *)src;
+
+	while (len--) {
+		writeb(*s, dst);
+		dst++;
+		s++;
+	}
+}
+
+static int atmel_qpsi_set_ifr_width(enum spi_flash_protocol proto, u32 *ifr)
+{
+	u32 ifr_width;
+
+	switch (proto) {
+	case SPI_FLASH_PROTO_1_1_1:
+		ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
+		break;
+
+	case SPI_FLASH_PROTO_1_1_2:
+		ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
+		break;
+
+	case SPI_FLASH_PROTO_1_2_2:
+		ifr_width = QSPI_IFR_WIDTH_DUAL_IO;
+		break;
+
+	case SPI_FLASH_PROTO_2_2_2:
+		ifr_width = QSPI_IFR_WIDTH_DUAL_CMD;
+		break;
+
+	case SPI_FLASH_PROTO_1_1_4:
+		ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
+		break;
+
+	case SPI_FLASH_PROTO_1_4_4:
+		ifr_width = QSPI_IFR_WIDTH_QUAD_IO;
+		break;
+
+	case SPI_FLASH_PROTO_4_4_4:
+		ifr_width = QSPI_IFR_WIDTH_QUAD_CMD;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	*ifr = (*ifr & ~QSPI_IFR_WIDTH) | ifr_width;
+	return 0;
+}
+
+static int atmel_qspi_send_command(struct atmel_qspi_priv *aq,
+				   const struct atmel_qspi_command *cmd)
+{
+	unsigned int iar, icr, ifr;
+	unsigned int offset;
+	unsigned int imr, sr;
+	unsigned long memaddr;
+	int err;
+
+	iar = 0;
+	icr = 0;
+	ifr = cmd->ifr_tfrtype;
+
+	err = atmel_qpsi_set_ifr_width(cmd->protocol, &ifr);
+	if (err)
+		return err;
+
+	/* Compute instruction parameters */
+	if (cmd->enable.bits.instruction) {
+		icr |= QSPI_ICR_INST_(cmd->instruction);
+		ifr |= QSPI_IFR_INSTEN;
+	}
+
+	/* Compute address parameters. */
+	switch (cmd->enable.bits.address) {
+	case 4:
+		ifr |= QSPI_IFR_ADDRL_32_BIT;
+		//break; /* fall through the 24bit (3 byte) address case */
+	case 3:
+		iar = (cmd->enable.bits.data) ? 0 : cmd->address;
+		ifr |= QSPI_IFR_ADDREN;
+		offset = cmd->address;
+		break;
+	case 0:
+		offset = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Compute option parameters. */
+	if (cmd->enable.bits.mode && cmd->num_mode_cycles) {
+		unsigned int mode_cycle_bits, mode_bits;
+
+		icr |= QSPI_ICR_OPT_(cmd->mode);
+		ifr |= QSPI_IFR_OPTEN;
+
+		switch (ifr & QSPI_IFR_WIDTH) {
+		case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
+		case QSPI_IFR_WIDTH_DUAL_OUTPUT:
+		case QSPI_IFR_WIDTH_QUAD_OUTPUT:
+			mode_cycle_bits = 1;
+			break;
+		case QSPI_IFR_WIDTH_DUAL_IO:
+		case QSPI_IFR_WIDTH_DUAL_CMD:
+			mode_cycle_bits = 2;
+			break;
+		case QSPI_IFR_WIDTH_QUAD_IO:
+		case QSPI_IFR_WIDTH_QUAD_CMD:
+			mode_cycle_bits = 4;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		mode_bits = cmd->num_mode_cycles * mode_cycle_bits;
+		switch (mode_bits) {
+		case 1:
+			ifr |= QSPI_IFR_OPTL_1BIT;
+			break;
+
+		case 2:
+			ifr |= QSPI_IFR_OPTL_2BIT;
+			break;
+
+		case 4:
+			ifr |= QSPI_IFR_OPTL_4BIT;
+			break;
+
+		case 8:
+			ifr |= QSPI_IFR_OPTL_8BIT;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/* Set the number of dummy cycles. */
+	if (cmd->enable.bits.dummy)
+		ifr |= QSPI_IFR_NBDUM_(cmd->num_dummy_cycles);
+
+	/* Set data enable. */
+	if (cmd->enable.bits.data) {
+		ifr |= QSPI_IFR_DATAEN;
+
+		/* Special case for Continuous Read Mode. */
+		if (!cmd->tx_buf && !cmd->rx_buf)
+			ifr |= QSPI_IFR_CRM;
+	}
+
+	/* Clear pending interrupts. */
+	(void)qspi_readl(aq, QSPI_SR);
+
+	/* Set QSPI Instruction Frame registers. */
+	qspi_writel(aq, QSPI_IAR, iar);
+	qspi_writel(aq, QSPI_ICR, icr);
+	qspi_writel(aq, QSPI_IFR, ifr);
+
+	/* Skip to the final steps if there is no data. */
+	if (!cmd->enable.bits.data)
+		goto no_data;
+
+	/* Dummy read of QSPI_IFR to synchronize APB and AHB accesses. */
+	(void)qspi_readl(aq, QSPI_IFR);
+
+	/* Stop here for Continuous Read. */
+	memaddr = (unsigned long)(aq->membase + offset);
+	if (cmd->tx_buf)
+		/* Write data. */
+		atmel_qspi_memcpy_toio(memaddr, cmd->tx_buf, cmd->buf_len);
+	else if (cmd->rx_buf)
+		/* Read data. */
+		atmel_qspi_memcpy_fromio(cmd->rx_buf, memaddr, cmd->buf_len);
+	else
+		/* Stop here for continuous read */
+		return 0;
+
+	/* Release the chip-select. */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_LASTXFER);
+
+no_data:
+	/* Poll INSTruction End and Chip Select Rise flags. */
+	imr = (QSPI_SR_INSTRE | QSPI_SR_CSR);
+	sr = 0;
+	while (sr != (QSPI_SR_INSTRE | QSPI_SR_CSR))
+		sr |= qspi_readl(aq, QSPI_SR) & imr;
+
+	return 0;
+}
+
+static int atmel_qspi_read_reg(struct udevice *dev, u8 opcode,
+			       size_t len, void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	struct atmel_qspi_priv *aq = dev_get_priv(dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.data = 1;
+	cmd.instruction = opcode;
+	cmd.rx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->reg_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_READ;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_write_reg(struct udevice *dev, u8 opcode,
+				size_t len, const void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	struct atmel_qspi_priv *aq = dev_get_priv(dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.data = (buf && len);
+	cmd.instruction = opcode;
+	cmd.tx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->reg_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_read_impl(struct spi_flash *flash, u32 offset,
+				size_t len, void *buf)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(flash->dev->parent);
+	struct atmel_qspi_command cmd;
+	u8 lshift;
+
+	switch (SPI_FLASH_PROTO_ADR_FROM_PROTO(flash->read_proto)) {
+	case 1:
+		lshift = 3;
+		break;
+
+	case 2:
+		lshift = 2;
+		break;
+
+	case 4:
+		lshift = 1;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.address = flash->addr_width;
+	cmd.enable.bits.mode = 0;
+	cmd.enable.bits.dummy = (flash->dummy_byte > 0);
+	cmd.enable.bits.data = 1;
+	cmd.instruction = flash->read_cmd;
+	cmd.address = offset;
+	cmd.num_dummy_cycles = flash->dummy_byte << lshift;
+	cmd.rx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->read_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_READ_MEMORY;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_read(struct udevice *dev, u32 offset,
+			   size_t len, void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_read_alg(flash, offset, len, buf,
+				  atmel_qspi_read_impl);
+}
+
+static int atmel_qspi_write_impl(struct spi_flash *flash, u32 offset,
+				 size_t len, const void *buf)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(flash->dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.address = flash->addr_width;
+	cmd.enable.bits.data = 1;
+	cmd.instruction = flash->write_cmd;
+	cmd.address = offset;
+	cmd.tx_buf = buf;
+	cmd.buf_len = len;
+	cmd.protocol = flash->write_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE_MEMORY;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_write(struct udevice *dev, u32 offset,
+			    size_t len, const void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_write_alg(flash, offset, len, buf,
+				   atmel_qspi_write_impl);
+}
+
+static int atmel_qspi_erase_impl(struct spi_flash *flash, u32 offset)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(flash->dev->parent);
+	struct atmel_qspi_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.enable.bits.instruction = 1;
+	cmd.enable.bits.address = flash->addr_width;
+	cmd.instruction = flash->erase_cmd;
+	cmd.address = offset;
+	cmd.protocol = flash->erase_proto;
+	cmd.ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE;
+	return atmel_qspi_send_command(aq, &cmd);
+}
+
+static int atmel_qspi_erase(struct udevice *dev, u32 offset, size_t len)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+	return spi_flash_erase_alg(flash, offset, len,
+				   atmel_qspi_erase_impl);
+}
+
+static const struct dm_spi_flash_ops atmel_qspi_flash_ops = {
+	.read_reg	= atmel_qspi_read_reg,
+	.write_reg	= atmel_qspi_write_reg,
+	.read		= atmel_qspi_read,
+	.write		= atmel_qspi_write,
+	.erase		= atmel_qspi_erase,
+};
+
+static int atmel_qspi_flash_probe(struct udevice *dev)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	struct spi_slave *slave = dev_get_parent_priv(dev);
+	int ret;
+
+	flash->dev = dev;
+	flash->spi = slave;
+
+	/* Claim spi bus */
+	ret = spi_claim_bus(slave);
+	if (ret) {
+		debug("SF: Failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	/* The Quad SPI controller supports all Dual & Quad I/O protocols */
+	slave->mode |= (SPI_TX_QUAD | SPI_TX_DUAL);
+	ret = spi_flash_scan(flash, RD_FCMD);
+	if (ret) {
+		ret = -EINVAL;
+		goto release;
+	}
+
+#ifdef CONFIG_SPI_FLASH_MTD
+	ret = spi_flash_mtd_register(flash);
+#endif
+
+release:
+	spi_release_bus(slave);
+	return ret;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct udevice_id atmel_qspi_flash_ids[] = {
+	{ .compatible = "atmel,sama5d2-qspi-flash" },
+	{ }
+};
+#endif
+
+U_BOOT_DRIVER(atmel_qspi_flash) = {
+	.name		= "atmel_qspi_flash",
+	.id		= UCLASS_SPI_FLASH,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_match	= atmel_qspi_flash_ids,
+#endif
+	.probe		= atmel_qspi_flash_probe,
+	.ops		= &atmel_qspi_flash_ops,
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f0258f84afeb..d478c5d953c6 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -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
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3eca7456d6a6..eb3bd95f5ee7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -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
diff --git a/drivers/spi/atmel_qspi.c b/drivers/spi/atmel_qspi.c
new file mode 100644
index 000000000000..b8e280553d99
--- /dev/null
+++ b/drivers/spi/atmel_qspi.c
@@ -0,0 +1,150 @@
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <mach/clk.h>
+
+#include "atmel_qspi.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+
+static int atmel_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+			   const void *dout, void *din, unsigned long flags)
+{
+	/* This controller can only be used with SPI NOR flashes. */
+	return -EINVAL;
+}
+
+static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(bus);
+	unsigned long src_rate;
+	u32 scr, scbr, mask, new_value;
+
+	/* Compute the QSPI baudrate */
+	src_rate = get_qspi_clk_rate(aq->dev_id);
+	scbr = DIV_ROUND_UP(src_rate, hz);
+	if (scbr > 0)
+		scbr--;
+
+	new_value = QSPI_SCR_SCBR_(scbr);
+	mask = QSPI_SCR_SCBR;
+
+	scr = qspi_readl(aq, QSPI_SCR);
+	if ((scr & mask) == new_value)
+		return 0;
+
+	scr = (scr & ~mask) | new_value;
+	qspi_writel(aq, QSPI_SCR, scr);
+
+	return 0;
+}
+
+static int atmel_qspi_set_mode(struct udevice *bus, uint mode)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(bus);
+	u32 scr, mask, new_value;
+
+	new_value = (QSPI_SCR_CPOL_((mode & SPI_CPOL) != 0) |
+		     QSPI_SCR_CPHA_((mode & SPI_CPHA) != 0));
+	mask = (QSPI_SCR_CPOL | QSPI_SCR_CPHA);
+
+	scr = qspi_readl(aq, QSPI_SCR);
+	if ((scr & mask) == new_value)
+		return 0;
+
+	scr = (scr & ~mask) | new_value;
+	qspi_writel(aq, QSPI_SCR, scr);
+
+	return 0;
+}
+
+static const struct dm_spi_ops atmel_qspi_ops = {
+	.xfer		= atmel_qspi_xfer,
+	.set_speed	= atmel_qspi_set_speed,
+	.set_mode	= atmel_qspi_set_mode,
+};
+
+static int atmel_qspi_probe(struct udevice *dev)
+{
+	const struct atmel_qspi_platdata *plat = dev_get_platdata(dev);
+	struct atmel_qspi_priv *aq = dev_get_priv(dev);
+	u32 mr;
+
+	aq->regbase = plat->regbase;
+	aq->membase = plat->membase;
+	aq->dev_id = plat->dev_id;
+
+	/* Reset the QSPI controler */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_SWRST);
+
+	/* Set the QSPI controller in Serial Memory Mode */
+	mr = (QSPI_MR_NBBITS_8_BIT |
+	      QSPI_MR_SMM_MEMORY |
+	      QSPI_MR_CSMODE_LASTXFER);
+	qspi_writel(aq, QSPI_MR, mr);
+
+	/* Enable the QSPI controller */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIEN);
+
+	return 0;
+}
+
+static int atmel_qspi_remove(struct udevice *dev)
+{
+	struct atmel_qspi_priv *aq = dev_get_priv(dev);
+
+	/* Disable the QSPI controller */
+	qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIDIS);
+
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int atmel_qspi_ofdata_to_platdata(struct udevice *dev)
+{
+	struct atmel_qspi_platdata *plat = dev_get_platdata(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	u32 data[4];
+	int ret, seq;
+
+	ret = fdtdec_get_int_array(blob, node, "reg", data, ARRAY_SIZE(data));
+	if (ret) {
+		printf("Error: Can't get base addresses (ret=%d)!\n", ret);
+		return -ENODEV;
+	}
+	plat->regbase = (void *)data[0];
+	plat->membase = (void *)data[2];
+
+	ret = fdtdec_get_alias_seq(blob, "spi", node, &seq);
+	if (ret) {
+		printf("Error: Can't get device ID (ret=%d)!\n", ret);
+		return -ENODEV;
+	}
+	plat->dev_id = (unsigned int)seq;
+
+	return 0;
+}
+
+static const struct udevice_id atmel_qspi_ids[] = {
+	{ .compatible = "atmel,sama5d2-qspi" },
+	{ }
+};
+#endif
+
+U_BOOT_DRIVER(atmel_qspi) = {
+	.name		= "atmel_qspi",
+	.id		= UCLASS_SPI,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_match	= atmel_qspi_ids,
+	.ofdata_to_platdata = atmel_qspi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct atmel_qspi_platdata),
+#endif
+	.priv_auto_alloc_size = sizeof(struct atmel_qspi_priv),
+	.ops		= &atmel_qspi_ops,
+	.probe		= atmel_qspi_probe,
+	.remove		= atmel_qspi_remove,
+};
diff --git a/drivers/spi/atmel_qspi.h b/drivers/spi/atmel_qspi.h
new file mode 100644
index 000000000000..2b221dd44335
--- /dev/null
+++ b/drivers/spi/atmel_qspi.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2016
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ATMEL_QSPI_H__
+#define __ATMEL_QSPI_H__
+
+/*
+ * Register Definitions
+ */
+#define	QSPI_CR		0x00	/* Control Register */
+#define	QSPI_MR		0x04	/* Mode Register */
+#define	QSPI_RDR	0x08	/* Receive Data Register */
+#define	QSPI_TDR	0x0c	/* Transmit Data Register */
+#define	QSPI_SR		0x10	/* Status Register */
+#define	QSPI_IER	0x14	/* Interrupt Enable Register */
+#define	QSPI_IDR	0x18	/* Interrupt Disable Register */
+#define	QSPI_IMR	0x1c	/* Interrupt Mask Register */
+#define	QSPI_SCR	0x20	/* Serial Clock Register */
+#define	QSPI_IAR	0x30	/* Instruction Address Register */
+#define	QSPI_ICR	0x34	/* Instruction Code Register */
+#define	QSPI_IFR	0x38	/* Instruction Frame Register */
+/* 0x3c Reserved */
+#define	QSPI_SMR	0x40	/* Scrambling Mode Register */
+#define	QSPI_SKR	0x44	/* Scrambling Key Register */
+/* 0x48 ~ 0xe0 */
+#define	QSPI_WPMR	0xe4	/* Write Protection Mode Register */
+#define	QSPI_WPSR	0xe8	/* Write Protection Status Register */
+/* 0xec ~ 0xf8 Reserved */
+/* 0xfc Reserved */
+
+/*
+ * Register Field Definitions
+ */
+/* QSPI_CR */
+#define	QSPI_CR_QSPIEN		(0x1 << 0)	/* QSPI Enable */
+#define	QSPI_CR_QSPIDIS		(0x1 << 1)	/* QSPI Disable */
+#define	QSPI_CR_SWRST		(0x1 << 7)	/* QSPI Software Reset */
+#define	QSPI_CR_LASTXFER	(0x1 << 24)	/* Last Transfer */
+
+/* QSPI_MR */
+#define	QSPI_MR_SMM		(0x1 << 0)	/* Serial Memort Mode */
+#define		QSPI_MR_SMM_SPI		(0x0 << 0)
+#define		QSPI_MR_SMM_MEMORY	(0x1 << 0)
+#define	QSPI_MR_LLB		(0x1 << 1)	/* Local Localback Enable */
+#define		QSPI_MR_LLB_DISABLED	(0x0 << 1)
+#define		QSPI_MR_LLB_ENABLED	(0x1 << 1)
+#define	QSPI_MR_WDRBT		(0x1 << 2)	/* Wait Data Read Before Transfer */
+#define		QSPI_MR_WDRBT_DISABLED		(0x0 << 2)
+#define		QSPI_MR_WDRBT_ENABLED		(0x1 << 2)
+#define	QSPI_MR_SMRM		(0x1 << 3)	/* Serial Memory Register Mode */
+#define		QSPI_MR_SMRM_AHB	(0x0 << 3)
+#define		QSPI_MR_SMRM_APB	(0x1 << 3)
+#define	QSPI_MR_CSMODE		(0x3 << 4)	/* Chip Select Mode */
+#define		QSPI_MR_CSMODE_NOT_RELOADED	(0x0 << 4)
+#define		QSPI_MR_CSMODE_LASTXFER		(0x1 << 4)
+#define		QSPI_MR_CSMODE_SYSTEMATICALLY	(0x2 << 4)
+#define	QSPI_MR_NBBITS		(0xf << 8)	/* Number of Bits Per Transfer */
+#define		QSPI_MR_NBBITS_8_BIT		(0x0 << 8)
+#define		QSPI_MR_NBBITS_16_BIT		(0x8 << 8)
+#define	QSPI_MR_DLYBCT		(0xff << 16)	/* Delay Between Consecutive Transfers */
+#define	QSPI_MR_DLYCS		(0xff << 24)	/* Minimum Inactive QCS Delay */
+
+/* QSPI_SR */
+#define	QSPI_SR_RDRF		(0x1 << 0)	/* Receive Data Register Full */
+#define	QSPI_SR_TDRE		(0x1 << 1)	/* Transmit Data Register Empty */
+#define	QSPI_SR_TXEMPTY		(0x1 << 2)	/* Transmission Registers Empty */
+#define	QSPI_SR_OVRES		(0x1 << 3)	/* Overrun Error Status */
+#define	QSPI_SR_CSR		(0x1 << 8)	/* Chip Select Rise */
+#define	QSPI_SR_CSS		(0x1 << 9)	/* Chip Select Status */
+#define	QSPI_SR_INSTRE		(0x1 << 10)	/* Instruction End Status */
+#define	QSPI_SR_QSPIENS		(0x1 << 24)	/* QSPI Enable Status */
+
+/* QSPI_SCR */
+#define	QSPI_SCR_CPOL		(0x1 << 0)	/* Clock Polarity */
+#define	QSPI_SCR_CPOL_(x)	((x) << 0)
+#define	QSPI_SCR_CPHA		(0x1 << 1)	/* Clock Phase */
+#define	QSPI_SCR_CPHA_(x)	((x) << 1)
+#define	QSPI_SCR_SCBR		(0xff << 8)	/* Serial Clock Baud Rate */
+#define	QSPI_SCR_SCBR_(x)	((x) << 8)
+#define	QSPI_SCR_DLYBS_(x)	((x) << 16)	/* Delay Before QSCK */
+
+/* QSPI_ICR */
+#define	QSPI_ICR_INST_(x)	((x) << 0)	/* Instruction Code */
+#define	QSPI_ICR_OPT_(x)	((x) << 16)	/* Option Code */
+
+/* QSPI_IFR */
+#define	QSPI_IFR_WIDTH		(0x7 << 0)	/* Width of Instruction Code, Address, Option Code and Data */
+#define		QSPI_IFR_WIDTH_SINGLE_BIT_SPI	(0x0 << 0)
+#define		QSPI_IFR_WIDTH_DUAL_OUTPUT	(0x1 << 0)
+#define		QSPI_IFR_WIDTH_QUAD_OUTPUT	(0x2 << 0)
+#define		QSPI_IFR_WIDTH_DUAL_IO		(0x3 << 0)
+#define		QSPI_IFR_WIDTH_QUAD_IO		(0x4 << 0)
+#define		QSPI_IFR_WIDTH_DUAL_CMD		(0x5 << 0)
+#define		QSPI_IFR_WIDTH_QUAD_CMD		(0x6 << 0)
+#define QSPI_IFR_WIDTH_(x)	(((x) << 0) & QSPI_IFR_WIDTH)
+#define	QSPI_IFR_INSTEN		(0x1 << 4)	/* Instruction Enable*/
+#define	QSPI_IFR_ADDREN		(0x1 << 5)	/* Address Enable*/
+#define	QSPI_IFR_OPTEN		(0x1 << 6)	/* Option Enable*/
+#define	QSPI_IFR_DATAEN		(0x1 << 7)	/* Data Enable*/
+#define	QSPI_IFR_OPTL		(0x3 << 8)	/* Option Code Length */
+#define		QSPI_IFR_OPTL_1BIT		(0x0 << 8)
+#define		QSPI_IFR_OPTL_2BIT		(0x1 << 8)
+#define		QSPI_IFR_OPTL_4BIT		(0x2 << 8)
+#define		QSPI_IFR_OPTL_8BIT		(0x3 << 8)
+#define	QSPI_IFR_ADDRL		(0x1 << 10)	/* Address Length */
+#define		QSPI_IFR_ADDRL_24_BIT		(0x0 << 10)
+#define		QSPI_IFR_ADDRL_32_BIT		(0x1 << 10)
+#define	QSPI_IFR_TFRTYPE	(0x3 << 12)	/* Data Transfer Type */
+#define		QSPI_IFR_TFRTYPE_READ		(0x0 << 12)
+#define		QSPI_IFR_TFRTYPE_READ_MEMORY	(0x1 << 12)
+#define		QSPI_IFR_TFRTYPE_WRITE		(0x2 << 12)
+#define		QSPI_IFR_TFRTYPE_WRITE_MEMORY	(0x3 << 12)
+#define QSPI_IFR_TFRTYPE_(x)	(((x) << 12) & QSPI_IFR_TFRTYPE)
+#define	QSPI_IFR_CRM		(0x1 << 14)	/* Continuous Read Mode */
+#define	QSPI_IFR_NBDUM_(x)	((x) << 16)	/* Number Of Dummy Cycles */
+
+
+struct atmel_qspi_platdata {
+	unsigned int	dev_id;
+	void		*regbase;
+	void		*membase;
+};
+
+struct atmel_qspi_priv {
+	unsigned int	dev_id;
+	void		*regbase;
+	void		*membase;
+};
+
+#include <asm/io.h>
+
+static inline u32 qspi_readl(struct atmel_qspi_priv *aq, u32 reg)
+{
+	return readl(aq->regbase + reg);
+}
+
+static inline void qspi_writel(struct atmel_qspi_priv *aq, u32 reg, u32 value)
+{
+	writel(value, aq->regbase + reg);
+}
+
+#endif /* __ATMEL_QSPI_H__ */
-- 
1.8.2.2

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
                   ` (17 preceding siblings ...)
  2016-03-15 18:12 ` [U-Boot] [PATCH 18/18] sf: add driver for Atmel QSPI controller Cyrille Pitchen
@ 2016-03-15 18:21 ` Jagan Teki
  2016-03-15 19:17   ` Marek Vasut
  2016-03-16 13:30   ` Cyrille Pitchen
  18 siblings, 2 replies; 36+ messages in thread
From: Jagan Teki @ 2016-03-15 18:21 UTC (permalink / raw)
  To: u-boot

On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
> 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

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 

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-15 18:21 ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Jagan Teki
@ 2016-03-15 19:17   ` Marek Vasut
  2016-03-16 13:30   ` Cyrille Pitchen
  1 sibling, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2016-03-15 19:17 UTC (permalink / raw)
  To: u-boot

On 03/15/2016 07:21 PM, Jagan Teki wrote:
> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>> 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
> 
> 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.

-- 
Best regards,
Marek Vasut

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-15 18:21 ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Jagan Teki
  2016-03-15 19:17   ` Marek Vasut
@ 2016-03-16 13:30   ` Cyrille Pitchen
  2016-03-16 14:14     ` Jagan Teki
  1 sibling, 1 reply; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-16 13:30 UTC (permalink / raw)
  To: u-boot

Le 15/03/2016 19:21, Jagan Teki a ?crit :
> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>> 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
> 
> 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

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-16 13:30   ` Cyrille Pitchen
@ 2016-03-16 14:14     ` Jagan Teki
  2016-03-16 16:23       ` Albert ARIBAUD
                         ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Jagan Teki @ 2016-03-16 14:14 UTC (permalink / raw)
  To: u-boot

On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
> Le 15/03/2016 19:21, Jagan Teki a ?crit :
>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>>> 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
>>
>> 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.

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

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-16 14:14     ` Jagan Teki
@ 2016-03-16 16:23       ` Albert ARIBAUD
  2016-03-16 16:34         ` Jagan Teki
  2016-03-16 16:30       ` Cyrille Pitchen
  2016-03-18 13:48       ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Stefan Roese
  2 siblings, 1 reply; 36+ messages in thread
From: Albert ARIBAUD @ 2016-03-16 16:23 UTC (permalink / raw)
  To: u-boot

Hello Jagan,

On Wed, 16 Mar 2016 19:44:26 +0530, Jagan Teki <jteki@openedev.com>
wrote:
> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
> > Le 15/03/2016 19:21, Jagan Teki a ?crit :
> >> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
> >>> 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
> >>
> >> 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.
> 
> 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!

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.

> -- 
> Jagan

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-16 14:14     ` Jagan Teki
  2016-03-16 16:23       ` Albert ARIBAUD
@ 2016-03-16 16:30       ` Cyrille Pitchen
  2016-03-16 16:41         ` [U-Boot] [PATCH 1/4] rework board config files Cyrille Pitchen
  2016-03-18 13:48       ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Stefan Roese
  2 siblings, 1 reply; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-16 16:30 UTC (permalink / raw)
  To: u-boot

Le 16/03/2016 15:14, Jagan Teki a ?crit :
> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
>> Le 15/03/2016 19:21, Jagan Teki a ?crit :
>>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>>>> 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
>>>
>>> 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.
> 
> 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

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-16 16:23       ` Albert ARIBAUD
@ 2016-03-16 16:34         ` Jagan Teki
  2016-03-17  7:30           ` Albert ARIBAUD
  0 siblings, 1 reply; 36+ messages in thread
From: Jagan Teki @ 2016-03-16 16:34 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On Wednesday 16 March 2016 09:53 PM, Albert ARIBAUD wrote:
> Hello Jagan,
>
> On Wed, 16 Mar 2016 19:44:26 +0530, Jagan Teki <jteki@openedev.com>
> wrote:
>> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
>>> Le 15/03/2016 19:21, Jagan Teki a ?crit :
>>>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>>>>> 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
>>>>
>>>> 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.
>>
>> 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!
>
> 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.

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!

-- 
Jagan

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

* [U-Boot] [PATCH 1/4] rework board config files
  2016-03-16 16:30       ` Cyrille Pitchen
@ 2016-03-16 16:41         ` Cyrille Pitchen
  2016-03-16 16:41           ` [U-Boot] [PATCH 2/4] sama5d2_xplained: add support of QSPI controllers Cyrille Pitchen
                             ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-16 16:41 UTC (permalink / raw)
  To: u-boot

---
 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(-)

diff --git a/board/atmel/sama5d2_xplained/Kconfig b/board/atmel/sama5d2_xplained/Kconfig
index 55712e97454b..d4106b90f599 100644
--- a/board/atmel/sama5d2_xplained/Kconfig
+++ b/board/atmel/sama5d2_xplained/Kconfig
@@ -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
diff --git a/board/atmel/sama5d2_xplained/sama5d2_xplained.c b/board/atmel/sama5d2_xplained/sama5d2_xplained.c
index 10edf28a9bd6..4dd83e5e991f 100644
--- a/board/atmel/sama5d2_xplained/sama5d2_xplained.c
+++ b/board/atmel/sama5d2_xplained/sama5d2_xplained.c
@@ -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)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index dc8532fe9373..b3d085119ac8 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -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
diff --git a/include/configs/at91-sama5_common.h b/include/configs/at91-sama5_common.h
index 6525b5c3701e..0297fd781dc6 100644
--- a/include/configs/at91-sama5_common.h
+++ b/include/configs/at91-sama5_common.h
@@ -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
diff --git a/include/configs/sama5d2_xplained.h b/include/configs/sama5d2_xplained.h
index 272257ea0edd..3391a0ea5b45 100644
--- a/include/configs/sama5d2_xplained.h
+++ b/include/configs/sama5d2_xplained.h
@@ -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
 
-- 
1.8.2.2

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

* [U-Boot] [PATCH 2/4] sama5d2_xplained: add support of QSPI controllers
  2016-03-16 16:41         ` [U-Boot] [PATCH 1/4] rework board config files Cyrille Pitchen
@ 2016-03-16 16:41           ` Cyrille Pitchen
  2016-03-16 16:41           ` [U-Boot] [PATCH 3/4] dts: add dts file for Atmel sama5d2 xplained board Cyrille Pitchen
  2016-03-16 16:41           ` [U-Boot] [PATCH 4/4] sf: fix sf probe Cyrille Pitchen
  2 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-16 16:41 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 board/atmel/sama5d2_xplained/Kconfig            |  6 ++++++
 board/atmel/sama5d2_xplained/sama5d2_xplained.c | 18 ++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/board/atmel/sama5d2_xplained/Kconfig b/board/atmel/sama5d2_xplained/Kconfig
index d4106b90f599..1659a2043b04 100644
--- a/board/atmel/sama5d2_xplained/Kconfig
+++ b/board/atmel/sama5d2_xplained/Kconfig
@@ -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
diff --git a/board/atmel/sama5d2_xplained/sama5d2_xplained.c b/board/atmel/sama5d2_xplained/sama5d2_xplained.c
index 4dd83e5e991f..6d4c2da99bc3 100644
--- a/board/atmel/sama5d2_xplained/sama5d2_xplained.c
+++ b/board/atmel/sama5d2_xplained/sama5d2_xplained.c
@@ -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
-- 
1.8.2.2

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

* [U-Boot] [PATCH 3/4] dts: add dts file for Atmel sama5d2 xplained board
  2016-03-16 16:41         ` [U-Boot] [PATCH 1/4] rework board config files Cyrille Pitchen
  2016-03-16 16:41           ` [U-Boot] [PATCH 2/4] sama5d2_xplained: add support of QSPI controllers Cyrille Pitchen
@ 2016-03-16 16:41           ` Cyrille Pitchen
  2016-03-16 16:41           ` [U-Boot] [PATCH 4/4] sf: fix sf probe Cyrille Pitchen
  2 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-16 16:41 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 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

diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 578038be21f9..97521f16aac4 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -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
diff --git a/arch/arm/dts/at91-sama5d2_xplained.dts b/arch/arm/dts/at91-sama5d2_xplained.dts
new file mode 100644
index 000000000000..2394f6bd4249
--- /dev/null
+++ b/arch/arm/dts/at91-sama5d2_xplained.dts
@@ -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>;
+		};
+	};
+};
diff --git a/arch/arm/dts/sama5d2.dtsi b/arch/arm/dts/sama5d2.dtsi
new file mode 100644
index 000000000000..dccc66cccb88
--- /dev/null
+++ b/arch/arm/dts/sama5d2.dtsi
@@ -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
-- 
1.8.2.2

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

* [U-Boot] [PATCH 4/4] sf: fix sf probe
  2016-03-16 16:41         ` [U-Boot] [PATCH 1/4] rework board config files Cyrille Pitchen
  2016-03-16 16:41           ` [U-Boot] [PATCH 2/4] sama5d2_xplained: add support of QSPI controllers Cyrille Pitchen
  2016-03-16 16:41           ` [U-Boot] [PATCH 3/4] dts: add dts file for Atmel sama5d2 xplained board Cyrille Pitchen
@ 2016-03-16 16:41           ` Cyrille Pitchen
  2 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-16 16:41 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 cmd/sf.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/cmd/sf.c b/cmd/sf.c
index 42862d9d921a..5a666bbe9491 100644
--- a/cmd/sf.c
+++ b/cmd/sf.c
@@ -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);
-- 
1.8.2.2

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-16 16:34         ` Jagan Teki
@ 2016-03-17  7:30           ` Albert ARIBAUD
  0 siblings, 0 replies; 36+ messages in thread
From: Albert ARIBAUD @ 2016-03-17  7:30 UTC (permalink / raw)
  To: u-boot

Hello Jagan,

On Wed, 16 Mar 2016 22:04:23 +0530, Jagan Teki <jteki@openedev.com>
wrote:
> Hi Albert,
> 
> On Wednesday 16 March 2016 09:53 PM, Albert ARIBAUD wrote:
> > Hello Jagan,
> >
> > On Wed, 16 Mar 2016 19:44:26 +0530, Jagan Teki <jteki@openedev.com>
> > wrote:
> >> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
> >>> Le 15/03/2016 19:21, Jagan Teki a ?crit :
> >>>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
> >>>>> 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
> >>>>
> >>>> 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.
> >>
> >> 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!
> >
> > 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.
> 
> 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.

> 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).

> 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?
 
> -- 
> Jagan

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-16 14:14     ` Jagan Teki
  2016-03-16 16:23       ` Albert ARIBAUD
  2016-03-16 16:30       ` Cyrille Pitchen
@ 2016-03-18 13:48       ` Stefan Roese
  2016-03-18 15:18         ` Cyrille Pitchen
  2 siblings, 1 reply; 36+ messages in thread
From: Stefan Roese @ 2016-03-18 13:48 UTC (permalink / raw)
  To: u-boot

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.

On 16.03.2016 15:14, Jagan Teki wrote:
> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
>> Le 15/03/2016 19:21, Jagan Teki a ?crit :
>>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>>>> 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
>>>
>>> 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.

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... ;)

> 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

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-18 13:48       ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Stefan Roese
@ 2016-03-18 15:18         ` Cyrille Pitchen
  2016-03-21  9:07           ` Jagan Teki
  0 siblings, 1 reply; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-18 15:18 UTC (permalink / raw)
  To: u-boot

Hi Stefan,

Le 18/03/2016 14:48, Stefan Roese a ?crit :
> 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.
> 
> On 16.03.2016 15:14, Jagan Teki wrote:
>> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
>>> Le 15/03/2016 19:21, Jagan Teki a ?crit :
>>>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>>>>> 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
>>>>
>>>> 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.
> 
> 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... ;)
> 
>> 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?
> 

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


> Comments welcome.
> 
> Thanks,
> Stefan
> 
> 

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

* [U-Boot] [PATCH 14/18 v2] sf: add 4byte address opcodes
  2016-03-15 18:12 ` [U-Boot] [PATCH 14/18] sf: add 4byte address opcodes Cyrille Pitchen
@ 2016-03-21  8:58   ` Cyrille Pitchen
  0 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-21  8:58 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---

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(-)

diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 3f7433cbc214..999c3176adee 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -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
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 86a0276f8518..a98c011218ce 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -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
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 01a073d81eb9..8c327961302c 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -22,12 +22,15 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static void spi_flash_addr(u32 addr, u8 *cmd)
+static void spi_flash_addr(const struct spi_flash *flash, u32 addr, u8 *cmd)
 {
+	u8 shift = flash->addr_width * 8;
+
 	/* cmd[0] is actual command */
-	cmd[1] = addr >> 16;
-	cmd[2] = addr >> 8;
-	cmd[3] = addr >> 0;
+	cmd[1] = addr >> (shift -  8);
+	cmd[2] = addr >> (shift - 16);
+	cmd[3] = addr >> (shift - 24);
+	cmd[4] = addr >> (shift - 32);
 }
 
 static int read_sr(struct spi_flash *flash, u8 *rs)
@@ -154,6 +157,63 @@ bar_end:
 }
 #endif
 
+#ifdef CONFIG_SPI_FLASH_4B_OPCODES
+struct address_entry {
+	u8	src_opcode;
+	u8	dst_opcode;
+};
+
+static u8 spi_flash_convert_opcode(u8 opcode,
+				   const struct address_entry *entries,
+				   size_t num_entries)
+{
+	int b, e;
+
+	b = 0;
+	e = num_entries - 1;
+	while (b <= e) {
+		int m = (b + e) >> 1;
+		const struct address_entry *entry = &entries[m];
+
+		if (opcode == entry->src_opcode)
+			return entry->dst_opcode;
+
+		if (opcode < entry->src_opcode)
+			e = m - 1;
+		else
+			b = m + 1;
+	}
+
+	/* No convertion found */
+	return opcode;
+}
+
+static u8 spi_flash_3to4_opcode(u8 opcode)
+{
+	/* MUST be sorted by 3byte opcode */
+#define ENTRY_3TO4(_opcode)	{ _opcode, _opcode##_4B }
+	static const struct address_entry spi_flash_3to4_table[] = {
+		ENTRY_3TO4(CMD_PAGE_PROGRAM),		/* 0x02 */
+		ENTRY_3TO4(CMD_READ_ARRAY_SLOW),	/* 0x03 */
+		ENTRY_3TO4(CMD_READ_ARRAY_FAST),	/* 0x0b */
+		ENTRY_3TO4(CMD_ERASE_4K),		/* 0x20 */
+		ENTRY_3TO4(CMD_QUAD_PAGE_PROGRAM),	/* 0x32 */
+		ENTRY_3TO4(CMD_QUAD_PAGE_PROGRAM_MXIC),	/* 0x38 */
+		ENTRY_3TO4(CMD_READ_DUAL_OUTPUT_FAST),	/* 0x3b */
+		ENTRY_3TO4(CMD_ERASE_32K),		/* 0x52 */
+		ENTRY_3TO4(CMD_READ_QUAD_OUTPUT_FAST),	/* 0x6b */
+		ENTRY_3TO4(CMD_READ_DUAL_IO_FAST),	/* 0xbb */
+		ENTRY_3TO4(CMD_ERASE_64K),		/* 0xd8 */
+		ENTRY_3TO4(CMD_READ_QUAD_IO_FAST),	/* 0xeb */
+	};
+#undef ENTRY_3TO4
+
+	return spi_flash_convert_opcode(opcode,
+					spi_flash_3to4_table,
+					ARRAY_SIZE(spi_flash_3to4_table));
+}
+#endif /* CONFIG_SPI_FLASH_4B_OPCODES */
+
 #ifdef CONFIG_SF_DUAL_FLASH
 static void spi_flash_dual(struct spi_flash *flash, u32 *addr)
 {
@@ -353,10 +413,11 @@ static int spi_flash_erase_impl(struct spi_flash *flash, u32 offset)
 {
 	struct spi_slave *spi = flash->spi;
 	u8 cmd[SPI_FLASH_CMD_LEN];
+	size_t cmdsz = 1 + flash->addr_width;
 
 	cmd[0] = flash->erase_cmd;
-	spi_flash_addr(offset, cmd);
-	return spi_flash_cmd_write(spi, cmd, sizeof(cmd), NULL, 0);
+	spi_flash_addr(flash, offset, cmd);
+	return spi_flash_cmd_write(spi, cmd, cmdsz, NULL, 0);
 }
 
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
@@ -461,10 +522,10 @@ static int spi_flash_write_impl(struct spi_flash *flash, u32 offset,
 {
 	struct spi_slave *spi = flash->spi;
 	u8 cmd[SPI_FLASH_CMD_LEN];
-	size_t cmdsz = sizeof(cmd);
+	size_t cmdsz = 1 + flash->addr_width;
 
 	cmd[0] = flash->write_cmd;
-	spi_flash_addr(offset, cmd);
+	spi_flash_addr(flash, offset, cmd);
 #ifdef CONFIG_SPI_FLASH_SST
 	if (flash->flags & SNOR_F_SST_WR_2ND)
 		cmdsz = 1;
@@ -567,7 +628,7 @@ static int spi_flash_read_impl(struct spi_flash *flash, u32 offset,
 	size_t cmdsz;
 	int ret;
 
-	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+	cmdsz = 1 + flash->addr_width + flash->dummy_byte;
 	cmd = calloc(1, cmdsz);
 	if (!cmd) {
 		debug("SF: Failed to allocate cmd\n");
@@ -575,7 +636,7 @@ static int spi_flash_read_impl(struct spi_flash *flash, u32 offset,
 	}
 
 	cmd[0] = flash->read_cmd;
-	spi_flash_addr(offset, cmd);
+	spi_flash_addr(flash, offset, cmd);
 	ret = spi_flash_cmd_read(spi, cmd, cmdsz, buf, len);
 	free(cmd);
 	return ret;
@@ -1255,15 +1316,22 @@ int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 	puts("\n");
 #endif
 
-#ifndef CONFIG_SPI_FLASH_BAR
+	/* Set number of bytes for address and convert opcodes if needed */
+	flash->addr_width = 3;
 	if (((flash->dual_flash == SF_SINGLE_FLASH) &&
 	     (flash->size > SPI_FLASH_16MB_BOUN)) ||
 	     ((flash->dual_flash > SF_SINGLE_FLASH) &&
 	     (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
+#if defined(CONFIG_SPI_FLASH_4B_OPCODES)
+		flash->addr_width = 4;
+		flash->read_cmd  = spi_flash_3to4_opcode(flash->read_cmd);
+		flash->write_cmd = spi_flash_3to4_opcode(flash->write_cmd);
+		flash->erase_cmd = spi_flash_3to4_opcode(flash->erase_cmd);
+#elif !defined(CONFIG_SPI_FLASH_BAR)
 		puts("SF: Warning - Only lower 16MiB accessible,");
-		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
-	}
+		puts(" Full access #define CONFIG_SPI_FLASH_ABOVE_16MB\n");
 #endif
+	}
 
 	return ret;
 }
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 945cc07ee8b2..5db06e5133f3 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -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;
-- 
1.8.2.2

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-18 15:18         ` Cyrille Pitchen
@ 2016-03-21  9:07           ` Jagan Teki
  2016-03-21 13:13             ` Cyrille Pitchen
  0 siblings, 1 reply; 36+ messages in thread
From: Jagan Teki @ 2016-03-21  9:07 UTC (permalink / raw)
  To: u-boot

Hi Cyrille,

On 18 March 2016 at 20:48, Cyrille Pitchen <cyrille.pitchen@atmel.com> wrote:
> Hi Stefan,
>
> Le 18/03/2016 14:48, Stefan Roese a ?crit :
>> 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.
>>
>> On 16.03.2016 15:14, Jagan Teki wrote:
>>> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
>>>> Le 15/03/2016 19:21, Jagan Teki a ?crit :
>>>>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>>>>>> 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
>>>>>
>>>>> 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.
>>
>> 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... ;)
>>
>>> 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?
>>
>
> 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.

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?

>
> 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.

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!
-- 
Jagan.

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

* [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers
  2016-03-21  9:07           ` Jagan Teki
@ 2016-03-21 13:13             ` Cyrille Pitchen
  0 siblings, 0 replies; 36+ messages in thread
From: Cyrille Pitchen @ 2016-03-21 13:13 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Le 21/03/2016 10:07, Jagan Teki a ?crit :
> Hi Cyrille,
> 
> On 18 March 2016 at 20:48, Cyrille Pitchen <cyrille.pitchen@atmel.com> wrote:
>> Hi Stefan,
>>
>> Le 18/03/2016 14:48, Stefan Roese a ?crit :
>>> 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.
>>>
>>> On 16.03.2016 15:14, Jagan Teki wrote:
>>>> On Wednesday 16 March 2016 07:00 PM, Cyrille Pitchen wrote:
>>>>> Le 15/03/2016 19:21, Jagan Teki a ?crit :
>>>>>> On Tuesday 15 March 2016 11:42 PM, Cyrille Pitchen wrote:
>>>>>>> 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
>>>>>>
>>>>>> 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.
>>>
>>> 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... ;)
>>>
>>>> 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?
>>>
>>
>> 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.
> 
> 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?
> 

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
...


>>
>> 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.
> 
> 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.

> 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.

> 
> 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

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

end of thread, other threads:[~2016-03-21 13:13 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 01/18] Revert "sf: Fix quad bit set for micron devices" Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 02/18] sf: call spi_claim_bus() and spi_release_bus() only once per read, write or erase Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 03/18] sf: replace spi_flash_read_common() calls by spi_flash_cmd_read() Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 04/18] sf: remove spi_flash_write_common() Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 05/18] sf: export spi_flash_wait_ready() function Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 06/18] sf: share erase generic algorithm Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 07/18] sf: share write " Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 08/18] sf: share read " Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 09/18] sf: add hooks to handle register read and write operations Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 10/18] sf: move support of SST flash into generic spi_flash_write_alg() Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 11/18] sf: fix selection of supported READ commands for QSPI memories Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 12/18] sf: fix detection of QSPI memories when they boot in Quad or Dual mode Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 13/18] sf: add helper function to set the number of dummy bytes Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 14/18] sf: add 4byte address opcodes Cyrille Pitchen
2016-03-21  8:58   ` [U-Boot] [PATCH 14/18 v2] " Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 15/18] sf: prepare next fixes to support of QSPI memories by manufacturer Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 16/18] sf: fix support of Micron memories Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 17/18] ARM: at91: clock: add function to get QSPI clocks Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 18/18] sf: add driver for Atmel QSPI controller Cyrille Pitchen
2016-03-15 18:21 ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Jagan Teki
2016-03-15 19:17   ` Marek Vasut
2016-03-16 13:30   ` Cyrille Pitchen
2016-03-16 14:14     ` Jagan Teki
2016-03-16 16:23       ` Albert ARIBAUD
2016-03-16 16:34         ` Jagan Teki
2016-03-17  7:30           ` Albert ARIBAUD
2016-03-16 16:30       ` Cyrille Pitchen
2016-03-16 16:41         ` [U-Boot] [PATCH 1/4] rework board config files Cyrille Pitchen
2016-03-16 16:41           ` [U-Boot] [PATCH 2/4] sama5d2_xplained: add support of QSPI controllers Cyrille Pitchen
2016-03-16 16:41           ` [U-Boot] [PATCH 3/4] dts: add dts file for Atmel sama5d2 xplained board Cyrille Pitchen
2016-03-16 16:41           ` [U-Boot] [PATCH 4/4] sf: fix sf probe Cyrille Pitchen
2016-03-18 13:48       ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Stefan Roese
2016-03-18 15:18         ` Cyrille Pitchen
2016-03-21  9:07           ` Jagan Teki
2016-03-21 13:13             ` Cyrille Pitchen

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