From mboxrd@z Thu Jan 1 00:00:00 1970 From: Wenyou Yang Date: Tue, 25 Jul 2017 15:01:00 +0800 Subject: [U-Boot] [PATCH v3 6/8] sf: add new option to support SPI flash above 16MiB In-Reply-To: <20170725070102.1344-1-wenyou.yang@microchip.com> References: <20170725070102.1344-1-wenyou.yang@microchip.com> Message-ID: <20170725070102.1344-7-wenyou.yang@microchip.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de From: Cyrille Pitchen 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. Signed-off-by: Cyrille Pitchen Signed-off-by: Wenyou Yang --- Changes in v3: None 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(-) diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 5700859ff2..985aefd96c 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -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 diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 8b8c951bcc..30994f9f46 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -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[]; diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index d6942d57b2..89ceae2221 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -176,6 +176,67 @@ bar_end: } #endif +#ifdef CONFIG_SPI_FLASH_4BAIS +static u8 spi_flash_convert_opcode(u8 opcode, const u8 table[][2], size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + if (table[i][0] == opcode) + return table[i][1]; + + /* No conversion found, keep input op code. */ + return opcode; +} + +static u8 spi_flash_convert_3to4_read(u8 opcode) +{ + static const u8 spi_flash_3to4_read[][2] = { + {CMD_READ_ARRAY_SLOW, CMD_READ_ARRAY_SLOW_4B}, + {CMD_READ_ARRAY_FAST, CMD_READ_ARRAY_FAST_4B}, + {CMD_READ_DUAL_OUTPUT_FAST, CMD_READ_DUAL_OUTPUT_FAST_4B}, + {CMD_READ_DUAL_IO_FAST, CMD_READ_DUAL_IO_FAST_4B}, + {CMD_READ_QUAD_OUTPUT_FAST, CMD_READ_QUAD_OUTPUT_FAST_4B}, + {CMD_READ_QUAD_IO_FAST, CMD_READ_QUAD_IO_FAST_4B}, + }; + + return spi_flash_convert_opcode(opcode, spi_flash_3to4_read, + ARRAY_SIZE(spi_flash_3to4_read)); +} + +static u8 spi_flash_convert_3to4_write(u8 opcode) +{ + static const u8 spi_flash_3to4_write[][2] = { + {CMD_PAGE_PROGRAM, CMD_PAGE_PROGRAM_4B}, + {CMD_PAGE_PROGRAM_1_1_4, CMD_PAGE_PROGRAM_1_1_4_4B}, + {CMD_PAGE_PROGRAM_1_4_4, CMD_PAGE_PROGRAM_1_4_4_4B}, + }; + + return spi_flash_convert_opcode(opcode, spi_flash_3to4_write, + ARRAY_SIZE(spi_flash_3to4_write)); +} + +static u8 spi_flash_convert_3to4_erase(u8 opcode) +{ + static const u8 spi_flash_3to4_erase[][2] = { + {CMD_ERASE_4K, CMD_ERASE_4K_4B}, + {CMD_ERASE_64K, CMD_ERASE_64K_4B}, + }; + + return spi_flash_convert_opcode(opcode, spi_flash_3to4_erase, + ARRAY_SIZE(spi_flash_3to4_erase)); +} + +static void spi_flash_set_4byte_addr_opcodes(struct spi_flash *flash, + const struct spi_flash_info *info) +{ + flash->read_cmd = spi_flash_convert_3to4_read(flash->read_cmd); + flash->write_cmd = spi_flash_convert_3to4_write(flash->write_cmd); + flash->erase_cmd = spi_flash_convert_3to4_erase(flash->erase_cmd); + flash->addr_len = SPI_FLASH_4B_ADDR_LEN; +} +#endif + #ifdef CONFIG_SF_DUAL_FLASH static void spi_flash_dual(struct spi_flash *flash, u32 *addr) { @@ -965,6 +1026,7 @@ int spi_flash_scan(struct spi_flash *flash) { struct spi_slave *spi = flash->spi; const struct spi_flash_info *info = NULL; + bool above_16MB; int ret; info = spi_flash_read_id(flash); @@ -1105,6 +1167,26 @@ int spi_flash_scan(struct spi_flash *flash) /* Set the address length */ flash->addr_len = SPI_FLASH_3B_ADDR_LEN; + above_16MB = ((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)); + + /* + * replace the selected 3-byte address op codes with the associated + * 4-byte address op codes, if needed (flash->size > 16 MiB) + */ +#ifdef CONFIG_SPI_FLASH_4BAIS + if (above_16MB) { + if (info->flags & NO_4BAIS) { + puts("SF: Warning - Only lower 16MiB accessible,"); + puts(" 4-byte address instruction set not supported\n"); + } else { + spi_flash_set_4byte_addr_opcodes(flash, info); + } + } +#endif + /* Configure the BAR - discover bank cmds and read current bank */ #ifdef CONFIG_SPI_FLASH_BAR ret = read_bar(flash, info); @@ -1130,13 +1212,11 @@ int spi_flash_scan(struct spi_flash *flash) puts("\n"); #endif -#ifndef CONFIG_SPI_FLASH_BAR - 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_BAR) && !defined(CONFIG_SPI_FLASH_4BAIS) + if (above_16MB) { puts("SF: Warning - Only lower 16MiB accessible,"); - puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); + puts(" Full access #define CONFIG_SPI_FLASH_BAR"); + puts(" or CONFIG_SPI_FLASH_4BAIS\n"); } #endif -- 2.13.0