[U-Boot] [PATCH v3] sf: Add auto detection of 4-byte mode (vs standard 3-byte mode)

Rajat Srivastava rajat.srivastava at nxp.com
Wed Oct 17 11:52:26 UTC 2018


Hi Stefan

Sorry for top-posting.

Why can't we read SFDP parameters from flash and auto-detect 3-byte/4-byte addressing mode?
Using address width information we can support both types of flash i.e. flashes supporting 3-byte addressing mode as well as flashes supporting 4-byte addressing mode.

I've floated a similar patch in U-boot that reads and parses SFDP parameters from flash and auto-detects its addressing mode. It send commands according to the address width it detects.
Please find the patch set at:
https://patchwork.ozlabs.org/cover/985326/
https://patchwork.ozlabs.org/patch/985327/
https://patchwork.ozlabs.org/patch/985329/
https://patchwork.ozlabs.org/patch/985328/

Thanks
Rajat

> -----Original Message-----
> From: U-Boot <u-boot-bounces at lists.denx.de> On Behalf Of Stefan Roese
> Sent: Thursday, October 11, 2018 8:20 PM
> To: u-boot at lists.denx.de
> Cc: Jagan Teki <jagan at openedev.com>
> Subject: [U-Boot] [PATCH v3] sf: Add auto detection of 4-byte mode (vs 
> standard 3-byte mode)
> 
> Some SPI NOR chips only support 4-byte mode addressing. Here the 
> default 3- byte mode does not work and leads to incorrect accesses. 
> This patch now reads the 4-byte mode status bit (in this case in the 
> CR register of the Macronix SPI
> NOR) and configures the SPI transfers accordingly.
> 
> This was noticed on the LinkIt Smart 7688 modul, which is equipped 
> with an Macronix MX25L25635F device. But this device does *NOT* 
> support switching to 3-byte mode via the EX4B command.
> 
> This should also work when the bootrom configures the SPI flash to 
> 4-byte mode and runs U-Boot after this. U-Boot should dectect this 
> mode (if the 4-byte mode detection is available for this chip) and use the correct OPs in this case.
> 
> Signed-off-by: Stefan Roese <sr at denx.de>
> Cc: Jagan Teki <jagan at openedev.com>
> Tested-by: Simon Goldschmidt <simon.k.r.goldschmidt at gmail.com>
> ---
> v3:
> - Rebased on latest version (merge conflict because of new patches
>   from Simon Glass)
> - Added Tested-by tag from Simon Goldschmidt
> 
> v2:
> - Integrated STMICRO 4-byte detection from Simon
> 
>  drivers/mtd/spi/sf_internal.h |   3 +-
>  drivers/mtd/spi/spi_flash.c   | 131 ++++++++++++++++++++++++++++------
>  include/spi_flash.h           |   5 ++
>  3 files changed, 118 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/mtd/spi/sf_internal.h 
> b/drivers/mtd/spi/sf_internal.h index
> 4f63cacc64..eb076401d1 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -26,7 +26,8 @@ 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_4B_ADDR_LEN		4
> +#define SPI_FLASH_CMD_MAX_LEN		(1 +
> SPI_FLASH_4B_ADDR_LEN)
>  #define SPI_FLASH_16MB_BOUN		0x1000000
> 
>  /* CFI Manufacture ID's */
> diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c 
> index 9230060364..b22eea2d1c 100644
> --- a/drivers/mtd/spi/spi_flash.c
> +++ b/drivers/mtd/spi/spi_flash.c
> @@ -20,12 +20,19 @@
> 
>  #include "sf_internal.h"
> 
> -static void spi_flash_addr(u32 addr, u8 *cmd)
> +static void spi_flash_addr(struct spi_flash *flash, u32 addr, u8 
> +*cmd)
>  {
>  	/* cmd[0] is actual command */
> -	cmd[1] = addr >> 16;
> -	cmd[2] = addr >> 8;
> -	cmd[3] = addr >> 0;
> +	if (flash->in_4byte_mode) {
> +		cmd[1] = addr >> 24;
> +		cmd[2] = addr >> 16;
> +		cmd[3] = addr >> 8;
> +		cmd[4] = addr >> 0;
> +	} else {
> +		cmd[1] = addr >> 16;
> +		cmd[2] = addr >> 8;
> +		cmd[3] = addr >> 0;
> +	}
>  }
> 
>  static int read_sr(struct spi_flash *flash, u8 *rs) @@ -110,6 +117,72 
> @@ static int write_cr(struct spi_flash *flash, u8 wc)  }  #endif
> 
> +#if defined(CONFIG_SPI_FLASH_MACRONIX)
> +static bool flash_in_4byte_mode_macronix(struct spi_flash *flash) {
> +	int ret;
> +	u8 cr;
> +	u8 cmd;
> +
> +	cmd = 0x15;	/* Macronix: read configuration register RDCR */
> +	ret = spi_flash_read_common(flash, &cmd, 1, &cr, 1);
> +	if (ret < 0) {
> +		debug("SF: fail to read config register\n");
> +		return false;
> +	}
> +
> +	/* Return true, if 4-byte mode is enabled */
> +	if (cr & BIT(5))
> +		return true;
> +
> +	return false;
> +}
> +#else
> +static bool flash_in_4byte_mode_macronix(struct spi_flash *flash) {
> +	return false;
> +}
> +#endif
> +
> +#if defined(CONFIG_SPI_FLASH_STMICRO) static bool 
> +flash_in_4byte_mode_stmicro(struct spi_flash *flash) {
> +	int ret;
> +	u8 fsr;
> +	u8 cmd;
> +
> +	cmd = 0x70;	/* STMicro/Micron: read flag status register */
> +	ret = spi_flash_read_common(flash, &cmd, 1, &fsr, 1);
> +	if (ret < 0) {
> +		debug("SF: fail to read config register\n");
> +		return false;
> +	}
> +
> +	/* Return true, if 4-byte mode is enabled */
> +	if (fsr & BIT(0))
> +		return true;
> +
> +	return false;
> +}
> +#else
> +static bool flash_in_4byte_mode_stmicro(struct spi_flash *flash) {
> +	return false;
> +}
> +#endif
> +
> +static bool flash_in_4byte_mode(struct spi_flash *flash,
> +				const struct spi_flash_info *info) {
> +	if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_MACRONIX)
> +		return flash_in_4byte_mode_macronix(flash);
> +
> +	if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_STMICRO)
> +		return flash_in_4byte_mode_stmicro(flash);
> +
> +	return false;
> +}
> +
>  #ifdef CONFIG_SPI_FLASH_BAR
>  /*
>   * This "clean_bar" is necessary in a situation when one was 
> accessing @@ -
> 314,7 +387,7 @@ 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];
> +	u8 cmd[SPI_FLASH_CMD_MAX_LEN];
>  	int ret = -1;
> 
>  	erase_size = flash->erase_size;
> @@ -344,12 +417,13 @@ int spi_flash_cmd_erase_ops(struct spi_flash 
> *flash,
> u32 offset, size_t len)
>  		if (ret < 0)
>  			return ret;
>  #endif
> -		spi_flash_addr(erase_addr, cmd);
> +		spi_flash_addr(flash, erase_addr, cmd);
> 
>  		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, flash->cmdlen,
> +					     NULL, 0);
>  		if (ret < 0) {
>  			debug("SF: erase failed\n");
>  			break;
> @@ -373,7 +447,7 @@ int spi_flash_cmd_write_ops(struct spi_flash 
> *flash,
> u32 offset,
>  	unsigned long byte_addr, page_size;
>  	u32 write_addr;
>  	size_t chunk_len, actual;
> -	u8 cmd[SPI_FLASH_CMD_LEN];
> +	u8 cmd[SPI_FLASH_CMD_MAX_LEN];
>  	int ret = -1;
> 
>  	page_size = flash->page_size;
> @@ -404,15 +478,15 @@ int spi_flash_cmd_write_ops(struct spi_flash 
> *flash,
> u32 offset,
> 
>  		if (spi->max_write_size)
>  			chunk_len = min(chunk_len,
> -					spi->max_write_size - sizeof(cmd));
> +					spi->max_write_size - flash->cmdlen);
> 
> -		spi_flash_addr(write_addr, cmd);
> +		spi_flash_addr(flash, write_addr, cmd);
> 
>  		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),
> -					buf + actual, chunk_len);
> +		ret = spi_flash_write_common(flash, cmd, flash->cmdlen,
> +					     buf + actual, chunk_len);
>  		if (ret < 0) {
>  			debug("SF: write failed\n");
>  			break;
> @@ -469,9 +543,11 @@ int spi_flash_cmd_read_ops(struct spi_flash 
> *flash,
> u32 offset,  {
>  	struct spi_slave *spi = flash->spi;
>  	u8 cmdsz;
> -	u32 remain_len, read_len, read_addr;
> +	u64 remain_len;
> +	u32 read_len, read_addr;
>  	int bank_sel = 0;
>  	int ret = 0;
> +	int shift;
> 
>  	/* Handle memory-mapped SPI */
>  	if (flash->memory_map) {
> @@ -487,7 +563,7 @@ int spi_flash_cmd_read_ops(struct spi_flash 
> *flash, u32 offset,
>  		return 0;
>  	}
> 
> -	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
> +	cmdsz = flash->cmdlen + flash->dummy_byte;
>  	u8 cmd[cmdsz];
> 
>  	cmd[0] = flash->read_cmd;
> @@ -504,8 +580,13 @@ int spi_flash_cmd_read_ops(struct spi_flash 
> *flash,
> u32 offset,
>  			return log_ret(ret);
>  		bank_sel = flash->bank_curr;
>  #endif
> -		remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
> -				(bank_sel + 1)) - offset;
> +		shift = flash->shift;
> +		if (flash->in_4byte_mode)
> +			shift += 8;
> +
> +		remain_len = (((u64)SPI_FLASH_16MB_BOUN << shift) *
> +			      (bank_sel + 1)) - offset;
> +
>  		if (len < remain_len)
>  			read_len = len;
>  		else
> @@ -514,7 +595,7 @@ int spi_flash_cmd_read_ops(struct spi_flash 
> *flash, u32 offset,
>  		if (spi->max_read_size)
>  			read_len = min(read_len, spi->max_read_size);
> 
> -		spi_flash_addr(read_addr, cmd);
> +		spi_flash_addr(flash, read_addr, cmd);
> 
>  		ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
>  		if (ret < 0) {
> @@ -1155,6 +1236,13 @@ int spi_flash_scan(struct spi_flash *flash)
>  		write_sr(flash, sr);
>  	}
> 
> +	/* Set default value for cmd length */
> +	flash->cmdlen = 1 + SPI_FLASH_3B_ADDR_LEN;
> +	if (flash_in_4byte_mode(flash, info)) {
> +		flash->in_4byte_mode = true;
> +		flash->cmdlen = 1 + SPI_FLASH_4B_ADDR_LEN;
> +	}
> +
>  	flash->name = info->name;
>  	flash->memory_map = spi->memory_map;
> 
> @@ -1306,14 +1394,17 @@ int spi_flash_scan(struct spi_flash *flash)
>  	print_size(flash->size, "");
>  	if (flash->memory_map)
>  		printf(", mapped at %p", flash->memory_map);
> +	if (flash->in_4byte_mode)
> +		printf(" (4-byte mode)");
>  	puts("\n");
>  #endif
> 
>  #ifndef CONFIG_SPI_FLASH_BAR
> -	if (((flash->dual_flash == SF_SINGLE_FLASH) &&
> -	     (flash->size > SPI_FLASH_16MB_BOUN)) ||
> +	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))) {
> +	      (flash->size > SPI_FLASH_16MB_BOUN << 1))) &&
> +	    !flash->in_4byte_mode) {
>  		puts("SF: Warning - Only lower 16MiB accessible,");
>  		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
>  	}
> diff --git a/include/spi_flash.h b/include/spi_flash.h index
> 0ec98fb55d..b5bc4a85f6 100644
> --- a/include/spi_flash.h
> +++ b/include/spi_flash.h
> @@ -36,6 +36,8 @@ struct spi_slave;
>   * @dual_flash:		Indicates dual flash memories - dual stacked, parallel
>   * @shift:		Flash shift useful in dual parallel
>   * @flags:		Indication of spi flash flags
> + * @in_4byte_mode:	True if flash is detected to be in 4-byte mode
> + * @cmdlen:		CMD length (3-byte vs 4-byte mode)
>   * @size:		Total flash size
>   * @page_size:		Write (page) size
>   * @sector_size:	Sector size
> @@ -69,6 +71,9 @@ struct spi_flash {
>  	u8 shift;
>  	u16 flags;
> 
> +	bool in_4byte_mode;
> +	int cmdlen;
> +
>  	u32 size;
>  	u32 page_size;
>  	u32 sector_size;
> --
> 2.19.1
> 
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flis
> ts.de
> nx.de%2Flistinfo%2Fu-
> boot&data=02%7C01%7Cprabhakar.kushwaha%40nxp.com%7C532d6ed3
> ad764b27306b08d62f88d688%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0
> %7C0%7C636748662097523237&sdata=FpR4s4evDeod9zQPSTMSjigIIAn
> mOj50aFqqH21Ofms%3D&reserved=0


More information about the U-Boot mailing list