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

Rajat Srivastava rajat.srivastava at nxp.com
Wed Oct 31 09:29:58 UTC 2018



> -----Original Message-----
> From: Simon Goldschmidt <simon.k.r.goldschmidt at gmail.com>
> Sent: Wednesday, October 31, 2018 2:51 PM
> To: Rajat Srivastava <rajat.srivastava at nxp.com>
> Cc: vigneshr at ti.com; U-Boot Mailing List <u-boot at lists.denx.de>; Jagan Teki
> <jagan at 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.srivastava at nxp.com> wrote:
> >
> >
> >
> > > -----Original Message-----
> > > From: Vignesh R <vigneshr at ti.com>
> > > Sent: Wednesday, October 31, 2018 1:47 PM
> > > To: Rajat Srivastava <rajat.srivastava at nxp.com>; u-boot at lists.denx.de
> > > Cc: jagan at 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.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.
> >
> > 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 = &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);
> 
> 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 at 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


More information about the U-Boot mailing list