Read SFDP parameters and access flash above 16MB
Subsystems (2)
v2 cover Read SFDP parameters and access flash above 16MB
Add functionality to read and parse SFDP parameters to auto-detect flash size, page size and address width of flash. This enables flash access above 16MB using 4-byte addressing mode.
Add driver support to get SFDP information of flash and use it to access flash above 16MB.
---
Changes in v2:
- Make SFDP parsing the default way to read flash parameters.
- Change SPI_FLASH_USE_SFDP flag to SPI_FLASH_SKIP_SFDP to provide an option to skip SFDP parsing for a particular flash.
- Convert patch-set of 3 patches to 2 patches.
---
Rajat Srivastava (2):
mtd/spi: Add JEDEC SFDP support in SPI framework
fsl_qspi: Access flash above 16MB using SFDP
drivers/mtd/spi/sf_internal.h | 4 + drivers/mtd/spi/spi_flash.c | 301 +++++++++++++++++++++++++++++++++++++++--- drivers/spi/fsl_qspi.c | 103 ++++++++++++++- include/spi.h | 2 + include/spi_flash.h | 120 +++++++++++++++++ 5 files changed, 502 insertions(+), 28 deletions(-)
Signature · 1 line
2.14.1
PATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated. A flag is created to skip SFDP parsing for a particular flash, if required.
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.
---
Changes in v2:
- Make SFDP parsing the default method.
- Change SPI_FLASH_USE_SFDP flag to SPI_FLASH_USE_SFDP to provide an option to skip SFDP parsing for a particular flash.
--- drivers/mtd/spi/sf_internal.h | 4 + drivers/mtd/spi/spi_flash.c | 301 +++++++++++++++++++++++++++++++++++++++--- include/spi.h | 2 + include/spi_flash.h | 120 +++++++++++++++++ 4 files changed, 406 insertions(+), 21 deletions(-)
drivers/mtd/spi/sf_internal.h +4 -0
@@ -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_SKIP_SFDP BIT(8)/* parse SFDP to get flash info */ #define RD_FULL (RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO) };
drivers/mtd/spi/spi_flash.c +280 -21
391 lines not on this page · raw message
include/spi.h +2 -0
@@ -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;
include/spi_flash.h +120 -0
138 lines not on this page · raw message
Signature · 1 line
2.14.1
Vignesh R
maintainerPATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Hi Rajat,
Quoted 29 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated. A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso 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 <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPto provide an option to skip SFDP parsing for a particular flash.
---
[...]
Quoted 36 lines
drivers/mtd/spi/spi_flash.c +36
-0+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.
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+* 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 ; +
I see your are updating flash->addr_width to 4 bytes here. But I don't see any code in this patch that changes flash->read_cmd (and write/erase cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration when CONFIG_SPI_FLASH_BAR is defined and SFDP is available.
This patch will most certainly break SPI controller drivers(like cadence_qspi.c) that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guess fsl_qspi modifies read opcode internal to the driver and gets away with it.
Please modify the patch to update read_cmd/erase_cmd/write_cmd to use 4 byte addressing opcodes
Regards
Vigensh
Quoted 356 lines
drivers/mtd/spi/spi_flash.c +151
-6+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) {@@ -1130,7 +1366,7 @@ int spi_flash_scan(struct spi_flash *flash) {struct spi_slave *spi = flash->spi;const struct spi_flash_info *info =NULL ; -int ret; +int ret, sfdp =0 ; info =spi_flash_read_id (flash);if (IS_ERR_OR_NULL (info))@@ -1196,9 +1432,28 @@ 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_SKIP_SFDP )) { + flash->size =0 ; + sfdp =spi_flash_parse_sfdp (flash); +if (sfdp <0 ) +debug ("Unable to get SFDP information\n" ); + } +/* 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_SKIP_SFDP || sfdp <0 ) { + 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 +1468,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_SKIP_SFDP || sfdp <0 ) { + 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 +1570,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_SKIP_SFDP || sfdp <0 ) && + (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" );include/spi.h +2
-0@@ -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;include/spi_flash.h +120
-0@@ -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,
PATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Quoted 82 lines
-----Original Message-----
From: Vignesh R <[email protected]>
Sent: Thursday, November 15, 2018 2:52 PM
To: Rajat Srivastava <[email protected]>; u-boot at lists.denx.de
Cc: jagan at openedev.com
Subject: Re: [U-Boot] [PATCH v2 1/2] mtd/spi: Add JEDEC SFDP support in SPI frameworkHi Rajat,
Quoted 27 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso 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 <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPto provide an option to skip SFDP parsing for a particular flash.
---[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_header
*bfpt_header) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 6 lines
drivers/mtd/spi/spi_flash.c +6
-0+struct sfdp_bfpt bfpt; +size_t len; +int i, err; +u32 addr; + +/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+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));drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+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
Quoted 15 lines
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+* in struct spi_flash for every command. +*/ + flash->addr_width =4 ; +break ; + +case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY : + flash->addr_width =4 ; +break ; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.
We don't have any flash that supports CONFIG_SPI_FLASH_BAR. What do you suggest, shall we skip SFDP parsing in case CONFIG_SPI_FLASH_BAR is defined?
Quoted 8 lines
This patch will most certainly break SPI controller
drivers(like cadence_qspi.c)that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guessfsl_qspimodifies read opcode internal to the driver and gets away with it.
Please modify the patch to update read_cmd/erase_cmd/write_cmd to use 4 byte addressing opcodes
If the flash supports only supports 4-byte opcodes then there will be no mismatch wrt opcode used and number of address bytes sent since all of the opcodes that the flash supports will be 4-bytes opcodes.
But if the flash supports both 3-byte as well as 4-byte address widths (which is a separate case) then this code will default the address mode to 4-byte but gives an option to use 3-byte by setting addrwd_3_in_use flag.
Regards
Rajat
Quoted 377 lines
Regards
VigenshQuoted 28 lines
drivers/mtd/spi/spi_flash.c +28
-0+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. */ drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
drivers/mtd/spi/spi_flash.c +17
-0+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 drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+* 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
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 5 lines
drivers/mtd/spi/spi_flash.c +5
-0+* tables. +* Hence we read the parameter headers once for all to reduce the +* processing time +*/ +if (header.nph) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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 parameterheaders\n");
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 12 lines
drivers/mtd/spi/spi_flash.c +12
-0+ 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&&Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+ 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);drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+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) { @@ -1130,7+1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash){drivers/mtd/spi/spi_flash.c +9
-1struct spi_slave *spi = flash->spi;const struct spi_flash_info *info =NULL ; -int ret; +int ret, sfdp =0 ; info =spi_flash_read_id (flash);if (IS_ERR_OR_NULL (info))@@ -1196,9 +1432,28 @@ 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 drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+*/ +if (!(info->flags &SPI_FLASH_SKIP_SFDP )) { + flash->size =0 ; + sfdp =spi_flash_parse_sfdp (flash); +if (sfdp <0 ) +debug ("Unable to get SFDP information\n" ); + } +/* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash)
Quoted 7 lines
drivers/mtd/spi/spi_flash.c +4
-1- flash->page_size = info->page_size; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + flash->page_size = info->page_size; + flash->addr_width =SPI_FLASH_3B_ADDR_LEN ; + }/* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
Quoted 17 lines
drivers/mtd/spi/spi_flash.c +4
-1* yet use the 0x4d00 Extended JEDEC code. The rest of the Spansion @@ -1213,7 +1468,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_SKIP_SFDP || sfdp <0 ) { + 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 +1570,10 @@ int spi_flash_scan(struct spi_flash *flash)#endif #ifndef CONFIG_SPI_FLASH_BAR drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1579
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +4
-3-if (((flash->dual_flash ==SF_SINGLE_FLASH ) && - (flash->size >SPI_FLASH_16MB_BOUN )) || - ((flash->dual_flash >SF_SINGLE_FLASH ) && +if ((info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) && + (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
Quoted 24 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave;
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 34 lines
include/spi_flash.h +22
-0* @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. */ include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 10 lines
include/spi_flash.h +10
-0+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 */
Quoted 13 lines
include/spi_flash.h +13
-0+#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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 25 lines
include/spi_flash.h +25
-0+ +/* 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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+* [...] +* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash {
Quoted 3 lines
include/spi_flash.h +3
-0+#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 */
Quoted 9 lines
include/spi_flash.h +5
-0+ +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,
Vignesh R
maintainerPATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Quoted 88 lines · Rajat Srivastava
Quoted 72 lines
Hi Rajat,
Quoted 27 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso 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 <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPto provide an option to skip SFDP parsing for a particular flash.
---[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_header
*bfpt_header) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 6 lines
drivers/mtd/spi/spi_flash.c +6
-0+struct sfdp_bfpt bfpt; +size_t len; +int i, err; +u32 addr; + +/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+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));drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+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
Quoted 15 lines
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+* in struct spi_flash for every command. +*/ + flash->addr_width =4 ; +break ; + +case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY : + flash->addr_width =4 ; +break ; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.
Quoted 2 lines
We don't have any flash that supports
CONFIG_SPI_FLASH_BAR. What do you suggest, shall we skip SFDP parsing in caseCONFIG_SPI_FLASH_BARis defined?
I suggest skipping BAR configuration completely if flash supports address width of 4 as per SFDP. BAR configuration is only needed if flash does not support 4 byte addressing and flash size is > 16MB
Quoted 9 lines
Quoted 8 lines
This patch will most certainly break SPI controller
drivers(like cadence_qspi.c)that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guessfsl_qspimodifies read opcode internal to the driver and gets away with it.
Please modify the patch to update read_cmd/erase_cmd/write_cmd to use 4 byte addressing opcodes
Quoted 7 lines
If the flash supports only supports 4-byte opcodes then there will be no mismatch wrt opcode used and number of address bytes sent since all of the opcodes that the flash supports will be 4-bytes opcodes.
But if the flash supports both 3-byte as well as 4-byte address widths (which is a separate case) then this code will default the address mode to 4-byte but gives an option to use 3-byte by settingaddrwd_3_in_useflag.
Lets assume flash supports both 3 and 4 byte addressing (AFAIK, majority of flash parts do that). In this case, this patch is defaulting to 4 byte address width but flash->read_cmd/write_cmd/erase_cmd are still set to 3 byte addressing opcodes.
So, SPI controller would end up send 3 addressing byte opcode but 4 byte of address. The flash would interpret last byte of address as first byte of data and thus lead to data corruption in case of write. Isn't that a problem?
In particular you are not parsing entire bfpt like in [1] and will break flash operations
[1]https://elixir.bootlin.com/linux/latest/source/drivers/mtd/spi-nor/spi-nor.c#L2259
Regards
Vignesh
Quoted 380 lines
Regards
RajatQuoted 377 lines
Regards
VigenshQuoted 28 lines
drivers/mtd/spi/spi_flash.c +28
-0+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. */ drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
drivers/mtd/spi/spi_flash.c +17
-0+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 drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+* 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
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 5 lines
drivers/mtd/spi/spi_flash.c +5
-0+* tables. +* Hence we read the parameter headers once for all to reduce the +* processing time +*/ +if (header.nph) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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 parameterheaders\n");
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 12 lines
drivers/mtd/spi/spi_flash.c +12
-0+ 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&&Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+ 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);drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+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) { @@ -1130,7+1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash){drivers/mtd/spi/spi_flash.c +9
-1struct spi_slave *spi = flash->spi;const struct spi_flash_info *info =NULL ; -int ret; +int ret, sfdp =0 ; info =spi_flash_read_id (flash);if (IS_ERR_OR_NULL (info))@@ -1196,9 +1432,28 @@ 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 drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+*/ +if (!(info->flags &SPI_FLASH_SKIP_SFDP )) { + flash->size =0 ; + sfdp =spi_flash_parse_sfdp (flash); +if (sfdp <0 ) +debug ("Unable to get SFDP information\n" ); + } +/* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash)
Quoted 7 lines
drivers/mtd/spi/spi_flash.c +4
-1- flash->page_size = info->page_size; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + flash->page_size = info->page_size; + flash->addr_width =SPI_FLASH_3B_ADDR_LEN ; + }/* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
Quoted 17 lines
drivers/mtd/spi/spi_flash.c +4
-1* yet use the 0x4d00 Extended JEDEC code. The rest of the Spansion @@ -1213,7 +1468,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_SKIP_SFDP || sfdp <0 ) { + 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 +1570,10 @@ int spi_flash_scan(struct spi_flash *flash)#endif #ifndef CONFIG_SPI_FLASH_BAR drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1579
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +4
-3-if (((flash->dual_flash ==SF_SINGLE_FLASH ) && - (flash->size >SPI_FLASH_16MB_BOUN )) || - ((flash->dual_flash >SF_SINGLE_FLASH ) && +if ((info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) && + (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
Quoted 24 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave;
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 34 lines
include/spi_flash.h +22
-0* @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. */ include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 10 lines
include/spi_flash.h +10
-0+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 */
Quoted 13 lines
include/spi_flash.h +13
-0+#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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 25 lines
include/spi_flash.h +25
-0+ +/* 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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+* [...] +* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash {
Quoted 3 lines
include/spi_flash.h +3
-0+#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 */
Quoted 9 lines
include/spi_flash.h +5
-0+ +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,
Signature · 2 lines
Regards Vignesh
PATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Quoted 116 lines · Vignesh R
Quoted 88 lines · Rajat Srivastava
Quoted 72 lines
Hi Rajat,
Quoted 27 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso 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 <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPto provide an option to skip SFDP parsing for a particular flash.
---[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_header
*bfpt_header) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 6 lines
drivers/mtd/spi/spi_flash.c +6
-0+struct sfdp_bfpt bfpt; +size_t len; +int i, err; +u32 addr; + +/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+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));drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+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
Quoted 15 lines
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+* in struct spi_flash for every command. +*/ + flash->addr_width =4 ; +break ; + +case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY : + flash->addr_width =4 ; +break ; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.Quoted 2 lines
We don't have any flash that supports
CONFIG_SPI_FLASH_BAR. What do you suggest, shall we skip SFDP parsing in caseCONFIG_SPI_FLASH_BARis defined?I suggest skipping BAR configuration completely if flash supports address width of 4 as per SFDP. BAR configuration is only needed if flash does not support 4 byte addressing and flash size is > 16MB
Quoted 9 lines
Quoted 8 lines
This patch will most certainly break SPI controller
drivers(like cadence_qspi.c)that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guessfsl_qspimodifies read opcode internal to the driver and gets away with it.
Please modify the patch to update read_cmd/erase_cmd/write_cmd to use 4 byte addressing opcodesQuoted 7 lines
If the flash supports only supports 4-byte opcodes then there will be no mismatch wrt opcode used and number of address bytes sent since all of the opcodes that the flash supports will be 4-bytes opcodes.
But if the flash supports both 3-byte as well as 4-byte address widths (which is a separate case) then this code will default the address mode to 4-byte but gives an option to use 3-byte by settingaddrwd_3_in_useflag.
Quoted 8 lines
Lets assume flash supports both 3 and 4 byte addressing (AFAIK, majority of flash parts do that). In this case, this patch is defaulting to 4 byte address width but flash->read_cmd/write_cmd/erase_cmd are still set to 3 byte addressing opcodes.
So, SPI controller would end up send 3 addressing byte opcode but 4 byte of address. The flash would interpret last byte of address as first byte of data and thus lead to data corruption in case of write. Isn't that a problem?
Additionally, there are flash chips with a 3-/4-byte mode change instruction. But using 4-byte opcodes should be preferred.
Simon
Quoted 397 lines
In particular you are not parsing entire bfpt like in [1] and will break flash operations
[1]https://elixir.bootlin.com/linux/latest/source/drivers/mtd/spi-nor/spi-nor.c#L2259
Regards
VigneshQuoted 371 lines
Regards
RajatQuoted 368 lines
Regards
VigenshQuoted 28 lines
drivers/mtd/spi/spi_flash.c +28
-0+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. */ drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
drivers/mtd/spi/spi_flash.c +17
-0+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 drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+* 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
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 5 lines
drivers/mtd/spi/spi_flash.c +5
-0+* tables. +* Hence we read the parameter headers once for all to reduce the +* processing time +*/ +if (header.nph) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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 parameterheaders\n");
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 12 lines
drivers/mtd/spi/spi_flash.c +12
-0+ 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&&Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+ 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);drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+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) { @@ -1130,7+1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash) { struct spi_slave *spi = flash->spi; const struct spi_flash_info *info = NULL;drivers/mtd/spi/spi_flash.c +9
-1-int ret; +int ret, sfdp =0 ; info =spi_flash_read_id (flash);if (IS_ERR_OR_NULL (info))@@ -1196,9 +1432,28 @@ 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 drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+*/ +if (!(info->flags &SPI_FLASH_SKIP_SFDP )) { + flash->size =0 ; + sfdp =spi_flash_parse_sfdp (flash); +if (sfdp <0 ) +debug ("Unable to get SFDP information\n" ); + } +/* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash)
Quoted 7 lines
drivers/mtd/spi/spi_flash.c +4
-1- flash->page_size = info->page_size; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + flash->page_size = info->page_size; + flash->addr_width =SPI_FLASH_3B_ADDR_LEN ; + }/* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
Quoted 17 lines
drivers/mtd/spi/spi_flash.c +4
-1* yet use the 0x4d00 Extended JEDEC code. The rest of the Spansion @@ -1213,7 +1468,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_SKIP_SFDP || sfdp <0 ) { + 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 +1570,10 @@ int spi_flash_scan(struct spi_flash *flash)#endif #ifndef CONFIG_SPI_FLASH_BAR drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1579
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +4
-3-if (((flash->dual_flash ==SF_SINGLE_FLASH ) && - (flash->size >SPI_FLASH_16MB_BOUN )) || - ((flash->dual_flash >SF_SINGLE_FLASH ) && +if ((info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) && + (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
Quoted 24 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave;
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 34 lines
include/spi_flash.h +22
-0* @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. */ include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 10 lines
include/spi_flash.h +10
-0+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 */
Quoted 13 lines
include/spi_flash.h +13
-0+#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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 25 lines
include/spi_flash.h +25
-0+ +/* 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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+* [...] +* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash {
Quoted 3 lines
include/spi_flash.h +3
-0+#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 */
Quoted 9 lines
Quoted 9 lines
include/spi_flash.h struct spi_flash {
Quoted 9 lines
include/spi_flash.h +5
-0+ +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://lists.denx.de/listinfo/u-boot
PATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Quoted 132 lines
-----Original Message-----
From: Simon Goldschmidt <[email protected]>
Sent: Friday, November 16, 2018 3:53 PM
To: vigneshr at ti.com
Cc: Rajat Srivastava <[email protected]>; U-Boot Mailing List <u- boot at lists.denx.de>; Jagan Teki <[email protected]>
Subject: Re: [U-Boot] [PATCH v2 1/2] mtd/spi: Add JEDEC SFDP support in SPI frameworkQuoted 24 lines · Vignesh R
Quoted 20 lines · Rajat Srivastava
Quoted 20 lines
Hi Rajat,
Quoted 17 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso that driver can have access to SFDP data.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Introduce new structures and functions to read and parse SFDP data. This is loosely based on Linux SFDP framework.
Signed-off-by Rajat Srivastava <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPtoprovide
Quoted 62 lines
Quoted 62 lines
Quoted 61 lines
Quoted 2 lines
an option to skip SFDP parsing for a particular flash.
---[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_header
*bfpt_header) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 6 lines
drivers/mtd/spi/spi_flash.c +6
-0+struct sfdp_bfpt bfpt; +size_t len; +int i, err; +u32 addr; + +/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+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));drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 11 lines
drivers/mtd/spi/spi_flash.c +11
-0+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
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+* in struct spi_flash for every command. +*/ + flash->addr_width =4 ; +break ; + +case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY : + flash->addr_width =4 ; +break ; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase
cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.Quoted 1 line
Quoted 1 line
We don't have any flash that supports
CONFIG_SPI_FLASH_BAR. What doyou suggest, shall we skip SFDP parsing in case
CONFIG_SPI_FLASH_BARis defined?Quoted 22 lines
Quoted 1 line
I suggest skipping BAR configuration completely if flash supports address width of 4 as per SFDP. BAR configuration is only needed if flash does not support 4 byte addressing and flash size is > 16MB
Quoted 16 lines
Quoted 9 lines
This patch will most certainly break SPI controller
drivers(like cadence_qspi.c)that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guessfsl_qspimodifies read opcode internal to the driver and gets away with it. Please modify the patch to update read_cmd/erase_cmd/write_cmd to use
4 byte addressing opcodesIf the flash supports only supports 4-byte opcodes then there will be no mismatch wrt opcode used and number of address bytes sent since all of the opcodes that the flash supports will be 4-bytes opcodes. But if the flash supports both 3-byte as well as 4-byte address widths (which is a separate case) then this code will default the address mode to 4-byte but gives an option to use 3-byte by setting
Quoted 12 lines
addrwd_3_in_useflag.Quoted 6 lines
Quoted 1 line
Lets assume flash supports both 3 and 4 byte addressing (AFAIK, majority of flash parts do that). In this case, this patch is defaulting to 4 byte address width but flash->read_cmd/write_cmd/erase_cmd are still set to 3 byte addressing
opcodes.
Quoted 4 lines
So, SPI controller would end up send 3 addressing byte opcode but 4 byte of address. The flash would interpret last byte of address as first byte of data and thus lead to data corruption in case of write. Isn't that a problem?
Ok. But I'm curious if a flash supports both 3 and 4 byte address widths (and it does not have BAR support), then why would one use 3-byte read/write/erase commands? How would one access >16 MB in such case?
Also, initially I wanted to make SFDP optional so that none of the drivers are affected and one could enable it using a flag as per requirement. Shall we get back to making this optional (similar to v1 of this patch)?
Regards
Rajat
Quoted 432 lines
Additionally, there are flash chips with a 3-/4-byte mode change instruction. But using 4-byte opcodes should be preferred.
Simon
Quoted 5 lines
In particular you are not parsing entire bfpt like in [1] and will break flash operations
[1]https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2F
Quoted 1 line
elixir.bootlin.com%2Flinux%2Flatest%2Fsource%2Fdrivers%2Fmtd%2Fspi-
nor
Quoted 1 line
%2Fspi-
nor.c%23L2259&data=02%7C01%7Crajat.srivastava%40nxp.com%7Ca
Quoted 1 line
cee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92cd99c5c301635 %7C0
Quoted 1 line
%7C0%7C636779606107591743&sdata=UACl919%2BMQmdtBo5GUTAy M428u1bT1bU
Quoted 189 lines
rXuX2GsSjb0%3D&reserved=0
Regards
VigneshQuoted 184 lines
Regards
RajatQuoted 181 lines
Regards
VigenshQuoted 28 lines
drivers/mtd/spi/spi_flash.c +28
-0+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. */ drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
drivers/mtd/spi/spi_flash.c +17
-0+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 drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+* 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
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 5 lines
drivers/mtd/spi/spi_flash.c +5
-0+* tables. +* Hence we read the parameter headers once for all to reduce the +* processing time +*/ +if (header.nph) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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 parameterheaders\n");
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 12 lines
drivers/mtd/spi/spi_flash.c +12
-0+ 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&&Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+ 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)drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +7
-1+ goto exit; + +exit: +free (param_headers); +return err; +} +static int set_quad_mode (struct spi_flash *flash, const struct spi_flash_info *info) { @@ -1130 ,7 +1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash) { struct spi_slave *spi = flash->spi; const struct spi_flash_info *info = NULL;drivers/mtd/spi/spi_flash.c +9
-1-int ret; +int ret, sfdp =0 ; info =spi_flash_read_id (flash);if (IS_ERR_OR_NULL (info))@@ -1196,9 +1432,28 @@ 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 drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+*/ +if (!(info->flags &SPI_FLASH_SKIP_SFDP )) { + flash->size =0 ; + sfdp =spi_flash_parse_sfdp (flash); +if (sfdp <0 ) +debug ("Unable to get SFDP information\n" ); + } +/* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash)
Quoted 7 lines
drivers/mtd/spi/spi_flash.c +4
-1- flash->page_size = info->page_size; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + flash->page_size = info->page_size; + flash->addr_width =SPI_FLASH_3B_ADDR_LEN ; + }/* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
Quoted 2 lines
(quoted diff) +0
-0* yet use the 0x4d00 Extended JEDEC code. The rest of theSpansion @@ -1213,7 +1468,10 @@ int spi_flash_scan(struct
spi_flash*flash)
Quoted 145 lines
Quoted 145 lines
Quoted 145 lines
Quoted 25 lines
} flash->page_size <<= flash->shift; flash->sector_size = info->sector_size << flash->shift;drivers/mtd/spi/spi_flash.c +8
-4- flash->size = flash->sector_size * info->n_sectors << flash->shift; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + 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 +1570,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_SKIP_SFDP || sfdp <0 ) && + (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" );Quoted 1 line
diff -
-git
Quoted 25 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave;
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 34 lines
include/spi_flash.h +23
-0* @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. */ include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 10 lines
include/spi_flash.h +10
-0+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 */
Quoted 13 lines
include/spi_flash.h +13
-0+#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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
include/spi_flash.h struct spi_flash {
Quoted 7 lines
include/spi_flash.h +7
-0+ +/* 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
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h struct spi_flash { #endif }; · line 188
Quoted 1 line
include/spi_flash.h +1
-0+* reads based on instruction. DQ3/HOLD# functions are hold during
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
include/spi_flash.h struct spi_flash {
Quoted 5 lines
include/spi_flash.h +5
-0+* 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
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 12 lines
include/spi_flash.h +12
-0+* 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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+* [...] +* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash {
Quoted 3 lines
include/spi_flash.h +3
-0+#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 */
Quoted 17 lines
Quoted 9 lines
Quoted 9 lines
include/spi_flash.h struct spi_flash {
Quoted 9 lines
include/spi_flash.h +5
-0+ +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.dehttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flis
Quoted 1 line
ts.denx.de%2Flistinfo%2Fu-
boot&data=02%7C01%7Crajat.srivastava%40n
Quoted 1 line
xp.com%7Cacee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92c d99c5c
Quoted 1 line
301635%7C0%7C0%7C636779606107591743&sdata=u9H5PMJiRNVKyyFI7 y5eCmDx
Quoted 1 line
0KPmAHXvF8kusaJVUdM%3D&reserved=0
PATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Quoted 146 lines · Rajat Srivastava
Quoted 133 lines
-----Original Message-----
From: Simon Goldschmidt <[email protected]>
Sent: Friday, November 16, 2018 3:53 PM
To: vigneshr at ti.com
Cc: Rajat Srivastava <[email protected]>; U-Boot Mailing List <u- boot at lists.denx.de>; Jagan Teki <[email protected]>
Subject: Re: [U-Boot] [PATCH v2 1/2] mtd/spi: Add JEDEC SFDP support in SPI frameworkQuoted 24 lines · Vignesh R
Quoted 20 lines · Rajat Srivastava
Quoted 20 lines
Hi Rajat,
Quoted 17 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso that driver can have access to SFDP data.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Introduce new structures and functions to read and parse SFDP data. This is loosely based on Linux SFDP framework.
Signed-off-by Rajat Srivastava <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPtoprovide
Quoted 62 lines
Quoted 62 lines
Quoted 61 lines
Quoted 2 lines
an option to skip SFDP parsing for a particular flash.
---[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_header
*bfpt_header) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 6 lines
drivers/mtd/spi/spi_flash.c +6
-0+struct sfdp_bfpt bfpt; +size_t len; +int i, err; +u32 addr; + +/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+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));drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 11 lines
drivers/mtd/spi/spi_flash.c +11
-0+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
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+* in struct spi_flash for every command. +*/ + flash->addr_width =4 ; +break ; + +case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY : + flash->addr_width =4 ; +break ; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase
cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.Quoted 1 line
Quoted 1 line
We don't have any flash that supports
CONFIG_SPI_FLASH_BAR. What doyou suggest, shall we skip SFDP parsing in case
CONFIG_SPI_FLASH_BARis defined?Quoted 22 lines
Quoted 1 line
I suggest skipping BAR configuration completely if flash supports address width of 4 as per SFDP. BAR configuration is only needed if flash does not support 4 byte addressing and flash size is > 16MB
Quoted 16 lines
Quoted 9 lines
This patch will most certainly break SPI controller
drivers(like cadence_qspi.c)that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guessfsl_qspimodifies read opcode internal to the driver and gets away with it. Please modify the patch to update read_cmd/erase_cmd/write_cmd to use
4 byte addressing opcodesIf the flash supports only supports 4-byte opcodes then there will be no mismatch wrt opcode used and number of address bytes sent since all of the opcodes that the flash supports will be 4-bytes opcodes. But if the flash supports both 3-byte as well as 4-byte address widths (which is a separate case) then this code will default the address mode to 4-byte but gives an option to use 3-byte by setting
Quoted 12 lines
addrwd_3_in_useflag.Quoted 6 lines
Quoted 1 line
Lets assume flash supports both 3 and 4 byte addressing (AFAIK, majority of flash parts do that). In this case, this patch is defaulting to 4 byte address width but flash->read_cmd/write_cmd/erase_cmd are still set to 3 byte addressing
opcodes.
Quoted 4 lines
So, SPI controller would end up send 3 addressing byte opcode but 4 byte of address. The flash would interpret last byte of address as first byte of data and thus lead to data corruption in case of write. Isn't that a problem?
Quoted 7 lines
Ok. But I'm curious if a flash supports both 3 and 4 byte address widths (and it does not have BAR support), then why would one use 3-byte read/write/erase commands? How would one access >16 MB in such case?
Also, initially I wanted to make SFDP optional so that none of the drivers are affected and one could enable it using a flag as per requirement. Shall we get back to making this optional (similar to v1 of this patch)?
My preference here is to make SFDP the default in future. If driver support is required and we can't implement support on all drivers right away, compatibility workaraounds are needed.
However, I don't think making it an opt-in option as in v1 is a good idea...
Simon
Quoted 436 lines
Regards
RajatQuoted 432 lines
Additionally, there are flash chips with a 3-/4-byte mode change instruction. But using 4-byte opcodes should be preferred.
Simon
Quoted 5 lines
In particular you are not parsing entire bfpt like in [1] and will break flash operations
[1]https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2F
Quoted 1 line
elixir.bootlin.com%2Flinux%2Flatest%2Fsource%2Fdrivers%2Fmtd%2Fspi-
nor
Quoted 1 line
%2Fspi-
nor.c%23L2259&data=02%7C01%7Crajat.srivastava%40nxp.com%7Ca
Quoted 1 line
cee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92cd99c5c301635 %7C0
Quoted 1 line
%7C0%7C636779606107591743&sdata=UACl919%2BMQmdtBo5GUTAy M428u1bT1bU
Quoted 189 lines
rXuX2GsSjb0%3D&reserved=0
Regards
VigneshQuoted 184 lines
Regards
RajatQuoted 181 lines
Regards
VigenshQuoted 28 lines
drivers/mtd/spi/spi_flash.c +28
-0+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. */ drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
drivers/mtd/spi/spi_flash.c +17
-0+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 drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+* 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
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 5 lines
drivers/mtd/spi/spi_flash.c +5
-0+* tables. +* Hence we read the parameter headers once for all to reduce the +* processing time +*/ +if (header.nph) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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 parameterheaders\n");
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 12 lines
drivers/mtd/spi/spi_flash.c +12
-0+ 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&&Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+ 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)drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +7
-1+ goto exit; + +exit: +free (param_headers); +return err; +} +static int set_quad_mode (struct spi_flash *flash, const struct spi_flash_info *info) { @@ -1130 ,7 +1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash) { struct spi_slave *spi = flash->spi; const struct spi_flash_info *info = NULL;drivers/mtd/spi/spi_flash.c +9
-1-int ret; +int ret, sfdp =0 ; info =spi_flash_read_id (flash);if (IS_ERR_OR_NULL (info))@@ -1196,9 +1432,28 @@ 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 drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+*/ +if (!(info->flags &SPI_FLASH_SKIP_SFDP )) { + flash->size =0 ; + sfdp =spi_flash_parse_sfdp (flash); +if (sfdp <0 ) +debug ("Unable to get SFDP information\n" ); + } +/* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash)
Quoted 7 lines
drivers/mtd/spi/spi_flash.c +4
-1- flash->page_size = info->page_size; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + flash->page_size = info->page_size; + flash->addr_width =SPI_FLASH_3B_ADDR_LEN ; + }/* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
Quoted 2 lines
(quoted diff) +0
-0* yet use the 0x4d00 Extended JEDEC code. The rest of theSpansion @@ -1213,7 +1468,10 @@ int spi_flash_scan(struct
spi_flash*flash)
Quoted 145 lines
Quoted 145 lines
Quoted 145 lines
Quoted 25 lines
} flash->page_size <<= flash->shift; flash->sector_size = info->sector_size << flash->shift;drivers/mtd/spi/spi_flash.c +8
-4- flash->size = flash->sector_size * info->n_sectors << flash->shift; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + 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 +1570,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_SKIP_SFDP || sfdp <0 ) && + (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" );Quoted 1 line
diff -
-git
Quoted 25 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave;
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 34 lines
include/spi_flash.h +23
-0* @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. */ include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 10 lines
include/spi_flash.h +10
-0+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 */
Quoted 13 lines
include/spi_flash.h +13
-0+#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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
include/spi_flash.h struct spi_flash {
Quoted 7 lines
include/spi_flash.h +7
-0+ +/* 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
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h struct spi_flash { #endif }; · line 188
Quoted 1 line
include/spi_flash.h +1
-0+* reads based on instruction. DQ3/HOLD# functions are hold during
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
include/spi_flash.h struct spi_flash {
Quoted 5 lines
include/spi_flash.h +5
-0+* 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
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 12 lines
include/spi_flash.h +12
-0+* 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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+* [...] +* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash {
Quoted 3 lines
include/spi_flash.h +3
-0+#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 */
Quoted 17 lines
Quoted 9 lines
Quoted 9 lines
include/spi_flash.h struct spi_flash {
Quoted 9 lines
include/spi_flash.h +5
-0+ +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.dehttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flis
Quoted 1 line
ts.denx.de%2Flistinfo%2Fu-
boot&data=02%7C01%7Crajat.srivastava%40n
Quoted 1 line
xp.com%7Cacee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92c d99c5c
Quoted 1 line
301635%7C0%7C0%7C636779606107591743&sdata=u9H5PMJiRNVKyyFI7 y5eCmDx
Quoted 1 line
0KPmAHXvF8kusaJVUdM%3D&reserved=0
Vignesh R
maintainerPATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
In reply to Rajat SrivastavaQuoted 126 lines · Rajat Srivastava
Quoted 126 lines · Vignesh R
Quoted 21 lines · Rajat Srivastava
Quoted 20 lines
Quoted 20 lines
Hi Rajat,
Quoted 17 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso that driver can have access to SFDP data.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Introduce new structures and functions to read and parse SFDP data. This is loosely based on Linux SFDP framework.
Signed-off-by Rajat Srivastava <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPtoprovide
Quoted 62 lines
Quoted 62 lines
Quoted 61 lines
Quoted 2 lines
an option to skip SFDP parsing for a particular flash.
---[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_header
*bfpt_header) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 6 lines
drivers/mtd/spi/spi_flash.c +6
-0+struct sfdp_bfpt bfpt; +size_t len; +int i, err; +u32 addr; + +/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+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));drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 11 lines
drivers/mtd/spi/spi_flash.c +11
-0+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
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+* in struct spi_flash for every command. +*/ + flash->addr_width =4 ; +break ; + +case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY : + flash->addr_width =4 ; +break ; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase
cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.Quoted 1 line
Quoted 1 line
We don't have any flash that supports
CONFIG_SPI_FLASH_BAR. What doyou suggest, shall we skip SFDP parsing in case
CONFIG_SPI_FLASH_BARis defined?Quoted 22 lines
Quoted 1 line
I suggest skipping BAR configuration completely if flash supports address width of 4 as per SFDP. BAR configuration is only needed if flash does not support 4 byte addressing and flash size is > 16MB
Quoted 16 lines
Quoted 9 lines
This patch will most certainly break SPI controller
drivers(like cadence_qspi.c)that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guessfsl_qspimodifies read opcode internal to the driver and gets away with it. Please modify the patch to update read_cmd/erase_cmd/write_cmd to use
4 byte addressing opcodesIf the flash supports only supports 4-byte opcodes then there will be no mismatch wrt opcode used and number of address bytes sent since all of the opcodes that the flash supports will be 4-bytes opcodes. But if the flash supports both 3-byte as well as 4-byte address widths (which is a separate case) then this code will default the address mode to 4-byte but gives an option to use 3-byte by setting
addrwd_3_in_useflag.Quoted 6 lines
Quoted 1 line
Lets assume flash supports both 3 and 4 byte addressing (AFAIK, majority of flash parts do that). In this case, this patch is defaulting to 4 byte address width but flash->read_cmd/write_cmd/erase_cmd are still set to 3 byte addressing
opcodes.
Quoted 9 lines
Quoted 4 lines
Quoted 4 lines
So, SPI controller would end up send 3 addressing byte opcode but 4 byte of address. The flash would interpret last byte of address as first byte of data and thus lead to data corruption in case of write. Isn't that a problem?
Ok. But I'm curious if a flash supports both 3 and 4 byte address widths (and it does not have BAR support), then why would one use 3-byte read/write/erase commands? How would one access >16 MB in such case?
Unfortunately thats a problem with U-Boot spi_flash layer today. Many newer flashes like Micron's mt35x series dont support BAR registers. Accessing above 16MB is broken for such flashes today.
Quoted 4 lines
Also, initially I wanted to make SFDP optional so that none of the drivers are affected and one could enable it using a flag as per requirement. Shall we get back to making this optional (similar to v1 of this patch)?
How does that help? With opt-in approach you mark some flash devices as SFDP capable, but you still don't update opcodes, thus breaking boards that have such flash devices. So, porting full bfpt parsing and always using opcode to 4 byte addressing opcodes when available will be needed. Thus you would end up with SFDP as default instead of opt-in.
Quoted 435 lines
Regards
RajatQuoted 432 lines
Additionally, there are flash chips with a 3-/4-byte mode change instruction. But using 4-byte opcodes should be preferred.
Simon
Quoted 5 lines
In particular you are not parsing entire bfpt like in [1] and will break flash operations
[1]https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2F
Quoted 1 line
elixir.bootlin.com%2Flinux%2Flatest%2Fsource%2Fdrivers%2Fmtd%2Fspi-
nor
Quoted 1 line
%2Fspi-
nor.c%23L2259&data=02%7C01%7Crajat.srivastava%40nxp.com%7Ca
Quoted 1 line
cee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92cd99c5c301635 %7C0
Quoted 1 line
%7C0%7C636779606107591743&sdata=UACl919%2BMQmdtBo5GUTAy M428u1bT1bU
Quoted 189 lines
rXuX2GsSjb0%3D&reserved=0
Regards
VigneshQuoted 184 lines
Regards
RajatQuoted 181 lines
Regards
VigenshQuoted 28 lines
drivers/mtd/spi/spi_flash.c +28
-0+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. */ drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
drivers/mtd/spi/spi_flash.c +17
-0+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 drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+* 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
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 5 lines
drivers/mtd/spi/spi_flash.c +5
-0+* tables. +* Hence we read the parameter headers once for all to reduce the +* processing time +*/ +if (header.nph) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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 parameterheaders\n");
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 12 lines
drivers/mtd/spi/spi_flash.c +12
-0+ 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&&Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+ 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)drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +7
-1+ goto exit; + +exit: +free (param_headers); +return err; +} +static int set_quad_mode (struct spi_flash *flash, const struct spi_flash_info *info) { @@ -1130 ,7 +1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash) { struct spi_slave *spi = flash->spi; const struct spi_flash_info *info = NULL;drivers/mtd/spi/spi_flash.c +9
-1-int ret; +int ret, sfdp =0 ; info =spi_flash_read_id (flash);if (IS_ERR_OR_NULL (info))@@ -1196,9 +1432,28 @@ 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 drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +8
-0+*/ +if (!(info->flags &SPI_FLASH_SKIP_SFDP )) { + flash->size =0 ; + sfdp =spi_flash_parse_sfdp (flash); +if (sfdp <0 ) +debug ("Unable to get SFDP information\n" ); + } +/* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
drivers/mtd/spi/spi_flash.c int spi_flash_scan(struct spi_flash *flash)
Quoted 7 lines
drivers/mtd/spi/spi_flash.c +4
-1- flash->page_size = info->page_size; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + flash->page_size = info->page_size; + flash->addr_width =SPI_FLASH_3B_ADDR_LEN ; + }/* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
Quoted 2 lines
(quoted diff) +0
-0* yet use the 0x4d00 Extended JEDEC code. The rest of theSpansion @@ -1213,7 +1468,10 @@ int spi_flash_scan(struct
spi_flash*flash)
Quoted 145 lines
Quoted 145 lines
Quoted 145 lines
Quoted 25 lines
} flash->page_size <<= flash->shift; flash->sector_size = info->sector_size << flash->shift;drivers/mtd/spi/spi_flash.c +8
-4- flash->size = flash->sector_size * info->n_sectors << flash->shift; +if (info->flags &SPI_FLASH_SKIP_SFDP || sfdp <0 ) { + 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 +1570,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_SKIP_SFDP || sfdp <0 ) && + (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" );Quoted 1 line
diff -
-git
Quoted 25 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave;
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 34 lines
include/spi_flash.h +23
-0* @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. */ include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 10 lines
include/spi_flash.h +10
-0+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 */
Quoted 13 lines
include/spi_flash.h +13
-0+#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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
include/spi_flash.h struct spi_flash {
Quoted 7 lines
include/spi_flash.h +7
-0+ +/* 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
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h struct spi_flash { #endif }; · line 188
Quoted 1 line
include/spi_flash.h +1
-0+* reads based on instruction. DQ3/HOLD# functions are hold during
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
include/spi_flash.h struct spi_flash {
Quoted 5 lines
include/spi_flash.h +5
-0+* 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
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 12 lines
include/spi_flash.h +12
-0+* 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. include/spi_flash.h struct spi_flash {
Quoted 10 lines
include/spi_flash.h +10
-0+* [...] +* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash {
Quoted 3 lines
include/spi_flash.h +3
-0+#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 */
Quoted 17 lines
Quoted 9 lines
Quoted 9 lines
include/spi_flash.h struct spi_flash {
Quoted 9 lines
include/spi_flash.h +5
-0+ +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.dehttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flis
Quoted 1 line
ts.denx.de%2Flistinfo%2Fu-
boot&data=02%7C01%7Crajat.srivastava%40n
Quoted 1 line
xp.com%7Cacee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92c d99c5c
Quoted 1 line
301635%7C0%7C0%7C636779606107591743&sdata=u9H5PMJiRNVKyyFI7 y5eCmDx
Quoted 1 line
0KPmAHXvF8kusaJVUdM%3D&reserved=0
PATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Quoted 163 lines
-----Original Message-----
From: Vignesh R <[email protected]>
Sent: Friday, November 16, 2018 8:56 PM
To: Rajat Srivastava <[email protected]>; Simon Goldschmidt <[email protected]>; U-Boot Mailing List <u-
boot at lists.denx.de>
Cc: Jagan Teki <[email protected]>
Subject: Re: [U-Boot] [PATCH v2 1/2] mtd/spi: Add JEDEC SFDP support in SPI frameworkQuoted 14 lines · Rajat Srivastava
Quoted 14 lines · Vignesh R
Quoted 13 lines · Rajat Srivastava
Quoted 12 lines
Quoted 12 lines
Hi Rajat,
Quoted 9 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
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 SFDPdata
Quoted 18 lines
Quoted 18 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
read. Add pointer to struct
spi_flashin structspi_slaveso 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 <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPtoprovide
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
an option to skip SFDP parsing for a particular flash.
---[...]
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_headerQuoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
*bfpt_header) {Quoted 6 lines
(quoted diff) +6
-0+ struct sfdp_bfpt bfpt; + size_t len; + int i, err; + u32 addr; + + /* JESD216 Basic Flash Parameter Table length is at least 9DWORDs.
Quoted 49 lines
Quoted 49 lines
Quoted 49 lines
Quoted 49 lines
Quoted 48 lines
*/
Quoted 8 lines
(quoted diff) +8
-0+ 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));Review
Quoted 10 lines
(quoted diff) +10
-0+ 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) {Review
Quoted 11 lines
(quoted diff) +11
-0+ 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_useflag
Review
Quoted 9 lines
(quoted diff) +9
-0+ * in struct spi_flash for every command. + */ + flash->addr_width = 4; + break; + + case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY: + flash->addr_width = 4; + break; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase
cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
We don't have any flash that supports
CONFIG_SPI_FLASH_BAR. Whatdo
Quoted 8 lines
Quoted 8 lines
you suggest, shall we skip SFDP parsing in case
CONFIG_SPI_FLASH_BARis defined?Quoted 6 lines
Quoted 1 line
I suggest skipping BAR configuration completely if flash supports address width of 4 as per SFDP. BAR configuration is only needed if flash does not support 4 byte addressing and flash size is > 16MB
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
This patch will most certainly break SPI controller
drivers(like cadence_qspi.c)that expect sf layer to provide correct read opcode and address width information, since there will be mismatch wrt opcode used and number of address byte sent.
Not sure how this patch was tested, but I guessfsl_qspimodifies read opcode internal to the driver and gets away with it. Please modify the patch to update read_cmd/erase_cmd/write_cmdto
Quoted 17 lines
Quoted 17 lines
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines
use
4 byte addressing opcodesIf the flash supports only supports 4-byte opcodes then there will be no mismatch wrt opcode used and number of address bytes sent since all of the opcodes that the flash supports will be 4-bytes opcodes. But if the flash supports both 3-byte as well as 4-byte address widths (which is a separate case) then this code will default the address mode to 4-byte but gives an option to use 3-byte by setting
addrwd_3_in_useflag.Quoted 7 lines
Quoted 1 line
Lets assume flash supports both 3 and 4 byte addressing (AFAIK, majority of flash parts do that). In this case, this patch is defaulting to 4 byte address width but flash->read_cmd/write_cmd/erase_cmd are still set to 3 byte
flash->addressingQuoted 8 lines
Quoted 5 lines
opcodes.
Quoted 4 lines
So, SPI controller would end up send 3 addressing byte opcode but 4 byte of address. The flash would interpret last byte of address as first byte of data and thus lead to data corruption in case of write. Isn't that a problem?
Ok. But I'm curious if a flash supports both 3 and 4 byte address widths (and it does not have BAR support), then why would one use 3-byte
read/write/erase commands?
Quoted 2 lines
How would one access >16 MB in such case?
Unfortunately thats a problem with U-Boot
spi_flashlayer today. Many newer flashes like Micron's mt35x series dont support BAR registers. Accessing above 16MB is broken for such flashes today.Quoted 1 line
Also, initially I wanted to make SFDP optional so that none of the drivers
are affected
Quoted 1 line
and one could enable it using a flag as per requirement. Shall we get back
to making
Quoted 8 lines
Quoted 2 lines
this optional (similar to v1 of this patch)?
How does that help? With opt-in approach you mark some flash devices as SFDP capable, but you still don't update opcodes, thus breaking boards that have such flash devices. So, porting full bfpt parsing and always using opcode to 4 byte addressing opcodes when available will be needed. Thus you would end up with SFDP as default instead of opt-in.
Hi Vignesh
Porting full bftp parsing requires time. I am seeing a conflict with a patch of yours
https://patchwork.ozlabs.org/cover/1012146/
It seem above RFC patch will bring SFDP to U-boot. Do you still want me to put effort in porting SFDP in current version?
Regards
Rajat
Quoted 459 lines
Quoted 6 lines
Regards
RajatQuoted 2 lines
Additionally, there are flash chips with a 3-/4-byte mode change
instruction.
Quoted 10 lines
Quoted 10 lines
But using 4-byte opcodes should be preferred.
Simon
Quoted 5 lines
In particular you are not parsing entire bfpt like in [1] and will break flash operations
[1]https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2F
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
elixir.bootlin.com%2Flinux%2Flatest%2Fsource%2Fdrivers%2Fmtd%2Fspi-
nor
Quoted 1 line
%2Fspi-
nor.c%23L2259&data=02%7C01%7Crajat.srivastava%40nxp.com%7Ca
Quoted 1 line
cee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92cd99c5c30163 5
Quoted 3 lines
Quoted 3 lines
%7C0
Quoted 1 line
%7C0%7C636779606107591743&sdata=UACl919%2BMQmdtBo5GUTAy
Quoted 97 lines
Quoted 97 lines
M428u1bT1bU
Quoted 96 lines
rXuX2GsSjb0%3D&reserved=0
Regards
VigneshQuoted 91 lines
Regards
RajatQuoted 88 lines
Regards
VigenshQuoted 28 lines
(quoted diff) +28
-0+ 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. */Review
Quoted 10 lines
(quoted diff) +10
-0+ 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 DiscoverableParameters.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
(quoted diff) +17
-0+ 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 aReview
Quoted 10 lines
(quoted diff) +10
-0+ * 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 beparsed
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 2 lines
(quoted diff) +2
-0+ * tables. + * Hence we read the parameter headers once for all to reducethe
Quoted 85 lines
Quoted 85 lines
Quoted 85 lines
Quoted 85 lines
Quoted 85 lines
Review
Quoted 13 lines
(quoted diff) +13
-0+ * 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 parameterheaders\n");
Review
Quoted 12 lines
(quoted diff) +12
-0+ 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&&Quoted 9 lines
(quoted diff) +9
-0+ 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)Review
Quoted 10 lines
(quoted diff) +7
-1+ goto exit; + +exit: + free(param_headers); + return err; +} + static int set_quad_mode(struct spi_flash *flash, const struct spi_flash_info *info) { @@ -1130,7+1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash) { struct spi_slave *spi = flash->spi; const struct spi_flash_info *info = NULL;(quoted diff) +9
-1- int ret; + int ret, sfdp = 0; info = spi_flash_read_id(flash); if (IS_ERR_OR_NULL(info))@@ -1196,9 +1432,28 @@ 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 commandsReview int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
(quoted diff) +8
-0+ */ + if (!(info->flags & SPI_FLASH_SKIP_SFDP)) { + flash->size = 0; + sfdp = spi_flash_parse_sfdp(flash); + if (sfdp < 0) + debug("Unable to get SFDP information\n"); + } + /* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
Quoted 7 lines
(quoted diff) +4
-1- flash->page_size = info->page_size; + if (info->flags & SPI_FLASH_SKIP_SFDP || sfdp < 0) { + flash->page_size = info->page_size; + flash->addr_width = SPI_FLASH_3B_ADDR_LEN; + } /* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256bQuoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
pages,
Quoted 2 lines
(quoted diff) +0
-0* yet use the 0x4d00 Extended JEDEC code. The rest of theSpansion @@ -1213,7 +1468,10 @@ int spi_flash_scan(struct
spi_flashQuoted 97 lines
Quoted 97 lines
*flash)
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
Quoted 25 lines
} flash->page_size <<= flash->shift; flash->sector_size = info->sector_size << flash->shift;(quoted diff) +8
-4- flash->size = flash->sector_size * info->n_sectors << flash->shift; + if (info->flags & SPI_FLASH_SKIP_SFDP || sfdp < 0) { + 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 +1570,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_SKIP_SFDP || sfdp < 0) && + (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");Quoted 1 line
diff -
-git
Quoted 25 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave; · line 52
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 36 lines
include/spi_flash.h +25
-0* @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; +};Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 8 lines
include/spi_flash.h +8
-0+ +#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
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
*/
include/spi_flash.h struct spi_flash { #endif }; · line 154
Quoted 12 lines
include/spi_flash.h +12
-0+#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.
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
include/spi_flash.h struct spi_flash { #endif }; · line 165
Quoted 11 lines
include/spi_flash.h +11
-0+* 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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash { #endif }; · line 180
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
include/spi_flash.h struct spi_flash { #endif }; · line 187
Quoted 7 lines
include/spi_flash.h +7
-0+ +/* 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-
Quoted 5 lines
Quoted 5 lines
4
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h struct spi_flash { #endif }; · line 188
Quoted 1 line
include/spi_flash.h +1
-0+* reads based on instruction. DQ3/HOLD# functions are hold during
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
include/spi_flash.h +2
-0+* instruction phase. +* - 001b: QE is bit 1 of status register 2. It is set via Write Status with
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
include/spi_flash.h struct spi_flash { #endif }; · line 193
Quoted 3 lines
include/spi_flash.h +3
-0+* two data bytes where bit 1 of the second byte is one. +* [...] +* Writing only one byte to the status register has the side- effect
Quoted 2 lines
Quoted 2 lines
of
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h +1
-0+* clearing status register 2, including the QE bit. The 100b code is
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h struct spi_flash { #endif }; · line 195
Quoted 1 line
include/spi_flash.h +1
-0+* used if writing one byte to the status register does not modify
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
include/spi_flash.h struct spi_flash { #endif }; · line 197
Quoted 2 lines
include/spi_flash.h +2
-0+* status register 2. +* - 010b: QE is bit 6 of status register 1. It is set via Write Status with
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/spi_flash.h struct spi_flash { #endif }; · line 201
Quoted 4 lines
include/spi_flash.h +4
-0+* 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.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
include/spi_flash.h struct spi_flash { #endif }; · line 204
Quoted 3 lines
include/spi_flash.h +3
-0+* [...] +* 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
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
include/spi_flash.h struct spi_flash { #endif }; · line 209
Quoted 5 lines
include/spi_flash.h +5
-0+* 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
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
include/spi_flash.h struct spi_flash { #endif }; · line 215
Quoted 6 lines
include/spi_flash.h +6
-0+* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL <<20)
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash { #endif }; · line 220
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL <<20)
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
Quoted 11 lines
include/spi_flash.h struct spi_flash { #endif }; · line 221
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20)/* Spansion */
Quoted 9 lines
include/spi_flash.h +5
-0+ +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,Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
--
Regards
Vignesh
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.dehttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flis
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
ts.denx.de%2Flistinfo%2Fu-
boot&data=02%7C01%7Crajat.srivastava%40n
Quoted 1 line
xp.com%7Cacee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92c
Quoted 3 lines
Quoted 3 lines
d99c5c
Quoted 1 line
301635%7C0%7C0%7C636779606107591743&sdata=u9H5PMJiRNVKyyFI7
Quoted 2 lines
Quoted 2 lines
y5eCmDx
Quoted 1 line
0KPmAHXvF8kusaJVUdM%3D&reserved=0
Vignesh R
maintainerPATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
Hi,
Quoted 18 lines
Quoted 9 lines
Unfortunately thats a problem with U-Boot
spi_flashlayer today. Many newer flashes like Micron's mt35x series dont support BAR registers. Accessing above 16MB is broken for such flashes today.Quoted 1 line
Also, initially I wanted to make SFDP optional so that none of the drivers
are affected
Quoted 1 line
and one could enable it using a flag as per requirement. Shall we get back
to making
Quoted 8 lines
Quoted 2 lines
this optional (similar to v1 of this patch)?
How does that help? With opt-in approach you mark some flash devices as SFDP capable, but you still don't update opcodes, thus breaking boards that have such flash devices. So, porting full bfpt parsing and always using opcode to 4 byte addressing opcodes when available will be needed. Thus you would end up with SFDP as default instead of opt-in.
Quoted 5 lines
Hi Vignesh
Porting full bftp parsing requires time. I am seeing a conflict with a patch of yours
https://patchwork.ozlabs.org/cover/1012146/
Yes, I ended up porting all of Linux SPI NOR features including SFDP and 4 byte addressing.
Quoted 3 lines
It seem above RFC patch will bring SFDP to U-boot. Do you still want me to put effort in porting SFDP in current version?
No need to post this series as my patches including this change. I would appreciate any review/test of my series.
You can find Patch v1 here: https://patchwork.ozlabs.org/cover/1012146/
(Please drop patch 9/16 while testing). Thanks!
Regards
Vignesh
Quoted 462 lines
Regards
RajatQuoted 459 lines
Quoted 6 lines
Regards
RajatQuoted 2 lines
Additionally, there are flash chips with a 3-/4-byte mode change
instruction.
Quoted 10 lines
Quoted 10 lines
But using 4-byte opcodes should be preferred.
Simon
Quoted 5 lines
In particular you are not parsing entire bfpt like in [1] and will break flash operations
[1]https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2F
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
elixir.bootlin.com%2Flinux%2Flatest%2Fsource%2Fdrivers%2Fmtd%2Fspi-
nor
Quoted 1 line
%2Fspi-
nor.c%23L2259&data=02%7C01%7Crajat.srivastava%40nxp.com%7Ca
Quoted 1 line
cee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92cd99c5c30163 5
Quoted 3 lines
Quoted 3 lines
%7C0
Quoted 1 line
%7C0%7C636779606107591743&sdata=UACl919%2BMQmdtBo5GUTAy
Quoted 97 lines
Quoted 97 lines
M428u1bT1bU
Quoted 96 lines
rXuX2GsSjb0%3D&reserved=0
Regards
VigneshQuoted 91 lines
Regards
RajatQuoted 88 lines
Regards
VigenshQuoted 28 lines
(quoted diff) +28
-0+ 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. */Review
Quoted 10 lines
(quoted diff) +10
-0+ 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 DiscoverableParameters.
Review
Quoted 9 lines
+ * @flash: pointer to a 'struct
spi_flash'
+ *
+ * The Serial Flash Discoverable Parameters are described by the(quoted diff) +6
-0+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 flashoperations.
Review
Quoted 5 lines
+ *
+ * Return: 0 on success, -errno otherwise.
+ */(quoted diff) +2
-0+static int spi_flash_parse_sfdp(struct spi_flash *flash) { + const struct sfdp_parameter_header *param_header,
*bfpt_header;Quoted 17 lines
(quoted diff) +17
-0+ 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 aReview
Quoted 10 lines
(quoted diff) +10
-0+ * 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 beparsed
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supportedoptional
Quoted 2 lines
(quoted diff) +2
-0+ * tables. + * Hence we read the parameter headers once for all to reducethe
Quoted 85 lines
Quoted 85 lines
Quoted 85 lines
Quoted 85 lines
Quoted 85 lines
Review
Quoted 13 lines
(quoted diff) +13
-0+ * 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 parameterheaders\n");
Review
Quoted 12 lines
(quoted diff) +12
-0+ 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&&Quoted 9 lines
(quoted diff) +9
-0+ 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)Review
Quoted 10 lines
(quoted diff) +7
-1+ goto exit; + +exit: + free(param_headers); + return err; +} + static int set_quad_mode(struct spi_flash *flash, const struct spi_flash_info *info) { @@ -1130,7+1366,7 @@ int
Quoted 20 lines
spi_flash_scan(struct spi_flash *flash) { struct spi_slave *spi = flash->spi; const struct spi_flash_info *info = NULL;(quoted diff) +9
-1- int ret; + int ret, sfdp = 0; info = spi_flash_read_id(flash); if (IS_ERR_OR_NULL(info))@@ -1196,9 +1432,28 @@ 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 commandsReview int spi_flash_scan(struct spi_flash *flash) · line 1452
Quoted 10 lines
(quoted diff) +8
-0+ */ + if (!(info->flags & SPI_FLASH_SKIP_SFDP)) { + flash->size = 0; + sfdp = spi_flash_parse_sfdp(flash); + if (sfdp < 0) + debug("Unable to get SFDP information\n"); + } + /* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 :0;
Quoted 7 lines
(quoted diff) +4
-1- flash->page_size = info->page_size; + if (info->flags & SPI_FLASH_SKIP_SFDP || sfdp < 0) { + flash->page_size = info->page_size; + flash->addr_width = SPI_FLASH_3B_ADDR_LEN; + } /* * The Spansion S25FS512S, S25FL032P and S25FL064P have 256bQuoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
pages,
Quoted 2 lines
(quoted diff) +0
-0* yet use the 0x4d00 Extended JEDEC code. The rest of theSpansion @@ -1213,7 +1468,10 @@ int spi_flash_scan(struct
spi_flashQuoted 97 lines
Quoted 97 lines
*flash)
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
Quoted 25 lines
} flash->page_size <<= flash->shift; flash->sector_size = info->sector_size << flash->shift;(quoted diff) +8
-4- flash->size = flash->sector_size * info->n_sectors << flash->shift; + if (info->flags & SPI_FLASH_SKIP_SFDP || sfdp < 0) { + 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 +1570,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_SKIP_SFDP || sfdp < 0) && + (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");Quoted 1 line
diff -
-git
Quoted 25 lines
a/include/spi.hb/include/spi.hindex938627bc01..7189e60581100644include/spi.h +2
-0@@ -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;include/spi_flash.h index renamed from include/spi_flash.h +0
-0
0ec98fb55d..6558a4a1d5100644include/spi_flash.h struct spi_slave; · line 47
Quoted 1 line
include/spi_flash.h +0
-0@@ -47,6 +47,9 @@ struct spi_slave;* @read_cmd: Read cmd - Array Fast, Extn read and quad read.
include/spi_flash.h struct spi_slave; · line 52
Quoted 5 lines
include/spi_flash.h +3
-0* @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.
Quoted 36 lines
include/spi_flash.h +25
-0* @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; +};Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
include/spi_flash.h struct spi_flash { #endif }; · line 142
Quoted 8 lines
include/spi_flash.h +8
-0+ +#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
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
*/
include/spi_flash.h struct spi_flash { #endif }; · line 154
Quoted 12 lines
include/spi_flash.h +12
-0+#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.
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
include/spi_flash.h struct spi_flash { #endif }; · line 165
Quoted 11 lines
include/spi_flash.h +11
-0+* 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)Quoted 5 lines
include/spi_flash.h +5
-0+#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)include/spi_flash.h struct spi_flash { #endif }; · line 180
Quoted 10 lines
include/spi_flash.h +10
-0+#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)
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
include/spi_flash.h struct spi_flash { #endif }; · line 187
Quoted 7 lines
include/spi_flash.h +7
-0+ +/* 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-
Quoted 5 lines
Quoted 5 lines
4
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h struct spi_flash { #endif }; · line 188
Quoted 1 line
include/spi_flash.h +1
-0+* reads based on instruction. DQ3/HOLD# functions are hold during
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
include/spi_flash.h +2
-0+* instruction phase. +* - 001b: QE is bit 1 of status register 2. It is set via Write Status with
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
include/spi_flash.h struct spi_flash { #endif }; · line 193
Quoted 3 lines
include/spi_flash.h +3
-0+* two data bytes where bit 1 of the second byte is one. +* [...] +* Writing only one byte to the status register has the side- effect
Quoted 2 lines
Quoted 2 lines
of
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h +1
-0+* clearing status register 2, including the QE bit. The 100b code is
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
include/spi_flash.h struct spi_flash { #endif }; · line 195
Quoted 1 line
include/spi_flash.h +1
-0+* used if writing one byte to the status register does not modify
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
include/spi_flash.h struct spi_flash { #endif }; · line 197
Quoted 2 lines
include/spi_flash.h +2
-0+* status register 2. +* - 010b: QE is bit 6 of status register 1. It is set via Write Status with
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/spi_flash.h struct spi_flash { #endif }; · line 201
Quoted 4 lines
include/spi_flash.h +4
-0+* 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.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
include/spi_flash.h struct spi_flash { #endif }; · line 204
Quoted 3 lines
include/spi_flash.h +3
-0+* [...] +* 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
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
include/spi_flash.h struct spi_flash { #endif }; · line 209
Quoted 5 lines
include/spi_flash.h +5
-0+* 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
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
include/spi_flash.h struct spi_flash { #endif }; · line 215
Quoted 6 lines
include/spi_flash.h +6
-0+* 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)include/spi_flash.h struct spi_flash { #endif }; · line 216
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_NONE (0x0UL << 20)/* Micron */
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL <<20)
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/spi_flash.h struct spi_flash { #endif }; · line 218
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20)/* Macronix */
include/spi_flash.h struct spi_flash { #endif }; · line 220
Quoted 2 lines
include/spi_flash.h +2
-0+#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL <<20)
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
Quoted 11 lines
include/spi_flash.h struct spi_flash { #endif }; · line 221
Quoted 1 line
include/spi_flash.h +1
-0+#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20)/* Spansion */
Quoted 9 lines
include/spi_flash.h +5
-0+ +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,Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
--
Regards
Vignesh
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.dehttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flis
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
ts.denx.de%2Flistinfo%2Fu-
boot&data=02%7C01%7Crajat.srivastava%40n
Quoted 1 line
xp.com%7Cacee153f50194bba71c808d64bad8d2e%7C686ea1d3bc2b4c6fa92c
Quoted 3 lines
Quoted 3 lines
d99c5c
Quoted 1 line
301635%7C0%7C0%7C636779606107591743&sdata=u9H5PMJiRNVKyyFI7
Quoted 2 lines
Quoted 2 lines
y5eCmDx
Quoted 1 line
0KPmAHXvF8kusaJVUdM%3D&reserved=0
Signature · 2 lines
Regards Vignesh
PATCH v2 1/2 mtd/spi: Add JEDEC SFDP support in SPI framework
In reply to Vignesh RQuoted 91 lines · Vignesh R
Quoted 88 lines · Rajat Srivastava
Quoted 87 lines
Hi Rajat,
Quoted 27 lines · Rajat Srivastava
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.
SFDP parsing is made default but already existing method for parsing these parameters are not deprecated.
A flag is created to skip SFDP parsing for a particular flash, if required.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 structspi_flashin structspi_slaveso 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 <[email protected]>---
Changes in v2:
- Make SFDP parsing the default method.
- ChangeSPI_FLASH_USE_SFDPflag toSPI_FLASH_USE_SFDPto provide an option to skip SFDP parsing for a particular flash.
---[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+static int spi_flash_parse_bfpt(struct spi_flash *flash, + const struct sfdp_parameter_header
*bfpt_header) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 6 lines
drivers/mtd/spi/spi_flash.c +6
-0+struct sfdp_bfpt bfpt; +size_t len; +int i, err; +u32 addr; + +/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
Quoted 8 lines
drivers/mtd/spi/spi_flash.c +8
-0+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));drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+ 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) {drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
Quoted 10 lines
drivers/mtd/spi/spi_flash.c +10
-0+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
drivers/mtd/spi/spi_flash.c static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash) · line 1192
Quoted 9 lines
drivers/mtd/spi/spi_flash.c +9
-0+* in struct spi_flash for every command. +*/ + flash->addr_width =4 ; +break ; + +case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY : + flash->addr_width =4 ; +break ; +I see your are updating
flash->addr_widthto 4 bytes here. But I don't see any code in this patch that changesflash->read_cmd(and write/erase cmds) to use 4B addressing opcodes. Also, I dont see any code that bypasses BAR register configuration whenCONFIG_SPI_FLASH_BARis defined and SFDP is available.
Quoted 6 lines
Quoted 2 lines
We don't have any flash that supports
CONFIG_SPI_FLASH_BAR. What do you suggest, shall we skip SFDP parsing in caseCONFIG_SPI_FLASH_BARis defined?I suggest skipping BAR configuration completely if flash supports address width of 4 as per SFDP. BAR configuration is only needed if flash does not support 4 byte addressing and flash size is > 16MB
And also some controller do support > 16MB flash, but have in-capable to handle 4-byte addressing commands, so for those cases BAR would require.
PATCH v2 2/2 fsl_qspi: Access flash above 16MB using SFDP
In reply to Rajat SrivastavaAdd functionality to read SFDP parameters in fsl_qspi driver. Also, use the address width information from SFDP to enable flash access above 16 MB.
Introduce a way to access parent structure by adding pointer to struct spi_slave in struct fsl_qspi_priv.
---
Changes in v2:
- none
--- drivers/spi/fsl_qspi.c | 103 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 7 deletions(-)
drivers/spi/fsl_qspi.c +96 -7
@@ -26,7 +26,7 @@ DECLARE_GLOBAL_DATA_PTR;#define TX_BUFFER_SIZE 0x40#endif -#define OFFSET_BITS_MASK GENMASK(23, 0) +#define SET_BITS_MASK (X ) GENMASK(X, 0)#define FLASH_STATUS_WEL 0x02
@@ -47,6 +47,7 @@ DECLARE_GLOBAL_DATA_PTR;#endif #define SEQID_WRAR 13#define SEQID_RDAR 14 +#define SEQID_RDSFDP 15/* QSPI CMD */ #define QSPI_CMD_PP 0x02/* Page program (up to 256 bytes) */
@@ -57,6 +58,7 @@ DECLARE_GLOBAL_DATA_PTR;#define QSPI_CMD_CHIP_ERASE 0xc7/* Erase whole flash chip */ #define QSPI_CMD_SE 0xd8/* Sector erase (usually 64KiB) */ #define QSPI_CMD_RDID 0x9f/* Read JEDEC ID */ +#define QSPI_CMD_RDSFDP 0x5a/* Read SFDP parameters from flash */ /* Used for Micron, winbond and Macronix flashes */ #define QSPI_CMD_WREAR 0xc5/* EAR register write */
@@ -132,6 +134,7 @@ struct fsl_qspi_priv {u32 flash_num;u32 num_chipselect;struct fsl_qspi_regs *regs; +void *spi_slave; };
@@ -363,6 +366,19 @@ static void qspi_set_lut(struct fsl_qspi_priv *priv)qspi_write32 (priv->flags, ®s->lut[lut_base +1 ],OPRND0 (1 ) |PAD0 (LUT_PAD1 ) |INSTR0 (LUT_WRITE )); +/* Read SFDP information */ + lut_base =SEQID_RDSFDP *4 ; +qspi_write32 (priv->flags, ®s->lut[lut_base], +OPRND0 (QSPI_CMD_RDSFDP ) |PAD0 (LUT_PAD1 ) | +INSTR0 (LUT_CMD ) |OPRND1 (ADDR24BIT ) | +PAD1 (LUT_PAD1 ) |INSTR1 (LUT_ADDR )); +qspi_write32 (priv->flags, ®s->lut[lut_base +1 ], +OPRND0 (8 ) |PAD0 (LUT_PAD1 ) |INSTR0 (LUT_DUMMY ) | +OPRND1 (RX_BUFFER_SIZE ) |PAD1 (LUT_PAD1 ) | +INSTR1 (LUT_READ )); +qspi_write32 (priv->flags, ®s->lut[lut_base +2 ],0 ); +qspi_write32 (priv->flags, ®s->lut[lut_base +3 ],0 ); +/* Lock the LUT */ qspi_write32 (priv->flags, ®s->lutkey,LUT_KEY_VALUE );qspi_write32 (priv->flags, ®s->lckcr,QSPI_LCKCR_LOCK );
@@ -562,6 +578,61 @@ static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)qspi_write32 (priv->flags, ®s->mcr, mcr_reg); } +static void qspi_op_rdsfdp (struct fsl_qspi_priv *priv,u32 *rxbuf,u32 len) +{ +struct fsl_qspi_regs *regs = priv->regs; +u32 mcr_reg, data; +int i, size; +u32 to_or_from; +u32 seqid; + + seqid =SEQID_RDSFDP ; + + mcr_reg =qspi_read32 (priv->flags, ®s->mcr); +qspi_write32 (priv->flags, ®s->mcr, +QSPI_MCR_CLR_RXF_MASK |QSPI_MCR_CLR_TXF_MASK | +QSPI_MCR_RESERVED_MASK |QSPI_MCR_END_CFD_LE ); +qspi_write32 (priv->flags, ®s->rbct,QSPI_RBCT_RXBRD_USEIPS ); + + to_or_from = priv->sf_addr + priv->cur_amba_base; + +while (len >0 ) { +WATCHDOG_RESET (); + +qspi_write32 (priv->flags, ®s->sfar, to_or_from); + + size = (len >RX_BUFFER_SIZE ) ? +RX_BUFFER_SIZE : len; + +qspi_write32 (priv->flags, ®s->ipcr, + (seqid <<QSPI_IPCR_SEQID_SHIFT ) | + size); +while (qspi_read32 (priv->flags, ®s->sr) &QSPI_SR_BUSY_MASK ) + ; + + to_or_from += size; + len -= size; + + i =0 ; +while ((size <RX_BUFFER_SIZE ) && (size >0 )) { + data =qspi_read32 (priv->flags, ®s->rbdr[i]); + data =qspi_endian_xchg (data); +if (size <4 ) +memcpy (rxbuf, &data, size); +else +memcpy (rxbuf, &data,4 ); + rxbuf++; + size -=4 ; + i++; + } +qspi_write32 (priv->flags, ®s->mcr, +qspi_read32 (priv->flags, ®s->mcr) | +QSPI_MCR_CLR_RXF_MASK ); + } + +qspi_write32 (priv->flags, ®s->mcr, mcr_reg); +} +/* If not use AHB read, read data from ip interface */ static void qspi_op_read (struct fsl_qspi_priv *priv,u32 *rxbuf,u32 len) {
@@ -772,14 +843,25 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen, {u32 bytes =DIV_ROUND_UP (bitlen,8 );static u32 wr_sfaddr; -u32 txbuf; +u32 txbuf, bits_mask; +struct spi_flash *flash; + + flash = ((struct spi_slave *)(priv->spi_slave))->flash;WATCHDOG_RESET (); +if (flash->cmd_len ==5 && flash->size >SZ_16M ) + bits_mask =SET_BITS_MASK (27 ); +else + bits_mask =SET_BITS_MASK (23 ); +if (dout) {if (flags &SPI_XFER_BEGIN ) { priv->cur_seqid = *(u8 *)dout; -memcpy (&txbuf, dout,4 ); +if (flash->size >SZ_16M && bytes >4 ) +memcpy (&txbuf, dout +1 ,4 ); +else +memcpy (&txbuf, dout,4 ); }if (flags ==SPI_XFER_END ) {
@@ -790,20 +872,21 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,if (priv->cur_seqid ==QSPI_CMD_FAST_READ || priv->cur_seqid ==QSPI_CMD_RDAR ) { - priv->sf_addr =swab32 (txbuf) &OFFSET_BITS_MASK ; + priv->sf_addr =swab32 (txbuf) & bits_mask; }else if ((priv->cur_seqid ==QSPI_CMD_SE ) || (priv->cur_seqid ==QSPI_CMD_BE_4K )) { - priv->sf_addr =swab32 (txbuf) &OFFSET_BITS_MASK ; + priv->sf_addr =swab32 (txbuf) & bits_mask;qspi_op_erase (priv); }else if (priv->cur_seqid ==QSPI_CMD_PP || priv->cur_seqid ==QSPI_CMD_WRAR ) { - wr_sfaddr =swab32 (txbuf) &OFFSET_BITS_MASK ; + wr_sfaddr =swab32 (txbuf) & bits_mask; }else if ((priv->cur_seqid ==QSPI_CMD_BRWR ) || (priv->cur_seqid ==QSPI_CMD_WREAR )) {#ifdef CONFIG_SPI_FLASH_BAR wr_sfaddr =0 ;#endif - } + }else if (priv->cur_seqid ==QSPI_CMD_RDSFDP ) + priv->sf_addr =swab32 (txbuf) & bits_mask; }if (din) {
@@ -819,6 +902,8 @@ int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,qspi_op_rdid (priv, din, bytes); else if (priv->cur_seqid == QSPI_CMD_RDSR) qspi_op_rdsr(priv, din, bytes); + else if (priv->cur_seqid == QSPI_CMD_RDSFDP) + qspi_op_rdsfdp(priv, din, bytes);#ifdef CONFIG_SPI_FLASH_BAR else if ((priv->cur_seqid == QSPI_CMD_BRRD) || (priv->cur_seqid == QSPI_CMD_RDEAR)) {
@@ -1044,9 +1129,13 @@ static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen, {struct fsl_qspi_priv *priv;struct udevice *bus; +struct spi_slave *slave; bus = dev->parent; priv =dev_get_priv (bus); + slave =dev_get_parent_priv (dev); + + priv->spi_slave = slave;return qspi_xfer (priv, bitlen, dout, din, flags); }
Signature · 1 line
2.14.1