From f0c4d1c53c9503ab08bcdf899ccc387decc31f58 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 10 Sep 2024 08:37:37 +0530 Subject: [PATCH] drivers: flash_nxp_s32: create common source code Create common source code to use for supporting HyperFlash. Rename 'FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME' to 'FLASH_NXP_S32_QSPI_SFDP_RUNTIME' as a common kconfig. Add the 'max-program-buffer-size' property to use for setting memory pageSize, instead of using 'CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE' for setting. Add the 'write-block-size' propertyto use for setting the number of bytes used in write operations, it also uses to instead of the 'memory-alignment' property. Signed-off-by: Cong Nguyen Huu --- boards/nxp/mr_canhubk3/mr_canhubk3.dts | 4 +- drivers/flash/CMakeLists.txt | 1 + drivers/flash/Kconfig.nxp_s32 | 2 +- drivers/flash/flash_nxp_s32_qspi.c | 274 ++++++++++++++++ drivers/flash/flash_nxp_s32_qspi.h | 111 +++++++ drivers/flash/flash_nxp_s32_qspi_nor.c | 365 ++-------------------- dts/bindings/mtd/nxp,s32-qspi-device.yaml | 16 +- tests/drivers/flash/common/testcase.yaml | 2 +- 8 files changed, 420 insertions(+), 355 deletions(-) create mode 100644 drivers/flash/flash_nxp_s32_qspi.c create mode 100644 drivers/flash/flash_nxp_s32_qspi.h diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3.dts b/boards/nxp/mr_canhubk3/mr_canhubk3.dts index 6abf6438d9b..c8df4985fbf 100644 --- a/boards/nxp/mr_canhubk3/mr_canhubk3.dts +++ b/boards/nxp/mr_canhubk3/mr_canhubk3.dts @@ -1,5 +1,5 @@ /* - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -344,6 +344,8 @@ readoc = "1-4-4"; writeoc = "1-4-4"; has-32k-erase; + max-program-buffer-size = <256>; + write-block-size = <1>; status = "okay"; partitions { diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 617f1422a90..ef7e779fdd6 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -149,6 +149,7 @@ zephyr_library_include_directories_ifdef( ) zephyr_library_sources_ifdef(CONFIG_FLASH_NXP_S32_QSPI_NOR flash_nxp_s32_qspi_nor.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_NXP_S32_QSPI_NOR flash_nxp_s32_qspi.c) zephyr_library_include_directories_ifdef( CONFIG_FLASH_NXP_S32_QSPI_NOR ${ZEPHYR_BASE}/drivers/memc diff --git a/drivers/flash/Kconfig.nxp_s32 b/drivers/flash/Kconfig.nxp_s32 index 47db1ab654e..459a7b2376f 100644 --- a/drivers/flash/Kconfig.nxp_s32 +++ b/drivers/flash/Kconfig.nxp_s32 @@ -16,7 +16,7 @@ config FLASH_NXP_S32_QSPI_NOR if FLASH_NXP_S32_QSPI_NOR -config FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME +config FLASH_NXP_S32_QSPI_SFDP_RUNTIME bool "Read flash parameters at runtime" help Read flash device characteristics from the device at runtime. diff --git a/drivers/flash/flash_nxp_s32_qspi.c b/drivers/flash/flash_nxp_s32_qspi.c new file mode 100644 index 00000000000..424960935ba --- /dev/null +++ b/drivers/flash/flash_nxp_s32_qspi.c @@ -0,0 +1,274 @@ +/* + * Copyright 2023-2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include "flash_nxp_s32_qspi.h" + +LOG_MODULE_REGISTER(flash_nxp_s32_qspi, CONFIG_FLASH_LOG_LEVEL); + +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) && + ((memory_cfg->memSize - offset) >= size)); +} + +uint8_t nxp_s32_qspi_register_device(void) +{ + static uint8_t instance_cnt; + + return instance_cnt++; +} + +/* Must be called with lock */ +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; +} + +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 -EINVAL; + } + + 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; +} + +int nxp_s32_qspi_write(const struct device *dev, off_t offset, const void *src, size_t size) +{ + const struct nxp_s32_qspi_config *config = dev->config; + 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 || !size) { + return -EINVAL; + } + + if (!area_is_subregion(dev, offset, size) || + (offset % config->flash_parameters.write_block_size) || + (size % config->flash_parameters.write_block_size)) { + return -EINVAL; + } + + 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; +} + +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) || !size) { + return -EINVAL; + } + + 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; +} + +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) +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 */ + +#if defined(CONFIG_FLASH_JESD216_API) || !defined(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME) +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_SFDP_RUNTIME */ diff --git a/drivers/flash/flash_nxp_s32_qspi.h b/drivers/flash/flash_nxp_s32_qspi.h new file mode 100644 index 00000000000..5a296ca4d66 --- /dev/null +++ b/drivers/flash/flash_nxp_s32_qspi.h @@ -0,0 +1,111 @@ +/* + * Copyright 2023-2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_FLASH_NXP_S32_QSPI_H_ +#define ZEPHYR_DRIVERS_FLASH_NXP_S32_QSPI_H_ + +#include "jesd216.h" + +#define QSPI_ERASE_VALUE 0xff + +#define QSPI_IS_ALIGNED(addr, bits) (((addr) & BIT_MASK(bits)) == 0) + +#if defined(CONFIG_FLASH_NXP_S32_QSPI_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_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_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_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 +}; + +static ALWAYS_INLINE Qspi_Ip_MemoryConfigType *get_memory_config(const struct device *dev) +{ +#if defined(CONFIG_FLASH_NXP_S32_QSPI_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 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 +} + +/* + * This function retrieves the device instance used by the HAL + * to access the internal driver state. + */ +uint8_t nxp_s32_qspi_register_device(void); + +int nxp_s32_qspi_wait_until_ready(const struct device *dev); + +int nxp_s32_qspi_read(const struct device *dev, off_t offset, void *dest, size_t size); + +int nxp_s32_qspi_write(const struct device *dev, off_t offset, const void *src, size_t size); + +int nxp_s32_qspi_erase(const struct device *dev, off_t offset, size_t size); + +const struct flash_parameters *nxp_s32_qspi_get_parameters(const struct device *dev); + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +void nxp_s32_qspi_pages_layout(const struct device *dev, const struct flash_pages_layout **layout, + size_t *layout_size); +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +#if defined(CONFIG_FLASH_JESD216_API) || !defined(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME) +int nxp_s32_qspi_read_id(const struct device *dev, uint8_t *id); +#endif /* CONFIG_FLASH_JESD216_API || !CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME */ + +#endif /* ZEPHYR_DRIVERS_FLASH_NXP_S32_QSPI_H_ */ diff --git a/drivers/flash/flash_nxp_s32_qspi_nor.c b/drivers/flash/flash_nxp_s32_qspi_nor.c index 9250b3ec0ea..b7c13290b3a 100644 --- a/drivers/flash/flash_nxp_s32_qspi_nor.c +++ b/drivers/flash/flash_nxp_s32_qspi_nor.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,7 @@ LOG_MODULE_REGISTER(nxp_s32_qspi_nor, CONFIG_FLASH_LOG_LEVEL); #include "jesd216.h" #include "memc_nxp_s32_qspi.h" +#include "flash_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), \ @@ -55,52 +56,9 @@ LOG_MODULE_REGISTER(nxp_s32_qspi_nor, CONFIG_FLASH_LOG_LEVEL); (_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, @@ -145,7 +103,7 @@ enum { #endif }; -#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +#if !defined(CONFIG_FLASH_NXP_S32_QSPI_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), @@ -309,73 +267,9 @@ static const Qspi_Ip_InstrOpType nxp_s32_qspi_lut[][QSPI_LUT_ENTRY_SIZE] = { }, #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; -} +#endif /* !defined(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME) */ -#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +#if !defined(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME) static int nxp_s32_qspi_read_status_register(const struct device *dev, uint8_t reg_num, uint8_t *val) @@ -565,210 +459,7 @@ static int nxp_s32_qspi_set_quad_mode(const struct device *dev, bool enabled) 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 */ +#endif /* !defined(CONFIG_FLASH_NXP_S32_QSPI_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) @@ -792,7 +483,7 @@ static int nxp_s32_qspi_sfdp_read(const struct device *dev, off_t offset, void * } #endif /* CONFIG_FLASH_JESD216_API */ -#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +#if defined(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME) static int nxp_s32_qspi_sfdp_config(const struct device *dev) { struct nxp_s32_qspi_data *data = dev->data; @@ -852,36 +543,16 @@ static int nxp_s32_qspi_sfdp_config(const struct device *dev) } #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++; + data->instance = nxp_s32_qspi_register_device(); __ASSERT_NO_MSG(data->instance < QSPI_IP_MEM_INSTANCE_COUNT); data->memory_conn_cfg.qspiInstance = memc_nxp_s32_qspi_get_instance(config->controller); @@ -889,7 +560,7 @@ static int nxp_s32_qspi_init(const struct device *dev) k_sem_init(&data->sem, 1, 1); #endif -#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +#if defined(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME) nxp_s32_qspi_sfdp_config(dev); #endif @@ -903,7 +574,7 @@ static int nxp_s32_qspi_init(const struct device *dev) } -#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +#if !defined(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME) uint8_t jedec_id[JESD216_READ_ID_LEN]; /* Verify connectivity by reading the device ID */ @@ -930,7 +601,7 @@ static int nxp_s32_qspi_init(const struct device *dev) if (ret < 0) { return ret; } -#endif /* !CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME */ +#endif /* !CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME */ return ret; } @@ -966,7 +637,7 @@ static DEVICE_API(flash, nxp_s32_qspi_api) = { #define QSPI_MEMORY_CONN_CFG(n) \ { \ .connectionType = (Qspi_Ip_ConnectionType)DT_INST_REG_ADDR(n), \ - .memAlignment = DT_INST_PROP_OR(n, memory_alignment, 1) \ + .memAlignment = DT_INST_PROP(n, write_block_size) \ } #define QSPI_ERASE_CFG(n) \ @@ -1037,7 +708,7 @@ static DEVICE_API(flash, nxp_s32_qspi_api) = { .memType = QSPI_IP_SERIAL_FLASH, \ .hfConfig = NULL, \ .memSize = DT_INST_PROP(n, size) / 8, \ - .pageSize = CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \ + .pageSize = DT_INST_PROP(n, max_program_buffer_size), \ .writeLut = QSPI_LUT_IDX(QSPI_WRITE_SEQ(n)), \ .readLut = QSPI_LUT_IDX(QSPI_READ_SEQ(n)), \ .read0xxLut = QSPI_IP_LUT_INVALID, \ @@ -1048,7 +719,7 @@ static DEVICE_API(flash, nxp_s32_qspi_api) = { .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, (), ( \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME, (), ( \ .readIdSettings = QSPI_READ_ID_CFG(n),) \ ) \ .suspendSettings = { \ @@ -1065,7 +736,7 @@ static DEVICE_API(flash, nxp_s32_qspi_api) = { } #define FLASH_NXP_S32_QSPI_INIT_DEVICE(n) \ - COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_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,\ @@ -1075,12 +746,12 @@ static DEVICE_API(flash, nxp_s32_qspi_api) = { 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, \ + .write_block_size = DT_INST_PROP(n, 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, (), ( \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME, (), ( \ .memory_cfg = QSPI_MEMORY_CFG(n), \ .qer_type = QSPI_QER_TYPE(n), \ .quad_mode = QSPI_HAS_QUAD_MODE(n) \ @@ -1089,7 +760,7 @@ static DEVICE_API(flash, nxp_s32_qspi_api) = { \ 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, (), ( \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME, (), ( \ .read_sfdp_lut_idx = QSPI_LUT_IDX(QSPI_SEQ_READ_SFDP), \ )) \ }; \ diff --git a/dts/bindings/mtd/nxp,s32-qspi-device.yaml b/dts/bindings/mtd/nxp,s32-qspi-device.yaml index 23de077121e..889c3995f01 100644 --- a/dts/bindings/mtd/nxp,s32-qspi-device.yaml +++ b/dts/bindings/mtd/nxp,s32-qspi-device.yaml @@ -1,4 +1,4 @@ -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 description: | @@ -14,9 +14,15 @@ properties: reg: required: true - memory-alignment: + max-program-buffer-size: type: int + required: true + description: | + The maximum of programming page buffer size of the flash memory device, + as specified in the flash memory device datasheet. + + write-block-size: + type: int + required: true description: | - Memory alignment in bytes, used to calculate padding when performing - unaligned accesses. - If not provided, 1 byte alignment will be selected. + The number of bytes used in write operations. diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index 700c411066c..3eec21e19c8 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -65,7 +65,7 @@ tests: drivers.flash.common.mr_canhubk3_sfdp_runtime: platform_allow: mr_canhubk3 extra_configs: - - CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME=y + - CONFIG_FLASH_NXP_S32_QSPI_SFDP_RUNTIME=y drivers.flash.common.spi_nor: platform_allow: nrf52840dk/nrf52840 extra_configs: