> -----Original Message----- > From: Simon Goldschmidt <simon.k.r.goldschm...@gmail.com> > Sent: Wednesday, October 31, 2018 2:51 PM > To: Rajat Srivastava <rajat.srivast...@nxp.com> > Cc: vigne...@ti.com; U-Boot Mailing List <u-boot@lists.denx.de>; Jagan Teki > <ja...@openedev.com> > Subject: Re: [U-Boot] [PATCH 1/3] mtd/spi: Add JEDEC SFDP support in SPI > framework > > On Wed, Oct 31, 2018 at 10:01 AM Rajat Srivastava > <rajat.srivast...@nxp.com> wrote: > > > > > > > > > -----Original Message----- > > > From: Vignesh R <vigne...@ti.com> > > > Sent: Wednesday, October 31, 2018 1:47 PM > > > To: Rajat Srivastava <rajat.srivast...@nxp.com>; u-boot@lists.denx.de > > > Cc: ja...@openedev.com > > > Subject: Re: [U-Boot] [PATCH 1/3] mtd/spi: Add JEDEC SFDP support in > SPI > > > framework > > > > > > > > > > > > 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.srivast...@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. > > > > You are correct. But, currently no drivers have implementation to send > READ SFDP > > command from their respective drivers. Once most have migrated to SFDP > standard > > then we can change this flag (making it the default mode). > > But can't we start now with making it default? What happens if the > driver doesn't support it? Can't we implement a fallback mode now so > we can make it default? That would encourage adoption, wouldn't it?
Ok. I'll make SFDP reading the default method and implement the fallback path for SPI framework, in v2 patch. Rajat > > Simon > > > Is it possible that a flash that supports SFDP parameter reading can send > some incorrect > > signature? In that case I'll have to add an alternate path for fail > > scenario. > > You're checking the signature already. But you're not checking the > return value of 'spi_flash_parse_sfdp'. See below. > > > > > > > > > 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); > > Check return value here and ensure the next block checking > 'info->flags & SPI_FLASH_USE_SFDP' is executed? Fallback path will be implemented here. Rajat > > Simon > > > > > + } > > > > + > > > > /* 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 > > _______________________________________________ > > U-Boot mailing list > > U-Boot@lists.denx.de > > > https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flist > s.denx.de%2Flistinfo%2Fu- > boot&data=02%7C01%7Crajat.srivastava%40nxp.com%7C59ecda360c19 > 437aa84608d63f124063%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0% > 7C636765744965696179&sdata=4IMDM2b9Zle2WKqDNNx45%2BkbvD5Q > l7odSfccyS8jIK8%3D&reserved=0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot