Skip to contentSkip to conversation

sf: improve support of (Q)SPI flash memories

PATCH Superseded Wenyou Yang 1 participant 9 messages Jul 20, 2017

Subsystems (3)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover sf: improve support of (Q)SPI flash memories

This series of patches are based and have been tested on the 'master' branch of the u-boot.git tree.

Tests were passed with a sama5d2 xplained board which embeds both SPI and QSPI controllers.

The following tests have been passed:

- QSPI0 + Macronix MX25L25673G:
+ probe: OK
+ Fast Read 1-1-4 at offset 0x10000 (u-boot env): OK
+ Page Program 1-1-4 at offset 0x10000: OK
The Macronix datasheet tells that only Page Program 1-4-4 is supported, not Page Program 1-1-4, however it worked, I don't know why...

- QSPI0 + Microchip SST26
+ probe: OK
+ Fast Read 1-1-4 at offset 0x10000 (u-boot env): OK
+ Page Program 1-1-1 at offset 0x10000: OK
SST26 memories support Page Program 1-4-4 but with the op code of Page Program 1-1-4, which is not standard so I don't use it.

- QSPI0 + Adesto AT25DF321A
+ probe: OK
+ Fast Read 1-1-1 at offset 0x10000 (u-boot env): OK
+ Page Program 1-1-1 at offset 0x10000: OK

- SPI0 + Adesto AT25DF321A
+ probe: OK
+ Fast Read 1-1-1 at offset 0x6000 (u-boot env): OK
+ Page Program 1-1-1 at offest 0x6000: OK

- SPI1 + Atmel AT45
+ probe: OK
+ Read at offset 0 and other than 0: OK
+ Write at offset 0 and other than 0: OK

During my tests, I used:
- setenv/saveenv, reboot, printenv
or
- sf probe, sf read, sf write, sf erase and sf update.

Changes in v2:
- Rebase on the latest u-boot/master(2710d54f5).

Cyrille Pitchen (8):
spi: add support of SPI flash commands
sf: describe all SPI flash commands with 'struct spi_flash_command'
sf: select the relevant SPI flash protocol for read and write commands
sf: differentiate Page Program 1-1-4 and 1-4-4
sf: add 'addr_len' member to 'struct spi_flash'
sf: add new option to support SPI flash above 16MiB
sf: add support to Microchip SST26 QSPI memories
sf: add driver for Atmel QSPI controller

 drivers/mtd/spi/Kconfig         |  16 +-
 drivers/mtd/spi/sf.c            |  78 ++++++--
 drivers/mtd/spi/sf_dataflash.c  | 119 ++++++------
 drivers/mtd/spi/sf_internal.h   |  48 +++--
 drivers/mtd/spi/spi_flash.c     | 341 +++++++++++++++++++++++----------
 drivers/mtd/spi/spi_flash_ids.c |   5 +
 drivers/spi/Kconfig             |   7 +
 drivers/spi/Makefile            |   1 +
 drivers/spi/atmel_qspi.c        | 404 ++++++++++++++++++++++++++++++++++++++++
 drivers/spi/atmel_qspi.h        | 169 +++++++++++++++++
 drivers/spi/spi-uclass.c        |  40 ++++
 drivers/spi/spi.c               |  13 ++
 include/spi.h                   | 168 +++++++++++++++++
 include/spi_flash.h             |   6 +
 14 files changed, 1225 insertions(+), 190 deletions(-)
 create mode 100644 drivers/spi/atmel_qspi.c
 create mode 100644 drivers/spi/atmel_qspi.h
Signature · 1 line
2.13.0
#1 lore raw

PATCH v2 1/8 spi: add support of SPI flash commands

From: Cyrille Pitchen <[email protected]>

This patch introduces 'struct spi_flash_command' and functions spi_is_flash_command_supported() / spi_exec_flash_command().

The 'struct spi_flash_command' describes all the relevant parameters to execute any SPI flash command:
- the instruction op code
- the number of bytes used to send the address: 0, 3 or 4 bytes
- the number of mode and wait-state clock cycles, also called dummy cycles
- the number and values of data bytes to be sent or received
- the SPI x-y-z protocol [1]
- the flash command type [2]

[1] SPI x-y-z protocol:
- x is the number of I/O lines used to send the instruction op code.
- y is the number of I/O lines used during address, mode and wait-state clock cycles.
- z is the number of I/O lines used to send or received data.

[2] Flash command type:
The flash command type is provided to differenciate "memory" read/write/erase operations from "flash internal register" read/write operations. Indeed some SPI controller drivers handle those command type in different ways.
However SPI controller drivers should not check the value of the instruction op code to guess the actual kind of flash command to perform. Many instruction op codes are SPI flash manufacturer specific and only drivers/mtd/spi/spi_flash.c should have the knowledge of all of them.

