[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 = ¶m_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