[U-Boot] [PATCH] mtd: spi: Add 4bytes extend address support
Ye Li
ye.li at nxp.com
Mon Jan 7 05:22:36 UTC 2019
Current SPI flash framework only supports to set bank register
(CONFIG_SPI_FLASH_BAR) for flash with size > 16MiB. But some new flash device
(for example, mt35xu512g) does not support this way, it only supports
4bytes extend address.
To access the whole memory size for such flash device, we add the support
for this 4bytes extend address mode to SPI flash framework.
The configuration CONFIG_SPI_FLASH_4BYTES_ADDR is used to enable the feature.
Signed-off-by: Ye Li <ye.li at nxp.com>
---
drivers/mtd/spi/Kconfig | 7 ++++
drivers/mtd/spi/sf_internal.h | 8 +++++
drivers/mtd/spi/spi_flash.c | 75 ++++++++++++++++++++++++++++++++++++++-----
3 files changed, 82 insertions(+), 8 deletions(-)
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 76d5a1d..ffc80dd 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -42,6 +42,13 @@ config SPI_FLASH_BAR
Bank/Extended address registers are used to access the flash
which has size > 16MiB in 3-byte addressing.
+config SPI_FLASH_4BYTES_ADDR
+ bool "SPI flash 4bytes (32) address mode support"
+ depends on SPI_FLASH && !SPI_FLASH_BAR
+ help
+ Enable the SPI flash 4bytes extend address mode support to access the flash
+ which has size > 16MiB.
+
config SF_DUAL_FLASH
bool "SPI DUAL flash memory support"
depends on SPI_FLASH
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 46a5044..50d0863 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -63,6 +63,14 @@ enum spi_nor_option_flags {
#define CMD_READ_CONFIG 0x35
#define CMD_FLAG_STATUS 0x70
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+#define CMD_READ_ARRAY_FAST_4B 0x0c
+#define CMD_PAGE_PROGRAM_4B 0x12
+#define CMD_ERASE_64K_4B 0xdc
+#define CMD_ERASE_4K_4B 0x21
+#define CMD_EN4B 0xB7
+#endif
+
/* Bank addr access commands */
#ifdef CONFIG_SPI_FLASH_BAR
# define CMD_BANKADDR_BRWR 0x17
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 0c2392f..312bedb 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -28,6 +28,17 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
cmd[3] = addr >> 0;
}
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+static void spi_flash_addr_4b(u32 addr, u8 *cmd)
+{
+ /* cmd[0] is actual command */
+ cmd[1] = addr >> 24;
+ cmd[2] = addr >> 16;
+ cmd[3] = addr >> 8;
+ cmd[4] = addr >> 0;
+}
+#endif
+
static int read_sr(struct spi_flash *flash, u8 *rs)
{
int ret;
@@ -325,8 +336,8 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
{
- u32 erase_size, erase_addr;
- u8 cmd[SPI_FLASH_CMD_LEN];
+ u32 erase_size, erase_addr, cmd_len;
+ u8 cmd[SPI_FLASH_CMD_LEN + 1];
int ret = -1;
erase_size = flash->erase_size;
@@ -357,11 +368,19 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
return ret;
#endif
spi_flash_addr(erase_addr, cmd);
+ cmd_len = SPI_FLASH_CMD_LEN;
+
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+ if (flash->size > SPI_FLASH_16MB_BOUN) {
+ spi_flash_addr_4b(erase_addr, cmd);
+ cmd_len = SPI_FLASH_CMD_LEN + 1;
+ }
+#endif
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_write_common(flash, cmd, cmd_len, NULL, 0);
if (ret < 0) {
debug("SF: erase failed\n");
break;
@@ -384,8 +403,8 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
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];
+ size_t chunk_len, actual, cmd_len;
+ u8 cmd[SPI_FLASH_CMD_LEN + 1];
int ret = -1;
page_size = flash->page_size;
@@ -419,11 +438,19 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
spi->max_write_size - sizeof(cmd));
spi_flash_addr(write_addr, cmd);
+ cmd_len = SPI_FLASH_CMD_LEN;
+
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+ if (flash->size > SPI_FLASH_16MB_BOUN) {
+ spi_flash_addr_4b(write_addr, cmd);
+ cmd_len = SPI_FLASH_CMD_LEN + 1;
+ }
+#endif
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),
+ ret = spi_flash_write_common(flash, cmd, cmd_len,
buf + actual, chunk_len);
if (ret < 0) {
debug("SF: write failed\n");
@@ -500,6 +527,10 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
}
cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+ if (flash->size > SPI_FLASH_16MB_BOUN)
+ cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte + 1;
+#endif
u8 cmd[cmdsz];
cmd[0] = flash->read_cmd;
@@ -528,6 +559,12 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
spi_flash_addr(read_addr, cmd);
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+ if (flash->size > SPI_FLASH_16MB_BOUN) {
+ spi_flash_addr_4b(read_addr, cmd);
+ read_len = len; /* Not care remain len for current bank */
+ }
+#endif
ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
if (ret < 0) {
debug("SF: read failed\n");
@@ -1114,6 +1151,13 @@ static int set_quad_mode(struct spi_flash *flash,
}
}
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+static int enter_4bytes_addr(struct spi_flash *flash)
+{
+ return spi_flash_cmd(flash->spi, CMD_EN4B, NULL, 0);
+}
+#endif
+
#if CONFIG_IS_ENABLED(OF_CONTROL)
int spi_flash_decode_fdt(struct spi_flash *flash)
{
@@ -1262,6 +1306,21 @@ int spi_flash_scan(struct spi_flash *flash)
/* Go for default supported write cmd */
flash->write_cmd = CMD_PAGE_PROGRAM;
+#ifdef CONFIG_SPI_FLASH_4BYTES_ADDR
+ if (flash->size > SPI_FLASH_16MB_BOUN) {
+ flash->read_cmd = CMD_READ_ARRAY_FAST_4B;
+ flash->write_cmd = CMD_PAGE_PROGRAM_4B;
+
+ if (flash->erase_cmd == CMD_ERASE_4K)
+ flash->erase_cmd = CMD_ERASE_4K_4B;
+ else
+ flash->erase_cmd = CMD_ERASE_64K_4B;
+
+ enter_4bytes_addr(flash);
+ }
+#endif
+
+
/* 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) ||
@@ -1323,13 +1382,13 @@ int spi_flash_scan(struct spi_flash *flash)
puts("\n");
#endif
-#ifndef CONFIG_SPI_FLASH_BAR
+#if !defined(CONFIG_SPI_FLASH_BAR) && !defined(CONFIG_SPI_FLASH_4BYTES_ADDR)
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))) {
puts("SF: Warning - Only lower 16MiB accessible,");
- puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
+ puts(" Full access #define CONFIG_SPI_FLASH_BAR or #define CONFIG_SPI_FLASH_4BYTES_ADDR\n");
}
#endif
--
2.7.4
More information about the U-Boot
mailing list