Besides, more and more QSPI controllers, like those of TI and Candence, have special way to support (Fast) Read operations using some "memory like" area mapped into the system bus. Hence, if those drivers choose to override the default implementation of spi_is_flash_command_supported() so that their own functions return true only for a "memory read" flash command type, then spi_exec_flash_command() might be used to implement the read from the "memory like" area mapped into the system bus.
It means that spi_exec_flash_command() could be used to supersede the actual flash->memory_map mechanism; spi_is_flash_command_supported() / spi_exec_flash_command() being more generic and covering more use cases.

For instance, the Atmel QSPI hardware controller uses its "memory like" area mapped ino the system to perform not only (Fast) Read operations but actually all other types of flash commands. Hence the regular SPI API based on the spi_xfer() function is not suited to support the Atmel QSPI controller.

---

Changes in v2: None

 drivers/spi/spi-uclass.c |  40 +++++++++++
 drivers/spi/spi.c        |  13 ++++
 include/spi.h            | 168 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 221 insertions(+)
drivers/spi/spi-uclass.c +40 -0
index e06a603ab1..5de4510363 100644
@@ -91,6 +91,30 @@ int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
 	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
+bool dm_spi_is_flash_command_supported(struct udevice *dev,
+				       const struct spi_flash_command *cmd)
+{
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->is_flash_command_supported)
+		return ops->is_flash_command_supported(dev, cmd);
+
+	return false;
+}
+
+int dm_spi_exec_flash_command(struct udevice *dev,
+			      const struct spi_flash_command *cmd)
+{
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->exec_flash_command)
+		return ops->exec_flash_command(dev, cmd);
+
+	return -EINVAL;
+}
+
 int spi_claim_bus(struct spi_slave *slave)
 {
 	return dm_spi_claim_bus(slave->dev);
@@ -107,6 +131,18 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
 }
 
+bool spi_is_flash_command_supported(struct spi_slave *slave,
+				    const struct spi_flash_command *cmd)
+{
+	return dm_spi_is_flash_command_supported(slave->dev, cmd);
+}
+
+int spi_exec_flash_command(struct spi_slave *slave,
+			   const struct spi_flash_command *cmd)
+{
+	return dm_spi_exec_flash_command(slave->dev, cmd);
+}
+
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
 static int spi_child_post_bind(struct udevice *dev)
 {
@@ -144,6 +180,10 @@ static int spi_post_probe(struct udevice *bus)
 		ops->set_mode += gd->reloc_off;
 	if (ops->cs_info)
 		ops->cs_info += gd->reloc_off;
+	if (ops->is_flash_command_supported)
+		ops->is_flash_command_supported += gd->reloc_off;
+	if (ops->exec_flash_command)
+		ops->exec_flash_command += gd->reloc_off;
 #endif
 
 	return 0;
drivers/spi/spi.c +13 -0
index 7d81fbd7f8..e47acdc9e4 100644
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
 #include <spi.h>
@@ -58,3 +59,15 @@ struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum,
 	return spi_setup_slave(busnum, cs, max_hz, mode);
 }
 #endif
+
+__weak bool spi_is_flash_command_supported(struct spi_slave *slave,
+					   const struct spi_flash_command *cmd)
+{
+	return false;
+}
+
+__weak int spi_exec_flash_command(struct spi_slave *slave,
+				  const struct spi_flash_command *cmd)
+{
+	return -EINVAL;
+}
include/spi.h +168 -0

198 lines not on this page · raw message

Signature · 1 line
2.13.0
#2 lore raw

PATCH v2 2/8 sf: describe all SPI flash commands with 'struct spi_flash_command'

In reply to Wenyou Yang

From: Cyrille Pitchen <[email protected]>

Now that the SPI sub-system API has been extended with 'struct spi_flash_command' and spi_is_flash_command_supported() / spi_exec_flash_command() functions, we update the SPI FLASH sub-system to use this new API.

---

Changes in v2: None

 drivers/mtd/spi/sf.c           |  78 +++++++++++++----
 drivers/mtd/spi/sf_dataflash.c | 119 +++++++++++++-------------
 drivers/mtd/spi/sf_internal.h  |  24 +++---
 drivers/mtd/spi/spi_flash.c    | 184 +++++++++++++++++++++++------------------
 4 files changed, 236 insertions(+), 169 deletions(-)
drivers/mtd/spi/sf.c +60 -18
index d5e175ca00..6178b0aa98 100644
@@ -9,46 +9,88 @@
 
 #include <common.h>
 #include <spi.h>
+#include <spi_flash.h>
 
