[U-Boot] [PATCH 1/3] mtd/spi: Add JEDEC SFDP support in SPI framework

Vignesh R vigneshr at ti.com
Wed Oct 31 08:17:08 UTC 2018



On 17/10/18 4:58 PM, Rajat Srivastava wrote:
> Add support for JESD216 rev B standard JEDEC Serial
> Flash Discoverable Parameters (SFDP) tables to
> dynamically initialize flash size, page size and
> address width of the flash. More parameters can be
> added as per requirement.
> Already existing method for parsing these parameters
> are not deprecated, which can be done once most flash
> start using SFDP data.
> 
> SFDP data lets us auto-detect the addressing mode
> supported by the flash which helps us access the
> flash using 4-byte address.
> 
> Add a new argument in spi_flash_addr() function to create
> commands with 3-byte or 4-byte address depending on the
> SFDP data read. Add pointer to struct spi_flash in struct
> spi_slave so that driver can have access to SFDP data.
> 
> Introduce new structures and functions to read and parse
> SFDP data. This is loosely based on Linux SFDP framework.
> 
> Signed-off-by: Rajat Srivastava <rajat.srivastava at nxp.com>
> ---
>  drivers/mtd/spi/sf_internal.h |   4 +
>  drivers/mtd/spi/spi_flash.c   | 297 +++++++++++++++++++++++++++++++++++++++---
>  include/spi.h                 |   2 +
>  include/spi_flash.h           | 120 +++++++++++++++++
>  4 files changed, 403 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index 26f5c7c995..1bb4431d84 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -26,7 +26,9 @@ 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)
> +#define SPI_FLASH_CMD_MAX_LEN		(1 + SPI_FLASH_4B_ADDR_LEN)
>  #define SPI_FLASH_16MB_BOUN		0x1000000
>  
>  /* CFI Manufacture ID's */
> @@ -62,6 +64,7 @@ enum spi_nor_option_flags {
>  #define CMD_READ_STATUS1		0x35
>  #define CMD_READ_CONFIG			0x35
>  #define CMD_FLAG_STATUS			0x70
> +#define CMD_READ_SFDP			0x5a
>  
>  /* Bank addr access commands */
>  #ifdef CONFIG_SPI_FLASH_BAR
> @@ -144,6 +147,7 @@ struct spi_flash_info {
>  #define RD_DUAL			BIT(5)	/* use Dual Read */
>  #define RD_QUADIO		BIT(6)	/* use Quad IO Read */
>  #define RD_DUALIO		BIT(7)	/* use Dual IO Read */
> +#define SPI_FLASH_USE_SFDP	BIT(8)  /* parse SFDP to get flash info */

I suggest to SFDP not be a opt-in but default option like Linux kernel,
since that's SFDP is a standard. If flash does not support SFDP that can
be detected by looking for SFPD signature and code can fallback
gracefully. If a flash has a broken SFDP table then such parts can use
"SPI_FLASH_BROKEN_SFDP" flag or something. That way we don't need to add
above flag to almost all flash entries here.

Regards
Vignesh

>  #define RD_FULL			(RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
>  };
>  
> diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
> index a87bacd4ac..5d2728cc00 100644
> --- a/drivers/mtd/spi/spi_flash.c
> +++ b/drivers/mtd/spi/spi_flash.c
> @@ -20,12 +20,24 @@
>  
>  #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;
> +	int i;
> +
> +	/* Remember to unset addrwd_3_in_use */
> +	if (flash->addrwd_3_in_use) {
> +		flash->addr_width = SPI_FLASH_3B_ADDR_LEN;
> +		debug("SF: addrwd_3_in_use flag needs to be reset to false ");
> +		debug("after the intended command is triggered to flash.\n");
> +	}
> +
> +	flash->cmd_len = 1 + flash->addr_width;
> +
> +	for (i = flash->cmd_len - 1; i > 0; i--) {
> +		cmd[i] = addr;
> +		addr = addr >> 8;
> +	}
>  }
>  
>  static int read_sr(struct spi_flash *flash, u8 *rs)
> @@ -314,7 +326,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 +356,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->cmd_len,
> +					     NULL, 0);
>  		if (ret < 0) {
>  			debug("SF: erase failed\n");
>  			break;
> @@ -373,7 +386,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;
> @@ -406,13 +419,13 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
>  			chunk_len = min(chunk_len,
>  					spi->max_write_size - sizeof(cmd));
>  
> -		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->cmd_len,
> +					     buf + actual, chunk_len);
>  		if (ret < 0) {
>  			debug("SF: write failed\n");
>  			break;
> @@ -487,7 +500,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->cmd_len + flash->dummy_byte;
>  	u8 cmd[cmdsz];
>  
>  	cmd[0] = flash->read_cmd;
> @@ -504,8 +517,11 @@ 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;
> +		if (flash->cmd_len == SPI_FLASH_CMD_MAX_LEN)
> +			remain_len = flash->size - offset;
> +		else
> +			remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
> +				      (bank_sel + 1)) - offset;
>  		if (len < remain_len)
>  			read_len = len;
>  		else
> @@ -514,7 +530,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) {
> @@ -1076,6 +1092,226 @@ static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
>  	return ERR_PTR(-ENODEV);
>  }
>  
> +/*
> + * Serial Flash Discoverable Parameters (SFDP) parsing
> + */
> +
> +/*
> + * spi_flash_read_sfdp() - read Serial Flash Discoverable Parameters.
> + * @flash:	pointer to a 'struct spi_flash'
> + * @addr:	offset in the SFDP area to start reading data from
> + * @len:	number of bytes to read
> + * @buf:	buffer where the SFDP data are copied into
> + *
> + * Return: 0 on success, -errno otherwise.
> + */
> +static int spi_flash_read_sfdp(struct spi_flash *flash, u32 addr, size_t len,
> +			       void *buf)
> +{
> +	u8 cmd[4];
> +	int ret;
> +
> +	cmd[0] = CMD_READ_SFDP;
> +
> +	/*
> +	 * In case of flashes that support 3 or 4-byte addressing modes
> +	 * based on command fired, CMD_READ_SFDP is a 3-byte command.
> +	 * To make sure a 3-byte command is fired, change addrwd_3_in_use
> +	 * to true and reset it after triggering the command.
> +	 */
> +	flash->addrwd_3_in_use = true;
> +	spi_flash_addr(flash, addr, cmd);
> +	flash->addrwd_3_in_use = false;
> +
> +	ret = spi_flash_read_common(flash, cmd, 4, buf, len);
> +	if (ret)
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +/**
> + * spi_flash_parse_bfpt() - read and parse the Basic Flash Parameter Table.
> + * @flash:		pointer to a 'struct spi_flash'
> + * @bfpt_header:	pointer to the 'struct sfdp_parameter_header' describing
> + *			the Basic Flash Parameter Table length and version
> + *
> + * The Basic Flash Parameter Table is the main and only mandatory table as
> + * defined by the SFDP (JESD216) specification.
> + * It provides us with the total size (memory density) of the data array, page
> + * size and the number of address bytes to perform flash operations, among
> + * other information.
> + *
> + * Return: 0 on success, -errno otherwise.
> + */
> +static int spi_flash_parse_bfpt(struct spi_flash *flash,
> +				const struct sfdp_parameter_header *bfpt_header)
> +{
> +	struct sfdp_bfpt bfpt;
> +	size_t len;
> +	int i, err;
> +	u32 addr;
> +
> +	/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
> +	if (bfpt_header->length < BFPT_DWORD_MAX_JESD216)
> +		return -EINVAL;
> +
> +	/* Read the Basic Flash Parameter Table. */
> +	len = min_t(size_t, sizeof(bfpt),
> +		    bfpt_header->length * sizeof(u32));
> +	addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
> +	memset(&bfpt, 0, sizeof(bfpt));
> +	err = spi_flash_read_sfdp(flash, addr, len, &bfpt);
> +	if (err < 0)
> +		return err;
> +
> +	/* Fix endianness of the BFPT DWORDs. */
> +	for (i = 0; i < BFPT_DWORD_MAX; i++)
> +		bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]);
> +
> +	/* Number of address bytes. */
> +	switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) {
> +	case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY:
> +		flash->addr_width = 3;
> +		break;
> +
> +	case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4:
> +		printf("SF: Flash defaults to 3-Byte mode; enters 4-Byte ");
> +		printf("mode on command\n");
> +		/*
> +		 * By default, 4-byte addressing mode is set.
> +		 * To enforce 3-byte addressing mode, set addrwd_3_in_use flag
> +		 * in struct spi_flash for every command.
> +		 */
> +		flash->addr_width = 4;
> +		break;
> +
> +	case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY:
> +		flash->addr_width = 4;
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	/* Flash Memory Density (in bits). */
> +	flash->size = bfpt.dwords[BFPT_DWORD(2)];
> +	if (flash->size & BIT(31)) {
> +		flash->size &= ~BIT(31);
> +
> +		/*
> +		 * Prevent overflows on flash->size. Anyway, a NOR of 2^64
> +		 * bits is unlikely to exist so this error probably means
> +		 * the BFPT we are reading is corrupted/wrong.
> +		 */
> +		if (flash->size > 63)
> +			return -EINVAL;
> +
> +		flash->size = 1ULL << flash->size;
> +	} else {
> +		flash->size++;
> +	}
> +	flash->size >>= 3; /* Convert to bytes. */
> +
> +	/* Stop here if not JESD216 rev A or later. */
> +	if (bfpt_header->length < BFPT_DWORD_MAX)
> +		return 0;
> +
> +	/* Page size: this field specifies 'N' so the page size = 2^N bytes. */
> +	flash->page_size = bfpt.dwords[BFPT_DWORD(11)];
> +	flash->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK;
> +	flash->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT;
> +	flash->page_size = 1U << flash->page_size;
> +
> +	return 0;
> +}
> +
> +/*
> + * spi_flash_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
> + * @flash:	pointer to a 'struct spi_flash'
> + *
> + * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216
> + * specification. This is a standard which tends to supported by almost all
> + * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at
> + * runtime the main parameters needed to perform basic SPI flash operations.
> + *
> + * Return: 0 on success, -errno otherwise.
> + */
> +static int spi_flash_parse_sfdp(struct spi_flash *flash)
> +{
> +	const struct sfdp_parameter_header *param_header, *bfpt_header;
> +	struct sfdp_parameter_header *param_headers = NULL;
> +	struct sfdp_header header;
> +	size_t psize;
> +	int i, err;
> +
> +	/* Get the SFDP header. */
> +	err = spi_flash_read_sfdp(flash, 0, sizeof(header), &header);
> +	if (err < 0)
> +		return err;
> +
> +	/* Check the SFDP header version. */
> +	if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
> +	    header.major != SFDP_JESD216_MAJOR)
> +		return -EINVAL;
> +
> +	/*
> +	 * Verify that the first and only mandatory parameter header is a
> +	 * Basic Flash Parameter Table header as specified in JESD216.
> +	 */
> +	bfpt_header = &header.bfpt_header;
> +	if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID ||
> +	    bfpt_header->major != SFDP_JESD216_MAJOR)
> +		return -EINVAL;
> +
> +	/*
> +	 * Allocate memory then read all parameter headers with a single
> +	 * Read SFDP command. These parameter headers will actually be parsed
> +	 * twice: a first time to get the latest revision of the basic flash
> +	 * parameter table, then a second time to handle the supported optional
> +	 * tables.
> +	 * Hence we read the parameter headers once for all to reduce the
> +	 * processing time
> +	 */
> +	if (header.nph) {
> +		psize = header.nph * sizeof(*param_headers);
> +
> +		param_headers = malloc(psize);
> +		if (!param_headers)
> +			return -ENOMEM;
> +
> +		err = spi_flash_read_sfdp(flash, sizeof(header),
> +					  psize, param_headers);
> +		if (err < 0) {
> +			dev_err(dev, "failed to read SFDP parameter headers\n");
> +			goto exit;
> +		}
> +	}
> +
> +	/*
> +	 * Check other parameter headers to get the latest revision of
> +	 * the basic flash parameter table.
> +	 */
> +	for (i = 0; i < header.nph; i++) {
> +		param_header = &param_headers[i];
> +
> +		if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID &&
> +		    param_header->major == SFDP_JESD216_MAJOR &&
> +		    (param_header->minor > bfpt_header->minor ||
> +		     (param_header->minor == bfpt_header->minor &&
> +		      param_header->length > bfpt_header->length)))
> +			bfpt_header = param_header;
> +	}
> +
> +	err = spi_flash_parse_bfpt(flash, bfpt_header);
> +	if (err)
> +		goto exit;
> +
> +exit:
> +	free(param_headers);
> +	return err;
> +}
> +
>  static int set_quad_mode(struct spi_flash *flash,
>  			 const struct spi_flash_info *info)
>  {
> @@ -1196,9 +1432,26 @@ int spi_flash_scan(struct spi_flash *flash)
>  	}
>  #endif
>  
> +	spi->flash = flash;
> +	flash->addrwd_3_in_use = false;
> +
> +	/* Read Serial Flash Discoverable Parameters and initialize
> +	 * the following parameters of flash:
> +	 * 1. Flash size
> +	 * 2. Page size
> +	 * 3. Address width to be used for commands
> +	 */
> +	if (info->flags & SPI_FLASH_USE_SFDP) {
> +		flash->size = 0;
> +		spi_flash_parse_sfdp(flash);
> +	}
> +
>  	/* Compute the flash size */
>  	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
> -	flash->page_size = info->page_size;
> +	if (!(info->flags & SPI_FLASH_USE_SFDP)) {
> +		flash->page_size = info->page_size;
> +		flash->addr_width = SPI_FLASH_3B_ADDR_LEN;
> +	}
>  	/*
>  	 * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
>  	 * yet use the 0x4d00 Extended JEDEC code. The rest of the Spansion
> @@ -1213,7 +1466,10 @@ int spi_flash_scan(struct spi_flash *flash)
>  	}
>  	flash->page_size <<= flash->shift;
>  	flash->sector_size = info->sector_size << flash->shift;
> -	flash->size = flash->sector_size * info->n_sectors << flash->shift;
> +	if (!(info->flags & SPI_FLASH_USE_SFDP)) {
> +		flash->size = flash->sector_size * info->n_sectors <<
> +			flash->shift;
> +	}
>  #ifdef CONFIG_SF_DUAL_FLASH
>  	if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
>  		flash->size <<= 1;
> @@ -1312,9 +1568,10 @@ int spi_flash_scan(struct spi_flash *flash)
>  #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) &&
> +	if (!(info->flags & SPI_FLASH_USE_SFDP) &&
> +	    (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");
> diff --git a/include/spi.h b/include/spi.h
> index 938627bc01..7189e60581 100644
> --- a/include/spi.h
> +++ b/include/spi.h
> @@ -10,6 +10,7 @@
>  #define _SPI_H_
>  
>  #include <common.h>
> +#include <spi_flash.h>
>  
>  /* SPI mode flags */
>  #define SPI_CPHA	BIT(0)			/* clock phase */
> @@ -103,6 +104,7 @@ struct spi_slave {
>  	unsigned int bus;
>  	unsigned int cs;
>  #endif
> +	struct spi_flash *flash;
>  	uint mode;
>  	unsigned int wordlen;
>  	unsigned int max_read_size;
> diff --git a/include/spi_flash.h b/include/spi_flash.h
> index 0ec98fb55d..6558a4a1d5 100644
> --- a/include/spi_flash.h
> +++ b/include/spi_flash.h
> @@ -47,6 +47,9 @@ struct spi_slave;
>   * @read_cmd:		Read cmd - Array Fast, Extn read and quad read.
>   * @write_cmd:		Write cmd - page and quad program.
>   * @dummy_byte:		Dummy cycles for read operation.
> + * @cmd_len:		Total length of command.
> + * @addr_width:		Number of address bytes.
> + * @addrwd_3_in_use:	Flag to send command in 3-byte address mode.
>   * @memory_map:		Address of read-only SPI flash access
>   * @flash_lock:		lock a region of the SPI Flash
>   * @flash_unlock:	unlock a region of the SPI Flash
> @@ -82,6 +85,9 @@ struct spi_flash {
>  	u8 read_cmd;
>  	u8 write_cmd;
>  	u8 dummy_byte;
> +	u8 cmd_len;
> +	u8 addr_width;
> +	bool addrwd_3_in_use;
>  
>  	void *memory_map;
>  
> @@ -107,6 +113,120 @@ struct spi_flash {
>  #endif
>  };
>  
> +/*
> + * Serial Flash Discoverable Parameter Headers
> + */
> +struct sfdp_parameter_header {
> +	u8	id_lsb;
> +	u8	minor;
> +	u8	major;
> +	u8	length; /* in double words */
> +	u8	parameter_table_pointer[3]; /* byte address */
> +	u8	id_msb;
> +};
> +
> +struct sfdp_header {
> +	u32	signature; /* Ox50444653U <=> "SFDP" */
> +	u8	minor;
> +	u8	major;
> +	u8	nph; /* 0-base number of parameter headers */
> +	u8	unused;
> +
> +	/* Basic Flash Parameter Table. */
> +	struct sfdp_parameter_header	bfpt_header;
> +};
> +
> +#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb)
> +#define SFDP_PARAM_HEADER_PTP(p) \
> +	(((p)->parameter_table_pointer[2] << 16) | \
> +	 ((p)->parameter_table_pointer[1] <<  8) | \
> +	 ((p)->parameter_table_pointer[0] <<  0))
> +
> +#define SFDP_BFPT_ID		0xff00  /* Basic Flash Parameter Table */
> +#define SFDP_SECTOR_MAP_ID	0xff81  /* Sector Map Table */
> +
> +#define SFDP_SIGNATURE		0x50444653U
> +#define SFDP_JESD216_MAJOR	1
> +#define SFDP_JESD216_MINOR	0
> +#define SFDP_JESD216A_MINOR	5
> +#define SFDP_JESD216B_MINOR	6
> +
> +/* Basic Flash Parameter Table */
> +
> +/*
> + * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
> + * They are indexed from 1 but C arrays are indexed from 0.
> + */
> +#define BFPT_DWORD(i)		((i) - 1)
> +#define BFPT_DWORD_MAX		16
> +
> +/* The first version of JESB216 defined only 9 DWORDs. */
> +#define BFPT_DWORD_MAX_JESD216			9
> +
> +/* 1st DWORD. */
> +#define BFPT_DWORD1_FAST_READ_1_1_2		BIT(16)
> +#define BFPT_DWORD1_ADDRESS_BYTES_MASK		GENMASK(18, 17)
> +#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY	(0x0UL << 17)
> +#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4	(0x1UL << 17)
> +#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY	(0x2UL << 17)
> +#define BFPT_DWORD1_DTR				BIT(19)
> +#define BFPT_DWORD1_FAST_READ_1_2_2		BIT(20)
> +#define BFPT_DWORD1_FAST_READ_1_4_4		BIT(21)
> +#define BFPT_DWORD1_FAST_READ_1_1_4		BIT(22)
> +
> +/* 5th DWORD. */
> +#define BFPT_DWORD5_FAST_READ_2_2_2		BIT(0)
> +#define BFPT_DWORD5_FAST_READ_4_4_4		BIT(4)
> +
> +/* 11th DWORD. */
> +#define BFPT_DWORD11_PAGE_SIZE_SHIFT		4
> +#define BFPT_DWORD11_PAGE_SIZE_MASK		GENMASK(7, 4)
> +
> +/* 15th DWORD. */
> +
> +/*
> + * (from JESD216 rev B)
> + * Quad Enable Requirements (QER):
> + * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
> + *         reads based on instruction. DQ3/HOLD# functions are hold during
> + *         instruction phase.
> + * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
> + *         two data bytes where bit 1 of the second byte is one.
> + *         [...]
> + *         Writing only one byte to the status register has the side-effect of
> + *         clearing status register 2, including the QE bit. The 100b code is
> + *         used if writing one byte to the status register does not modify
> + *         status register 2.
> + * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
> + *         one data byte where bit 6 is one.
> + *         [...]
> + * - 011b: QE is bit 7 of status register 2. It is set via Write status
> + *         register 2 instruction 3Eh with one data byte where bit 7 is one.
> + *         [...]
> + *         The status register 2 is read using instruction 3Fh.
> + * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
> + *         two data bytes where bit 1 of the second byte is one.
> + *         [...]
> + *         In contrast to the 001b code, writing one byte to the status
> + *         register does not modify status register 2.
> + * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
> + *         Read Status instruction 05h. Status register2 is read using
> + *         instruction 35h. QE is set via Writ Status instruction 01h with
> + *         two data bytes where bit 1 of the second byte is one.
> + *         [...]
> + */
> +#define BFPT_DWORD15_QER_MASK			GENMASK(22, 20)
> +#define BFPT_DWORD15_QER_NONE			(0x0UL << 20) /* Micron */
> +#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY		(0x1UL << 20)
> +#define BFPT_DWORD15_QER_SR1_BIT6		(0x2UL << 20) /* Macronix */
> +#define BFPT_DWORD15_QER_SR2_BIT7		(0x3UL << 20)
> +#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD		(0x4UL << 20)
> +#define BFPT_DWORD15_QER_SR2_BIT1		(0x5UL << 20) /* Spansion */
> +
> +struct sfdp_bfpt {
> +	u32	dwords[BFPT_DWORD_MAX];
> +};
> +
>  struct dm_spi_flash_ops {
>  	int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf);
>  	int (*write)(struct udevice *dev, u32 offset, size_t len,
> 

-- 
Regards
Vignesh


More information about the U-Boot mailing list