[U-Boot] mtd: spi: Add 4bytes extend address support
diff mbox series

Message ID 1546838540-19675-1-git-send-email-ye.li@nxp.com
State Superseded
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series
  • [U-Boot] mtd: spi: Add 4bytes extend address support
Related show

Commit Message

Ye Li Jan. 7, 2019, 5:22 a.m. UTC
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@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(-)

Patch
diff mbox series

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