-static int spi_flash_read_write(struct spi_slave *spi,
-				const u8 *cmd, size_t cmd_len,
-				const u8 *data_out, u8 *data_in,
-				size_t data_len)
+#include "sf_internal.h"
+
+static void spi_flash_addr(u32 addr, u8 addr_len, u8 *cmd_buf)
 {
+	u8 i;
+
+	for (i = 0; i < addr_len; i++)
+		cmd_buf[i] = addr >> ((addr_len - 1 - i) * 8);
+}
+
+static u8 spi_compute_num_dummy_bytes(enum spi_flash_protocol proto,
+				      u8 num_dummy_clock_cycles)
+{
+	int shift = fls(spi_flash_protocol_get_addr_nbits(proto)) - 1;
+
+	if (shift < 0)
+		shift = 0;
+	return (num_dummy_clock_cycles << shift) >> 3;
+}
+
+static int spi_flash_exec(struct spi_flash *flash,
+			  const struct spi_flash_command *cmd)
+{
+	struct spi_slave *spi = flash->spi;
+	u8 cmd_buf[SPI_FLASH_CMD_LEN];
+	size_t cmd_len, num_dummy_bytes;
 	unsigned long flags = SPI_XFER_BEGIN;
 	int ret;
 
-	if (data_len == 0)
+	if (spi_is_flash_command_supported(spi, cmd))
+		return spi_exec_flash_command(spi, cmd);
+
+	if (cmd->data_len == 0)
 		flags |= SPI_XFER_END;
 
-	ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
+	cmd_buf[0] = cmd->inst;
+	spi_flash_addr(cmd->addr, cmd->addr_len, cmd_buf + 1);
+	cmd_len = 1 + cmd->addr_len;
+
+	num_dummy_bytes = spi_compute_num_dummy_bytes(cmd->proto,
+						      cmd->num_mode_cycles +
+						      cmd->num_wait_states);
+	memset(cmd_buf + cmd_len, 0xff, num_dummy_bytes);
+	cmd_len += num_dummy_bytes;
+
+	ret = spi_xfer(spi, cmd_len * 8, cmd_buf, NULL, flags);
 	if (ret) {
 		debug("SF: Failed to send command (%zu bytes): %d\n",
 		      cmd_len, ret);
-	} else if (data_len != 0) {
-		ret = spi_xfer(spi, data_len * 8, data_out, data_in,
-					SPI_XFER_END);
+	} else if (cmd->data_len != 0) {
+		ret = spi_xfer(spi, cmd->data_len * 8,
+			       cmd->tx_data, cmd->rx_data,
+			       SPI_XFER_END);
 		if (ret)
 			debug("SF: Failed to transfer %zu bytes of data: %d\n",
-			      data_len, ret);
+			      cmd->data_len, ret);
 	}
 
 	return ret;
 }
 
-int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
-		size_t cmd_len, void *data, size_t data_len)
+int spi_flash_cmd_read(struct spi_flash *flash,
+		       const struct spi_flash_command *cmd)
 {
-	return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len);
+	return spi_flash_exec(flash, cmd);
 }
 
-int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len)
+int spi_flash_cmd(struct spi_flash *flash, u8 instr, void *response, size_t len)
 {
-	return spi_flash_cmd_read(spi, &cmd, 1, response, len);
+	struct spi_flash_command cmd;
+	u8 flags = (response && len) ? SPI_FCMD_READ_REG : SPI_FCMD_WRITE_REG;
+
+	spi_flash_command_init(&cmd, instr, 0, flags);
+	cmd.data_len = len;
+	cmd.rx_data = response;
+	return spi_flash_exec(flash, &cmd);
 }
 
-int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
-		const void *data, size_t data_len)
+int spi_flash_cmd_write(struct spi_flash *flash,
+			const struct spi_flash_command *cmd)
 {
-	return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);
+	return spi_flash_exec(flash, cmd);
 }
drivers/mtd/spi/sf_dataflash.c +61 -58

294 lines not on this page · raw message

drivers/mtd/spi/sf_internal.h +12 -12
index 839cdbe1b0..5c551089d6 100644
@@ -27,7 +27,7 @@ enum spi_nor_option_flags {
 };
 
 #define SPI_FLASH_3B_ADDR_LEN		3
-#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN)
+#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN + 16)
 #define SPI_FLASH_16MB_BOUN		0x1000000
 
 /* CFI Manufacture ID's */
