blob: bc1fa6bad02e607b253eb20d850e9109cb4e1dc0 [file] [log] [blame]
/*
* 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 <sys/byteorder.h>
#include <sys/util.h>
#include <zephyr/types.h>
/* 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
/* 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_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_ */