zephyr/drivers/flash/jesd216.h
Francois Ramu 6143579c85 drivers: flash: stm32 ospi driver with read ID from octoflash
This commit adds the jedec216 read JEDEC ID function API.
The ospi commands are issued to the octo flash device or
by the DTS jedec-id property.
Availability of this API is conditional
on selecting CONFIG_FLASH_JESD216_API.

Signed-off-by: Francois Ramu <francois.ramu@st.com>
2022-11-22 14:26:57 +00:00

533 lines
16 KiB
C

/*
* 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.
*/
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[];
} __packed;
/* 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);
#endif /* ZEPHYR_DRIVERS_FLASH_JESD216_H_ */