@@ -137,21 +137,21 @@ struct spi_flash_info {
 extern const struct spi_flash_info spi_flash_ids[];
 
 /* Send a single-byte command to the device and read the response */
-int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
+int spi_flash_cmd(struct spi_flash *flash, u8 instr, void *response, size_t len);
 
 /*
  * Send a multi-byte command to the device and read the response. Used
  * for flash array reads, etc.
  */
-int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
-		size_t cmd_len, void *data, size_t data_len);
+int spi_flash_cmd_read(struct spi_flash *flash,
+		       const struct spi_flash_command *cmd);
 
 /*
  * Send a multi-byte command to the device followed by (optional)
  * data. Used for programming the flash array, etc.
  */
-int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
-		const void *data, size_t data_len);
+int spi_flash_cmd_write(struct spi_flash *flash,
+			const struct spi_flash_command *cmd);
 
 
 /* Flash erase(sectors) operation, support all possible erase commands */
@@ -169,13 +169,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_cmd(flash, CMD_WRITE_ENABLE, NULL, 0);
 }
 
 /* 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_cmd(flash, CMD_WRITE_DISABLE, NULL, 0);
 }
 
 /*
@@ -186,8 +186,8 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
  * - spi_flash_wait_till_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);
+int spi_flash_write_common(struct spi_flash *flash,
+			   const struct spi_flash_command *cmd);
 
 /*
  * Flash write operation, support all possible write commands.
@@ -201,8 +201,8 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
  * Same as spi_flash_cmd_read() except it also claims/releases the SPI
  * bus. 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);
+int spi_flash_read_common(struct spi_flash *flash,
+			  const struct spi_flash_command *cmd);
 
 /* Flash read operation, support all possible read commands */
 int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
drivers/mtd/spi/spi_flash.c +103 -81

397 lines not on this page · raw message

Signature · 1 line
2.13.0
#3 lore raw

PATCH v2 3/8 sf: select the relevant SPI flash protocol for read and write commands

In reply to Wenyou Yang

From: Cyrille Pitchen <[email protected]>

SPI controller drivers should not check the instruction op code byte to guess which SPI x-y-z protocol is to be used for Fast Read or Page Program operations.

Indeed, the op code values are not so reliable. For instance, the 32h op code is generally used for Page Program 1-1-4 operations. However Microchip SST26 memories use this 32h op code for their Page Program 1-4-4 operations. There are many other examples of those SPI flash manufacturer quirks.

Instead, the SPI FLASH sub-system now fills the 'proto' member of 'struct spi_flash_command' with flash->read_proto for Fast Read operations and flash->write_proto for Page Program operations.

---

Changes in v2: None

 drivers/mtd/spi/spi_flash.c | 24 ++++++++++++++++--------
 include/spi_flash.h         |  4 ++++
 2 files changed, 20 insertions(+), 8 deletions(-)
drivers/mtd/spi/spi_flash.c +16 -8
index 80541d0ab4..588e5729b4 100644
@@ -379,6 +379,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 
 	spi_flash_command_init(&cmd, flash->write_cmd, SPI_FLASH_3B_ADDR_LEN,
 			       SPI_FCMD_WRITE);
