drivers: flash: spi_nor: add option for 4byte opcodes
some flashes support special opcodes for 4-byte addressing, that can be used without switching to 4-byte mode. Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
This commit is contained in:
parent
1f55b8d8a4
commit
cf4a398477
3 changed files with 118 additions and 5 deletions
|
|
@ -43,7 +43,7 @@ LOG_MODULE_REGISTER(spi_nor, CONFIG_FLASH_LOG_LEVEL);
|
|||
*/
|
||||
|
||||
#define SPI_NOR_MAX_ADDR_WIDTH 4
|
||||
|
||||
#define SPI_NOR_3B_ADDR_MAX 0xFFFFFF
|
||||
|
||||
#define ANY_INST_HAS_TRUE_(idx, bool_prop) \
|
||||
COND_CODE_1(DT_INST_PROP(idx, bool_prop), (1,), ())
|
||||
|
|
@ -65,6 +65,7 @@ LOG_MODULE_REGISTER(spi_nor, CONFIG_FLASH_LOG_LEVEL);
|
|||
#define ANY_INST_HAS_RESET_GPIOS ANY_INST_HAS_PROP(reset_gpios)
|
||||
#define ANY_INST_HAS_WP_GPIOS ANY_INST_HAS_PROP(wp_gpios)
|
||||
#define ANY_INST_HAS_HOLD_GPIOS ANY_INST_HAS_PROP(hold_gpios)
|
||||
#define ANY_INST_USE_4B_ADDR_OPCODES ANY_INST_HAS_TRUE(use_4b_addr_opcodes)
|
||||
|
||||
#ifdef CONFIG_SPI_NOR_ACTIVE_DWELL_MS
|
||||
#define ACTIVE_DWELL_MS CONFIG_SPI_NOR_ACTIVE_DWELL_MS
|
||||
|
|
@ -152,6 +153,7 @@ struct spi_nor_config {
|
|||
#if ANY_INST_HAS_MXICY_MX25R_POWER_MODE
|
||||
bool mxicy_mx25r_power_mode;
|
||||
#endif
|
||||
bool use_4b_addr_opcodes:1;
|
||||
|
||||
/* exist flags for dts opt-ins */
|
||||
bool dpd_exist:1;
|
||||
|
|
@ -220,6 +222,16 @@ static const struct jesd216_erase_type minimal_erase_types[JESD216_NUM_ERASE_TYP
|
|||
.exp = 12,
|
||||
},
|
||||
};
|
||||
static const struct jesd216_erase_type minimal_erase_types_4b[JESD216_NUM_ERASE_TYPES] = {
|
||||
{
|
||||
.cmd = SPI_NOR_CMD_BE_4B,
|
||||
.exp = 16,
|
||||
},
|
||||
{
|
||||
.cmd = SPI_NOR_CMD_SE_4B,
|
||||
.exp = 12,
|
||||
},
|
||||
};
|
||||
#endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */
|
||||
|
||||
/* Register writes should be ready extremely quickly */
|
||||
|
|
@ -239,6 +251,9 @@ static inline const struct jesd216_erase_type *
|
|||
dev_erase_types(const struct device *dev)
|
||||
{
|
||||
#ifdef CONFIG_SPI_NOR_SFDP_MINIMAL
|
||||
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && DEV_CFG(dev)->use_4b_addr_opcodes) {
|
||||
return minimal_erase_types_4b;
|
||||
}
|
||||
return minimal_erase_types;
|
||||
#else /* CONFIG_SPI_NOR_SFDP_MINIMAL */
|
||||
const struct spi_nor_data *data = dev->data;
|
||||
|
|
@ -432,11 +447,25 @@ static int spi_nor_access(const struct device *const dev,
|
|||
spi_nor_access(dev, opcode, 0, 0, dest, length)
|
||||
#define spi_nor_cmd_addr_read(dev, opcode, addr, dest, length) \
|
||||
spi_nor_access(dev, opcode, NOR_ACCESS_ADDRESSED, addr, dest, length)
|
||||
#define spi_nor_cmd_addr_read_3b(dev, opcode, addr, dest, length) \
|
||||
spi_nor_access(dev, opcode, NOR_ACCESS_24BIT_ADDR | NOR_ACCESS_ADDRESSED, addr, dest, \
|
||||
length)
|
||||
#define spi_nor_cmd_addr_read_4b(dev, opcode, addr, dest, length) \
|
||||
spi_nor_access(dev, opcode, NOR_ACCESS_32BIT_ADDR | NOR_ACCESS_ADDRESSED, addr, dest, \
|
||||
length)
|
||||
#define spi_nor_cmd_write(dev, opcode) \
|
||||
spi_nor_access(dev, opcode, NOR_ACCESS_WRITE, 0, NULL, 0)
|
||||
#define spi_nor_cmd_addr_write(dev, opcode, addr, src, length) \
|
||||
spi_nor_access(dev, opcode, NOR_ACCESS_WRITE | NOR_ACCESS_ADDRESSED, \
|
||||
addr, (void *)src, length)
|
||||
#define spi_nor_cmd_addr_write_3b(dev, opcode, addr, src, length) \
|
||||
spi_nor_access(dev, opcode, \
|
||||
NOR_ACCESS_24BIT_ADDR | NOR_ACCESS_WRITE | NOR_ACCESS_ADDRESSED, addr, \
|
||||
(void *)src, length)
|
||||
#define spi_nor_cmd_addr_write_4b(dev, opcode, addr, src, length) \
|
||||
spi_nor_access(dev, opcode, \
|
||||
NOR_ACCESS_32BIT_ADDR | NOR_ACCESS_WRITE | NOR_ACCESS_ADDRESSED, addr, \
|
||||
(void *)src, length)
|
||||
|
||||
/**
|
||||
* @brief Wait until the flash is ready
|
||||
|
|
@ -784,7 +813,15 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest,
|
|||
|
||||
acquire_device(dev);
|
||||
|
||||
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
|
||||
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && DEV_CFG(dev)->use_4b_addr_opcodes) {
|
||||
if (addr > SPI_NOR_3B_ADDR_MAX) {
|
||||
ret = spi_nor_cmd_addr_read_4b(dev, SPI_NOR_CMD_READ_4B, addr, dest, size);
|
||||
} else {
|
||||
ret = spi_nor_cmd_addr_read_3b(dev, SPI_NOR_CMD_READ, addr, dest, size);
|
||||
}
|
||||
} else {
|
||||
ret = spi_nor_cmd_addr_read(dev, SPI_NOR_CMD_READ, addr, dest, size);
|
||||
}
|
||||
|
||||
release_device(dev);
|
||||
|
||||
|
|
@ -867,8 +904,20 @@ static int spi_nor_write(const struct device *dev, off_t addr,
|
|||
break;
|
||||
}
|
||||
|
||||
ret = spi_nor_cmd_addr_write(dev, SPI_NOR_CMD_PP, addr,
|
||||
src, to_write);
|
||||
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) &&
|
||||
DEV_CFG(dev)->use_4b_addr_opcodes) {
|
||||
if (addr > SPI_NOR_3B_ADDR_MAX) {
|
||||
ret = spi_nor_cmd_addr_write_4b(dev, SPI_NOR_CMD_PP_4B,
|
||||
addr, src, to_write);
|
||||
} else {
|
||||
ret = spi_nor_cmd_addr_write_3b(dev, SPI_NOR_CMD_PP, addr,
|
||||
src, to_write);
|
||||
}
|
||||
} else {
|
||||
ret = spi_nor_cmd_addr_write(dev, SPI_NOR_CMD_PP, addr, src,
|
||||
to_write);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -953,7 +1002,13 @@ static int spi_nor_erase(const struct device *dev, off_t addr, size_t size)
|
|||
}
|
||||
}
|
||||
if (bet != NULL) {
|
||||
ret = spi_nor_cmd_addr_write(dev, bet->cmd, addr, NULL, 0);
|
||||
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) &&
|
||||
DEV_CFG(dev)->use_4b_addr_opcodes) {
|
||||
ret = spi_nor_cmd_addr_write_4b(dev, bet->cmd, addr, NULL,
|
||||
0);
|
||||
} else {
|
||||
ret = spi_nor_cmd_addr_write(dev, bet->cmd, addr, NULL, 0);
|
||||
}
|
||||
addr += BIT(bet->exp);
|
||||
size -= BIT(bet->exp);
|
||||
} else {
|
||||
|
|
@ -1164,6 +1219,11 @@ static int spi_nor_process_bfp(const struct device *dev,
|
|||
struct jesd216_bfp_dw16 dw16;
|
||||
int rc = 0;
|
||||
|
||||
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) && DEV_CFG(dev)->use_4b_addr_opcodes) {
|
||||
LOG_DBG("4-byte addressing supported, using it via specific opcodes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (jesd216_bfp_decode_dw16(php, bfp, &dw16) == 0) {
|
||||
rc = spi_nor_set_address_mode(dev, dw16.enter_4ba);
|
||||
}
|
||||
|
|
@ -1181,6 +1241,7 @@ static int spi_nor_process_sfdp(const struct device *dev)
|
|||
int rc;
|
||||
|
||||
#if defined(CONFIG_SPI_NOR_SFDP_RUNTIME)
|
||||
struct spi_nor_data *dev_data = dev->data;
|
||||
/* For runtime we need to read the SFDP table, identify the
|
||||
* BFP block, and process it.
|
||||
*/
|
||||
|
|
@ -1236,6 +1297,45 @@ static int spi_nor_process_sfdp(const struct device *dev)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (id == JESD216_SFDP_PARAM_ID_4B_ADDR_INSTR) {
|
||||
if (IS_ENABLED(ANY_INST_USE_4B_ADDR_OPCODES) &&
|
||||
DEV_CFG(dev)->use_4b_addr_opcodes) {
|
||||
/*
|
||||
* Check table 4 byte address instruction table to get supported
|
||||
* erase opcodes when running in 4 byte address mode
|
||||
*/
|
||||
union {
|
||||
uint32_t dw[2];
|
||||
struct {
|
||||
uint32_t dummy;
|
||||
uint8_t type[4];
|
||||
} types;
|
||||
} u2;
|
||||
rc = spi_nor_sfdp_read(
|
||||
dev, jesd216_param_addr(php), (uint8_t *)u2.dw,
|
||||
MIN(sizeof(uint32_t) * php->len_dw, sizeof(u2.dw)));
|
||||
if (rc != 0) {
|
||||
break;
|
||||
}
|
||||
for (uint8_t ei = 0; ei < JESD216_NUM_ERASE_TYPES; ++ei) {
|
||||
struct jesd216_erase_type *etp = &dev_data->erase_types[ei];
|
||||
const uint8_t cmd = u2.types.type[ei];
|
||||
/* 0xff means not supported */
|
||||
if (cmd == 0xff) {
|
||||
etp->exp = 0;
|
||||
etp->cmd = 0;
|
||||
} else {
|
||||
etp->cmd = cmd;
|
||||
};
|
||||
}
|
||||
|
||||
if (!((sys_le32_to_cpu(u2.dw[0]) & BIT(0)) &&
|
||||
(sys_le32_to_cpu(u2.dw[1]) & BIT(6)))) {
|
||||
LOG_ERR("4-byte addressing not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
++php;
|
||||
}
|
||||
#elif defined(CONFIG_SPI_NOR_SFDP_DEVICETREE)
|
||||
|
|
@ -1692,6 +1792,7 @@ static const struct flash_driver_api spi_nor_api = {
|
|||
.requires_ulbpr_exist = DT_INST_PROP(idx, requires_ulbpr), \
|
||||
.wp_gpios_exist = DT_INST_NODE_HAS_PROP(idx, wp_gpios), \
|
||||
.hold_gpios_exist = DT_INST_NODE_HAS_PROP(idx, hold_gpios), \
|
||||
.use_4b_addr_opcodes = DT_INST_PROP(idx, use_4b_addr_opcodes), \
|
||||
IF_ENABLED(INST_HAS_LOCK(idx), (.has_lock = DT_INST_PROP(idx, has_lock),)) \
|
||||
IF_ENABLED(ANY_INST_HAS_DPD, (INIT_T_ENTER_DPD(idx),)) \
|
||||
IF_ENABLED(UTIL_AND(ANY_INST_HAS_DPD, ANY_INST_HAS_T_EXIT_DPD), \
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#define SPI_NOR_CMD_SE_4B 0x21 /* Sector erase 4 byte address*/
|
||||
#define SPI_NOR_CMD_BE_32K 0x52 /* Block erase 32KB */
|
||||
#define SPI_NOR_CMD_BE 0xD8 /* Block erase */
|
||||
#define SPI_NOR_CMD_BE_4B 0xDC /* Block erase 4 byte address*/
|
||||
#define SPI_NOR_CMD_CE 0xC7 /* Chip erase */
|
||||
#define SPI_NOR_CMD_RDID 0x9F /* Read JEDEC ID */
|
||||
#define SPI_NOR_CMD_ULBPR 0x98 /* Global Block Protection Unlock */
|
||||
|
|
|
|||
|
|
@ -102,3 +102,14 @@ properties:
|
|||
low power mode.
|
||||
|
||||
Only supported on Macronix MX25R Ultra Low Power series.
|
||||
|
||||
use-4b-addr-opcodes:
|
||||
type: boolean
|
||||
description: |
|
||||
Indicates the device uses special 4-byte address opcodes.
|
||||
Instead of switching to 4-byte addressing mode, the device uses
|
||||
special opcodes for 4-byte addressing.
|
||||
|
||||
Some devices support 4-byte address opcodes for read/write/erase
|
||||
operations. Use this property to indicate that the device supports
|
||||
4-byte address opcodes.
|
||||
|
|
|
|||
Loading…
Reference in a new issue