Browse Source

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 <cong.nguyenhuu@nxp.com>
pull/84302/head
Cong Nguyen Huu 10 months ago committed by Benjamin Cabé
parent
commit
f0c4d1c53c
  1. 4
      boards/nxp/mr_canhubk3/mr_canhubk3.dts
  2. 1
      drivers/flash/CMakeLists.txt
  3. 2
      drivers/flash/Kconfig.nxp_s32
  4. 274
      drivers/flash/flash_nxp_s32_qspi.c
  5. 111
      drivers/flash/flash_nxp_s32_qspi.h
  6. 365
      drivers/flash/flash_nxp_s32_qspi_nor.c
  7. 16
      dts/bindings/mtd/nxp,s32-qspi-device.yaml
  8. 2
      tests/drivers/flash/common/testcase.yaml

4
boards/nxp/mr_canhubk3/mr_canhubk3.dts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2023 NXP
* Copyright 2023-2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -344,6 +344,8 @@ @@ -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 {

1
drivers/flash/CMakeLists.txt

@ -149,6 +149,7 @@ zephyr_library_include_directories_ifdef( @@ -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

2
drivers/flash/Kconfig.nxp_s32

@ -16,7 +16,7 @@ config FLASH_NXP_S32_QSPI_NOR @@ -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.

274
drivers/flash/flash_nxp_s32_qspi.c

@ -0,0 +1,274 @@ @@ -0,0 +1,274 @@
/*
* Copyright 2023-2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/logging/log.h>
#include <Qspi_Ip.h>
#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 */

111
drivers/flash/flash_nxp_s32_qspi.h

@ -0,0 +1,111 @@ @@ -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_ */

365
drivers/flash/flash_nxp_s32_qspi_nor.c

@ -1,5 +1,5 @@ @@ -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); @@ -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); @@ -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 { @@ -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] = { @@ -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) @@ -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 * @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) = { @@ -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) = { @@ -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) = { @@ -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) = { @@ -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) = { @@ -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) = { @@ -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), \
)) \
}; \

16
dts/bindings/mtd/nxp,s32-qspi-device.yaml

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
# Copyright 2023 NXP
# Copyright 2023-2024 NXP
# SPDX-License-Identifier: Apache-2.0
description: |
@ -14,9 +14,15 @@ properties: @@ -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.

2
tests/drivers/flash/common/testcase.yaml

@ -65,7 +65,7 @@ tests: @@ -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:

Loading…
Cancel
Save