+	cmd.proto = flash->write_proto;
 	for (actual = 0; actual < len; actual += chunk_len) {
 		write_addr = offset;
 
@@ -482,6 +483,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 
 	spi_flash_command_init(&cmd, flash->read_cmd, SPI_FLASH_3B_ADDR_LEN,
 			       SPI_FCMD_READ);
+	cmd.proto = flash->read_proto;
 	cmd.num_wait_states = flash->dummy_byte * 8;
 	while (len) {
 		read_addr = offset;
@@ -1044,24 +1046,30 @@ int spi_flash_scan(struct spi_flash *flash)
 
 	/* Look for read commands */
 	flash->read_cmd = CMD_READ_ARRAY_FAST;
-	if (spi->mode & SPI_RX_SLOW)
+	flash->read_proto = SPI_FPROTO_1_1_1;
+	if (spi->mode & SPI_RX_SLOW) {
 		flash->read_cmd = CMD_READ_ARRAY_SLOW;
-	else if (spi->mode & SPI_RX_QUAD && info->flags & RD_QUAD)
+	} else if (spi->mode & SPI_RX_QUAD && info->flags & RD_QUAD) {
 		flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST;
-	else if (spi->mode & SPI_RX_DUAL && info->flags & RD_DUAL)
+		flash->read_proto = SPI_FPROTO_1_1_4;
+	} else if (spi->mode & SPI_RX_DUAL && info->flags & RD_DUAL) {
 		flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST;
+		flash->read_proto = SPI_FPROTO_1_1_2;
+	}
 
 	/* Look for write commands */
-	if (info->flags & WR_QPP && spi->mode & SPI_TX_QUAD)
+	if (info->flags & WR_QPP && spi->mode & SPI_TX_QUAD) {
 		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
-	else
+		flash->write_proto = SPI_FPROTO_1_1_4;
+	} else {
 		/* Go for default supported write cmd */
 		flash->write_cmd = CMD_PAGE_PROGRAM;
+		flash->write_proto = SPI_FPROTO_1_1_1;
+	}
 
 	/* 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)) {
+	if (spi_flash_protocol_get_data_nbits(flash->read_proto) == 4 ||
+	    spi_flash_protocol_get_data_nbits(flash->write_proto) == 4) {
 		ret = set_quad_mode(flash, info);
 		if (ret) {
 			debug("SF: Fail to set QEB for %02x\n",
include/spi_flash.h +4 -0
index be2fe3f84c..ac2b37f020 100644
@@ -48,6 +48,8 @@ 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.
+ * @read_proto:		SPI x-y-z protocol for flash read ops
+ * @write_proto:	SPI x-y-z protocol for flash write 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
@@ -83,6 +85,8 @@ struct spi_flash {
 	u8 read_cmd;
 	u8 write_cmd;
 	u8 dummy_byte;
+	enum spi_flash_protocol read_proto;
+	enum spi_flash_protocol write_proto;
 
 	void *memory_map;
 
Signature · 1 line
2.13.0
#4 lore raw

PATCH v2 4/8 sf: differentiate Page Program 1-1-4 and 1-4-4

In reply to Wenyou Yang

From: Cyrille Pitchen <[email protected]>

This patch simply renames the ambiguous CMD_QUAD_PAGE_PROGRAM macro into the more explicit CMD_PAGE_PROGRAM_1_1_4.
Also it defines the CMD_PAGE_PROGRAM_1_4_4 macro to the standard 38h op code.

---

Changes in v2: None

 drivers/mtd/spi/sf_internal.h | 3 ++-
 drivers/mtd/spi/spi_flash.c   | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)
drivers/mtd/spi/sf_internal.h +2 -1
index 5c551089d6..8b8c951bcc 100644
@@ -48,7 +48,8 @@ enum spi_nor_option_flags {
 #define CMD_PAGE_PROGRAM		0x02
 #define CMD_WRITE_DISABLE		0x04
 #define CMD_WRITE_ENABLE		0x06
-#define CMD_QUAD_PAGE_PROGRAM		0x32
+#define CMD_PAGE_PROGRAM_1_1_4		0x32
+#define CMD_PAGE_PROGRAM_1_4_4		0x38
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW		0x03
drivers/mtd/spi/spi_flash.c +1 -1
index 588e5729b4..8712e5eef0 100644
@@ -1059,7 +1059,7 @@ int spi_flash_scan(struct spi_flash *flash)
 
 	/* Look for write commands */
 	if (info->flags & WR_QPP && spi->mode & SPI_TX_QUAD) {
-		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+		flash->write_cmd = CMD_PAGE_PROGRAM_1_1_4;
 		flash->write_proto = SPI_FPROTO_1_1_4;
 	} else {
 		/* Go for default supported write cmd */
Signature · 1 line
2.13.0
#5 lore raw

PATCH v2 5/8 sf: add 'addr_len' member to 'struct spi_flash'

In reply to Wenyou Yang

From: Cyrille Pitchen <[email protected]>

This is a transitional patch to prepare the SPI FLASH sub-system to support the 4-byte address instruction set later.
For now, flash->addr_len is always set to SPI_FLASH_3B_ADDR_LEN.

---

Changes in v2: None

 drivers/mtd/spi/spi_flash.c | 13 ++++++++-----
 include/spi_flash.h         |  2 ++
 2 files changed, 10 insertions(+), 5 deletions(-)
drivers/mtd/spi/spi_flash.c +8 -5
index 8712e5eef0..d6942d57b2 100644
@@ -322,7 +322,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		}
 	}
 
-	spi_flash_command_init(&cmd, flash->erase_cmd, SPI_FLASH_3B_ADDR_LEN,
+	spi_flash_command_init(&cmd, flash->erase_cmd, flash->addr_len,
 			       SPI_FCMD_ERASE);
 	while (len) {
 		erase_addr = offset;
@@ -377,7 +377,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 		}
 	}
 
-	spi_flash_command_init(&cmd, flash->write_cmd, SPI_FLASH_3B_ADDR_LEN,
+	spi_flash_command_init(&cmd, flash->write_cmd, flash->addr_len,
 			       SPI_FCMD_WRITE);
 	cmd.proto = flash->write_proto;
 	for (actual = 0; actual < len; actual += chunk_len) {
@@ -481,7 +481,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		return 0;
 	}
 
-	spi_flash_command_init(&cmd, flash->read_cmd, SPI_FLASH_3B_ADDR_LEN,
+	spi_flash_command_init(&cmd, flash->read_cmd, flash->addr_len,
 			       SPI_FCMD_READ);
 	cmd.proto = flash->read_proto;
 	cmd.num_wait_states = flash->dummy_byte * 8;
@@ -529,7 +529,7 @@ static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
 	int ret;
 	u8 sr = 0xFFu;
 
-	spi_flash_command_init(&cmd, CMD_SST_BP, SPI_FLASH_3B_ADDR_LEN,
+	spi_flash_command_init(&cmd, CMD_SST_BP, flash->addr_len,
 			       SPI_FCMD_WRITE);
 	cmd.addr = offset;
 	cmd.data_len = 1;
@@ -580,7 +580,7 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 	if (ret)
 		goto done;
 
-	spi_flash_command_init(&cmd, CMD_SST_AAI_WP, SPI_FLASH_3B_ADDR_LEN,
+	spi_flash_command_init(&cmd, CMD_SST_AAI_WP, flash->addr_len,
 			       SPI_FCMD_WRITE);
 	cmd.addr = offset;
 	cmd.data_len = 2;
@@ -1102,6 +1102,9 @@ int spi_flash_scan(struct spi_flash *flash)
 		flash->flags |= SNOR_F_USE_FSR;
 #endif
 
+	/* Set the address length */
+	flash->addr_len = SPI_FLASH_3B_ADDR_LEN;
+
 	/* Configure the BAR - discover bank cmds and read current bank */
 #ifdef CONFIG_SPI_FLASH_BAR
 	ret = read_bar(flash, info);
include/spi_flash.h +2 -0
index ac2b37f020..9168fca8f9 100644
@@ -44,6 +44,7 @@ struct spi_slave;
  * @bank_read_cmd:	Bank read cmd
  * @bank_write_cmd:	Bank write cmd
  * @bank_curr:		Current flash bank
+ * @addr_len:		Number of bytes for the address
  * @erase_cmd:		Erase cmd 4K, 32K, 64K
  * @read_cmd:		Read cmd - Array Fast, Extn read and quad read.
  * @write_cmd:		Write cmd - page and quad program.
@@ -81,6 +82,7 @@ struct spi_flash {
 	u8 bank_write_cmd;
 	u8 bank_curr;
 #endif
+	u8 addr_len;
 	u8 erase_cmd;
 	u8 read_cmd;
 	u8 write_cmd;
Signature · 1 line
2.13.0
#6 lore raw

PATCH v2 6/8 sf: add new option to support SPI flash above 16MiB

In reply to Wenyou Yang

From: Cyrille Pitchen <[email protected]>

The patch provides an alternative method to support SPI flash size greater than 16MiB (128Mib).

Indeed using the Base Address Register (BAR) is stateful. Hence, once the BAR has been modified, if a spurious CPU reset occurs with no reset/power off at the SPI flash side, early boot loarders may try to read from offset 0 but fails because of the new BAR value.

On the other hand, using the 4-byte address instruction set is stateless. When supported by the SPI flash memory, it allows us to access memory data area above 16MiB without changing the internal state of this SPI flash memory. Then if a spirious reboot occurs, early boot loaders can still access data from offset 0.

---

Changes in v2: None

 drivers/mtd/spi/Kconfig       | 16 +++++++-
 drivers/mtd/spi/sf_internal.h | 18 +++++++++
 drivers/mtd/spi/spi_flash.c   | 92 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 119 insertions(+), 7 deletions(-)
drivers/mtd/spi/Kconfig +15 -1
index 5700859ff2..985aefd96c 100644
@@ -34,14 +34,28 @@ config SPI_FLASH
 
 	  If unsure, say N
 
+choice
+	prompt "Support SPI flash above 16MiB"
+	depends on SPI_FLASH
+	optional
+
 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_4BAIS
+	bool "SPI flash 4-byte address instruction set support"
+	help
+	  Convert the selected 3-byte address op codes into their associated
+	  4-byte address op codes. Using this instruction set does not change
+	  the internal state of the SPI flash device.
+
+endchoice
+
+
 config SF_DUAL_FLASH
 	bool "SPI DUAL flash memory support"
 	depends on SPI_FLASH
drivers/mtd/spi/sf_internal.h +18 -0
index 8b8c951bcc..30994f9f46 100644
@@ -27,6 +27,7 @@ enum spi_nor_option_flags {
 };
 
 #define SPI_FLASH_3B_ADDR_LEN		3
+#define SPI_FLASH_4B_ADDR_LEN		4
 #define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN + 16)
 #define SPI_FLASH_16MB_BOUN		0x1000000
 
@@ -64,6 +65,19 @@ enum spi_nor_option_flags {
 #define CMD_READ_CONFIG			0x35
 #define CMD_FLAG_STATUS			0x70
 
+/* 4-byte address instruction set */
+#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_PAGE_PROGRAM_4B		0x12
+#define CMD_PAGE_PROGRAM_1_1_4_4B	0x34
+#define CMD_PAGE_PROGRAM_1_4_4_4B	0x3e
+#define CMD_ERASE_4K_4B			0x21
+#define CMD_ERASE_64K_4B		0xdc
+
 /* Bank addr access commands */
 #ifdef CONFIG_SPI_FLASH_BAR
 # define CMD_BANKADDR_BRWR		0x17
@@ -133,6 +147,10 @@ struct spi_flash_info {
 #define RD_QUADIO		BIT(6)	/* use Quad IO Read */
 #define RD_DUALIO		BIT(7)	/* use Dual IO Read */
 #define RD_FULL			(RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
+#define NO_4BAIS		BIT(8)	/*
+					 * 4-byte address instruction set
+					 * NOT supported
+					 */
 };
 
 extern const struct spi_flash_info spi_flash_ids[];
drivers/mtd/spi/spi_flash.c +86 -6

117 lines not on this page · raw message

Signature · 1 line
2.13.0
#7 lore raw

PATCH v2 7/8 sf: add support to Microchip SST26 QSPI memories

In reply to Wenyou Yang

From: Cyrille Pitchen <[email protected]>

This patch adds support to Microchip SST26 QSPI memories.

Erase blocks are protected at power up and must be unlocked first before being erased then programmed.

Also, the erase block sizes are not uniform. The memory layout is uniform only for the 4K sector blocks. The 64K Block Erase (D8h) op code cannot be used as currently done by the SPI FLASH sub-system.
The 4K Sector Erase (20h) op code should be chosen instead even if CONFIG_SPI_FLASH_USE_4K_SECTORS is not set.

---

Changes in v2: None

 drivers/mtd/spi/sf_internal.h   |  3 +++
 drivers/mtd/spi/spi_flash.c     | 36 ++++++++++++++++++++++++++++++++----
 drivers/mtd/spi/spi_flash_ids.c |  5 +++++
 3 files changed, 40 insertions(+), 4 deletions(-)
drivers/mtd/spi/sf_internal.h +3 -0
index 30994f9f46..4354a2aa53 100644
@@ -104,6 +104,7 @@ 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 */
+# define CMD_SST_ULBPR		0x98	/* Global Block Protection Unlock */
 
 int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 		const void *buf);
@@ -151,6 +152,8 @@ struct spi_flash_info {
 					 * 4-byte address instruction set
 					 * NOT supported
 					 */
+#define SECT_4K_ONLY		BIT(9)  /* use only CMD_ERASE_4K */
+#define SST_ULBPR		BIT(10)	/* use SST unlock block protection */
 };
 
 extern const struct spi_flash_info spi_flash_ids[];
drivers/mtd/spi/spi_flash.c +32 -4
index 89ceae2221..503059cacd 100644
@@ -73,7 +73,8 @@ static int write_sr(struct spi_flash *flash, u8 ws)
 	return 0;
 }
 
-#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) || \
+    defined(CONFIG_SPI_FLASH_SST)
 static int read_cr(struct spi_flash *flash, u8 *rc)
 {
 	struct spi_flash_command cmd;
@@ -891,6 +892,22 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len)
 }
 #endif
 
+#ifdef CONFIG_SPI_FLASH_SST
+static int sst26_unlock(struct spi_flash *flash)
+{
+	struct spi_flash_command cmd;
+	int ret;
+
+	spi_flash_command_init(&cmd, CMD_SST_ULBPR, 0, SPI_FCMD_WRITE_REG);
+	ret = spi_flash_write_common(flash, &cmd);
+	if (ret) {
+		debug("SF: SST26 is still locked (read-only)\n");
+		return ret;
+	}
+
+	return 0;
+}
+#endif
 
 #ifdef CONFIG_SPI_FLASH_MACRONIX
 static int macronix_quad_enable(struct spi_flash *flash)
@@ -920,7 +937,8 @@ static int macronix_quad_enable(struct spi_flash *flash)
 }
 #endif
 
-#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) ||\
+    defined(CONFIG_SPI_FLASH_SST)
 static int spansion_quad_enable(struct spi_flash *flash)
 {
 	u8 qeb_status;
@@ -981,9 +999,11 @@ static int set_quad_mode(struct spi_flash *flash,
 	case SPI_FLASH_CFI_MFR_MACRONIX:
 		return macronix_quad_enable(flash);
 #endif
-#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) ||\
+    defined(CONFIG_SPI_FLASH_SST)
 	case SPI_FLASH_CFI_MFR_SPANSION:
 	case SPI_FLASH_CFI_MFR_WINBOND:
+	case SPI_FLASH_CFI_MFR_SST:
 		return spansion_quad_enable(flash);
 #endif
 #ifdef CONFIG_SPI_FLASH_STMICRO
@@ -1039,6 +1059,11 @@ int spi_flash_scan(struct spi_flash *flash)
 	    JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST)
 		write_sr(flash, 0);
 
+#ifdef CONFIG_SPI_FLASH_SST
+	if (info->flags & SST_ULBPR)
+		sst26_unlock(flash);
+#endif
+
 	flash->name = info->name;
 	flash->memory_map = spi->memory_map;
 
@@ -1098,7 +1123,10 @@ int spi_flash_scan(struct spi_flash *flash)
 		flash->erase_size = 4096 << flash->shift;
 	} else
 #endif
-	{
+	if (info->flags & SECT_4K_ONLY) {
+		flash->erase_cmd = CMD_ERASE_4K;
+		flash->erase_size = 4096 << flash->shift;
+	} else {
 		flash->erase_cmd = CMD_ERASE_64K;
 		flash->erase_size = flash->sector_size;
 	}
drivers/mtd/spi/spi_flash_ids.c +5 -0
index edca94e30c..3d3132bc3b 100644
@@ -146,6 +146,11 @@ const struct spi_flash_info spi_flash_ids[] = {
 	{"sst25wf040",	   INFO(0xbf2504, 0x0,	64 * 1024,     8, SECT_4K | SST_WR) },
 	{"sst25wf040b",	   INFO(0x621613, 0x0,	64 * 1024,     8, SECT_4K) },
 	{"sst25wf080",	   INFO(0xbf2505, 0x0,	64 * 1024,    16, SECT_4K | SST_WR) },
+	{"sst26vf016b",	   INFO(0xbf2641, 0x0,   4 * 1024,   512, SECT_4K_ONLY | SST_ULBPR | RD_FULL) },
+	{"sst26vf032b",	   INFO(0xbf2642, 0x0,   4 * 1024,  1024, SECT_4K_ONLY | SST_ULBPR | RD_FULL) },
+	{"sst26vf064b",	   INFO(0xbf2643, 0x0,   4 * 1024,  2048, SECT_4K_ONLY | SST_ULBPR | RD_FULL) },
+	{"sst26wf040b",	   INFO(0xbf2654, 0x0,   4 * 1024,   128, SECT_4K_ONLY | SST_ULBPR | RD_FULL) },
+	{"sst26wf080b",	   INFO(0xbf2658, 0x0,   4 * 1024,   256, SECT_4K_ONLY | SST_ULBPR | RD_FULL) },
 #endif
 #ifdef CONFIG_SPI_FLASH_WINBOND		/* WINBOND */
 	{"w25p80",	   INFO(0xef2014, 0x0,	64 * 1024,    16, 0) },
Signature · 1 line
2.13.0
#8 lore raw

PATCH v2 8/8 sf: add driver for Atmel QSPI controller

In reply to Wenyou Yang

From: Cyrille Pitchen <[email protected]>

This patch adds support to the Atmel Quad SPI controller.

---

Changes in v2:
- Rebase on the latest u-boot/master(2710d54f5).

 drivers/spi/Kconfig      |   7 +
 drivers/spi/Makefile     |   1 +
 drivers/spi/atmel_qspi.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/atmel_qspi.h | 169 ++++++++++++++++++++
 4 files changed, 581 insertions(+)
 create mode 100644 drivers/spi/atmel_qspi.c
 create mode 100644 drivers/spi/atmel_qspi.h
drivers/spi/Kconfig +7 -0
index 8a8e8e480f..b3e8cb941e 100644
@@ -32,6 +32,13 @@ config ATH79_SPI
 	  uses driver model and requires a device tree binding to operate.
 	  please refer to doc/device-tree-bindings/spi/spi-ath79.txt.
 
+config ATMEL_QSPI
+	bool "Atmel QSPI driver"
+	depends on ARCH_AT91
+	help
+	  Enable the Ateml Quad-SPI (QSPI) driver. This driver can only be
+	  used to access SPI NOR flashes.
+
 config ATMEL_SPI
 	bool "Atmel SPI driver"
 	depends on ARCH_AT91
drivers/spi/Makefile +1 -0
index 9f8b86de76..358db2b065 100644
@@ -18,6 +18,7 @@ endif
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
 obj-$(CONFIG_ATH79_SPI) += ath79_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_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o
 obj-$(CONFIG_CF_SPI) += cf_spi.o
drivers/spi/atmel_qspi.c new file +404 -0

404 lines not on this page · raw message

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

169 lines not on this page · raw message

Signature · 1 line
2.13.0