[U-Boot] [PATCH 6/8] sf: add new option to support SPI flash above 16MiB

Yang, Wenyou Wenyou.Yang at Microchip.com
Mon May 22 01:20:14 UTC 2017



On 2017/5/19 22:59, Cyrille Pitchen wrote:
> 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 <cyrille.pitchen at atmel.com>

Acked-by Wenyou Yang <wenyou.yang at atmel.com>


Best Regards,
Wenyou Yang
> ---
>   drivers/mtd/spi/Kconfig       | 15 ++++++-
>   drivers/mtd/spi/sf_internal.h | 18 +++++++++
>   drivers/mtd/spi/spi_flash.c   | 92 ++++++++++++++++++++++++++++++++++++++++---
>   3 files changed, 118 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
> index 5ca0a712d84a..c11e83263b16 100644
> --- a/drivers/mtd/spi/Kconfig
> +++ b/drivers/mtd/spi/Kconfig
> @@ -34,14 +34,27 @@ 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
> +
>   if SPI_FLASH
>   
>   config SPI_FLASH_ATMEL
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index 8b8c951bcc55..30994f9f460c 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 c5e00772f241..695c8555db3f 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)
>   {
> @@ -966,6 +1027,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);
> @@ -1106,6 +1168,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);
> @@ -1131,13 +1213,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
>   



More information about the U-Boot mailing list