diff --git a/doc/releases/release-notes-2.5.rst b/doc/releases/release-notes-2.5.rst index f7e2a5690cf1f..02680dc1bdbf5 100644 --- a/doc/releases/release-notes-2.5.rst +++ b/doc/releases/release-notes-2.5.rst @@ -167,6 +167,9 @@ Drivers and Sensors * Flash + * CONFIG_NORDIC_QSPI_NOR_QE_BIT has been removed. The + quad-enable-requirements devicetree property should be used instead. + * GPIO * Hardware Info diff --git a/drivers/flash/Kconfig.nordic_qspi_nor b/drivers/flash/Kconfig.nordic_qspi_nor index 794f168664ea8..b690c555cb88f 100644 --- a/drivers/flash/Kconfig.nordic_qspi_nor +++ b/drivers/flash/Kconfig.nordic_qspi_nor @@ -5,16 +5,13 @@ menuconfig NORDIC_QSPI_NOR bool "QSPI NOR Flash" select FLASH_HAS_DRIVER_ENABLED select NRFX_QSPI + select FLASH_JESD216 depends on HAS_HW_NRF_QSPI help Enable support for nrfx QSPI driver with EasyDMA. if NORDIC_QSPI_NOR -config NORDIC_QSPI_NOR_QE_BIT - int "Quad Enable bit number in Status Register" - default 6 - config NORDIC_QSPI_NOR_INIT_PRIORITY int default 80 diff --git a/drivers/flash/jesd216.c b/drivers/flash/jesd216.c index b3e2c928a794e..93787af7d0bb9 100644 --- a/drivers/flash/jesd216.c +++ b/drivers/flash/jesd216.c @@ -286,3 +286,44 @@ int jesd216_bfp_decode_dw14(const struct jesd216_param_header *php, return 0; } + +int jesd216_bfp_decode_dw15(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + struct jesd216_bfp_dw15 *res) +{ + /* DW15 introduced in JESD216A */ + if (php->len_dw < 15) { + return -ENOTSUP; + } + + uint32_t dw15 = sys_le32_to_cpu(bfp->dw10[5]); + + res->hold_reset_disable = (dw15 & BIT(23)) != 0U; + res->qer = (dw15 >> 20) & 0x07; + res->entry_044 = (dw15 >> 16) & 0x0F; + res->exit_044 = (dw15 >> 10) & 0x3F; + res->support_044 = (dw15 & BIT(9)) != 0U; + res->enable_444 = (dw15 >> 4) & 0x1F; + res->disable_444 = (dw15 >> 0) & 0x0F; + + return 0; +} + +int jesd216_bfp_decode_dw16(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + struct jesd216_bfp_dw16 *res) +{ + /* DW16 introduced in JESD216A */ + if (php->len_dw < 16) { + return -ENOTSUP; + } + + uint32_t dw16 = sys_le32_to_cpu(bfp->dw10[6]); + + res->enter_4ba = (dw16 >> 24) & 0xFF; + res->exit_4ba = (dw16 >> 14) & 0x3FF; + res->srrs_support = (dw16 >> 8) & 0x3F; + res->sr1_interface = (dw16 >> 0) & 0x7F; + + return 0; +} diff --git a/drivers/flash/jesd216.h b/drivers/flash/jesd216.h index ad9888a8e509a..8ea7ea099b408 100644 --- a/drivers/flash/jesd216.h +++ b/drivers/flash/jesd216.h @@ -383,12 +383,12 @@ 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 */ +/* Decoded data from JESD216 DW14 */ struct jesd216_bfp_dw14 { - /* Instruct used to enter deep power-down */ + /* Instruction used to enter deep power-down */ uint8_t enter_dpd_instr; - /* Instruct used to exit deep power-down */ + /* Instruction used to exit deep power-down */ uint8_t exit_dpd_instr; /* Bits defining ways busy status may be polled. */ @@ -415,4 +415,94 @@ 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, +}; + +/* 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_ */ diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 268a2dcd95efb..b3a6765952a44 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -13,6 +13,7 @@ #include #include "spi_nor.h" +#include "jesd216.h" #include "flash_priv.h" #include #include @@ -25,8 +26,6 @@ struct qspi_nor_config { uint32_t size; }; -#define QSPI_NOR_MAX_ID_LEN SPI_NOR_MAX_ID_LEN - /* Status register bits */ #define QSPI_SECTOR_SIZE SPI_NOR_SECTOR_SIZE #define QSPI_BLOCK_SIZE SPI_NOR_BLOCK_SIZE @@ -43,6 +42,14 @@ BUILD_ASSERT(INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 16), #define QSPI_PROP_AT(prop, idx) DT_PROP_BY_IDX(QSPI_NODE, prop, idx) #define QSPI_PROP_LEN(prop) DT_PROP_LEN(QSPI_NODE, prop) +#define INST_0_QER _CONCAT(JESD216_DW15_QER_, \ + DT_ENUM_TOKEN(DT_DRV_INST(0), \ + quad_enable_requirements)) + +BUILD_ASSERT(((INST_0_QER == JESD216_DW15_QER_NONE) + || (INST_0_QER == JESD216_DW15_QER_S1B6)), + "Driver only supports NONE or S1B6 for quad-enable-requirements"); + #define WORD_SIZE 4 LOG_MODULE_REGISTER(qspi_nor, CONFIG_FLASH_LOG_LEVEL); @@ -114,7 +121,7 @@ static inline int qspi_get_mode(bool cpol, bool cpha) return ret; } -static inline bool qspi_is_used_write_quad_mode(nrf_qspi_writeoc_t lines) +static inline bool qspi_write_is_quad(nrf_qspi_writeoc_t lines) { switch (lines) { case NRF_QSPI_WRITEOC_PP4IO: @@ -125,7 +132,7 @@ static inline bool qspi_is_used_write_quad_mode(nrf_qspi_writeoc_t lines) } } -static inline bool qspi_is_used_read_quad_mode(nrf_qspi_readoc_t lines) +static inline bool qspi_read_is_quad(nrf_qspi_readoc_t lines) { switch (lines) { case NRF_QSPI_READOC_READ4IO: @@ -302,39 +309,99 @@ static void qspi_handler(nrfx_qspi_evt_t event, void *p_context) } -/* QSPI send custom command */ -static int qspi_send_cmd(const struct device *dev, const struct qspi_cmd *cmd) +/* QSPI send custom command. + * + * If this is used for both send and receive the buffer sizes must be + * equal and cover the whole transaction. + */ +static int qspi_send_cmd(const struct device *dev, const struct qspi_cmd *cmd, + bool wren) { /* Check input parameters */ if (!cmd) { return -EINVAL; } - qspi_lock(dev); + const void *tx_buf = NULL; + size_t tx_len = 0; + void *rx_buf = NULL; + size_t rx_len = 0; + size_t xfer_len = sizeof(cmd->op_code); + + if (cmd->tx_buf) { + tx_buf = cmd->tx_buf->buf; + tx_len = cmd->tx_buf->len; + } + + if (cmd->rx_buf) { + rx_buf = cmd->rx_buf->buf; + rx_len = cmd->rx_buf->len; + } + + if ((rx_len != 0) && (tx_len != 0)) { + if (rx_len != tx_len) { + return -EINVAL; + } + + xfer_len += tx_len; + } else { + /* At least one of these is zero. */ + xfer_len += tx_len + rx_len; + } + + if (xfer_len > NRF_QSPI_CINSTR_LEN_9B) { + LOG_WRN("cinstr %02x transfer too long: %zu", + cmd->op_code, xfer_len); + return -EINVAL; + } nrf_qspi_cinstr_conf_t cinstr_cfg = { .opcode = cmd->op_code, + .length = xfer_len, .io2_level = true, .io3_level = true, .wipwait = false, - .wren = true, + .wren = wren, }; - cinstr_cfg.length = sizeof(cmd->op_code); - if ((cmd->tx_buf != 0) && (cmd->rx_buf != 0)) { - cinstr_cfg.length += cmd->tx_buf->len + cmd->rx_buf->len; - } else if ((cmd->tx_buf != 0) && (cmd->rx_buf == 0)) { - cinstr_cfg.length += cmd->tx_buf->len; - } else if ((cmd->tx_buf == 0) && (cmd->rx_buf != 0)) { - cinstr_cfg.length += cmd->rx_buf->len; - } - int res = nrfx_qspi_cinstr_xfer(&cinstr_cfg, cmd->tx_buf->buf, - cmd->rx_buf->buf); + qspi_lock(dev); + + int res = nrfx_qspi_cinstr_xfer(&cinstr_cfg, tx_buf, rx_buf); qspi_unlock(dev); return qspi_get_zephyr_ret_code(res); } +/* RDSR wrapper. Negative value is error. */ +static int qspi_rdsr(const struct device *dev) +{ + uint8_t sr = -1; + const struct qspi_buf sr_buf = { + .buf = &sr, + .len = sizeof(sr), + }; + struct qspi_cmd cmd = { + .op_code = SPI_NOR_CMD_RDSR, + .rx_buf = &sr_buf, + }; + int ret = qspi_send_cmd(dev, &cmd, false); + + return (ret < 0) ? ret : sr; +} + +/* Wait until RDSR confirms write is not in progress. */ +static int qspi_wait_while_writing(const struct device *dev) +{ + int ret; + + do { + ret = qspi_rdsr(dev); + } while ((ret >= 0) + && ((ret & SPI_NOR_WIP_BIT) != 0U)); + + return (ret < 0) ? ret : 0; +} + /* QSPI erase */ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) { @@ -461,36 +528,129 @@ static int qspi_nrfx_configure(const struct device *dev) qspi_fill_init_struct(&QSPIconfig); nrfx_err_t res = nrfx_qspi_init(&QSPIconfig, qspi_handler, dev_data); + int ret = qspi_get_zephyr_ret_code(res); + + if ((ret == 0) + && (INST_0_QER != JESD216_DW15_QER_NONE)) { + /* Set QE to match transfer mode. If not using quad + * it's OK to leave QE set, but doing so prevents use + * of WP#/RESET#/HOLD# which might be useful. + * + * Note build assert above ensures QER is S1B6. Other + * options require more logic. + */ + + ret = qspi_rdsr(dev); + if (ret < 0) { + LOG_ERR("RDSR failed: %d", ret); + return ret; + } - if (res == NRFX_SUCCESS) { - /* If quad transfer was chosen - enable it now */ - if ((qspi_is_used_write_quad_mode(QSPIconfig.prot_if.writeoc)) - || (qspi_is_used_read_quad_mode(QSPIconfig.prot_if.readoc))) { + uint8_t sr = (uint8_t)ret; + bool qe_value = + (qspi_write_is_quad(QSPIconfig.prot_if.writeoc)) + || (qspi_read_is_quad(QSPIconfig.prot_if.readoc)); + const uint8_t qe_mask = BIT(6); /* only S1B6 */ + bool qe_state = ((sr & qe_mask) != 0U); - /* WRITE ENABLE has to be sent before QUAR ENABLE */ - struct qspi_cmd cmd = { .op_code = SPI_NOR_CMD_WREN }; + LOG_DBG("RDSR %02x QE %d need %d: %s", sr, qe_state, qe_value, + (qe_state != qe_value) ? "updating" : "no-change"); - if (qspi_send_cmd(dev, &cmd) != 0) { - return -EIO; + ret = 0; + if (qe_state != qe_value) { + const struct qspi_buf sr_buf = { + .buf = &sr, + .len = sizeof(sr), + }; + struct qspi_cmd cmd = { + .op_code = SPI_NOR_CMD_WRSR, + .tx_buf = &sr_buf, + }; + + sr ^= qe_mask; + ret = qspi_send_cmd(dev, &cmd, true); + + /* Writing SR can take some time, and further + * commands sent while it's happening can be + * corrupted. Wait. + */ + if (ret == 0) { + ret = qspi_wait_while_writing(dev); } + } - uint8_t tx = BIT(CONFIG_NORDIC_QSPI_NOR_QE_BIT); + if (ret < 0) { + LOG_ERR("QE %s failed: %d", qe_value ? "set" : "clear", + ret); + } + } + + return ret; +} + +static int qspi_read_jedec_id(const struct device *dev, + uint8_t *id) +{ + const struct qspi_buf rx_buf = { + .buf = id, + .len = 3 + }; + const struct qspi_cmd cmd = { + .op_code = SPI_NOR_CMD_RDID, + .rx_buf = &rx_buf, + }; - const struct qspi_buf tx_buff = { .buf = &tx, .len = sizeof(tx), }; + return qspi_send_cmd(dev, &cmd, false); +} - cmd.op_code = SPI_NOR_CMD_WRSR; - cmd.tx_buf = &tx_buff; - cmd.rx_buf = NULL; +#if defined(CONFIG_FLASH_JESD216_API) - if (qspi_send_cmd(dev, &cmd) != 0) { - return -EIO; - } - } +static int qspi_sfdp_read(const struct device *dev, off_t offset, + void *data, size_t len) +{ + __ASSERT(data != NULL, "null destination"); + + uint8_t addr_buf[] = { + offset >> 16, + offset >> 8, + offset, + 0, /* wait state */ + }; + nrf_qspi_cinstr_conf_t cinstr_cfg = { + .opcode = JESD216_CMD_READ_SFDP, + .length = NRF_QSPI_CINSTR_LEN_1B, + .io2_level = true, + .io3_level = true, + }; + + qspi_lock(dev); + + int res = nrfx_qspi_lfm_start(&cinstr_cfg); + + if (res != NRFX_SUCCESS) { + LOG_DBG("lfm_start: %x", res); + goto out; + } + + res = nrfx_qspi_lfm_xfer(addr_buf, NULL, sizeof(addr_buf), false); + if (res != NRFX_SUCCESS) { + LOG_DBG("lfm_xfer addr: %x", res); + goto out; } + res = nrfx_qspi_lfm_xfer(NULL, data, len, true); + if (res != NRFX_SUCCESS) { + LOG_DBG("lfm_xfer read: %x", res); + goto out; + } + +out: + qspi_unlock(dev); return qspi_get_zephyr_ret_code(res); } +#endif /* CONFIG_FLASH_JESD216_API */ + /** * @brief Retrieve the Flash JEDEC ID and compare it with the one expected * @@ -502,25 +662,17 @@ static int qspi_nrfx_configure(const struct device *dev) static inline int qspi_nor_read_id(const struct device *dev, const struct qspi_nor_config *const flash_id) { - uint8_t rx_b[QSPI_NOR_MAX_ID_LEN]; - const struct qspi_buf q_rx_buf = { - .buf = rx_b, - .len = QSPI_NOR_MAX_ID_LEN - }; - const struct qspi_cmd cmd = { - .op_code = SPI_NOR_CMD_RDID, - .rx_buf = &q_rx_buf, - .tx_buf = NULL - }; + uint8_t id[SPI_NOR_MAX_ID_LEN]; + int ret = qspi_read_jedec_id(dev, id); - if (qspi_send_cmd(dev, &cmd) != 0) { + if (ret != 0) { return -EIO; } - if (memcmp(flash_id->id, rx_b, QSPI_NOR_MAX_ID_LEN) != 0) { - LOG_ERR("flash id error. Extected: [%d %d %d], got: [%d %d %d]", - flash_id->id[0], flash_id->id[1], flash_id->id[2], - rx_b[0], rx_b[1], rx_b[2]); + if (memcmp(flash_id->id, id, SPI_NOR_MAX_ID_LEN) != 0) { + LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", + id[0], id[1], id[2], + flash_id->id[0], flash_id->id[1], flash_id->id[2]); return -ENODEV; } @@ -779,7 +931,7 @@ static int qspi_nor_write_protection_set(const struct device *dev, driver_data->write_protection = write_protect; - if (qspi_send_cmd(dev, &cmd) != 0) { + if (qspi_send_cmd(dev, &cmd, false) != 0) { ret = -EIO; } @@ -875,6 +1027,10 @@ static const struct flash_driver_api qspi_nor_api = { #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = qspi_nor_pages_layout, #endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = qspi_sfdp_read, + .read_jedec_id = qspi_read_jedec_id, +#endif /* CONFIG_FLASH_JESD216_API */ }; diff --git a/dts/bindings/mtd/jedec,jesd216.yaml b/dts/bindings/mtd/jedec,jesd216.yaml index c25c75ba43fe3..97022e8330c07 100644 --- a/dts/bindings/mtd/jedec,jesd216.yaml +++ b/dts/bindings/mtd/jedec,jesd216.yaml @@ -43,3 +43,22 @@ properties: required: false deprecated: true description: Not used after Zephyr 2.3.0 + + quad-enable-requirements: + type: string + enum: + - "NONE" + - "S2B1v1" + - "S1B6" + - "S2B7" + - "S2B1v4" + - "S2B1v5" + - "S2B1v6" + required: false + description: | + Quad Enable Requirements value from JESD216 BFP DW15. + + Use NONE if the device detects 1-1-4 and 1-4-4 modes by the + instruction. Use S1B6 if QE is bit 6 of the first status register + byte, and can be configured by reading then writing one byte with + RDSR and WRSR. For other fields see the specification. diff --git a/dts/bindings/mtd/nordic,qspi-nor.yaml b/dts/bindings/mtd/nordic,qspi-nor.yaml index 952e844326a25..770594da46528 100644 --- a/dts/bindings/mtd/nordic,qspi-nor.yaml +++ b/dts/bindings/mtd/nordic,qspi-nor.yaml @@ -23,6 +23,10 @@ properties: size: required: true + # Match original driver NORDIC_QSPI_NOR_QE_BIT Kconfig default. + quad-enable-requirements: + default: "S1B6" + readoc: type: string required: false diff --git a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.conf b/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.conf index 745d59d6a72e0..d89d913713643 100644 --- a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.conf +++ b/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.conf @@ -5,10 +5,6 @@ # SPDX-License-Identifier: Apache-2.0 # -# Need this when storage is on MX25R64 -#CONFIG_NORDIC_QSPI_NOR=y -#CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 -CONFIG_SPI=y -CONFIG_SPI_NOR=y -CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 -CONFIG_SPI_2=y +CONFIG_SPI=n +CONFIG_SPI_NOR=n +CONFIG_NORDIC_QSPI_NOR=y diff --git a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.overlay b/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.overlay deleted file mode 100644 index 329e88ec8d6ab..0000000000000 --- a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.overlay +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2019 Peter Bigot Consulting, LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &mx25r64; - -&qspi { - status = "disabled"; -}; - -&spi2 { - status = "okay"; - cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>, <&gpio1 5 GPIO_ACTIVE_LOW>; - mx25r64: mx25r6435f@0 { - status = "okay"; - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <8000000>; - label = "MX25R64"; - jedec-id = [c2 28 17]; - sfdp-bfp = [ - e5 20 f1 ff ff ff ff 03 44 eb 08 6b 08 3b 04 bb - ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 - 10 d8 00 ff 23 72 f5 00 82 ed 04 cc 44 83 68 44 - 30 b0 30 b0 f7 c4 d5 5c 00 be 29 ff f0 d0 ff ff - ]; - - size = <67108864>; - has-dpd; - t-enter-dpd = <10000>; - dpd-wakeup-sequence = <30000 20 45000>; - wp-gpios = <&gpio0 22 0>; - hold-gpios = <&gpio0 23 0>; - }; -}; - -&mx25r64 { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "storage"; - reg = <0x00000000 0x00010000>; - }; - }; -}; diff --git a/samples/drivers/jesd216/src/main.c b/samples/drivers/jesd216/src/main.c index 34ab184047b30..bbb92e5264aca 100644 --- a/samples/drivers/jesd216/src/main.c +++ b/samples/drivers/jesd216/src/main.c @@ -14,6 +14,8 @@ #if DT_NODE_HAS_STATUS(DT_INST(0, jedec_spi_nor), okay) #define FLASH_DEVICE DT_LABEL(DT_INST(0, jedec_spi_nor)) +#elif DT_NODE_HAS_STATUS(DT_INST(0, nordic_qspi_nor), okay) +#define FLASH_DEVICE DT_LABEL(DT_INST(0, nordic_qspi_nor)) #else #error Unsupported flash driver #define FLASH_DEVICE "" @@ -174,6 +176,51 @@ static void summarize_dw14(const struct jesd216_param_header *php, dw14.exit_delay_ns, dw14.poll_options); } +static void summarize_dw15(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp) +{ + struct jesd216_bfp_dw15 dw15; + + if (jesd216_bfp_decode_dw15(php, bfp, &dw15) != 0) { + return; + } + printf("HOLD or RESET Disable: %ssupported\n", + dw15.hold_reset_disable ? "" : "un"); + printf("QER: %u\n", dw15.qer); + if (dw15.support_044) { + printf("0-4-4 Mode methods: entry 0x%01x ; exit 0x%02x\n", + dw15.entry_044, dw15.exit_044); + } else { + printf("0-4-4 Mode: not supported"); + } + printf("4-4-4 Mode sequences: enable 0x%02x ; disable 0x%01x\n", + dw15.enable_444, dw15.disable_444); +} + +static void summarize_dw16(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp) +{ + struct jesd216_bfp_dw16 dw16; + + if (jesd216_bfp_decode_dw16(php, bfp, &dw16) != 0) { + return; + } + + uint32_t dw1 = sys_le32_to_cpu(bfp->dw1); + uint8_t addr_support = (dw1 & JESD216_SFDP_BFP_DW1_ADDRBYTES_MASK) + >> JESD216_SFDP_BFP_DW1_ADDRBYTES_SHFT; + + /* Don't display bits when 4-byte addressing is not supported. */ + if (addr_support != JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_3B) { + printf("4-byte addressing support: enter 0x%02x, exit 0x%03x\n", + dw16.enter_4ba, dw16.exit_4ba); + } + printf("Soft Reset and Rescue Sequence support: 0x%02x\n", + dw16.srrs_support); + printf("Status Register 1 support: 0x%02x\n", + dw16.sr1_interface); +} + /* Indexed from 1 to match JESD216 data word numbering */ static const dw_extractor extractor[] = { [1] = summarize_dw1, @@ -182,13 +229,15 @@ static const dw_extractor extractor[] = { [11] = summarize_dw11, [12] = summarize_dw12, [14] = summarize_dw14, + [15] = summarize_dw15, + [16] = summarize_dw16, }; static void dump_bfp(const struct jesd216_param_header *php, const struct jesd216_bfp *bfp) { uint8_t dw = 1; - uint8_t limit = MIN(php->len_dw, ARRAY_SIZE(extractor)); + uint8_t limit = MIN(1U + php->len_dw, ARRAY_SIZE(extractor)); printf("Summary of BFP content:\n"); while (dw < limit) {