From 265db8a3b88c9ccfc26e037ab139ff4dd103894a Mon Sep 17 00:00:00 2001 From: Ruijia Wang Date: Mon, 1 Sep 2025 22:31:41 +0800 Subject: [PATCH 1/6] drivers: xspi: add NXP xspi driver Add mcux xspi driver suppport. Add the flash and psram driver support based on xspi driver. Signed-off-by: Ruijia Wang --- drivers/flash/CMakeLists.txt | 11 + drivers/flash/Kconfig.mcux | 12 + drivers/flash/flash_mcux_xspi.c | 555 ++++++++++++++++++ drivers/memc/CMakeLists.txt | 6 + drivers/memc/Kconfig.mcux | 24 +- drivers/memc/memc_mcux_xspi.c | 257 ++++++++ drivers/memc/memc_mcux_xspi.h | 82 +++ drivers/memc/memc_mcux_xspi_psram.c | 373 ++++++++++++ .../mcux/mcux-sdk-ng/drivers/drivers.cmake | 8 + 9 files changed, 1327 insertions(+), 1 deletion(-) create mode 100644 drivers/flash/flash_mcux_xspi.c create mode 100644 drivers/memc/memc_mcux_xspi.c create mode 100644 drivers/memc/memc_mcux_xspi.h create mode 100644 drivers/memc/memc_mcux_xspi_psram.c diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 2ff0f66a59084..6508a4aaef484 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_INFINEON_CAT1 flash_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_HYPERFLASH flash_mcux_flexspi_hyperflash.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G flash_mcux_flexspi_mx25um51345g.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_NOR flash_mcux_flexspi_nor.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_XSPI flash_mcux_xspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_ATXP032 flash_mspi_atxp032.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_EMUL_DEVICE flash_mspi_emul_device.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_IS25XX0XX flash_mspi_is25xX0xx.c) @@ -100,6 +101,11 @@ if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) endif() endif() +if(CONFIG_FLASH_MCUX_XSPI_XIP) + zephyr_code_relocate(FILES flash_mcux_xspi.c LOCATION ${CONFIG_FLASH_MCUX_XSPI_XIP_MEM}_TEXT) + zephyr_code_relocate(FILES flash_mcux_xspi.c LOCATION ${CONFIG_FLASH_MCUX_XSPI_XIP_MEM}_RODATA) +endif() + if(CONFIG_SOC_FLASH_STM32) zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) if(CONFIG_SOC_SERIES_STM32H7X) @@ -160,6 +166,11 @@ zephyr_library_include_directories_ifdef( ${ZEPHYR_BASE}/drivers/memc ) +zephyr_library_include_directories_ifdef( + CONFIG_FLASH_MCUX_XSPI + ${ZEPHYR_BASE}/drivers/memc +) + 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_HYPERFLASH flash_nxp_s32_qspi_hyperflash.c) if(CONFIG_FLASH_NXP_S32_QSPI_NOR OR CONFIG_FLASH_NXP_S32_QSPI_HYPERFLASH) diff --git a/drivers/flash/Kconfig.mcux b/drivers/flash/Kconfig.mcux index dc15e01a394c5..17a2e7772cb44 100644 --- a/drivers/flash/Kconfig.mcux +++ b/drivers/flash/Kconfig.mcux @@ -118,3 +118,15 @@ choice FLASH_LOG_LEVEL_CHOICE endchoice endif # DT_HAS_NXP_IMX_FLEXSPI_ENABLED + +config FLASH_MCUX_XSPI + bool "MCUX XSPI flash driver" + default y + depends on DT_HAS_NXP_XSPI_NOR_ENABLED + select MEMC + select MEMC_MCUX_XSPI + select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_EXPLICIT_ERASE + help + Enable the mcux xspi flash driver. diff --git a/drivers/flash/flash_mcux_xspi.c b/drivers/flash/flash_mcux_xspi.c new file mode 100644 index 0000000000000..ea2fb16fd7ef7 --- /dev/null +++ b/drivers/flash/flash_mcux_xspi.c @@ -0,0 +1,555 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_xspi_nor + +#include +#include +#include +#include +#include +#include +#include +#include "memc_mcux_xspi.h" +#include "spi_nor.h" + +LOG_MODULE_REGISTER(flash_mcux_xspi); + +#define FLASH_MCUX_XSPI_LUT_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0][0])) + +#define FLASH_BUSY_STATUS_OFFSET 0 +#define FLASH_WE_STATUS_OFFSET 7 + +#define FLASH_MX25_WRCR2_DTR_OPI_ENABLE_OFFSET (1U << 1) + +enum { + FLASH_CMD_MEM_READ, + FLASH_CMD_READ_STATUS, + FLASH_CMD_READ_STATUS_OPI, + FLASH_CMD_WRITE_ENABLE, + FLASH_CMD_WRITE_ENABLE_OPI, + FLASH_CMD_PAGEPROGRAM_OCTAL, + FLASH_CMD_ERASE_SECTOR, + FLASH_CMD_READ_ID_OPI, + FLASH_CMD_ENTER_OPI, +}; + +struct flash_mcux_xspi_config { + bool enable_differential_clk; + xspi_sample_clk_config_t sample_clk_config; +}; + +struct flash_mcux_xspi_data { + xspi_config_t xspi_config; + const struct device *xspi_dev; + const char *dev_name; + uint32_t amba_address; + struct flash_parameters flash_param; + uint64_t flash_size; +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + struct flash_pages_layout layout; +#endif +}; + +/* + * Errata ERR052528: Limitation on LUT-Data Size < 8byte in xspi. + * Description: Read command including RDSR command can't work if LUT data size in read status is + * less than 8. Workaround: Use LUT data size of minimum 8 byte for read commands including RDSR. + */ +static const uint32_t flash_xspi_lut[][5] = { + /* Memory read. */ + [FLASH_CMD_MEM_READ] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0xEE, kXSPI_Command_DDR, + kXSPI_8PAD, 0x11), + XSPI_LUT_SEQ(kXSPI_Command_RADDR_DDR, kXSPI_8PAD, 0x20, + kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, 0x12), + XSPI_LUT_SEQ(kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, 0x2, + kXSPI_Command_READ_DDR, kXSPI_8PAD, 0x8), + XSPI_LUT_SEQ(kXSPI_Command_STOP, kXSPI_8PAD, 0x0, 0, 0, 0), + }, + + /* Read status SPI. */ + [FLASH_CMD_READ_STATUS] = { + XSPI_LUT_SEQ(kXSPI_Command_SDR, kXSPI_1PAD, 0x05, kXSPI_Command_READ_SDR, + kXSPI_1PAD, 0x08), + }, + + /* Read Status OPI. */ + [FLASH_CMD_READ_STATUS_OPI] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0x05, kXSPI_Command_DDR, + kXSPI_8PAD, 0xFA), + XSPI_LUT_SEQ(kXSPI_Command_RADDR_DDR, kXSPI_8PAD, 0x20, + kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, 0x12), + XSPI_LUT_SEQ(kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, 0x2, + kXSPI_Command_READ_DDR, kXSPI_8PAD, 0x8), + XSPI_LUT_SEQ(kXSPI_Command_STOP, kXSPI_8PAD, 0x0, 0, 0, 0), + }, + + /* Write enable. */ + [FLASH_CMD_WRITE_ENABLE] = { + XSPI_LUT_SEQ(kXSPI_Command_SDR, kXSPI_1PAD, 0x06, kXSPI_Command_STOP, + kXSPI_1PAD, 0x04), + }, + + /* Write Enable - OPI. */ + [FLASH_CMD_WRITE_ENABLE_OPI] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0x06, kXSPI_Command_DDR, + kXSPI_8PAD, 0xF9), + }, + + /* Read ID. */ + [FLASH_CMD_READ_ID_OPI] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0x9F, kXSPI_Command_DDR, + kXSPI_8PAD, 0x60), + XSPI_LUT_SEQ(kXSPI_Command_RADDR_DDR, kXSPI_8PAD, 0x20, + kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, 0x04), + XSPI_LUT_SEQ(kXSPI_Command_READ_DDR, kXSPI_8PAD, 0x08, kXSPI_Command_STOP, + kXSPI_1PAD, 0x0), + }, + + /* Erase Sector. */ + [FLASH_CMD_ERASE_SECTOR] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0x21, kXSPI_Command_DDR, + kXSPI_8PAD, 0xDE), + XSPI_LUT_SEQ(kXSPI_Command_RADDR_DDR, kXSPI_8PAD, 0x20, kXSPI_Command_STOP, + kXSPI_8PAD, 0x0), + }, + + /* Enable OPI DDR mode. */ + [FLASH_CMD_ENTER_OPI] = { + XSPI_LUT_SEQ(kXSPI_Command_SDR, kXSPI_1PAD, 0x72, kXSPI_Command_SDR, + kXSPI_1PAD, 0x00), + XSPI_LUT_SEQ(kXSPI_Command_SDR, kXSPI_1PAD, 0x00, kXSPI_Command_SDR, + kXSPI_1PAD, 0x00), + XSPI_LUT_SEQ(kXSPI_Command_SDR, kXSPI_1PAD, 0x00, kXSPI_Command_WRITE_SDR, + kXSPI_1PAD, 0x01), + }, + + /* Page program. */ + [FLASH_CMD_PAGEPROGRAM_OCTAL] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0x12, kXSPI_Command_DDR, kXSPI_8PAD, + 0xED), + XSPI_LUT_SEQ(kXSPI_Command_RADDR_DDR, kXSPI_8PAD, 0x20, kXSPI_Command_WRITE_DDR, + kXSPI_8PAD, 0x8), + }}; + +/* Memory devices table. */ +static struct memc_xspi_dev_config device_configs[] = { + { + .name_prefix = "mx25um51345g", + .xspi_dev_config = { + .deviceInterface = kXSPI_StrandardExtendedSPI, + .interfaceSettings.strandardExtendedSPISettings.pageSize = 256, + .CSHoldTime = 2, + .CSSetupTime = 2, + .addrMode = kXSPI_DeviceByteAddressable, + .columnAddrWidth = 0, + .enableCASInterleaving = false, + .ptrDeviceDdrConfig = + &(xspi_device_ddr_config_t){ + .ddrDataAlignedClk = + kXSPI_DDRDataAlignedWith2xInternalRefClk, + .enableByteSwapInOctalMode = false, + .enableDdr = true, + }, + .deviceSize = {64 * 1024, 64 * 1024}, + }, + .lut_array = &flash_xspi_lut[0][0], + .lut_count = FLASH_MCUX_XSPI_LUT_ARRAY_SIZE(flash_xspi_lut), + }, +}; + +static int flash_xspi_nor_wait_bus_busy(const struct device *dev, bool enableOctal) +{ + struct flash_mcux_xspi_data *devData = dev->data; + const struct device *xspi_dev = devData->xspi_dev; + xspi_transfer_t flashXfer; + uint32_t readValue; + bool isBusy; + int ret; + + flashXfer.deviceAddress = devData->amba_address; + flashXfer.cmdType = kXSPI_Read; + flashXfer.data = &readValue; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.dataSize = enableOctal ? 2 : 1; + flashXfer.seqIndex = enableOctal ? FLASH_CMD_READ_STATUS_OPI : FLASH_CMD_READ_STATUS; + flashXfer.lockArbitration = false; + + do { + ret = memc_mcux_xspi_transfer(xspi_dev, &flashXfer); + if (ret < 0) { + break; + } + + isBusy = (readValue & (1U << FLASH_BUSY_STATUS_OFFSET)) ? true : false; + } while (isBusy); + + return ret; +} + +static int flash_mcux_xspi_read(const struct device *dev, off_t offset, void *data, size_t len) +{ + struct flash_mcux_xspi_data *devData = dev->data; + uint8_t *src = (uint8_t *)devData->amba_address + offset; + + if (len == 0) { + return 0; + } + + if (!data) { + return -EINVAL; + } + + if ((offset < 0) || (offset >= devData->flash_size) || + ((devData->flash_size - offset) < len)) { + return -EINVAL; + } + + XSPI_Cache64_InvalidateCacheByRange((uint32_t)src, len); + + (void)memcpy(data, src, len); + + return 0; +} + +static int flash_mcux_xspi_write_enable(const struct device *dev, uint32_t baseAddr, + bool enableOctal) +{ + struct flash_mcux_xspi_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + xspi_transfer_t flashXfer; + + flashXfer.deviceAddress = data->amba_address + baseAddr; + flashXfer.cmdType = kXSPI_Command; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.data = NULL; + flashXfer.dataSize = 0; + flashXfer.lockArbitration = false; + flashXfer.seqIndex = enableOctal ? FLASH_CMD_WRITE_ENABLE_OPI : FLASH_CMD_WRITE_ENABLE; + + return memc_mcux_xspi_transfer(xspi_dev, &flashXfer); +} + +static int flash_mcux_xspi_write(const struct device *dev, off_t offset, const void *data, + size_t len) +{ + struct flash_mcux_xspi_data *devData = dev->data; + const struct device *xspi_dev = devData->xspi_dev; + uint8_t *p_data = (uint8_t *)(uintptr_t)data; + xspi_transfer_t flashXfer; + size_t write_size; + uint32_t key = 0; + int ret = 0; + + if (memc_xspi_is_running_xip(xspi_dev)) { + key = irq_lock(); + memc_xspi_wait_bus_idle(xspi_dev); + } + + while (len > 0) { + write_size = MIN(len, SPI_NOR_PAGE_SIZE); + + ret = flash_mcux_xspi_write_enable(dev, 0, true); + if (ret < 0) { + break; + } + + flashXfer.deviceAddress = devData->amba_address + offset; + flashXfer.cmdType = kXSPI_Write; + flashXfer.seqIndex = FLASH_CMD_PAGEPROGRAM_OCTAL; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.data = (uint32_t *)p_data; + flashXfer.dataSize = write_size; + flashXfer.lockArbitration = false; + + ret = memc_mcux_xspi_transfer(xspi_dev, &flashXfer); + if (ret < 0) { + break; + } + + ret = flash_xspi_nor_wait_bus_busy(dev, true); + if (ret < 0) { + break; + } + + len -= write_size; + p_data = p_data + write_size; + offset += write_size; + } + + if (memc_xspi_is_running_xip(xspi_dev)) { + irq_unlock(key); + } + + return ret; +} + +static int flash_mcux_xspi_erase_sector(const struct device *dev, off_t offset) +{ + struct flash_mcux_xspi_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + xspi_transfer_t flashXfer; + + flashXfer.deviceAddress = data->amba_address + offset; + flashXfer.cmdType = kXSPI_Command; + flashXfer.seqIndex = FLASH_CMD_ERASE_SECTOR; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.lockArbitration = false; + flashXfer.dataSize = 0; + flashXfer.data = NULL; + + return memc_mcux_xspi_transfer(xspi_dev, &flashXfer); +} + +static int flash_mcux_xspi_erase(const struct device *dev, off_t offset, size_t size) +{ + struct flash_mcux_xspi_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + uint32_t key = 0; + int ret = 0; + + if (0 != (offset % SPI_NOR_SECTOR_SIZE)) { + LOG_ERR("Invalid offset"); + return -EINVAL; + } + + if (size % SPI_NOR_SECTOR_SIZE) { + LOG_ERR("Invalid size"); + return -EINVAL; + } + + if (memc_xspi_is_running_xip(xspi_dev)) { + key = irq_lock(); + memc_xspi_wait_bus_idle(xspi_dev); + } + + for (int i = 0; i < size / SPI_NOR_SECTOR_SIZE; i++) { + ret = flash_mcux_xspi_write_enable(dev, 0, true); + if (ret < 0) { + break; + } + + ret = flash_mcux_xspi_erase_sector(dev, offset + i * SPI_NOR_SECTOR_SIZE); + if (ret < 0) { + break; + } + + ret = flash_xspi_nor_wait_bus_busy(dev, true); + if (ret < 0) { + break; + } + } + + if (memc_xspi_is_running_xip(xspi_dev)) { + irq_unlock(key); + } + + return ret; +} + +static int flash_mcux_xspi_enable_opi(const struct device *dev) +{ + uint32_t value = FLASH_MX25_WRCR2_DTR_OPI_ENABLE_OFFSET; + struct flash_mcux_xspi_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + xspi_transfer_t flashXfer; + int ret; + + ret = flash_mcux_xspi_write_enable(dev, 0, true); + if (ret < 0) { + return ret; + } + + flashXfer.deviceAddress = data->amba_address; + flashXfer.cmdType = kXSPI_Write; + flashXfer.seqIndex = FLASH_CMD_ENTER_OPI; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.data = &value; + flashXfer.dataSize = 1; + flashXfer.lockArbitration = false; + + ret = memc_mcux_xspi_transfer(xspi_dev, &flashXfer); + if (ret < 0) { + return ret; + } + + return flash_xspi_nor_wait_bus_busy(dev, true); +} + +static const struct flash_parameters *flash_mcux_xspi_get_parameters(const struct device *dev) +{ + return &((const struct flash_mcux_xspi_data *)dev->data)->flash_param; +} + +static int flash_mcux_xspi_get_size(const struct device *dev, uint64_t *size) +{ + *size = ((const struct flash_mcux_xspi_data *)dev->data)->flash_size; + + return 0; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void flash_mcux_xspi_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + struct flash_mcux_xspi_data *data = dev->data; + + *layout = &data->layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +#if defined(CONFIG_FLASH_JESD216_API) +static int flash_mcux_xspi_sfdp_read(const struct device *dev, off_t offset, void *data, size_t len) +{ + return -EOPNOTSUPP; +} + +static int flash_mcux_xspi_read_jedec_id(const struct device *dev, uint8_t *id) +{ + struct flash_mcux_xspi_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + xspi_transfer_t flashXfer; + + flashXfer.deviceAddress = data->amba_address; + flashXfer.cmdType = kXSPI_Read; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.seqIndex = FLASH_CMD_READ_ID_OPI; + flashXfer.data = id; + flashXfer.dataSize = 1; + flashXfer.lockArbitration = false; + + return memc_mcux_xspi_transfer(xspi_dev, &flashXfer); +} +#endif /* CONFIG_FLASH_JESD216_API */ + +static int flash_mcux_xspi_probe(const struct device *dev) +{ + const struct flash_mcux_xspi_config *flash_config = + (const struct flash_mcux_xspi_config *)dev->config; + struct flash_mcux_xspi_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + struct memc_xspi_dev_config *flash_dev_config = NULL; + xspi_device_config_t *dev_config = NULL; + uint32_t key = 0; + int ret; + + if (memc_xspi_is_running_xip(xspi_dev)) { + key = irq_lock(); + memc_xspi_wait_bus_idle(xspi_dev); + } + + /* Setup the specific flash parameters. */ + for (uint32_t i = 0; i < ARRAY_SIZE(device_configs); i++) { + if (strncmp(device_configs[i].name_prefix, data->dev_name, + strlen(device_configs[i].name_prefix)) == 0) { + flash_dev_config = &device_configs[i]; + break; + } + } + + do { + if (flash_dev_config == NULL) { + LOG_ERR("Unsupported device: %s", data->dev_name); + ret = -ENOTSUP; + break; + } + + /* Set special device configurations. */ + dev_config = &flash_dev_config->xspi_dev_config; + dev_config->enableCknPad = flash_config->enable_differential_clk; + dev_config->sampleClkConfig = flash_config->sample_clk_config; + + ret = memc_mcux_xspi_get_root_clock(xspi_dev, &dev_config->xspiRootClk); + if (ret < 0) { + break; + } + + ret = memc_xspi_set_device_config(xspi_dev, dev_config, flash_dev_config->lut_array, + flash_dev_config->lut_count); + } while (0); + + if (memc_xspi_is_running_xip(xspi_dev)) { + irq_unlock(key); + } + + return ret; +} + +static int flash_mcux_xspi_init(const struct device *dev) +{ + struct flash_mcux_xspi_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + int ret; + + if (!device_is_ready(xspi_dev)) { + LOG_ERR("XSPI device is not ready"); + return -ENODEV; + } + + ret = flash_mcux_xspi_probe(dev); + if (ret < 0) { + return ret; + } + + data->amba_address = memc_mcux_xspi_get_ahb_address(xspi_dev); + + return flash_mcux_xspi_enable_opi(dev); +} + +static DEVICE_API(flash, flash_mcux_xspi_api) = { + .read = flash_mcux_xspi_read, + .write = flash_mcux_xspi_write, + .erase = flash_mcux_xspi_erase, + .get_parameters = flash_mcux_xspi_get_parameters, + .get_size = flash_mcux_xspi_get_size, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_mcux_xspi_pages_layout, +#endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = flash_mcux_xspi_sfdp_read, + .read_jedec_id = flash_mcux_xspi_read_jedec_id, +#endif +}; + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +#define FLASH_MCUX_XSPI_LAYOUT(n) \ + .layout.pages_size = SPI_NOR_SECTOR_SIZE, \ + .layout.pages_count = DT_INST_PROP(n, size) / SPI_NOR_SECTOR_SIZE, +#else +#define FLASH_MCUX_XSPI_LAYOUT(n) +#endif + +#define FLASH_MCUX_XSPI_INIT(n) \ + static const struct flash_mcux_xspi_config flash_mcux_xspi_config_##n = { \ + .sample_clk_config.sampleClkSource = DT_INST_PROP(n, sample_clk_source), \ + .sample_clk_config.enableDQSLatency = DT_INST_PROP(n, enable_dqs_latency), \ + .sample_clk_config.dllConfig = { \ + .dllMode = kXSPI_AutoUpdateMode, \ + .useRefValue = true, \ + .enableCdl8 = true, \ + }, \ + }; \ + static struct flash_mcux_xspi_data flash_mcux_xspi_data_##n = { \ + .xspi_dev = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .dev_name = DT_INST_PROP(n, device_name), \ + .flash_param = { \ + .write_block_size = 1, \ + .erase_value = 0xFF, \ + .caps = { \ + .no_explicit_erase = false, \ + }, \ + }, \ + .flash_size = DT_INST_PROP(n, size), \ + FLASH_MCUX_XSPI_LAYOUT(n) \ + }; \ + DEVICE_DT_INST_DEFINE(n, &flash_mcux_xspi_init, NULL, &flash_mcux_xspi_data_##n, \ + &flash_mcux_xspi_config_##n, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_mcux_xspi_api); + +DT_INST_FOREACH_STATUS_OKAY(FLASH_MCUX_XSPI_INIT) diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index 2520652f9652e..df49de7b407b9 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -13,6 +13,12 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_W956A8MBYA memc_mcux_flexs if((DEFINED CONFIG_FLASH_MCUX_FLEXSPI_XIP) AND (DEFINED CONFIG_FLASH)) zephyr_code_relocate(FILES memc_mcux_flexspi.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) endif() +zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_XSPI memc_mcux_xspi.c) +if((DEFINED CONFIG_FLASH_MCUX_XSPI_XIP) AND (DEFINED CONFIG_FLASH)) + zephyr_code_relocate(FILES memc_mcux_xspi.c LOCATION ${CONFIG_FLASH_MCUX_XSPI_XIP_MEM}_TEXT) + zephyr_code_relocate(FILES memc_mcux_xspi.c LOCATION ${CONFIG_FLASH_MCUX_XSPI_XIP_MEM}_RODATA) +endif() +zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_XSPI_PSRAM memc_mcux_xspi_psram.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MSPI_APS6404L memc_mspi_aps6404l.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MSPI_APS_Z8 memc_mspi_aps_z8.c) diff --git a/drivers/memc/Kconfig.mcux b/drivers/memc/Kconfig.mcux index 54dc92144d927..1abd0726e6ba0 100644 --- a/drivers/memc/Kconfig.mcux +++ b/drivers/memc/Kconfig.mcux @@ -1,4 +1,4 @@ -# Copyright 2020-2023 NXP +# Copyright 2020-2023, 2025 NXP # Copyright (c) 2021 Basalte bv # Copyright (c) 2023, ithinx GmbH # Copyright (c) 2023, Tonies GmbH @@ -66,3 +66,25 @@ choice MEMC_LOG_LEVEL_CHOICE endchoice endif # DT_HAS_NXP_IMX_FLEXSPI_ENABLED + +config MEMC_MCUX_XSPI_INIT_XIP + bool "Initialize XSPI when using device for XIP" + help + Initialize the XSPI device even when using it for XIP. If this + Kconfig is enabled, the user must ensure that the pin control + state used does not reconfigure the pins used to interface with + the flash device used for XIP, and that the configuration settings + used for the XSPI are compatible with those needed for XIP from + the flash device. + +config MEMC_MCUX_XSPI_PSRAM + bool "MCUX XSPI psram driver" + default y + depends on DT_HAS_NXP_XSPI_PSRAM_ENABLED + select MEMC_MCUX_XSPI + help + Enable the mcux xspi psram driver. + +config MEMC_MCUX_XSPI + bool + select PINCTRL diff --git a/drivers/memc/memc_mcux_xspi.c b/drivers/memc/memc_mcux_xspi.c new file mode 100644 index 0000000000000..82d09943e96d0 --- /dev/null +++ b/drivers/memc/memc_mcux_xspi.c @@ -0,0 +1,257 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_xspi + +#include +#include +#include +#include +#include +#include "memc_mcux_xspi.h" + +LOG_MODULE_REGISTER(memc_mcux_xspi, CONFIG_MEMC_LOG_LEVEL); + +#define MEMC_XSPI_TARGET_GROUP_COUNT 2 +#define MEMC_XSPI_SFP_FRAD_COUNT 8 + +struct memc_mcux_xspi_config { + const struct pinctrl_dev_config *pincfg; + xspi_config_t xspi_config; + xspi_sfp_mdad_config_t mdad_configs; + bool mdad_valid; + xspi_sfp_frad_config_t frad_configs; + bool frad_valid; +}; + +struct memc_mcux_xspi_data { + XSPI_Type *base; + bool xip; + uint32_t amba_address; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; +}; + +void memc_mcux_xspi_update_device_addr_mode(const struct device *dev, + xspi_device_addr_mode_t addr_mode) +{ + XSPI_Type *base = ((struct memc_mcux_xspi_data *)dev->data)->base; + + XSPI_UpdateDeviceAddrMode(base, addr_mode); +} + +int memc_mcux_xspi_get_root_clock(const struct device *dev, uint32_t *clock_rate) +{ + struct memc_mcux_xspi_data *data = dev->data; + + return clock_control_get_rate(data->clock_dev, data->clock_subsys, clock_rate); +} + +void memc_xspi_wait_bus_idle(const struct device *dev) +{ + struct memc_mcux_xspi_data *data = dev->data; + + while (!XSPI_GetBusIdleStatus(data->base)) { + } +} + +int memc_xspi_set_device_config(const struct device *dev, const xspi_device_config_t *device_config, + const uint32_t *lut_array, uint8_t lut_count) +{ + struct memc_mcux_xspi_data *data = dev->data; + XSPI_Type *base = data->base; + status_t status; + + /* Configure flash settings according to serial flash feature. */ + status = XSPI_SetDeviceConfig(base, (xspi_device_config_t *)device_config); + if (status != kStatus_Success) { + LOG_ERR("XSPI_SetDeviceConfig failed with status %u\n", status); + return -ENODEV; + } + + XSPI_UpdateLUT(base, 0, lut_array, lut_count); + + return 0; +} + +uint32_t memc_mcux_xspi_get_ahb_address(const struct device *dev) +{ + return ((const struct memc_mcux_xspi_data *)dev->data)->amba_address; +} + +int memc_mcux_xspi_transfer(const struct device *dev, xspi_transfer_t *xfer) +{ + XSPI_Type *base = ((struct memc_mcux_xspi_data *)dev->data)->base; + status_t status; + + status = XSPI_TransferBlocking(base, xfer); + + return (status == kStatus_Success) ? 0 : -EIO; +} + +bool memc_xspi_is_running_xip(const struct device *dev) +{ + return ((const struct memc_mcux_xspi_data *)dev->data)->xip; +} + +static int memc_mcux_xspi_init(const struct device *dev) +{ + const struct memc_mcux_xspi_config *memc_xspi_config = dev->config; + const struct pinctrl_dev_config *pincfg = memc_xspi_config->pincfg; + xspi_config_t config = memc_xspi_config->xspi_config; + XSPI_Type *base = ((struct memc_mcux_xspi_data *)dev->data)->base; + int ret; + + if ((memc_xspi_is_running_xip(dev)) && (!IS_ENABLED(CONFIG_MEMC_MCUX_XSPI_INIT_XIP))) { + LOG_DBG("XIP active on %s, skipping init\n", dev->name); + return 0; + } + + ret = pinctrl_apply_state(pincfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to apply pinctrl state: %d", ret); + return ret; + } + + config.ptrAhbAccessConfig->ahbAlignment = kXSPI_AhbAlignmentNoLimit; + config.ptrAhbAccessConfig->ahbSplitSize = kXSPI_AhbSplitSizeDisabled; + + for (uint8_t i = 0U; i < XSPI_BUFCR_COUNT; i++) { + config.ptrAhbAccessConfig->buffer[i].masterId = i; + if (i == (XSPI_BUFCR_COUNT - 1U)) { + config.ptrAhbAccessConfig->buffer[i].enaPri.enableAllMaster = true; + } else { + config.ptrAhbAccessConfig->buffer[i].enaPri.enablePriority = false; + } + config.ptrAhbAccessConfig->buffer[i].bufferSize = 0x80U; + config.ptrAhbAccessConfig->buffer[i].ptrSubBuffer0Config = NULL; + config.ptrAhbAccessConfig->buffer[i].ptrSubBuffer1Config = NULL; + config.ptrAhbAccessConfig->buffer[i].ptrSubBuffer2Config = NULL; + config.ptrAhbAccessConfig->buffer[i].ptrSubBuffer3Config = NULL; + } + + if (memc_xspi_config->mdad_valid) { + config.ptrIpAccessConfig->ptrSfpMdadConfig = + (xspi_sfp_mdad_config_t *)&memc_xspi_config->mdad_configs; + } + if (memc_xspi_config->frad_valid) { + config.ptrIpAccessConfig->ptrSfpFradConfig = + (xspi_sfp_frad_config_t *)&memc_xspi_config->frad_configs; + } + + XSPI_Init(base, &config); + + return 0; +} + +#if defined(CONFIG_XIP) && defined(CONFIG_FLASH_MCUX_XSPI_XIP) +/* Checks if image flash base address is in the XSPI AHB base region */ +#define MEMC_XSPI_CFG_XIP(n) \ + ((CONFIG_FLASH_BASE_ADDRESS) >= DT_INST_REG_ADDR_BY_IDX(n, 1)) && \ + ((CONFIG_FLASH_BASE_ADDRESS) < \ + (DT_INST_REG_ADDR_BY_IDX(n, 1) + DT_INST_REG_SIZE_BY_IDX(n, 1))) + +#else +#define MEMC_XSPI_CFG_XIP(node_id) false +#endif + +#define MCUX_XSPI_GET_MDAD(n, idx, x) \ + DT_PROP(DT_CHILD(DT_DRV_INST(n), mdad_tg ## idx), x) +#define MCUX_XSPI_GET_FRAD(n, idx, x) \ + DT_PROP(DT_CHILD(DT_DRV_INST(n), frad_region ## idx), x) + +#define MCUX_XSPI_MDAD_INIT(idx, n) \ + COND_CODE_1(DT_NODE_EXISTS(DT_CHILD(DT_DRV_INST(n), mdad_tg ## idx)), \ + ({ \ + .enableDescriptorLock = \ + MCUX_XSPI_GET_MDAD(n, idx, enable_descriptor_lock), \ + .maskType = MCUX_XSPI_GET_MDAD(n, idx, mask_type), \ + .mask = MCUX_XSPI_GET_MDAD(n, idx, mask), \ + .masterIdReference = \ + MCUX_XSPI_GET_MDAD(n, idx, master_id_reference), \ + .secureAttribute = \ + MCUX_XSPI_GET_MDAD(n, idx, secure_attribute), \ + }), \ + ({ \ + 0 \ + })) + +#define MCUX_XSPI_FRAD_INIT(idx, n) \ + COND_CODE_1(DT_NODE_EXISTS(DT_CHILD(DT_DRV_INST(n), frad_region ## idx)), \ + ({ \ + .startAddress = MCUX_XSPI_GET_FRAD(n, idx, start_address), \ + .endAddress = MCUX_XSPI_GET_FRAD(n, idx, end_address), \ + .tg0MasterAccess = \ + MCUX_XSPI_GET_FRAD(n, idx, tg0_master_access), \ + .tg1MasterAccess = \ + MCUX_XSPI_GET_FRAD(n, idx, tg1_master_access), \ + .assignIsValid = true, \ + .descriptorLock = \ + MCUX_XSPI_GET_FRAD(n, idx, descriptor_lock), \ + .exclusiveAccessLock = \ + MCUX_XSPI_GET_FRAD(n, idx, exclusive_access_lock), \ + }), \ + ({ \ + 0 \ + })) + +#define MCUX_XSPI_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static const struct memc_mcux_xspi_config memc_mcux_xspi_config_##n = { \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .xspi_config = { \ + .byteOrder = DT_INST_PROP(n, byte_order), \ + .enableDoze = false, \ + .ptrAhbAccessConfig = &(xspi_ahb_access_config_t){ \ + .ahbErrorPayload = { \ + .highPayload = 0x5A5A5A5A, \ + .lowPayload = 0x5A5A5A5A, \ + }, \ + .ARDSeqIndex = 0, \ + .enableAHBBufferWriteFlush = \ + DT_INST_PROP(n, ahb_buffer_write_flush), \ + .enableAHBPrefetch = DT_INST_PROP(n, ahb_prefetch), \ + .ptrAhbWriteConfig = DT_INST_PROP(n, enable_ahb_write) ? \ + &(xspi_ahb_write_config_t){ \ + .AWRSeqIndex = 1, \ + .ARDSRSeqIndex = 0, \ + .blockRead = false, \ + .blockSequenceWrite = false, \ + } : NULL, \ + }, \ + .ptrIpAccessConfig = &(xspi_ip_access_config_t){ \ + .ipAccessTimeoutValue = 0xFFFFFFFF, \ + .ptrSfpFradConfig = NULL, \ + .ptrSfpMdadConfig = NULL, \ + .sfpArbitrationLockTimeoutValue = 0xFFFFFF, \ + }, \ + }, \ + .mdad_configs = { \ + .tgMdad = { \ + LISTIFY(MEMC_XSPI_TARGET_GROUP_COUNT, \ + MCUX_XSPI_MDAD_INIT, (,), n) \ + }, \ + }, \ + .mdad_valid = DT_NODE_EXISTS(DT_CHILD(DT_DRV_INST(n), mdad_tg0)), \ + .frad_configs = { \ + .fradConfig = { \ + LISTIFY(MEMC_XSPI_SFP_FRAD_COUNT, MCUX_XSPI_FRAD_INIT, (,), n) \ + }, \ + }, \ + .frad_valid = DT_NODE_EXISTS(DT_CHILD(DT_DRV_INST(n), frad_region0)), \ + }; \ + static struct memc_mcux_xspi_data memc_mcux_xspi_data_##n = { \ + .base = (XSPI_Type *)DT_INST_REG_ADDR(n), \ + .xip = MEMC_XSPI_CFG_XIP(n), \ + .amba_address = DT_INST_REG_ADDR_BY_IDX(n, 1), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ + }; \ + DEVICE_DT_INST_DEFINE(n, &memc_mcux_xspi_init, NULL, \ + &memc_mcux_xspi_data_##n, &memc_mcux_xspi_config_##n, \ + POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MCUX_XSPI_INIT) diff --git a/drivers/memc/memc_mcux_xspi.h b/drivers/memc/memc_mcux_xspi.h new file mode 100644 index 0000000000000..50f7e7961a8ab --- /dev/null +++ b/drivers/memc/memc_mcux_xspi.h @@ -0,0 +1,82 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_MEMC_MCUX_XSPI_H_ +#define ZEPHYR_DRIVERS_MEMC_MCUX_XSPI_H_ + +#include +#include + +struct memc_xspi_dev_config { + const char *name_prefix; + xspi_device_config_t xspi_dev_config; + const uint32_t *lut_array; + size_t lut_count; +}; + +/** + * @brief Update device address mode. + * + * @param dev: XSPI device + * @param addr_mode: Address mode. + */ +void memc_mcux_xspi_update_device_addr_mode(const struct device *dev, + xspi_device_addr_mode_t addr_mode); + +/** + * @brief Get XSPI root clock frequency with Hz. + * + * @return 0 on success, negative value on failure + */ +int memc_mcux_xspi_get_root_clock(const struct device *dev, uint32_t *clock_rate); + +/** + * @brief Wait the XSPI bus idle status. + * + * @param dev: XSPI device + */ +void memc_xspi_wait_bus_idle(const struct device *dev); + +/** + * @brief Check whether XSPI is running in XIP mode. + * + * @return 0 - Not in XIP mode, 1 - In XIP mode. + */ +bool memc_xspi_is_running_xip(const struct device *dev); + +/** + * @brief XSPI transfer function. + * + * Configures new device on the XSPI bus. + * @param dev: XSPI device + * @param xfer: XSPI transfer structure. + * @return 0 on success, negative value on failure + */ +int memc_mcux_xspi_transfer(const struct device *dev, xspi_transfer_t *xfer); + +/** + * @brief Configure new XSPI device + * + * Configures new device on the XSPI bus. + * @param dev: XSPI device + * @param device_config: External device configuration. + * @param lut_array: Lookup table of XSPI flash commands for device + * @param lut_count: number of LUT entries (4 bytes each) in lut array + * @return 0 on success, negative value on failure + */ +int memc_xspi_set_device_config(const struct device *dev, const xspi_device_config_t *device_config, + const uint32_t *lut_array, uint8_t lut_count); + +/** + * @brief Get AHB address for XSPI + * + * This address is memory mapped, and can be read and written as though it were internal memory. + * @param dev: XSPI device + * @return AHB access address for XSPI device + */ +uint32_t memc_mcux_xspi_get_ahb_address(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_MEMC_MCUX_XSPI_H_ */ diff --git a/drivers/memc/memc_mcux_xspi_psram.c b/drivers/memc/memc_mcux_xspi_psram.c new file mode 100644 index 0000000000000..3a47d7b53dba9 --- /dev/null +++ b/drivers/memc/memc_mcux_xspi_psram.c @@ -0,0 +1,373 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_xspi_psram + +#include +#include +#include +#include +#include +#include "memc_mcux_xspi.h" + +LOG_MODULE_REGISTER(memc_mcux_xspi_psram, CONFIG_MEMC_LOG_LEVEL); + +#define MEMC_MCUX_XSPI_LUT_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0][0])) + +#define ID0_REG_ADDR (0U) +#define CR0_REG_ADDR (0x800U) +#define CR1_REG_ADDR (0x801U) + +#define ID0_REG_ID_MASK (0xFU) + +#define CR0_REG_DRIVE_STRENGTH_SHIFT 4U +#define CR0_REG_DRIVE_STRENGTH_MASK (0x07U << CR0_REG_DRIVE_STRENGTH_SHIFT) +#define CR0_REG_DRIVE_STRENGTH_46OHMS 3U +#define CR0_REG_VARIABLE_LATENCY_MASK (1U << 3) + +#define CR1_DIFFERENTIAL_CLOCK_SHIFT 6U +#define CR1_DIFFERENTIAL_CLOCK_MASK (1U << CR1_DIFFERENTIAL_CLOCK_SHIFT) + +enum { + PSRAM_MANUFACTURER_ID_WINBOND = 0x6U, +}; + +enum { + PSRAM_CMD_MEM_READ, + PSRAM_CMD_MEM_WRITE, + PSRAM_CMD_REG_READ, + PSRAM_CMD_REG_WRITE, +}; + +struct memc_mcux_xspi_psram_config { + bool enable_differential_clk; + xspi_sample_clk_config_t sample_clk_config; +}; + +struct memc_mcux_xspi_psram_data { + const struct device *xspi_dev; + const char *dev_name; + uint32_t amba_address; + uint32_t size; +}; + +const uint32_t memc_xspi_w958d6nbkx_lut[][5] = { + /* Memory Read */ + [PSRAM_CMD_MEM_READ] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0xA0, kXSPI_Command_RADDR_DDR, + kXSPI_8PAD, 0x18), + XSPI_LUT_SEQ(kXSPI_Command_CADDR_DDR, kXSPI_8PAD, 0x10, + kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, 6), + XSPI_LUT_SEQ(kXSPI_Command_READ_DDR, kXSPI_8PAD, 0x08, kXSPI_Command_STOP, + kXSPI_1PAD, 0x0), + }, + + /* Memory Write */ + [PSRAM_CMD_MEM_WRITE] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0x20, kXSPI_Command_RADDR_DDR, + kXSPI_8PAD, 0x18), + XSPI_LUT_SEQ(kXSPI_Command_CADDR_DDR, kXSPI_8PAD, 0x10, + kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, 6), + XSPI_LUT_SEQ(kXSPI_Command_WRITE_DDR, kXSPI_8PAD, 0x08, kXSPI_Command_STOP, + kXSPI_1PAD, 0X0), + }, + + /* Register Read */ + [PSRAM_CMD_REG_READ] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0xE0, kXSPI_Command_RADDR_DDR, + kXSPI_8PAD, 0x18), + XSPI_LUT_SEQ(kXSPI_Command_CADDR_DDR, kXSPI_8PAD, 0x10, + kXSPI_Command_DUMMY_SDR, kXSPI_8PAD, + 6), /* Dummy cycle: 2 * 6 + 2 */ + XSPI_LUT_SEQ(kXSPI_Command_READ_DDR, kXSPI_8PAD, 0x08, kXSPI_Command_STOP, + kXSPI_1PAD, 0x0), + }, + + /* Register write */ + [PSRAM_CMD_REG_WRITE] = { + XSPI_LUT_SEQ(kXSPI_Command_DDR, kXSPI_8PAD, 0x60, kXSPI_Command_RADDR_DDR, + kXSPI_8PAD, 0x18), + XSPI_LUT_SEQ(kXSPI_Command_CADDR_DDR, kXSPI_8PAD, 0x10, + kXSPI_Command_WRITE_DDR, kXSPI_8PAD, 0x08), + XSPI_LUT_SEQ(kXSPI_Command_STOP, kXSPI_1PAD, 0x0, kXSPI_Command_STOP, + kXSPI_1PAD, 0x0), + }, +}; + +/* Memory devices table. */ +static struct memc_xspi_dev_config dev_configs[] = { + { + .name_prefix = "w958d6nbkx", + .xspi_dev_config = { + .deviceInterface = kXSPI_HyperBus, + .interfaceSettings.hyperBusSettings.x16Mode = kXSPI_x16ModeEnabledOnlyData, + .interfaceSettings.hyperBusSettings.enableVariableLatency = true, + .interfaceSettings.hyperBusSettings.forceBit10To1 = false, + .interfaceSettings.hyperBusSettings.pageSize = 1024, + .CSHoldTime = 2, + .CSSetupTime = 2, + .addrMode = kXSPI_Device4ByteAddressable, + .columnAddrWidth = 3, + .enableCASInterleaving = false, + .ptrDeviceDdrConfig = + &(xspi_device_ddr_config_t){ + .ddrDataAlignedClk = + kXSPI_DDRDataAlignedWith2xInternalRefClk, + .enableByteSwapInOctalMode = false, + .enableDdr = true, + }, + .deviceSize = {32 * 1024, 32 * 1024}, + }, + .lut_array = &memc_xspi_w958d6nbkx_lut[0][0], + .lut_count = MEMC_MCUX_XSPI_LUT_ARRAY_SIZE(memc_xspi_w958d6nbkx_lut), + }, +}; + +static int xspi_psram_write_reg(const struct device *dev, uint32_t regAddr, + uint8_t *data, uint32_t size); +static int xspi_psram_read_reg(const struct device *dev, uint32_t regAddr, + uint8_t *data, uint32_t size); + +static int memc_mcux_xspi_w958d6nbkx_enable_clk(const struct device *dev) +{ + uint16_t reg[2] = {0x0U, 0x0U}; + int ret = 0; + + do { + ret = xspi_psram_read_reg(dev, CR1_REG_ADDR, (uint8_t *)reg, 4); + if (ret < 0) { + break; + } + + reg[1] &= ~CR1_DIFFERENTIAL_CLOCK_MASK; + + ret = xspi_psram_write_reg(dev, CR1_REG_ADDR, (uint8_t *)reg, 4); + if (ret < 0) { + break; + } + + ret = xspi_psram_read_reg(dev, CR1_REG_ADDR, (uint8_t *)reg, 4); + if (ret < 0) { + break; + } + + if ((reg[1] & CR1_DIFFERENTIAL_CLOCK_MASK) != 0U) { + ret = -EIO; + break; + } + } while (0); + + return ret; +} + +static int memc_mcux_xspi_w958d6nbkx_enable_variable_latency(const struct device *dev) +{ + uint16_t reg[2] = {0x0U, 0x0U}; + int ret = 0; + + do { + ret = xspi_psram_read_reg(dev, CR0_REG_ADDR, (uint8_t *)reg, 4); + if (ret < 0) { + break; + } + + reg[1] &= ~CR0_REG_VARIABLE_LATENCY_MASK; + reg[0] &= ~CR0_REG_DRIVE_STRENGTH_MASK; + reg[0] |= (CR0_REG_DRIVE_STRENGTH_46OHMS << CR0_REG_DRIVE_STRENGTH_SHIFT); + + ret = xspi_psram_write_reg(dev, CR0_REG_ADDR, (uint8_t *)reg, 4); + if (ret < 0) { + break; + } + + ret = xspi_psram_read_reg(dev, CR0_REG_ADDR, (uint8_t *)reg, 4); + if (ret < 0) { + break; + } + + if ((reg[1] & CR0_REG_VARIABLE_LATENCY_MASK) != 0U) { + ret = -EIO; + break; + } + } while (0); + + return ret; +} + +static int memc_mcux_xspi_w958d6nbkx_setup(const struct device *dev, + xspi_device_config_t *config) +{ + struct memc_mcux_xspi_psram_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + uint16_t reg[2] = {0x0U, 0x0U}; + int ret = 0; + uint8_t id; + + memc_mcux_xspi_update_device_addr_mode(xspi_dev, kXSPI_DeviceByteAddressable); + + do { + ret = xspi_psram_read_reg(dev, ID0_REG_ADDR, (uint8_t *)reg, 4); + if (ret < 0) { + break; + } + + id = reg[1] & ID0_REG_ID_MASK; + if (id != PSRAM_MANUFACTURER_ID_WINBOND) { + LOG_ERR("Wrong manufacturer ID: 0x%X, expected: 0x%X", id, + PSRAM_MANUFACTURER_ID_WINBOND); + ret = -ENODEV; + break; + } + + if (config->enableCknPad) { + ret = memc_mcux_xspi_w958d6nbkx_enable_clk(dev); + if (ret < 0) { + break; + } + } + + if (config->interfaceSettings.hyperBusSettings.enableVariableLatency) { + ret = memc_mcux_xspi_w958d6nbkx_enable_variable_latency(dev); + if (ret < 0) { + break; + } + } + } while (0); + + memc_mcux_xspi_update_device_addr_mode(xspi_dev, kXSPI_Device4ByteAddressable); + + return ret; +} + +static int xspi_psram_write_reg(const struct device *dev, uint32_t regAddr, + uint8_t *data, uint32_t size) +{ + struct memc_mcux_xspi_psram_data *psram_data = dev->data; + xspi_transfer_t flashXfer; + + flashXfer.deviceAddress = psram_data->amba_address + regAddr; + flashXfer.cmdType = kXSPI_Write; + flashXfer.seqIndex = PSRAM_CMD_REG_WRITE; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.data = (uint32_t *)data; + flashXfer.dataSize = size; + flashXfer.lockArbitration = false; + + return memc_mcux_xspi_transfer(psram_data->xspi_dev, &flashXfer); +} + +static int xspi_psram_read_reg(const struct device *dev, uint32_t regAddr, + uint8_t *data, uint32_t size) +{ + struct memc_mcux_xspi_psram_data *psram_data = dev->data; + xspi_transfer_t flashXfer; + + flashXfer.deviceAddress = psram_data->amba_address + regAddr; + flashXfer.cmdType = kXSPI_Read; + flashXfer.seqIndex = PSRAM_CMD_REG_READ; + flashXfer.targetGroup = kXSPI_TargetGroup0; + flashXfer.data = (uint32_t *)data; + flashXfer.dataSize = size; + flashXfer.lockArbitration = false; + + return memc_mcux_xspi_transfer(psram_data->xspi_dev, &flashXfer); +} + +static int memc_mcux_xspi_psram_setup(const struct device *dev, + const char *dev_name_prefix, xspi_device_config_t *config) +{ + int ret = 0; + + if (strcmp(dev_name_prefix, "w958d6nbkx") == 0) { + ret = memc_mcux_xspi_w958d6nbkx_setup(dev, config); + } + + return ret; +} + +static int memc_mcux_xspi_psram_probe(const struct device *dev) +{ + const struct memc_mcux_xspi_psram_config *config = + (const struct memc_mcux_xspi_psram_config *)dev->config; + struct memc_mcux_xspi_psram_data *data = dev->data; + const struct device *xspi_dev = data->xspi_dev; + struct memc_xspi_dev_config *xspi_psram_config = NULL; + xspi_device_config_t *dev_config = NULL; + int ret; + + /* Get the specific memory parameters. */ + for (uint32_t i = 0; i < ARRAY_SIZE(dev_configs); i++) { + if (strncmp(dev_configs[i].name_prefix, data->dev_name, + strlen(dev_configs[i].name_prefix)) == 0) { + xspi_psram_config = (struct memc_xspi_dev_config *)&dev_configs[i]; + break; + } + } + + if (xspi_psram_config == NULL) { + LOG_ERR("Unsupported device: %s", data->dev_name); + return -ENOTSUP; + } + + /* Set special device configurations. */ + dev_config = &xspi_psram_config->xspi_dev_config; + dev_config->enableCknPad = config->enable_differential_clk; + dev_config->sampleClkConfig = config->sample_clk_config; + + ret = memc_mcux_xspi_get_root_clock(xspi_dev, &dev_config->xspiRootClk); + if (ret < 0) { + return ret; + } + + ret = memc_xspi_set_device_config(xspi_dev, dev_config, + xspi_psram_config->lut_array, xspi_psram_config->lut_count); + if (ret < 0) { + return ret; + } + + return memc_mcux_xspi_psram_setup(dev, xspi_psram_config->name_prefix, dev_config); +} + +static int memc_mcux_xspi_psram_init(const struct device *dev) +{ + struct memc_mcux_xspi_psram_data *psram_data = dev->data; + const struct device *xspi_dev = psram_data->xspi_dev; + + if (!device_is_ready(xspi_dev)) { + LOG_ERR("XSPI device is not ready"); + return -ENODEV; + } + + psram_data->amba_address = memc_mcux_xspi_get_ahb_address(xspi_dev); + + return memc_mcux_xspi_psram_probe(dev); +} + +#define MEMC_MCUX_XSPI_PSRAM_INIT(n) \ + static const struct memc_mcux_xspi_psram_config \ + memc_mcux_xspi_psram_config_##n = { \ + .enable_differential_clk = DT_INST_PROP(n, enable_differential_clk), \ + .sample_clk_config = { \ + .sampleClkSource = DT_INST_PROP(n, sample_clk_source), \ + .enableDQSLatency = DT_INST_PROP(n, enable_dqs_latency), \ + .dllConfig = { \ + .dllMode = kXSPI_AutoUpdateMode, \ + .useRefValue = true, \ + .enableCdl8 = true, \ + }, \ + }, \ + }; \ + static struct memc_mcux_xspi_psram_data memc_mcux_xspi_psram_data_##n = { \ + .xspi_dev = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .dev_name = DT_INST_PROP(n, device_name), \ + .size = DT_INST_PROP(n, size), \ + }; \ + DEVICE_DT_INST_DEFINE(n, &memc_mcux_xspi_psram_init, NULL, \ + &memc_mcux_xspi_psram_data_##n, \ + &memc_mcux_xspi_psram_config_##n, POST_KERNEL, \ + CONFIG_MEMC_MCUX_XSPI_PSRAM, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MEMC_MCUX_XSPI_PSRAM_INIT) diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index e1ecc7c2bcb4a..11aa68bfd3cf5 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -152,6 +152,7 @@ set_variable_ifdef(CONFIG_OPAMP_MCUX_OPAMP_FAST CONFIG_MCUX_COMPONENT_driver if(NOT CONFIG_SOC_MIMX9596) set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver.netc_switch) endif() +set_variable_ifdef(CONFIG_MEMC_MCUX_XSPI CONFIG_MCUX_COMPONENT_driver.xspi) set_variable_ifdef(CONFIG_SOC_SERIES_IMXRT10XX CONFIG_MCUX_COMPONENT_driver.ocotp) set_variable_ifdef(CONFIG_SOC_SERIES_IMXRT11XX CONFIG_MCUX_COMPONENT_driver.ocotp) @@ -317,5 +318,12 @@ if(CONFIG_SOC_MCXW236 OR CONFIG_SOC_MCXW235) set(CONFIG_MCUX_COMPONENT_driver.romapi ON) endif() +if((DEFINED CONFIG_FLASH_MCUX_XSPI_XIP) AND (DEFINED CONFIG_FLASH)) + zephyr_code_relocate(FILES ${MCUX_SDK_NG_DIR}/drivers/xspi/fsl_xspi.c + LOCATION ${CONFIG_FLASH_MCUX_XSPI_XIP_MEM}_TEXT) + zephyr_code_relocate(FILES ${MCUX_SDK_NG_DIR}/drivers/xspi/fsl_xspi.c + LOCATION ${CONFIG_FLASH_MCUX_XSPI_XIP_MEM}_RODATA) +endif() + # Load all drivers mcux_load_all_cmakelists_in_directory(${SdkRootDirPath}/drivers) From ec32e652d17fd88567446c59b56343c453930a53 Mon Sep 17 00:00:00 2001 From: Ruijia Wang Date: Sun, 24 Aug 2025 21:11:17 +0800 Subject: [PATCH 2/6] dts: Enable the xspi flash and psram cases on NXP RT700 Move nxp,xspi.yaml from spi bindings to mtd, it should be flash controllor rather than simple bus controller. Delete the xspi flash mx25um51345g bindling yaml file which is useless. Enable flash and two psrams on RT700 core0 and one psram on core1. Signed-off-by: Ruijia Wang --- dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi | 22 ++++- dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi | 9 ++ dts/arm/nxp/nxp_rt7xx_common.dtsi | 3 +- .../flash_controller/nxp,xspi-nor.yaml | 8 ++ .../memory-controllers/nxp,xspi-psram.yaml | 8 ++ dts/bindings/mtd/nxp,xspi-device.yaml | 28 +++++- dts/bindings/mtd/nxp,xspi-mx25um51345g.yaml | 8 -- dts/bindings/spi/nxp,xspi.yaml | 20 ----- dts/bindings/xspi/nxp,xspi.yaml | 88 +++++++++++++++++++ 9 files changed, 161 insertions(+), 33 deletions(-) create mode 100644 dts/bindings/flash_controller/nxp,xspi-nor.yaml create mode 100644 dts/bindings/memory-controllers/nxp,xspi-psram.yaml delete mode 100644 dts/bindings/mtd/nxp,xspi-mx25um51345g.yaml delete mode 100644 dts/bindings/spi/nxp,xspi.yaml create mode 100644 dts/bindings/xspi/nxp,xspi.yaml diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi index 451491ce28f24..bc94d4fbd656f 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi @@ -1110,8 +1110,26 @@ &xspi0 { compatible = "nxp,xspi"; status = "disabled"; - interrupts = <42 0>; + interrupts = <118 0>; #address-cells = <1>; #size-cells = <0>; - clocks = <&clkctl0 MCUX_XSPI_CLK>; + clocks = <&clkctl0 MCUX_XSPI0_CLK>; +}; + +&xspi1 { + compatible = "nxp,xspi"; + status = "disabled"; + interrupts = <119 0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkctl0 MCUX_XSPI1_CLK>; +}; + +&xspi2 { + compatible = "nxp,xspi"; + status = "disabled"; + interrupts = <120 0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkctl4 MCUX_XSPI2_CLK>; }; diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi index 6d7a8aef3115e..e3814b1a4a546 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu1.dtsi @@ -370,3 +370,12 @@ status = "disabled"; }; }; + +&xspi2 { + compatible = "nxp,xspi"; + status = "disabled"; + interrupts = <74 0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkctl4 MCUX_XSPI2_CLK>; +}; diff --git a/dts/arm/nxp/nxp_rt7xx_common.dtsi b/dts/arm/nxp/nxp_rt7xx_common.dtsi index e766fc5545114..414859695bbed 100644 --- a/dts/arm/nxp/nxp_rt7xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_common.dtsi @@ -83,8 +83,9 @@ }; sram1: memory@20200000 { - compatible = "mmio-sram"; + compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20200000 DT_SIZE_K(2048)>; + zephyr,memory-region = "SRAM1"; }; sram3: memory@205C0000 { diff --git a/dts/bindings/flash_controller/nxp,xspi-nor.yaml b/dts/bindings/flash_controller/nxp,xspi-nor.yaml new file mode 100644 index 0000000000000..65eafa8920d13 --- /dev/null +++ b/dts/bindings/flash_controller/nxp,xspi-nor.yaml @@ -0,0 +1,8 @@ +# Copyright 2024-2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP XSPI Flash Controller + +compatible: "nxp,xspi-nor" + +include: ["nxp,xspi-device.yaml", "jedec,jesd216.yaml"] diff --git a/dts/bindings/memory-controllers/nxp,xspi-psram.yaml b/dts/bindings/memory-controllers/nxp,xspi-psram.yaml new file mode 100644 index 0000000000000..a4320329e85c3 --- /dev/null +++ b/dts/bindings/memory-controllers/nxp,xspi-psram.yaml @@ -0,0 +1,8 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP XSPI PSRAM Controller + +compatible: "nxp,xspi-psram" + +include: ["nxp,xspi-device.yaml"] diff --git a/dts/bindings/mtd/nxp,xspi-device.yaml b/dts/bindings/mtd/nxp,xspi-device.yaml index d067b878c9306..2598d551f5013 100644 --- a/dts/bindings/mtd/nxp,xspi-device.yaml +++ b/dts/bindings/mtd/nxp,xspi-device.yaml @@ -1,6 +1,30 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 description: NXP XSPI device -include: [spi-device.yaml, "jedec,jesd216.yaml"] +include: [base.yaml] + +properties: + device-name: + type: string + description: Memory device name. + + size: + type: int + required: true + description: Total memory size in bytes. + + enable-differential-clk: + type: boolean + description: Enable differential clock pad. + + sample-clk-source: + type: int + default: 3 + enum: [1, 2, 3, 5, 9] + description: Sample clock source. + + enable-dqs-latency: + type: boolean + description: Enable DQS latency. diff --git a/dts/bindings/mtd/nxp,xspi-mx25um51345g.yaml b/dts/bindings/mtd/nxp,xspi-mx25um51345g.yaml deleted file mode 100644 index 6554d5d61afd5..0000000000000 --- a/dts/bindings/mtd/nxp,xspi-mx25um51345g.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2024 NXP -# SPDX-License-Identifier: Apache-2.0 - -description: NXP XSPI MX25UM51345G - -compatible: "nxp,xspi-mx25um51345g" - -include: ["nxp,xspi-device.yaml", soc-nv-flash.yaml] diff --git a/dts/bindings/spi/nxp,xspi.yaml b/dts/bindings/spi/nxp,xspi.yaml deleted file mode 100644 index 236ad62ba4880..0000000000000 --- a/dts/bindings/spi/nxp,xspi.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2024 NXP -# SPDX-License-Identifier: Apache-2.0 - -description: NXP XSPI controller - -compatible: "nxp,xspi" - -include: [spi-controller.yaml, pinctrl-device.yaml] - -properties: - reg: - required: true - - interrupts: - required: true - -child-binding: - description: NXP XSPI port - - include: nxp,xspi-device.yaml diff --git a/dts/bindings/xspi/nxp,xspi.yaml b/dts/bindings/xspi/nxp,xspi.yaml new file mode 100644 index 0000000000000..25867dfbedd1d --- /dev/null +++ b/dts/bindings/xspi/nxp,xspi.yaml @@ -0,0 +1,88 @@ +# Copyright 2024-2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP XSPI controller + +compatible: "nxp,xspi" + +include: [spi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + byte-order: + type: int + default: 3 + enum: [0, 1, 2, 3] + description: | + Byte ordering endianness. + 0 = 64-bit BE, 1 = 32-bit LE, 2 = 32-bit BE, 3 = 64-bit LE + + enable-ahb-write: + type: boolean + description: Enable AHB write access. + + ahb-buffer-write-flush: + type: boolean + description: Enable flushing AHB buffer on write or IP access. + + ahb-prefetch: + type: boolean + description: Enable AHB read prefetch feature. + +child-binding: + description: NXP XSPI configurations + + properties: + # MDAD configuration + enable-descriptor-lock: + type: int + description: Enable descriptor lock + mask-type: + type: int + description: Mask type (0=AND, 1=OR) + mask: + type: int + description: 6-bit mask value + master-id-reference: + type: int + description: Master ID reference value + secure-attribute: + type: int + enum: [1, 2, 3] + description: Security attribute setting + + # FRAD configuration + start-address: + type: int + description: Start address of the region + end-address: + type: int + description: End address of the region + tg0-master-access: + type: int + description: Target group 0 access permissions + tg1-master-access: + type: int + description: Target group 1 access permissions + descriptor-lock: + type: int + enum: [0, 1, 2, 3] + description: | + Descriptor lock mode: + - Disable + - Enable till hard reset + - Enable except master ID + - Enable + exclusive-access-lock: + type: int + enum: [0, 2, 3] + description: | + Exclusive access lock mode: + - Disable + - Enable except master ID + - Enable From 7acf10de3ac85eaa9073e02396025f09957b4ad3 Mon Sep 17 00:00:00 2001 From: Ruijia Wang Date: Sun, 24 Aug 2025 21:15:03 +0800 Subject: [PATCH 3/6] boards: Update related configuration for RT700 xspi case Add flash and psram dts based on RT700 board resource. Add the clock and power setting for XSPI in board specfic initilization function. Signed-off-by: Ruijia Wang --- boards/nxp/mimxrt700_evk/board.c | 28 ++++ .../mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi | 79 ++++++++++ .../mimxrt700_evk_mimxrt798s_cm33_cpu0.dts | 139 +++++++++++++----- .../mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml | 2 + .../mimxrt700_evk_mimxrt798s_cm33_cpu1.dts | 21 +++ .../mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml | 2 + 6 files changed, 235 insertions(+), 36 deletions(-) diff --git a/boards/nxp/mimxrt700_evk/board.c b/boards/nxp/mimxrt700_evk/board.c index a4b75c20d55de..7d07e73ad858e 100644 --- a/boards/nxp/mimxrt700_evk/board.c +++ b/boards/nxp/mimxrt700_evk/board.c @@ -544,6 +544,34 @@ void board_early_init_hook(void) CLOCK_EnableClock(kCLOCK_Acmp0); RESET_ClearPeripheralReset(kACMP0_RST_SHIFT_RSTn); #endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(xspi0), okay) + POWER_DisablePD(kPDRUNCFG_APD_XSPI0); + POWER_DisablePD(kPDRUNCFG_PPD_XSPI0); + POWER_ApplyPD(); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(xspi1), okay) + xspi_setup_clock(XSPI1, 1U, 1U); /* Audio PLL PDF1 DIV1. */ + + POWER_DisablePD(kPDRUNCFG_APD_XSPI1); + POWER_DisablePD(kPDRUNCFG_PPD_XSPI1); + POWER_ApplyPD(); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(xspi2), okay) +#if CONFIG_SOC_MIMXRT798S_CM33_CPU0 + CLOCK_AttachClk(kMAIN_PLL_PFD3_to_XSPI2); +#elif CONFIG_SOC_MIMXRT798S_CM33_CPU1 + CLOCK_AttachClk(kFRO1_DIV1_to_COMMON_BASE); + CLOCK_AttachClk(kCOMMON_BASE_to_XSPI2); +#endif + CLOCK_SetClkDiv(kCLOCK_DivXspi2Clk, 1U); + + POWER_DisablePD(kPDRUNCFG_APD_XSPI2); + POWER_DisablePD(kPDRUNCFG_PPD_XSPI2); + POWER_ApplyPD(); +#endif } static void GlikeyWriteEnable(GLIKEY_Type *base, uint8_t idx) diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi b/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi index 32afe95fe92ef..54927bd87c997 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi @@ -193,4 +193,83 @@ slew-rate = "normal"; }; }; + + pinmux_xspi0: pinmux_xspi0 { + group0 { + pinmux = , + , + , + , + , + , + , + , + , + , + , + , + ; + drive-strength = "normal"; + slew-rate = "normal"; + input-enable; + }; + }; + + pinmux_xspi1: pinmux_xspi1 { + group0 { + pinmux = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + drive-strength = "normal"; + slew-rate = "normal"; + input-enable; + }; + }; + + pinmux_xspi2: pinmux_xspi2 { + group0 { + pinmux = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + drive-strength = "normal"; + slew-rate = "normal"; + input-enable; + }; + }; }; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts index d35762b53e52f..de0a77e0db3b7 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts @@ -26,11 +26,12 @@ i2s-tx = &sai0; sdhc0 = &usdhc0; rtc = &rtc0; + sram-ext = &psram0; }; chosen { - zephyr,flash-controller = &mx25um51345g; - zephyr,flash = &mx25um51345g; + zephyr,flash-controller = &flash_controller0; + zephyr,flash = &ext_flash; zephyr,sram = &sram0; zephyr,console = &flexcomm0_lpuart0; zephyr,shell-uart = &flexcomm0_lpuart0; @@ -95,6 +96,19 @@ enable-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; regulator-boot-on; }; + + memc: memc@8000000 { + status = "okay"; + reg = <0x08000000 DT_SIZE_M(32)>; + #address-cells = <1>; + #size-cells = <1>; + + psram: memory@8000000 { + compatible = "zephyr,memory-region"; + reg = <0x08000000 DT_SIZE_M(32)>; + zephyr,memory-region = "PSRAM"; + }; + }; }; &ctimer0 { @@ -325,47 +339,100 @@ zephyr_lcdif: &lcdif {}; &xspi0 { status = "okay"; + pinctrl-0 = <&pinmux_xspi0>; + pinctrl-names = "default"; + byte-order = <3>; + ahb-buffer-write-flush; + ahb-prefetch; - mx25um51345g: mx25um51345g@0 { - compatible = "nxp,xspi-mx25um51345g"; - /* MX25UM51245G is 64MB, 512MBit flash part */ - size = ; - reg = <0>; - spi-max-frequency = ; + flash_controller0: flash-controller@0 { status = "okay"; - jedec-id = [c2 81 3a]; - erase-block-size = ; - write-block-size = <2>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - /* - * Partition sizes must be aligned - * to the flash memory sector size of 4KB. - */ - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 DT_SIZE_K(128)>; - }; - slot0_partition: partition@20000 { - label = "image-0"; - reg = <0x00020000 DT_SIZE_M(7)>; - }; - slot1_partition: partition@720000 { - label = "image-1"; - reg = <0x00720000 DT_SIZE_M(7)>; - }; - storage_partition: partition@E20000 { - label = "storage"; - reg = <0x00E20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; + compatible = "nxp,xspi-nor"; + device-name = "mx25um51345g"; + /* MX25UM51245G is 64MB, 512Mbit flash part. */ + size = ; + reg = <0>; + sample-clk-source = <3>; + #address-cells = <1>; + #size-cells = <1>; + + ext_flash: flash@38000000 { + compatible = "soc-nv-flash"; + reg = <0x38000000 DT_SIZE_M(64)>; + erase-block-size = ; + write-block-size = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Partition sizes must be aligned + * to the flash memory sector size of 4KB. + */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(128)>; + }; + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 DT_SIZE_M(7)>; + }; + slot1_partition: partition@720000 { + label = "image-1"; + reg = <0x00720000 DT_SIZE_M(7)>; + }; + storage_partition: partition@E20000 { + label = "storage"; + reg = <0x00E20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; + }; }; }; }; }; +&xspi1 { + status = "okay"; + pinctrl-0 = <&pinmux_xspi1>; + pinctrl-names = "default"; + byte-order = <3>; + ahb-buffer-write-flush; + ahb-prefetch; + enable-ahb-write; + /* Connect JP45 1-2 to use XSPI1. */ + + psram0: memory-controller@0 { + status = "okay"; + compatible = "nxp,xspi-psram"; + device-name = "w958d6nbkx5l"; + size = ; + reg = <0>; + enable-differential-clk; + sample-clk-source = <3>; + }; +}; + +&xspi2 { + status = "okay"; + pinctrl-0 = <&pinmux_xspi2>; + pinctrl-names = "default"; + byte-order = <3>; + ahb-buffer-write-flush; + ahb-prefetch; + enable-ahb-write; + + psram1: memory-controller@0 { + status = "okay"; + compatible = "nxp,xspi-psram"; + device-name = "w958d6nbkx4l"; + size = ; + reg = <0>; + enable-differential-clk; + sample-clk-source = <3>; + }; +}; + zephyr_udc0: &usb0 { status = "okay"; phy-handle = <&usbphy>; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml index 05aba621c702a..eeade2809eaa6 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.yaml @@ -24,4 +24,6 @@ supported: - usb_device - watchdog - hwinfo + - flash + - memc vendor: nxp diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts index da52780a04fba..43ff70ffb76e0 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.dts @@ -20,6 +20,7 @@ sw0 = &user_button_1; ambient-temp0 = &p3t1755; rtc = &rtc1; + sram-ext = &psram; }; chosen { @@ -114,3 +115,23 @@ &mbox1_b { status = "okay"; }; + +&xspi2 { + status = "okay"; + pinctrl-0 = <&pinmux_xspi2>; + pinctrl-names = "default"; + byte-order = <3>; + ahb-buffer-write-flush; + ahb-prefetch; + enable-ahb-write; + + psram: memory-controller@0 { + status = "okay"; + compatible = "nxp,xspi-psram"; + device-name = "w958d6nbkx4l"; + size = ; + reg = <0>; + enable-differential-clk; + sample-clk-source = <3>; + }; +}; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml index e562a648b4cb6..13f0b3b766028 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu1.yaml @@ -19,4 +19,6 @@ supported: - uart - adc - i3c + - flash + - memc vendor: nxp From 886338ec4af50aaea4e32746ab6661bcf4feccbb Mon Sep 17 00:00:00 2001 From: Ruijia Wang Date: Mon, 1 Sep 2025 22:41:25 +0800 Subject: [PATCH 4/6] soc: Update code to get flash size from dts Update the Kconfig to parse the dts. Signed-off-by: Ruijia Wang --- soc/nxp/common/Kconfig.xspi_xip | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/soc/nxp/common/Kconfig.xspi_xip b/soc/nxp/common/Kconfig.xspi_xip index d087e8b2d2e3e..a2ad8724871d1 100644 --- a/soc/nxp/common/Kconfig.xspi_xip +++ b/soc/nxp/common/Kconfig.xspi_xip @@ -1,26 +1,29 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 DT_CHOSEN_Z_FLASH := zephyr,flash DT_COMPAT_XSPI := nxp,xspi DT_CHOSEN_FLASH_NODE := $(dt_chosen_path,$(DT_CHOSEN_Z_FLASH)) -DT_CHOSEN_FLASH_PARENT := $(dt_node_parent,$(DT_CHOSEN_FLASH_NODE)) +DT_CHOSEN_FLASH_CTRL := $(dt_node_parent,$(DT_CHOSEN_FLASH_NODE)) +DT_CHOSEN_FLASH_CTRL_PARENT := $(dt_node_parent,$(DT_CHOSEN_FLASH_CTRL)) -DT_FLASH_PARENT_IS_XSPI := $(dt_node_has_compat,$(DT_CHOSEN_FLASH_PARENT),$(DT_COMPAT_XSPI)) -DT_FLASH_HAS_SIZE_PROP := $(dt_node_has_prop,$(DT_CHOSEN_FLASH_NODE),size) +DT_FLASH_CTRL_PARENT_IS_XSPI := $(dt_node_has_compat,$(DT_CHOSEN_FLASH_CTRL_PARENT),$(DT_COMPAT_XSPI)) +DT_FLASH_CTRL_HAS_SIZE_PROP := $(dt_node_has_prop,$(DT_CHOSEN_FLASH_CTRL),size) config FLASH_BASE_ADDRESS - default $(dt_node_reg_addr_hex,$(DT_CHOSEN_FLASH_PARENT),1) \ - if $(DT_FLASH_PARENT_IS_XSPI) + default $(dt_node_reg_addr_hex,$(DT_CHOSEN_FLASH_CTRL_PARENT),1) \ + if $(DT_FLASH_CTRL_PARENT_IS_XSPI) default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_FLASH)) config FLASH_SIZE - default $(dt_node_int_prop_int,$(DT_CHOSEN_FLASH_NODE),size,Kb) + default $(dt_node_int_prop_int,$(DT_CHOSEN_FLASH_CTRL),size,K) \ + if $(DT_FLASH_CTRL_HAS_SIZE_PROP) + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_FLASH),0,K) config FLASH_MCUX_XSPI_XIP bool - default $(DT_FLASH_PARENT_IS_XSPI) + default $(DT_FLASH_CTRL_PARENT_IS_XSPI) select XIP help Allows the soc to safely initialize the clocks for the From e8df10f02e2cc4f92f5d6647486582070281ba09 Mon Sep 17 00:00:00 2001 From: Ruijia Wang Date: Mon, 1 Sep 2025 22:58:19 +0800 Subject: [PATCH 5/6] samples: Update XSPI memc and flash samples on RT700 Add memc sample for XSPI PSRAM. Add spi_flash sample for XSPI Nor Flash. Signed-off-by: Ruijia Wang --- samples/drivers/memc/src/main.c | 5 +++++ samples/drivers/spi_flash/sample.yaml | 1 + samples/drivers/spi_flash/src/main.c | 2 ++ 3 files changed, 8 insertions(+) diff --git a/samples/drivers/memc/src/main.c b/samples/drivers/memc/src/main.c index 85d82b5ed02da..d03ffd07caaab 100644 --- a/samples/drivers/memc/src/main.c +++ b/samples/drivers/memc/src/main.c @@ -32,6 +32,11 @@ #define MEMC_DEV DT_ALIAS(sram_ext) #define MEMC_BASE DT_REG_ADDR(MEMC_DEV) #define MEMC_SIZE DT_REG_SIZE(MEMC_DEV) +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_xspi_psram) +#define MEMC_DEV DT_ALIAS(sram_ext) +#define MSPI_BUS DT_BUS(MEMC_DEV) +#define MEMC_BASE DT_REG_ADDR_BY_IDX(MSPI_BUS, 1) +#define MEMC_SIZE (DT_PROP(MEMC_DEV, size) / 8) #else #error At least one driver should be selected! #endif diff --git a/samples/drivers/spi_flash/sample.yaml b/samples/drivers/spi_flash/sample.yaml index d17972e95899c..9b38ffe6a2dc0 100644 --- a/samples/drivers/spi_flash/sample.yaml +++ b/samples/drivers/spi_flash/sample.yaml @@ -10,6 +10,7 @@ tests: filter: dt_compat_enabled("jedec,spi-nor") or dt_compat_enabled("st,stm32-qspi-nor") or dt_compat_enabled("st,stm32-ospi-nor") or dt_compat_enabled("st,stm32-xspi-nor") or dt_compat_enabled("nordic,qspi-nor") or dt_compat_enabled("jedec,mspi-nor") + or dt_compat_enabled("nxp,xspi-nor") platform_exclude: - hifive_unmatched/fu740/s7 - hifive_unmatched/fu740/u74 diff --git a/samples/drivers/spi_flash/src/main.c b/samples/drivers/spi_flash/src/main.c index 07adf7739becc..f75aad5e1f71b 100644 --- a/samples/drivers/spi_flash/src/main.c +++ b/samples/drivers/spi_flash/src/main.c @@ -58,6 +58,8 @@ #define SPI_FLASH_COMPAT renesas_ra_ospi_b_nor #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_qspi_nor) #define SPI_FLASH_COMPAT renesas_ra_qspi_nor +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_xspi_nor) +#define SPI_FLASH_COMPAT nxp_xspi_nor #else #define SPI_FLASH_COMPAT invalid #endif From 53ea406e9b9a537eba69e5f6ce2b98deba1c849a Mon Sep 17 00:00:00 2001 From: Ruijia Wang Date: Tue, 2 Sep 2025 12:45:59 +0800 Subject: [PATCH 6/6] west: update hal_nxp Update hal_nxp. Signed-off-by: Ruijia Wang --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 7eb0a6c84b057..7b51d89421533 100644 --- a/west.yml +++ b/west.yml @@ -210,7 +210,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 4377ecfba52fe0ff7352eadf426b523ed3e1d27f + revision: pull/597/head path: modules/hal/nxp groups: - hal