drivers: flash: jesd216: add JESD216 API for use in shared drivers
The spi_nor flash interface was designed for flash devices that use a standard SPI interface to devices that are compatible with the Micron M25P80 serial flash, identified in Linux as compatible jedec,spi-nor. The JEDEC Serial Flash Discoverable Parameters standard (JESD216) was designed to allow these devices to be self-describing. As we are increasingly being asked to support flash memories that do not use "standard" erase sizes or commands we need data structures and helper functions to extract information about a flash interface at runtime. For some of these devices the commands hard-coded in the current implementation are simply wrong. Define generic structures that support the SFDP hierarchy and the core Basic Flash Parameters table. The description will also support SPI-NAND and xSPI devices that conform to the JESD216 standards. Add bitfield values and helper functions to extract some information that drivers might need from JESD216 fields. At this time only information that is likely to be used is extracted; more may be added in the future. Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
parent
40a0d076e2
commit
bfcd64c29d
4 changed files with 713 additions and 0 deletions
|
@ -36,3 +36,4 @@ zephyr_include_directories_ifdef(
|
||||||
)
|
)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_FLASH_SHELL flash_shell.c)
|
zephyr_library_sources_ifdef(CONFIG_FLASH_SHELL flash_shell.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_FLASH_JESD216 jesd216.c)
|
||||||
|
|
|
@ -17,6 +17,12 @@ config FLASH_HAS_PAGE_LAYOUT
|
||||||
This option is enabled when the SoC flash driver supports
|
This option is enabled when the SoC flash driver supports
|
||||||
retrieving the layout of flash memory pages.
|
retrieving the layout of flash memory pages.
|
||||||
|
|
||||||
|
config FLASH_JESD216
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Selected by drivers that support JESD216-compatible flash
|
||||||
|
devices to enable building a common support module.
|
||||||
|
|
||||||
menuconfig FLASH
|
menuconfig FLASH
|
||||||
bool "Flash hardware support"
|
bool "Flash hardware support"
|
||||||
help
|
help
|
||||||
|
|
288
drivers/flash/jesd216.c
Normal file
288
drivers/flash/jesd216.c
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Peter Bigot Consulting, LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include "jesd216.h"
|
||||||
|
#include "spi_nor.h"
|
||||||
|
|
||||||
|
static bool extract_instr(uint16_t packed,
|
||||||
|
struct jesd216_instr *res)
|
||||||
|
{
|
||||||
|
bool rv = (res != NULL);
|
||||||
|
|
||||||
|
if (rv) {
|
||||||
|
res->instr = packed >> 8;
|
||||||
|
res->mode_clocks = (packed >> 5) & 0x07;
|
||||||
|
res->wait_states = packed & 0x1F;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int rv = -ENOTSUP;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case JESD216_MODE_044:
|
||||||
|
if ((php->len_dw >= 15)
|
||||||
|
&& (sys_le32_to_cpu(bfp->dw10[5]) & BIT(9))) {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_088:
|
||||||
|
if ((php->len_dw >= 19)
|
||||||
|
&& (sys_le32_to_cpu(bfp->dw10[9]) & BIT(9))) {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_111:
|
||||||
|
rv = 0;
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_112:
|
||||||
|
if (sys_le32_to_cpu(bfp->dw1) & BIT(16)) {
|
||||||
|
uint32_t dw4 = sys_le32_to_cpu(bfp->dw4);
|
||||||
|
|
||||||
|
rv = extract_instr(dw4 >> 0, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_114:
|
||||||
|
if (sys_le32_to_cpu(bfp->dw1) & BIT(22)) {
|
||||||
|
uint32_t dw3 = sys_le32_to_cpu(bfp->dw3);
|
||||||
|
|
||||||
|
rv = extract_instr(dw3 >> 16, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_118:
|
||||||
|
if (php->len_dw >= 17) {
|
||||||
|
uint32_t dw17 = sys_le32_to_cpu(bfp->dw10[7]);
|
||||||
|
|
||||||
|
if ((dw17 >> 24) != 0) {
|
||||||
|
rv = extract_instr(dw17 >> 16, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_122:
|
||||||
|
if (sys_le32_to_cpu(bfp->dw1) & BIT(20)) {
|
||||||
|
uint32_t dw4 = sys_le32_to_cpu(bfp->dw4);
|
||||||
|
|
||||||
|
rv = extract_instr(dw4 >> 16, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_144:
|
||||||
|
if (sys_le32_to_cpu(bfp->dw1) & BIT(21)) {
|
||||||
|
uint32_t dw3 = sys_le32_to_cpu(bfp->dw3);
|
||||||
|
|
||||||
|
rv = extract_instr(dw3 >> 0, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_188:
|
||||||
|
if (php->len_dw >= 17) {
|
||||||
|
uint32_t dw17 = sys_le32_to_cpu(bfp->dw10[7]);
|
||||||
|
|
||||||
|
if ((uint8_t)(dw17 >> 8) != 0) {
|
||||||
|
rv = extract_instr(dw17 >> 0, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_222:
|
||||||
|
if (sys_le32_to_cpu(bfp->dw5) & BIT(0)) {
|
||||||
|
uint32_t dw6 = sys_le32_to_cpu(bfp->dw6);
|
||||||
|
|
||||||
|
rv = extract_instr(dw6 >> 16, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JESD216_MODE_444:
|
||||||
|
if (sys_le32_to_cpu(bfp->dw5) & BIT(4)) {
|
||||||
|
uint32_t dw7 = sys_le32_to_cpu(bfp->dw7);
|
||||||
|
|
||||||
|
rv = extract_instr(dw7 >> 16, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* Not clear how to detect these; they are identified only by
|
||||||
|
* enable/disable sequences.
|
||||||
|
*/
|
||||||
|
case JESD216_MODE_44D4D:
|
||||||
|
case JESD216_MODE_888:
|
||||||
|
case JESD216_MODE_8D8D8D:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rv = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jesd216_bfp_erase(const struct jesd216_bfp *bfp,
|
||||||
|
uint8_t idx,
|
||||||
|
struct jesd216_erase_type *etp)
|
||||||
|
{
|
||||||
|
__ASSERT_NO_MSG((idx > 0) && (idx <= JESD216_NUM_ERASE_TYPES));
|
||||||
|
|
||||||
|
/* Types 1 and 2 are in dw8, types 3 and 4 in dw9 */
|
||||||
|
const uint32_t *dwp = &bfp->dw8 + (idx - 1U) / 2U;
|
||||||
|
uint32_t dw = sys_le32_to_cpu(*dwp);
|
||||||
|
|
||||||
|
/* Type 2(4) is in the upper half of the value. */
|
||||||
|
if ((idx & 0x01) == 0x00) {
|
||||||
|
dw >>= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the exponent and command */
|
||||||
|
uint8_t exp = (uint8_t)dw;
|
||||||
|
uint8_t cmd = (uint8_t)(dw >> 8);
|
||||||
|
|
||||||
|
if (exp == 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
etp->cmd = cmd;
|
||||||
|
etp->exp = exp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jesd216_bfp_erase_type_times(const struct jesd216_param_header *php,
|
||||||
|
const struct jesd216_bfp *bfp,
|
||||||
|
uint8_t idx,
|
||||||
|
uint32_t *typ_ms)
|
||||||
|
{
|
||||||
|
__ASSERT_NO_MSG((idx > 0) && (idx <= JESD216_NUM_ERASE_TYPES));
|
||||||
|
|
||||||
|
/* DW10 introduced in JESD216A */
|
||||||
|
if (php->len_dw < 10) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dw10 = sys_le32_to_cpu(bfp->dw10[0]);
|
||||||
|
|
||||||
|
/* Each 7-bit erase time entry has a 5-bit count in the lower
|
||||||
|
* bits, and a 2-bit unit in the upper bits. The actual count
|
||||||
|
* is the field content plus one.
|
||||||
|
*
|
||||||
|
* The entries start with ET1 at bit 4. The low four bits
|
||||||
|
* encode a value that is offset and scaled to produce a
|
||||||
|
* multipler to convert from typical time to maximum time.
|
||||||
|
*/
|
||||||
|
unsigned int count = 1 + ((dw10 >> (4 + (idx - 1) * 7)) & 0x1F);
|
||||||
|
unsigned int units = ((dw10 >> (4 + 5 + (idx - 1) * 7)) & 0x03);
|
||||||
|
unsigned int max_factor = 2 * (1 + (dw10 & 0x0F));
|
||||||
|
|
||||||
|
switch (units) {
|
||||||
|
case 0x00: /* 1 ms */
|
||||||
|
*typ_ms = count;
|
||||||
|
break;
|
||||||
|
case 0x01: /* 16 ms */
|
||||||
|
*typ_ms = count * 16;
|
||||||
|
break;
|
||||||
|
case 0x02: /* 128 ms */
|
||||||
|
*typ_ms = count * 128;
|
||||||
|
break;
|
||||||
|
case 0x03: /* 1 s */
|
||||||
|
*typ_ms = count * MSEC_PER_SEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jesd216_bfp_decode_dw11(const struct jesd216_param_header *php,
|
||||||
|
const struct jesd216_bfp *bfp,
|
||||||
|
struct jesd216_bfp_dw11 *res)
|
||||||
|
{
|
||||||
|
/* DW11 introduced in JESD216A */
|
||||||
|
if (php->len_dw < 11) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dw11 = sys_le32_to_cpu(bfp->dw10[1]);
|
||||||
|
uint32_t value = 1 + ((dw11 >> 24) & 0x1F);
|
||||||
|
|
||||||
|
switch ((dw11 >> 29) & 0x03) {
|
||||||
|
case 0x00: /* 16 ms */
|
||||||
|
value *= 16;
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
value *= 256;
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
value *= 4 * MSEC_PER_SEC;
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
value *= 64 * MSEC_PER_SEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res->chip_erase_ms = value;
|
||||||
|
|
||||||
|
value = 1 + ((dw11 >> 19) & 0x0F);
|
||||||
|
if (dw11 & BIT(23)) {
|
||||||
|
value *= 8;
|
||||||
|
}
|
||||||
|
res->byte_prog_addl_us = value;
|
||||||
|
|
||||||
|
value = 1 + ((dw11 >> 14) & 0x0F);
|
||||||
|
if (dw11 & BIT(18)) {
|
||||||
|
value *= 8;
|
||||||
|
}
|
||||||
|
res->byte_prog_first_us = value;
|
||||||
|
|
||||||
|
value = 1 + ((dw11 >> 8) & 0x01F);
|
||||||
|
if (dw11 & BIT(13)) {
|
||||||
|
value *= 64;
|
||||||
|
} else {
|
||||||
|
value *= 8;
|
||||||
|
}
|
||||||
|
res->page_prog_us = value;
|
||||||
|
|
||||||
|
res->page_size = BIT((dw11 >> 4) & 0x0F);
|
||||||
|
res->typ_max_factor = 2 * (1 + (dw11 & 0x0F));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jesd216_bfp_decode_dw14(const struct jesd216_param_header *php,
|
||||||
|
const struct jesd216_bfp *bfp,
|
||||||
|
struct jesd216_bfp_dw14 *res)
|
||||||
|
{
|
||||||
|
/* DW14 introduced in JESD216A */
|
||||||
|
if (php->len_dw < 14) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dw14 = sys_le32_to_cpu(bfp->dw10[4]);
|
||||||
|
|
||||||
|
if (dw14 & BIT(31)) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->enter_dpd_instr = (dw14 >> 23) & 0xFF;
|
||||||
|
res->exit_dpd_instr = (dw14 >> 15) & 0xFF;
|
||||||
|
|
||||||
|
uint32_t value = 1 + ((dw14 >> 8) & 0x1F);
|
||||||
|
|
||||||
|
switch ((dw14 >> 13) & 0x03) {
|
||||||
|
case 0x00: /* 128 ns */
|
||||||
|
value *= 128;
|
||||||
|
break;
|
||||||
|
case 0x01: /* 1 us */
|
||||||
|
value *= NSEC_PER_USEC;
|
||||||
|
break;
|
||||||
|
case 0x02: /* 8 us */
|
||||||
|
value *= 8 * NSEC_PER_USEC;
|
||||||
|
break;
|
||||||
|
case 0x03: /* 64 us */
|
||||||
|
value *= 64 * NSEC_PER_USEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->exit_delay_ns = value;
|
||||||
|
|
||||||
|
res->poll_options = (dw14 >> 2) & 0x3F;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
418
drivers/flash/jesd216.h
Normal file
418
drivers/flash/jesd216.h
Normal file
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
* 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 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);
|
||||||
|
|
||||||
|
/* Decode data from JESD216 DW14 */
|
||||||
|
struct jesd216_bfp_dw14 {
|
||||||
|
/* Instruct used to enter deep power-down */
|
||||||
|
uint8_t enter_dpd_instr;
|
||||||
|
|
||||||
|
/* Instruct 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);
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_DRIVERS_FLASH_JESD216_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue