You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
545 lines
17 KiB
545 lines
17 KiB
/* |
|
* Copyright (c) 2020 Peter Bigot Consulting, LLC |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#ifndef ZEPHYR_DRIVERS_FLASH_JESD216_H_ |
|
#define ZEPHYR_DRIVERS_FLASH_JESD216_H_ |
|
|
|
#include <errno.h> |
|
#include <zephyr/sys/byteorder.h> |
|
#include <zephyr/sys/util.h> |
|
#include <zephyr/types.h> |
|
|
|
/* JEDEC Read identification */ |
|
#define JESD216_CMD_READ_ID SPI_NOR_CMD_RDID |
|
#define JESD216_OCMD_READ_ID 0x9F60 |
|
#define JESD216_READ_ID_LEN 3 |
|
|
|
/* Following are structures and constants supporting the JEDEC Serial |
|
* Flash Discoverable Parameters standard, JESD216 and its successors, |
|
* available at |
|
* https://www.jedec.org/standards-documents/docs/jesd216b |
|
*/ |
|
|
|
#define JESD216_CMD_READ_SFDP 0x5A |
|
#define JESD216_CMD_BURST_SFDP 0x5B |
|
#define JESD216_OCMD_READ_SFDP 0x5AA5 |
|
|
|
/* Layout of a JESD216 parameter header. */ |
|
struct jesd216_param_header { |
|
uint8_t id_lsb; /* ID LSB */ |
|
uint8_t rev_minor; /* Minor revision number */ |
|
uint8_t rev_major; /* Major revision number */ |
|
uint8_t len_dw; /* Length of table in 32-bit DWORDs */ |
|
uint8_t ptp[3]; /* Address of table in SFDP space (LSB@0) */ |
|
uint8_t id_msb; /* ID MSB */ |
|
} __packed; |
|
|
|
/* Get the number of bytes required for the parameter table. */ |
|
static inline uint32_t jesd216_param_len(const struct jesd216_param_header *hp) |
|
{ |
|
return sizeof(uint32_t) * hp->len_dw; |
|
} |
|
|
|
/* Get the ID that identifies the content of the parameter table. */ |
|
static inline uint16_t jesd216_param_id(const struct jesd216_param_header *hp) |
|
{ |
|
return ((uint16_t)hp->id_msb << 8) | hp->id_lsb; |
|
} |
|
|
|
/* Get the address within the SFDP where the data for the table is |
|
* stored. |
|
*/ |
|
static inline uint32_t jesd216_param_addr(const struct jesd216_param_header *hp) |
|
{ |
|
return ((hp->ptp[2] << 16) |
|
| (hp->ptp[1] << 8) |
|
| (hp->ptp[0] << 0)); |
|
} |
|
|
|
/* Layout of the Serial Flash Discoverable Parameters header. */ |
|
struct jesd216_sfdp_header { |
|
uint32_t magic; /* "SFDP" in little endian */ |
|
uint8_t rev_minor; /* Minor revision number */ |
|
uint8_t rev_major; /* Major revision number */ |
|
uint8_t nph; /* Number of parameter headers */ |
|
uint8_t access; /* Access protocol */ |
|
struct jesd216_param_header phdr[]; /* Headers */ |
|
} __packed; |
|
|
|
/* SFDP access protocol for backwards compatibility with JESD216B. */ |
|
#define JESD216_SFDP_AP_LEGACY 0xFF |
|
|
|
/* The expected value from the jesd216_sfdp::magic field in host byte |
|
* order. |
|
*/ |
|
#define JESD216_SFDP_MAGIC 0x50444653 |
|
|
|
/* All JESD216 data is read from the device in little-endian byte |
|
* order. For JEDEC parameter tables defined through JESD216D-01 the |
|
* parameters are defined by 32-bit words that may need to be |
|
* byte-swapped to extract their information. |
|
* |
|
* A 16-bit ID from the parameter header is used to identify the |
|
* content of each table. The first parameter table in the SFDP |
|
* hierarchy must be a Basic Flash Parameter table (ID 0xFF00). |
|
*/ |
|
|
|
/* JESD216D-01 section 6.4: Basic Flash Parameter */ |
|
#define JESD216_SFDP_PARAM_ID_BFP 0xFF00 |
|
/* JESD216D-01 section 6.5: Sector Map Parameter */ |
|
#define JESD216_SFDP_PARAM_ID_SECTOR_MAP 0xFF81 |
|
/* JESD216D-01 section 6.6: 4-Byte Address Instruction Parameter */ |
|
#define JESD216_SFDP_PARAM_ID_4B_ADDR_INSTR 0xFF84 |
|
/* JESD216D-01 section 6.7: xSPI (Profile 1.0) Parameter */ |
|
#define JESD216_SFDP_PARAM_ID_XSPI_PROFILE_1V0 0xFF05 |
|
/* JESD216D-01 section 6.8: xSPI (Profile 2.0) Parameter */ |
|
#define JESD216_SFDP_PARAM_ID_XSPI_PROFILE_2V0 0xFF06 |
|
|
|
/* Macro to define the number of bytes required for the SFDP pheader |
|
* and @p nph parameter headers. |
|
* |
|
* @param nph the number of parameter headers to be read. 1 is |
|
* sufficient for basic functionality. |
|
* |
|
* @return required buffer size in bytes. |
|
*/ |
|
#define JESD216_SFDP_SIZE(nph) (sizeof(struct jesd216_sfdp_header) \ |
|
+ ((nph) * sizeof(struct jesd216_param_header))) |
|
|
|
/** Extract the magic number from the SFDP structure in host byte order. |
|
* |
|
* If this compares equal to JESD216_SFDP_MAGIC then the SFDP header |
|
* may have been read correctly. |
|
*/ |
|
static inline uint32_t jesd216_sfdp_magic(const struct jesd216_sfdp_header *hp) |
|
{ |
|
return sys_le32_to_cpu(hp->magic); |
|
} |
|
|
|
/* Layout of the Basic Flash Parameters table. |
|
* |
|
* SFDP through JESD216B supported 9 DWORD values. JESD216C extended |
|
* this to 17, and JESD216D to 20. |
|
* |
|
* All values are expected to be stored as little-endian and must be |
|
* converted to host byte order to extract the bit fields defined in |
|
* the standard. Rather than pre-define layouts to access to all |
|
* potential fields this header provides functions for specific fields |
|
* known to be important, such as density and erase command support. |
|
* |
|
* Must be aligned to a DWORD (32-bit) address according to JESD216F. |
|
*/ |
|
struct jesd216_bfp { |
|
uint32_t dw1; |
|
uint32_t dw2; |
|
uint32_t dw3; |
|
uint32_t dw4; |
|
uint32_t dw5; |
|
uint32_t dw6; |
|
uint32_t dw7; |
|
uint32_t dw8; |
|
uint32_t dw9; |
|
uint32_t dw10[]; |
|
} __aligned(4); |
|
|
|
/* Provide a few word-specific flags and bitfield ranges for values |
|
* that an application or driver might expect to want to extract. |
|
* |
|
* See the JESD216 specification for the interpretation of these |
|
* bitfields. |
|
*/ |
|
#define JESD216_SFDP_BFP_DW1_DTRCLK_FLG BIT(19) |
|
#define JESD216_SFDP_BFP_DW1_ADDRBYTES_MASK (BIT(17) | BIT(18)) |
|
#define JESD216_SFDP_BFP_DW1_ADDRBYTES_SHFT 17 |
|
#define JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_3B 0 |
|
#define JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_3B4B 1 |
|
#define JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_4B 2 |
|
#define JESD216_SFDP_BFP_DW1_4KERASEINSTR_SHFT 8 |
|
#define JESD216_SFDP_BFP_DW1_4KERASEINSTR_MASK (0xFF << JESD216_SFDP_BFP_DW1_4KERASEINSTR_SHFT) |
|
#define JESD216_SFDP_BFP_DW1_WEISWVSR_FLG BIT(4) |
|
#define JESD216_SFDP_BFP_DW1_VSRBP_FLG BIT(3) |
|
#define JESD216_SFDP_BFP_DW1_WRTGRAN_FLG BIT(2) |
|
#define JESD216_SFDP_BFP_DW1_BSERSZ_SHFT 0 |
|
#define JESD216_SFDP_BFP_DW1_BSERSZ_MASK (0x03 << JESD216_SFDP_BFP_DW1_BSERSZ_SHFT) |
|
#define JESD216_SFDP_BFP_DW1_BSERSZ_VAL_4KSUP 0x01 |
|
#define JESD216_SFDP_BFP_DW1_BSERSZ_VAL_4KNOTSUP 0x03 |
|
|
|
#define JESD216_SFDP_BFP_DW12_SUSPRESSUP_FLG BIT(31) |
|
|
|
/* Data can be extracted from the BFP words using these APIs: |
|
* |
|
* * DW1 (capabilities) use DW1 bitfield macros above or |
|
* jesd216_read_support(). |
|
* * DW2 (density) use jesd216_bfp_density(). |
|
* * DW3-DW7 (instr) use jesd216_bfp_read_support(). |
|
* * DW8-DW9 (erase types) use jesd216_bfp_erase(). |
|
* |
|
* JESD216A (16 DW) |
|
* |
|
* * DW10 (erase times) use jesd216_bfp_erase_type_times(). |
|
* * DW11 (other times) use jesd216_bfp_decode_dw11(). |
|
* * DW12-13 (suspend/resume) no API except |
|
* JESD216_SFDP_BFP_DW12_SUSPRESSUP_FLG. |
|
* * DW14 (deep power down) use jesd216_bfp_decode_dw14(). |
|
* * DW15-16 no API except jesd216_bfp_read_support(). |
|
* |
|
* JESD216C (20 DW) |
|
* * DW17-20 (quad/oct support) no API except jesd216_bfp_read_support(). |
|
*/ |
|
|
|
/* Extract the supported address bytes from BFP DW1. */ |
|
static inline uint8_t jesd216_bfp_addrbytes(const struct jesd216_bfp *hp) |
|
{ |
|
uint32_t dw1 = sys_le32_to_cpu(hp->dw1); |
|
uint8_t addr_support = (dw1 & JESD216_SFDP_BFP_DW1_ADDRBYTES_MASK) |
|
>> JESD216_SFDP_BFP_DW1_ADDRBYTES_SHFT; |
|
|
|
return addr_support; |
|
} |
|
|
|
/* Extract the density of the chip in bits from BFP DW2. */ |
|
static inline uint64_t jesd216_bfp_density(const struct jesd216_bfp *hp) |
|
{ |
|
uint32_t dw = sys_le32_to_cpu(hp->dw2); |
|
|
|
if (dw & BIT(31)) { |
|
return BIT64(dw & BIT_MASK(31)); |
|
} |
|
return 1U + (uint64_t)dw; |
|
} |
|
|
|
/* Protocol mode enumeration types. |
|
* |
|
* Modes are identified by fields representing the number of I/O |
|
* signals and the data rate in the transfer. The I/O width may be 1, |
|
* 2, 4, or 8 I/O signals. The data rate may be single or double. |
|
* SDR is assumed; DDR is indicated by a D following the I/O width. |
|
* |
|
* A transfer has three phases, and width/rate is specified for each |
|
* in turn: |
|
* * Transfer of the command |
|
* * Transfer of the command modifier (e.g. address) |
|
* * Transfer of the data. |
|
* |
|
* Modes explicitly mentioned in JESD216 or JESD251 are given |
|
* enumeration values below, which can be used to extract information |
|
* about instruction support. |
|
*/ |
|
enum jesd216_mode_type { |
|
JESD216_MODE_044, /* implied instruction, execute in place */ |
|
JESD216_MODE_088, |
|
JESD216_MODE_111, |
|
JESD216_MODE_112, |
|
JESD216_MODE_114, |
|
JESD216_MODE_118, |
|
JESD216_MODE_122, |
|
JESD216_MODE_144, |
|
JESD216_MODE_188, |
|
JESD216_MODE_222, |
|
JESD216_MODE_444, |
|
JESD216_MODE_44D4D, |
|
JESD216_MODE_888, |
|
JESD216_MODE_8D8D8D, |
|
JESD216_MODE_LIMIT, |
|
}; |
|
|
|
/* Command to use for fast read operations in a specified protocol |
|
* mode. |
|
*/ |
|
struct jesd216_instr { |
|
uint8_t instr; |
|
uint8_t mode_clocks; |
|
uint8_t wait_states; |
|
}; |
|
|
|
/* Determine whether a particular operational mode is supported for |
|
* read, and possibly what command may be used. |
|
* |
|
* @note For @p mode JESD216_MODE_111 this function will return zero |
|
* to indicate that standard read (instruction 03h) is supported, but |
|
* without providing information on how. SFDP does not provide an |
|
* indication of support for 1-1-1 Fast Read (0Bh). |
|
* |
|
* @param php pointer to the BFP header. |
|
* |
|
* @param bfp pointer to the BFP table. |
|
* |
|
* @param mode the desired protocol mode. |
|
* |
|
* @param res where to store instruction information. Pass a null |
|
* pointer to test for support without retrieving instruction |
|
* information. |
|
* |
|
* @retval positive if instruction is supported and *res has been set. |
|
* |
|
* @retval 0 if instruction is supported but *res has not been set |
|
* (e.g. no instruction needed, or instruction cannot be read from |
|
* BFP). |
|
* |
|
* @retval -ENOTSUP if instruction is not supported. |
|
*/ |
|
int jesd216_bfp_read_support(const struct jesd216_param_header *php, |
|
const struct jesd216_bfp *bfp, |
|
enum jesd216_mode_type mode, |
|
struct jesd216_instr *res); |
|
|
|
/* Description of a supported erase operation. */ |
|
struct jesd216_erase_type { |
|
/* The command opcode used for an erase operation. */ |
|
uint8_t cmd; |
|
|
|
/* The value N when the erase operation erases a 2^N byte |
|
* region. |
|
*/ |
|
uint8_t exp; |
|
}; |
|
|
|
/* The number of erase types defined in a JESD216 Basic Flash |
|
* Parameter table. |
|
*/ |
|
#define JESD216_NUM_ERASE_TYPES 4 |
|
|
|
/* Extract a supported erase size and command from BFP DW8 or DW9. |
|
* |
|
* @param bfp pointer to the parameter table. |
|
* |
|
* @param idx the erase type index, from 1 through 4. Only index 1 is |
|
* guaranteed to be present. |
|
* |
|
* @param etp where to store the command and size used for the erase. |
|
* |
|
* @retval 0 if the erase type index provided usable information. |
|
* @retval -EINVAL if the erase type index is undefined. |
|
*/ |
|
int jesd216_bfp_erase(const struct jesd216_bfp *bfp, |
|
uint8_t idx, |
|
struct jesd216_erase_type *etp); |
|
|
|
/* Extract typical and maximum erase times from DW10. |
|
* |
|
* @param php pointer to the BFP header. |
|
* |
|
* @param bfp pointer to the BFP table. |
|
* |
|
* @param idx the erase type index, from 1 through 4. For meaningful |
|
* results the index should be one for which jesd216_bfp_erase() |
|
* returns success. |
|
* |
|
* @param typ_ms where to store the typical erase time (in |
|
* milliseconds) for the specified erase type. |
|
* |
|
* @retval -ENOTSUP if the erase type index is undefined. |
|
* @retval positive is a multiplier that converts typical erase times |
|
* to maximum erase times. |
|
*/ |
|
int jesd216_bfp_erase_type_times(const struct jesd216_param_header *php, |
|
const struct jesd216_bfp *bfp, |
|
uint8_t idx, |
|
uint32_t *typ_ms); |
|
|
|
/* Get the page size from the Basic Flash Parameters. |
|
* |
|
* @param php pointer to the BFP header. |
|
* |
|
* @param bfp pointer to the BFP table. |
|
* |
|
* @return the page size in bytes from the parameters if supported, |
|
* otherwise 256. |
|
*/ |
|
static inline uint32_t jesd216_bfp_page_size(const struct jesd216_param_header *php, |
|
const struct jesd216_bfp *bfp) |
|
{ |
|
/* Page size introduced in JESD216A */ |
|
if (php->len_dw < 11) { |
|
return 256; |
|
} |
|
|
|
uint32_t dw11 = sys_le32_to_cpu(bfp->dw10[1]); |
|
uint8_t exp = (dw11 >> 4) & 0x0F; |
|
|
|
return BIT(exp); |
|
} |
|
|
|
/* Decoded data from JESD216 DW11. */ |
|
struct jesd216_bfp_dw11 { |
|
/* Typical time for chip (die) erase, in milliseconds */ |
|
uint16_t chip_erase_ms; |
|
|
|
/* Typical time for first byte program, in microseconds */ |
|
uint16_t byte_prog_first_us; |
|
|
|
/* Typical time per byte for byte program after first, in |
|
* microseconds |
|
*/ |
|
uint16_t byte_prog_addl_us; |
|
|
|
/* Typical time for page program, in microseconds */ |
|
uint16_t page_prog_us; |
|
|
|
/* Multiplier to get maximum time from typical times. */ |
|
uint16_t typ_max_factor; |
|
|
|
/* Number of bytes in a page. */ |
|
uint16_t page_size; |
|
}; |
|
|
|
/* Get data from BFP DW11. |
|
* |
|
* @param php pointer to the BFP header. |
|
* |
|
* @param bfp pointer to the BFP table. |
|
* |
|
* @param res pointer to where to store the decoded data. |
|
* |
|
* @retval -ENOTSUP if this information is not available from this BFP table. |
|
* @retval 0 on successful storage into @c *res. |
|
*/ |
|
int jesd216_bfp_decode_dw11(const struct jesd216_param_header *php, |
|
const struct jesd216_bfp *bfp, |
|
struct jesd216_bfp_dw11 *res); |
|
|
|
/* Decoded data from JESD216 DW14 */ |
|
struct jesd216_bfp_dw14 { |
|
/* Instruction used to enter deep power-down */ |
|
uint8_t enter_dpd_instr; |
|
|
|
/* Instruction used to exit deep power-down */ |
|
uint8_t exit_dpd_instr; |
|
|
|
/* Bits defining ways busy status may be polled. */ |
|
uint8_t poll_options; |
|
|
|
/* Time after issuing exit instruction until device is ready |
|
* to accept a command, in nanoseconds. |
|
*/ |
|
uint32_t exit_delay_ns; |
|
}; |
|
|
|
/* Get data from BFP DW14. |
|
* |
|
* @param php pointer to the BFP header. |
|
* |
|
* @param bfp pointer to the BFP table. |
|
* |
|
* @param res pointer to where to store the decoded data. |
|
* |
|
* @retval -ENOTSUP if this information is not available from this BFP table. |
|
* @retval 0 on successful storage into @c *res. |
|
*/ |
|
int jesd216_bfp_decode_dw14(const struct jesd216_param_header *php, |
|
const struct jesd216_bfp *bfp, |
|
struct jesd216_bfp_dw14 *res); |
|
|
|
/* DW15 Quad Enable Requirements specifies status register QE bits. |
|
* |
|
* Two common configurations are summarized; see the specification for |
|
* full details of how to use these values. |
|
*/ |
|
enum jesd216_dw15_qer_type { |
|
/* No QE status required for 1-1-4 or 1-4-4 mode */ |
|
JESD216_DW15_QER_NONE = 0, |
|
JESD216_DW15_QER_S2B1v1 = 1, |
|
/* Bit 6 of SR byte must be set to enable 1-1-4 or 1-4-4 mode. |
|
* SR is one byte. |
|
*/ |
|
JESD216_DW15_QER_S1B6 = 2, |
|
JESD216_DW15_QER_S2B7 = 3, |
|
JESD216_DW15_QER_S2B1v4 = 4, |
|
JESD216_DW15_QER_S2B1v5 = 5, |
|
JESD216_DW15_QER_S2B1v6 = 6, |
|
}; |
|
|
|
#define JESD216_DW15_QER_VAL_NONE 0 |
|
#define JESD216_DW15_QER_VAL_S2B1v1 1 |
|
#define JESD216_DW15_QER_VAL_S1B6 2 |
|
#define JESD216_DW15_QER_VAL_S2B7 3 |
|
#define JESD216_DW15_QER_VAL_S2B1v4 4 |
|
#define JESD216_DW15_QER_VAL_S2B1v5 5 |
|
#define JESD216_DW15_QER_VAL_S2B1v6 6 |
|
|
|
/* Decoded data from JESD216 DW15 */ |
|
struct jesd216_bfp_dw15 { |
|
/* If true clear NVECR bit 4 to disable HOLD/RESET */ |
|
bool hold_reset_disable: 1; |
|
/* Encoded jesd216_dw15_qer_type */ |
|
unsigned int qer: 3; |
|
/* 0-4-4 mode entry method */ |
|
unsigned int entry_044: 4; |
|
/* 0-4-4 mode exit method */ |
|
unsigned int exit_044: 6; |
|
/* True if 0-4-4 mode is supported */ |
|
bool support_044: 1; |
|
/* 4-4-4 mode enable sequences */ |
|
unsigned int enable_444: 5; |
|
/* 4-4-4 mode disable sequences */ |
|
unsigned int disable_444: 4; |
|
}; |
|
|
|
/* Get data from BFP DW15. |
|
* |
|
* @param php pointer to the BFP header. |
|
* |
|
* @param bfp pointer to the BFP table. |
|
* |
|
* @param res pointer to where to store the decoded data. |
|
* |
|
* @retval -ENOTSUP if this information is not available from this BFP table. |
|
* @retval 0 on successful storage into @c *res. |
|
*/ |
|
int jesd216_bfp_decode_dw15(const struct jesd216_param_header *php, |
|
const struct jesd216_bfp *bfp, |
|
struct jesd216_bfp_dw15 *res); |
|
|
|
/* Decoded data from JESD216_DW16 */ |
|
struct jesd216_bfp_dw16 { |
|
/* Bits specifying supported modes of entering 4-byte |
|
* addressing. |
|
*/ |
|
unsigned int enter_4ba: 8; |
|
|
|
/* Bits specifying supported modes of exiting 4-byte |
|
* addressing. |
|
*/ |
|
unsigned int exit_4ba: 10; |
|
|
|
/* Bits specifying the soft reset and rescue sequence to |
|
* restore the device to its power-on state. |
|
*/ |
|
unsigned int srrs_support: 6; |
|
|
|
/* Bits specifying how to modify status register 1, and which |
|
* bits are non-volatile. |
|
*/ |
|
unsigned int sr1_interface: 7; |
|
}; |
|
|
|
/* Get data from BFP DW16. |
|
* |
|
* @param php pointer to the BFP header. |
|
* |
|
* @param bfp pointer to the BFP table. |
|
* |
|
* @param res pointer to where to store the decoded data. |
|
* |
|
* @retval -ENOTSUP if this information is not available from this BFP table. |
|
* @retval 0 on successful storage into @c *res. |
|
*/ |
|
int jesd216_bfp_decode_dw16(const struct jesd216_param_header *php, |
|
const struct jesd216_bfp *bfp, |
|
struct jesd216_bfp_dw16 *res); |
|
|
|
/* JESD216D-01 section 6.6: 4-Byte Address Instruction Parameter */ |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_1S_1S_READ_13_SUP BIT(0) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_1S_1S_FAST_READ_0C_SUP BIT(1) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_1S_2_FAST_READ_3C_SUP BIT(2) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_2S_2S_FAST_READ_BC_SUP BIT(3) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_1S_4S_FAST_READ_6C_SUP BIT(4) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_4S_4_FAST_READ_EC_SUP BIT(5) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_1S_1S_PP_12_SUP BIT(6) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_1S_4S_PP_34_SUP BIT(7) |
|
#define JESD216_SFDP_4B_ADDR_DW1_1S_4S_4S_PP_3E_SUP BIT(8) |
|
|
|
#endif /* ZEPHYR_DRIVERS_FLASH_JESD216_H_ */
|
|
|