zephyr/drivers/flash/flash_nxp_s32_qspi_nor.c
Manuel Argüelles 6d0a876525 drivers: flash: add NXP S32 QSPI flash NOR driver
Add support for flash NOR memory devices on a NXP S32 QSPI bus. The
driver uses a fixed LUT configuration assuming a default standard page
size and erase types, and allows to select between multiple read/program
instructions/modes. It is also possible to read the flash device
characteristics from the device at run-time as long as the memory is
JESD216 compatible, providing more flexibility.

Signed-off-by: Manuel Argüelles <manuel.arguelles@nxp.com>
2023-07-26 09:44:14 +02:00

1107 lines
32 KiB
C

/*
* Copyright 2023 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_s32_qspi_nor
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(nxp_s32_qspi_nor, CONFIG_FLASH_LOG_LEVEL);
#include <zephyr/kernel.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/sys/util.h>
#include <Qspi_Ip.h>
#include "spi_nor.h"
#include "jesd216.h"
#include "memc_nxp_s32_qspi.h"
#define QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, prop, val) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, prop), \
(IS_EQ(DT_INST_ENUM_IDX(n, prop), val)), \
(0)) ||
#define QSPI_ANY_INST_HAS_PROP_EQ(prop, val) \
(DT_INST_FOREACH_STATUS_OKAY_VARGS(QSPI_INST_NODE_HAS_PROP_EQ_AND_OR, prop, val) 0)
#define QSPI_INST_NODE_NOT_HAS_PROP_AND_OR(n, prop) \
!DT_INST_NODE_HAS_PROP(n, prop) ||
#define QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(prop) \
(DT_INST_FOREACH_STATUS_OKAY_VARGS(QSPI_INST_NODE_NOT_HAS_PROP_AND_OR, prop) 0)
#define QSPI_QER_TYPE(n) \
_CONCAT(JESD216_DW15_QER_VAL_, \
DT_INST_STRING_TOKEN_OR(n, quad_enable_requirements, S1B6))
#define QSPI_HAS_QUAD_MODE(n) \
(QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, readoc, 3) \
QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, readoc, 4) \
QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, writeoc, 2) \
QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, writeoc, 3) \
0)
#define QSPI_WRITE_SEQ(n) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, writeoc), \
(_CONCAT(QSPI_SEQ_PP_, DT_INST_STRING_UPPER_TOKEN(n, writeoc))),\
(QSPI_SEQ_PP_1_1_1))
#define QSPI_READ_SEQ(n) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, readoc), \
(_CONCAT(QSPI_SEQ_READ_, DT_INST_STRING_UPPER_TOKEN(n, readoc))),\
(QSPI_SEQ_READ_1_1_1))
#define QSPI_ERASE_VALUE 0xff
#define QSPI_WRITE_BLOCK_SIZE 1U
#define QSPI_IS_ALIGNED(addr, bits) (((addr) & BIT_MASK(bits)) == 0)
#define QSPI_LUT_ENTRY_SIZE (FEATURE_QSPI_LUT_SEQUENCE_SIZE * 2)
#define QSPI_LUT_IDX(n) (n * QSPI_LUT_ENTRY_SIZE)
#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
/* Size of LUT */
#define QSPI_SFDP_LUT_SIZE 130U
/* Size of init operations */
#define QSPI_SFDP_INIT_OP_SIZE 8U
#if defined(CONFIG_FLASH_JESD216_API)
/* Size of all LUT sequences for JESD216 operations */
#define QSPI_JESD216_SEQ_SIZE 8U
#endif /* CONFIG_FLASH_JESD216_API */
#endif /* CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME */
struct nxp_s32_qspi_config {
const struct device *controller;
struct flash_parameters flash_parameters;
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
struct flash_pages_layout layout;
#endif
#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
const Qspi_Ip_MemoryConfigType memory_cfg;
enum jesd216_dw15_qer_type qer_type;
bool quad_mode;
#endif
};
struct nxp_s32_qspi_data {
uint8_t instance;
Qspi_Ip_MemoryConnectionType memory_conn_cfg;
uint8_t read_sfdp_lut_idx;
#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
Qspi_Ip_MemoryConfigType memory_cfg;
Qspi_Ip_InstrOpType lut_ops[QSPI_SFDP_LUT_SIZE];
Qspi_Ip_InitOperationType init_ops[QSPI_SFDP_INIT_OP_SIZE];
#endif
#if defined(CONFIG_MULTITHREADING)
struct k_sem sem;
#endif
};
enum {
QSPI_SEQ_RDSR,
QSPI_SEQ_RDSR2,
QSPI_SEQ_WRSR,
QSPI_SEQ_WRSR2,
QSPI_SEQ_WREN,
QSPI_SEQ_RESET,
QSPI_SEQ_SE,
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(has_32k_erase)
QSPI_SEQ_BE_32K,
#endif
QSPI_SEQ_BE,
QSPI_SEQ_CE,
QSPI_SEQ_READ_SFDP,
QSPI_SEQ_RDID,
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(readoc)
QSPI_SEQ_READ_1_1_1,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 1)
QSPI_SEQ_READ_1_1_2,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 2)
QSPI_SEQ_READ_1_2_2,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 3)
QSPI_SEQ_READ_1_1_4,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 4)
QSPI_SEQ_READ_1_4_4,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(writeoc)
QSPI_SEQ_PP_1_1_1,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 1)
QSPI_SEQ_PP_1_1_2,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 2)
QSPI_SEQ_PP_1_1_4,
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 3)
QSPI_SEQ_PP_1_4_4,
#endif
};
#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
static const Qspi_Ip_InstrOpType nxp_s32_qspi_lut[][QSPI_LUT_ENTRY_SIZE] = {
[QSPI_SEQ_RDSR] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RDSR),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 1U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_RDSR2] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RDSR2),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 1U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_WRSR] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_WRSR),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_1, 1U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_WRSR2] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_WRSR2),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_1, 1U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_WREN] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_WREN),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_RESET] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RESET_EN),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_PADS_1, 0U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RESET_MEM),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_PADS_1, 0U),
},
[QSPI_SEQ_SE] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_SE),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(has_32k_erase)
[QSPI_SEQ_BE_32K] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_BE_32K),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
[QSPI_SEQ_BE] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_BE),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_CE] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_CE),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_READ_SFDP] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, JESD216_CMD_READ_SFDP),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 16U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
[QSPI_SEQ_RDID] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, JESD216_CMD_READ_ID),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, JESD216_READ_ID_LEN),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(readoc)
[QSPI_SEQ_READ_1_1_1] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_READ_FAST),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 1)
[QSPI_SEQ_READ_1_1_2] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_DREAD),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_2, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 2)
[QSPI_SEQ_READ_1_2_2] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_2READ),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_2, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_2, 4U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_2, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 3)
[QSPI_SEQ_READ_1_1_4] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_QREAD),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_4, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 4)
[QSPI_SEQ_READ_1_4_4] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_4READ),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_4, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_MODE, QSPI_IP_LUT_PADS_4, 0U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_4, 4U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_4, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(writeoc)
[QSPI_SEQ_PP_1_1_1] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_1, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 1)
[QSPI_SEQ_PP_1_1_2] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP_1_1_2),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_2, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 2)
[QSPI_SEQ_PP_1_1_4] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP_1_1_4),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_4, 8U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 3)
[QSPI_SEQ_PP_1_4_4] = {
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP_1_4_4),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_4, 24U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_4, 16U),
QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END),
},
#endif
};
#endif /* !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) */
static ALWAYS_INLINE Qspi_Ip_MemoryConfigType *get_memory_config(const struct device *dev)
{
#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
return &((struct nxp_s32_qspi_data *)dev->data)->memory_cfg;
#else
return ((Qspi_Ip_MemoryConfigType *)
&((const struct nxp_s32_qspi_config *)dev->config)->memory_cfg);
#endif
}
static ALWAYS_INLINE bool area_is_subregion(const struct device *dev, off_t offset, size_t size)
{
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
return ((offset >= 0) && (offset < memory_cfg->memSize)
&& ((size + offset) <= memory_cfg->memSize));
}
static inline void nxp_s32_qspi_lock(const struct device *dev)
{
#ifdef CONFIG_MULTITHREADING
struct nxp_s32_qspi_data *data = dev->data;
k_sem_take(&data->sem, K_FOREVER);
#else
ARG_UNUSED(dev);
#endif
}
static inline void nxp_s32_qspi_unlock(const struct device *dev)
{
#ifdef CONFIG_MULTITHREADING
struct nxp_s32_qspi_data *data = dev->data;
k_sem_give(&data->sem);
#else
ARG_UNUSED(dev);
#endif
}
/* Must be called with lock */
static int nxp_s32_qspi_wait_until_ready(const struct device *dev)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_StatusType status;
uint32_t timeout = 0xFFFFFF;
int ret = 0;
do {
status = Qspi_Ip_GetMemoryStatus(data->instance);
timeout--;
} while ((status == STATUS_QSPI_IP_BUSY) && (timeout > 0));
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to read memory status (%d)", status);
ret = -EIO;
} else if (timeout <= 0) {
LOG_ERR("Timeout, memory is busy");
ret = -ETIMEDOUT;
}
return ret;
}
#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
static int nxp_s32_qspi_read_status_register(const struct device *dev,
uint8_t reg_num,
uint8_t *val)
{
struct nxp_s32_qspi_data *data = dev->data;
uint16_t lut_idx;
Qspi_Ip_StatusType status;
int ret = 0;
switch (reg_num) {
case 1U:
lut_idx = QSPI_LUT_IDX(QSPI_SEQ_RDSR);
break;
case 2U:
lut_idx = QSPI_LUT_IDX(QSPI_SEQ_RDSR2);
break;
default:
LOG_ERR("Reading SR%u is not supported", reg_num);
return -EINVAL;
}
nxp_s32_qspi_lock(dev);
status = Qspi_Ip_RunReadCommand(data->instance, lut_idx, 0U, val, NULL, sizeof(*val));
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to read SR%u (%d)", reg_num, status);
ret = -EIO;
}
nxp_s32_qspi_unlock(dev);
return ret;
}
static int nxp_s32_qspi_write_enable(const struct device *dev)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
Qspi_Ip_StatusType status;
int ret = 0;
nxp_s32_qspi_lock(dev);
status = Qspi_Ip_RunCommand(data->instance, memory_cfg->statusConfig.writeEnableSRLut, 0U);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to enable SR write (%d)", status);
ret = -EIO;
}
nxp_s32_qspi_unlock(dev);
return ret;
}
static int nxp_s32_qspi_write_status_register(const struct device *dev,
uint8_t reg_num,
uint8_t val)
{
const struct nxp_s32_qspi_config *config = dev->config;
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_StatusType status;
uint8_t buf[2] = { 0 };
uint16_t lut_idx;
size_t size;
int ret;
if (reg_num == 1) {
/* buf = [val] or [val, SR2] */
lut_idx = QSPI_LUT_IDX(QSPI_SEQ_WRSR);
size = 1U;
buf[0] = val;
if (config->qer_type == JESD216_DW15_QER_S2B1v1) {
/* Writing SR1 clears SR2 */
size = 2U;
ret = nxp_s32_qspi_read_status_register(dev, 2, &buf[1]);
if (ret < 0) {
return ret;
}
}
} else if (reg_num == 2) {
/* buf = [val] or [SR1, val] */
if ((config->qer_type == JESD216_DW15_QER_VAL_S2B1v1) ||
(config->qer_type == JESD216_DW15_QER_VAL_S2B1v4) ||
(config->qer_type == JESD216_DW15_QER_VAL_S2B1v5)) {
/* Writing SR2 requires writing SR1 as well */
lut_idx = QSPI_LUT_IDX(QSPI_SEQ_WRSR);
size = 2U;
buf[1] = val;
ret = nxp_s32_qspi_read_status_register(dev, 1, &buf[0]);
if (ret < 0) {
return ret;
}
} else {
lut_idx = QSPI_LUT_IDX(QSPI_SEQ_WRSR2);
size = 1U;
buf[0] = val;
}
} else {
return -EINVAL;
}
nxp_s32_qspi_lock(dev);
status = Qspi_Ip_RunWriteCommand(data->instance, lut_idx, 0U, (const uint8_t *)buf,
(uint32_t)size);
if (status == STATUS_QSPI_IP_SUCCESS) {
/* Wait for the write command to complete */
ret = nxp_s32_qspi_wait_until_ready(dev);
} else {
LOG_ERR("Failed to write to SR%u (%d)", reg_num, status);
ret = -EIO;
}
nxp_s32_qspi_unlock(dev);
return ret;
}
static int nxp_s32_qspi_set_quad_mode(const struct device *dev, bool enabled)
{
const struct nxp_s32_qspi_config *config = dev->config;
uint8_t sr_num;
uint8_t sr_val;
uint8_t qe_mask;
bool qe_state;
int ret;
switch (config->qer_type) {
case JESD216_DW15_QER_NONE:
/* no QE bit, device detects reads based on opcode */
return 0;
case JESD216_DW15_QER_S1B6:
sr_num = 1U;
qe_mask = BIT(6U);
break;
case JESD216_DW15_QER_S2B7:
sr_num = 2U;
qe_mask = BIT(7U);
break;
case JESD216_DW15_QER_S2B1v1:
__fallthrough;
case JESD216_DW15_QER_S2B1v4:
__fallthrough;
case JESD216_DW15_QER_S2B1v5:
__fallthrough;
case JESD216_DW15_QER_S2B1v6:
sr_num = 2U;
qe_mask = BIT(1U);
break;
default:
return -ENOTSUP;
}
ret = nxp_s32_qspi_read_status_register(dev, sr_num, &sr_val);
if (ret < 0) {
return ret;
}
qe_state = ((sr_val & qe_mask) != 0U);
if (qe_state == enabled) {
return 0;
}
sr_val ^= qe_mask;
ret = nxp_s32_qspi_write_enable(dev);
if (ret < 0) {
return ret;
}
ret = nxp_s32_qspi_write_status_register(dev, sr_num, sr_val);
if (ret < 0) {
return ret;
}
/* Verify write was successful */
ret = nxp_s32_qspi_read_status_register(dev, sr_num, &sr_val);
if (ret < 0) {
return ret;
}
qe_state = ((sr_val & qe_mask) != 0U);
if (qe_state != enabled) {
LOG_ERR("Failed to %s Quad mode", enabled ? "enable" : "disable");
return -EIO;
}
return ret;
}
#endif /* !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) */
static int nxp_s32_qspi_read(const struct device *dev, off_t offset, void *dest, size_t size)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_StatusType status;
int ret = 0;
if (!dest) {
return -EINVAL;
}
if (!area_is_subregion(dev, offset, size)) {
return -ENODEV;
}
if (size) {
nxp_s32_qspi_lock(dev);
status = Qspi_Ip_Read(data->instance, (uint32_t)offset, (uint8_t *)dest,
(uint32_t)size);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to read %zu bytes at 0x%lx (%d)",
size, offset, status);
ret = -EIO;
}
nxp_s32_qspi_unlock(dev);
}
return ret;
}
static int nxp_s32_qspi_write(const struct device *dev, off_t offset, const void *src, size_t size)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
Qspi_Ip_StatusType status;
size_t max_write = (size_t)MIN(QSPI_IP_MAX_WRITE_SIZE, memory_cfg->pageSize);
size_t len;
int ret = 0;
if (!src) {
return -EINVAL;
}
if (!area_is_subregion(dev, offset, size)) {
return -ENODEV;
}
nxp_s32_qspi_lock(dev);
while (size) {
len = MIN(max_write - (offset % max_write), size);
status = Qspi_Ip_Program(data->instance, (uint32_t)offset,
(const uint8_t *)src, (uint32_t)len);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to write %zu bytes at 0x%lx (%d)",
len, offset, status);
ret = -EIO;
break;
}
ret = nxp_s32_qspi_wait_until_ready(dev);
if (ret != 0) {
break;
}
if (IS_ENABLED(CONFIG_FLASH_NXP_S32_QSPI_VERIFY_WRITE)) {
status = Qspi_Ip_ProgramVerify(data->instance, (uint32_t)offset,
(const uint8_t *)src, (uint32_t)len);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Write verification failed at 0x%lx (%d)",
offset, status);
ret = -EIO;
break;
}
}
size -= len;
src = (const uint8_t *)src + len;
offset += len;
}
nxp_s32_qspi_unlock(dev);
return ret;
}
static int nxp_s32_qspi_erase_block(const struct device *dev, off_t offset,
size_t size, size_t *erase_size)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
Qspi_Ip_EraseVarConfigType *etp = NULL;
Qspi_Ip_EraseVarConfigType *etp_tmp;
Qspi_Ip_StatusType status;
int ret = 0;
/*
* Find the erase type with bigger size that can erase all or part of the
* requested memory size
*/
for (uint8_t i = 0; i < QSPI_IP_ERASE_TYPES; i++) {
etp_tmp = (Qspi_Ip_EraseVarConfigType *)&(memory_cfg->eraseSettings.eraseTypes[i]);
if ((etp_tmp->eraseLut != QSPI_IP_LUT_INVALID)
&& QSPI_IS_ALIGNED(offset, etp_tmp->size)
&& (BIT(etp_tmp->size) <= size)
&& ((etp == NULL) || (etp_tmp->size > etp->size))) {
etp = etp_tmp;
}
}
if (etp != NULL) {
*erase_size = BIT(etp->size);
status = Qspi_Ip_EraseBlock(data->instance, (uint32_t)offset, *erase_size);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to erase %zu bytes at 0x%lx (%d)",
*erase_size, (long)offset, status);
ret = -EIO;
}
} else {
LOG_ERR("Can't find erase size to erase %zu bytes", size);
ret = -EINVAL;
}
return ret;
}
static int nxp_s32_qspi_erase(const struct device *dev, off_t offset, size_t size)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
Qspi_Ip_StatusType status;
size_t erase_size;
int ret = 0;
if (!area_is_subregion(dev, offset, size)) {
return -ENODEV;
}
nxp_s32_qspi_lock(dev);
if (size == memory_cfg->memSize) {
status = Qspi_Ip_EraseChip(data->instance);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to erase chip (%d)", status);
ret = -EIO;
}
} else {
while (size > 0) {
erase_size = 0;
ret = nxp_s32_qspi_erase_block(dev, offset, size, &erase_size);
if (ret != 0) {
break;
}
ret = nxp_s32_qspi_wait_until_ready(dev);
if (ret != 0) {
break;
}
if (IS_ENABLED(CONFIG_FLASH_NXP_S32_QSPI_VERIFY_ERASE)) {
status = Qspi_Ip_EraseVerify(data->instance, (uint32_t)offset,
erase_size);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Erase verification failed at 0x%lx (%d)",
offset, status);
ret = -EIO;
break;
}
}
offset += erase_size;
size -= erase_size;
}
}
nxp_s32_qspi_unlock(dev);
return ret;
}
#if defined(CONFIG_FLASH_JESD216_API) || !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
static int nxp_s32_qspi_read_id(const struct device *dev, uint8_t *id)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_StatusType status;
int ret = 0;
nxp_s32_qspi_lock(dev);
status = Qspi_Ip_ReadId(data->instance, id);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to read device ID (%d)", status);
ret = -EIO;
}
nxp_s32_qspi_unlock(dev);
return ret;
}
#endif /* CONFIG_FLASH_JESD216_API || !CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME */
#if defined(CONFIG_FLASH_JESD216_API)
static int nxp_s32_qspi_sfdp_read(const struct device *dev, off_t offset, void *buf, size_t len)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_StatusType status;
int ret = 0;
nxp_s32_qspi_lock(dev);
status = Qspi_Ip_RunReadCommand(data->instance, data->read_sfdp_lut_idx,
(uint32_t)offset, (uint8_t *)buf, NULL, (uint32_t)len);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Failed to read SFDP at 0x%lx (%d)", offset, status);
ret = -EIO;
}
nxp_s32_qspi_unlock(dev);
return ret;
}
#endif /* CONFIG_FLASH_JESD216_API */
#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
static int nxp_s32_qspi_sfdp_config(const struct device *dev)
{
struct nxp_s32_qspi_data *data = dev->data;
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
Qspi_Ip_StatusType status;
/* Populate memory configuration with values obtained from SFDP */
memory_cfg->memType = QSPI_IP_SERIAL_FLASH;
memory_cfg->lutSequences.opCount = QSPI_SFDP_LUT_SIZE;
memory_cfg->lutSequences.lutOps = (Qspi_Ip_InstrOpType *)data->lut_ops;
memory_cfg->initConfiguration.opCount = QSPI_SFDP_INIT_OP_SIZE;
memory_cfg->initConfiguration.operations = (Qspi_Ip_InitOperationType *)data->init_ops;
status = Qspi_Ip_ReadSfdp(memory_cfg, &data->memory_conn_cfg);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Fail to read SFDP (%d)", status);
return -EIO;
}
#if defined(CONFIG_FLASH_JESD216_API)
/* The HAL does not populate LUTs for read SFDP and read ID */
uint8_t lut_idx = QSPI_SFDP_LUT_SIZE;
for (int i = 0; i < QSPI_SFDP_LUT_SIZE - 1; i++) {
if ((data->lut_ops[i] == QSPI_IP_LUT_SEQ_END)
&& (data->lut_ops[i+1] == QSPI_IP_LUT_SEQ_END)) {
lut_idx = i + 1;
break;
}
}
/* Make sure there's enough space to add the LUT sequences */
if ((lut_idx + QSPI_JESD216_SEQ_SIZE - 1) >= QSPI_SFDP_LUT_SIZE) {
return -ENOMEM;
}
data->read_sfdp_lut_idx = lut_idx;
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1,
JESD216_CMD_READ_SFDP);
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U);
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U);
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 16U);
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END,
QSPI_IP_LUT_SEQ_END);
memory_cfg->readIdSettings.readIdLut = lut_idx;
memory_cfg->readIdSettings.readIdSize = JESD216_READ_ID_LEN;
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1,
JESD216_CMD_READ_ID);
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1,
JESD216_READ_ID_LEN);
data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END,
QSPI_IP_LUT_SEQ_END);
#endif /* CONFIG_FLASH_JESD216_API */
return 0;
}
#endif
static const struct flash_parameters *nxp_s32_qspi_get_parameters(const struct device *dev)
{
const struct nxp_s32_qspi_config *config = dev->config;
return &config->flash_parameters;
}
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
static void nxp_s32_qspi_pages_layout(const struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
const struct nxp_s32_qspi_config *config = dev->config;
*layout = &config->layout;
*layout_size = 1;
}
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
static int nxp_s32_qspi_init(const struct device *dev)
{
struct nxp_s32_qspi_data *data = dev->data;
const struct nxp_s32_qspi_config *config = dev->config;
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
Qspi_Ip_StatusType status;
static uint8_t instance_cnt;
int ret = 0;
/* Used by the HAL to retrieve the internal driver state */
data->instance = instance_cnt++;
__ASSERT_NO_MSG(data->instance < QSPI_IP_MEM_INSTANCE_COUNT);
data->memory_conn_cfg.qspiInstance = memc_nxp_s32_qspi_get_instance(config->controller);
#if defined(CONFIG_MULTITHREADING)
k_sem_init(&data->sem, 1, 1);
#endif
#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
nxp_s32_qspi_sfdp_config(dev);
#endif
/* Init memory device connected to the bus */
status = Qspi_Ip_Init(data->instance,
(const Qspi_Ip_MemoryConfigType *)memory_cfg,
(const Qspi_Ip_MemoryConnectionType *)&data->memory_conn_cfg);
if (status != STATUS_QSPI_IP_SUCCESS) {
LOG_ERR("Fail to init memory device %d (%d)", data->instance, status);
return -EIO;
}
#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME)
uint8_t jedec_id[JESD216_READ_ID_LEN];
/* Verify connectivity by reading the device ID */
ret = nxp_s32_qspi_read_id(dev, jedec_id);
if (ret != 0) {
LOG_ERR("JEDEC ID read failed (%d)", ret);
return -ENODEV;
}
/*
* Check the memory device ID against the one configured from devicetree
* to verify we are talking to the correct device.
*/
if (memcmp(jedec_id, memory_cfg->readIdSettings.readIdExpected, sizeof(jedec_id)) != 0) {
LOG_ERR("Device id %02x %02x %02x does not match config %02x %02x %02x",
jedec_id[0], jedec_id[1], jedec_id[2],
memory_cfg->readIdSettings.readIdExpected[0],
memory_cfg->readIdSettings.readIdExpected[1],
memory_cfg->readIdSettings.readIdExpected[2]);
return -EINVAL;
}
ret = nxp_s32_qspi_set_quad_mode(dev, config->quad_mode);
if (ret < 0) {
return ret;
}
#endif /* !CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME */
return ret;
}
static const struct flash_driver_api nxp_s32_qspi_api = {
.erase = nxp_s32_qspi_erase,
.write = nxp_s32_qspi_write,
.read = nxp_s32_qspi_read,
.get_parameters = nxp_s32_qspi_get_parameters,
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
.page_layout = nxp_s32_qspi_pages_layout,
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
#if defined(CONFIG_FLASH_JESD216_API)
.sfdp_read = nxp_s32_qspi_sfdp_read,
.read_jedec_id = nxp_s32_qspi_read_id,
#endif /* CONFIG_FLASH_JESD216_API */
};
#define QSPI_PAGE_LAYOUT(n) \
.layout = { \
.pages_count = (DT_INST_PROP(n, size) / 8) \
/ CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \
.pages_size = CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \
}
#define QSPI_READ_ID_CFG(n) \
{ \
.readIdLut = QSPI_LUT_IDX(QSPI_SEQ_RDID), \
.readIdSize = DT_INST_PROP_LEN(n, jedec_id), \
.readIdExpected = DT_INST_PROP(n, jedec_id), \
}
#define QSPI_MEMORY_CONN_CFG(n) \
{ \
.connectionType = (Qspi_Ip_ConnectionType)DT_INST_REG_ADDR(n), \
.memAlignment = DT_INST_PROP_OR(n, memory_alignment, 1) \
}
#define QSPI_ERASE_CFG(n) \
{ \
.eraseTypes = { \
{ \
.eraseLut = QSPI_LUT_IDX(QSPI_SEQ_SE), \
.size = 12, /* 4 KB */ \
}, \
{ \
.eraseLut = QSPI_LUT_IDX(QSPI_SEQ_BE), \
.size = 16, /* 64 KB */ \
}, \
COND_CODE_1(DT_INST_PROP(n, has_32k_erase), ( \
{ \
.eraseLut = QSPI_LUT_IDX(QSPI_SEQ_BE_32K), \
.size = 15, /* 32 KB */ \
}, \
), ( \
{ \
.eraseLut = QSPI_IP_LUT_INVALID, \
}, \
)) \
{ \
.eraseLut = QSPI_IP_LUT_INVALID, \
}, \
}, \
.chipEraseLut = QSPI_LUT_IDX(QSPI_SEQ_CE), \
}
#define QSPI_RESET_CFG(n) \
{ \
.resetCmdLut = QSPI_LUT_IDX(QSPI_SEQ_RESET), \
.resetCmdCount = 4U, \
}
/*
* SR information used internally by the HAL to access fields BUSY and WEL
* during read/write/erase and polling status operations.
*/
#define QSPI_STATUS_REG_CFG(n) \
{ \
.statusRegInitReadLut = QSPI_LUT_IDX(QSPI_SEQ_RDSR), \
.statusRegReadLut = QSPI_LUT_IDX(QSPI_SEQ_RDSR), \
.statusRegWriteLut = QSPI_LUT_IDX(QSPI_SEQ_WRSR), \
.writeEnableSRLut = QSPI_LUT_IDX(QSPI_SEQ_WREN), \
.writeEnableLut = QSPI_LUT_IDX(QSPI_SEQ_WREN), \
.regSize = 1U, \
.busyOffset = 0U, \
.busyValue = 1U, \
.writeEnableOffset = 1U, \
}
#define QSPI_INIT_CFG(n) \
{ \
.opCount = 0U, \
.operations = NULL, \
}
#define QSPI_LUT_CFG(n) \
{ \
.opCount = ARRAY_SIZE(nxp_s32_qspi_lut), \
.lutOps = (Qspi_Ip_InstrOpType *)nxp_s32_qspi_lut, \
}
#define QSPI_MEMORY_CFG(n) \
{ \
.memType = QSPI_IP_SERIAL_FLASH, \
.hfConfig = NULL, \
.memSize = DT_INST_PROP(n, size) / 8, \
.pageSize = CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \
.writeLut = QSPI_LUT_IDX(QSPI_WRITE_SEQ(n)), \
.readLut = QSPI_LUT_IDX(QSPI_READ_SEQ(n)), \
.read0xxLut = QSPI_IP_LUT_INVALID, \
.read0xxLutAHB = QSPI_IP_LUT_INVALID, \
.eraseSettings = QSPI_ERASE_CFG(n), \
.statusConfig = QSPI_STATUS_REG_CFG(n), \
.resetSettings = QSPI_RESET_CFG(n), \
.initResetSettings = QSPI_RESET_CFG(n), \
.initConfiguration = QSPI_INIT_CFG(n), \
.lutSequences = QSPI_LUT_CFG(n), \
COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \
.readIdSettings = QSPI_READ_ID_CFG(n),) \
) \
.suspendSettings = { \
.eraseSuspendLut = QSPI_IP_LUT_INVALID, \
.eraseResumeLut = QSPI_IP_LUT_INVALID, \
.programSuspendLut = QSPI_IP_LUT_INVALID, \
.programResumeLut = QSPI_IP_LUT_INVALID, \
}, \
.initCallout = NULL, \
.resetCallout = NULL, \
.errorCheckCallout = NULL, \
.eccCheckCallout = NULL, \
.ctrlAutoCfgPtr = NULL, \
}
#define FLASH_NXP_S32_QSPI_INIT_DEVICE(n) \
COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \
BUILD_ASSERT(DT_INST_NODE_HAS_PROP(n, jedec_id), \
"jedec-id is required for non-runtime SFDP"); \
BUILD_ASSERT(DT_INST_PROP_LEN(n, jedec_id) == JESD216_READ_ID_LEN,\
"jedec-id must be of size JESD216_READ_ID_LEN bytes"); \
)) \
\
static const struct nxp_s32_qspi_config nxp_s32_qspi_config_##n = { \
.controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
.flash_parameters = { \
.write_block_size = QSPI_WRITE_BLOCK_SIZE, \
.erase_value = QSPI_ERASE_VALUE, \
}, \
IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, \
(QSPI_PAGE_LAYOUT(n),)) \
COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \
.memory_cfg = QSPI_MEMORY_CFG(n), \
.qer_type = QSPI_QER_TYPE(n), \
.quad_mode = QSPI_HAS_QUAD_MODE(n) \
)) \
}; \
\
static struct nxp_s32_qspi_data nxp_s32_qspi_data_##n = { \
.memory_conn_cfg = QSPI_MEMORY_CONN_CFG(n), \
COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \
.read_sfdp_lut_idx = QSPI_LUT_IDX(QSPI_SEQ_READ_SFDP), \
)) \
}; \
\
DEVICE_DT_INST_DEFINE(n, \
nxp_s32_qspi_init, \
NULL, \
&nxp_s32_qspi_data_##n, \
&nxp_s32_qspi_config_##n, \
POST_KERNEL, \
CONFIG_FLASH_INIT_PRIORITY, \
&nxp_s32_qspi_api);
DT_INST_FOREACH_STATUS_OKAY(FLASH_NXP_S32_QSPI_INIT_DEVICE)