From add98e766a28e59add27a38831779e2e00ab8f4f Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 15 Apr 2021 07:48:57 +0200 Subject: [PATCH] drivers: flash: Support i.MX FlexSPI NOR driver with XIP This change allows writing to the flash while running in XIP mode, and enables mcuboot or NVS settings to be used on i.MX RT socs. Signed-off-by: Pieter De Gendt --- drivers/flash/CMakeLists.txt | 4 ++ drivers/flash/Kconfig.mcux | 34 ++++++++++++ drivers/flash/flash_mcux_flexspi_nor.c | 71 ++++++++++++++++++++++---- drivers/memc/CMakeLists.txt | 4 ++ drivers/memc/memc_mcux_flexspi.c | 23 +++++++++ drivers/memc/memc_mcux_flexspi.h | 2 + soc/arm/nxp_imx/rt/soc.c | 4 +- west.yml | 2 +- 8 files changed, 133 insertions(+), 11 deletions(-) diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 2062c10f56f..44681b4d771 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -21,6 +21,10 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_NOR flash_mcux_flexspi_nor.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) +if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(flash_mcux_flexspi_nor.c ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) +endif() + if(CONFIG_SOC_FLASH_STM32) if(CONFIG_SOC_SERIES_STM32H7X) zephyr_sources_ifdef(CONFIG_SOC_SERIES_STM32H7X flash_stm32h7x.c) diff --git a/drivers/flash/Kconfig.mcux b/drivers/flash/Kconfig.mcux index af52ad06990..e1ad080f320 100644 --- a/drivers/flash/Kconfig.mcux +++ b/drivers/flash/Kconfig.mcux @@ -34,4 +34,38 @@ config FLASH_MCUX_FLEXSPI_NOR select MEMC select MEMC_MCUX_FLEXSPI +config FLASH_MCUX_FLEXSPI_XIP + bool "MCUX FlexSPI flash access with xip" + depends on MEMC_MCUX_FLEXSPI + depends on (CODE_FLEXSPI || CODE_FLEXSPI2) + select XIP + select CODE_DATA_RELOCATION + help + Allows using the flash API while running in XIP. + WARNING: It is possible to overwrite the running application itself. + +if FLASH_MCUX_FLEXSPI_XIP + +choice FLASH_MCUX_FLEXSPI_XIP_MEM_TARGET + prompt "FlexSPI drivers relocation target" + default FLASH_MCUX_FLEXSPI_XIP_MEM_ITCM + help + Select the location to run the FlexSPI drivers when using + the flash API. + +config FLASH_MCUX_FLEXSPI_XIP_MEM_ITCM + bool "ITCM" + +config FLASH_MCUX_FLEXSPI_XIP_MEM_SRAM + bool "SRAM" + +endchoice + +config FLASH_MCUX_FLEXSPI_XIP_MEM + string + default "ITCM" if FLASH_MCUX_FLEXSPI_XIP_MEM_ITCM + default "SRAM" if FLASH_MCUX_FLEXSPI_XIP_MEM_SRAM + +endif # FLASH_MCUX_FLEXSPI_XIP + endif # HAS_MCUX_FLEXSPI diff --git a/drivers/flash/flash_mcux_flexspi_nor.c b/drivers/flash/flash_mcux_flexspi_nor.c index 0f89e523c38..50f398ff18b 100644 --- a/drivers/flash/flash_mcux_flexspi_nor.c +++ b/drivers/flash/flash_mcux_flexspi_nor.c @@ -22,18 +22,21 @@ LOG_MODULE_REGISTER(flash_flexspi_nor, CONFIG_FLASH_LOG_LEVEL); enum { - /* SPI instructions */ - READ_ID, - READ_STATUS_REG, - WRITE_STATUS_REG, + /* Instructions matching with XIP layout */ + READ_FAST_QUAD_OUTPUT, + READ_FAST_OUTPUT, + READ_NORMAL_OUTPUT, + READ_STATUS, WRITE_ENABLE, ERASE_SECTOR, - ERASE_CHIP, - - /* Quad SPI instructions */ - READ_FAST_QUAD_OUTPUT, + PAGE_PROGRAM_INPUT, PAGE_PROGRAM_QUAD_INPUT, + READ_ID, + WRITE_STATUS_REG, ENTER_QPI, + EXIT_QPI, + READ_STATUS_REG, + ERASE_CHIP, }; struct flash_flexspi_nor_config { @@ -86,6 +89,32 @@ static const uint32_t flash_flexspi_nor_lut[][4] = { kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04), }, + [READ_FAST_OUTPUT] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + }, + + [READ_NORMAL_OUTPUT] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_READ, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + }, + + [READ_STATUS] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + }, + + [PAGE_PROGRAM_INPUT] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + }, + [PAGE_PROGRAM_QUAD_INPUT] = { FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), @@ -97,6 +126,11 @@ static const uint32_t flash_flexspi_nor_lut[][4] = { FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }, + + [EXIT_QPI] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + }, }; static int flash_flexspi_nor_get_vendor_id(const struct device *dev, @@ -300,11 +334,16 @@ static int flash_flexspi_nor_write(const struct device *dev, off_t offset, size_t size = len; uint8_t *src = (uint8_t *) buffer; int i; + unsigned int key = 0; uint8_t *dst = memc_flexspi_get_ahb_address(data->controller, config->port, offset); + if (memc_flexspi_is_running_xip(data->controller)) { + key = irq_lock(); + } + while (len) { i = MIN(SPI_NOR_PAGE_SIZE, len); flash_flexspi_nor_write_enable(dev); @@ -315,6 +354,10 @@ static int flash_flexspi_nor_write(const struct device *dev, off_t offset, len -= i; } + if (memc_flexspi_is_running_xip(data->controller)) { + irq_unlock(key); + } + #ifdef CONFIG_HAS_MCUX_CACHE DCACHE_InvalidateByRange((uint32_t) dst, size); #endif @@ -329,6 +372,7 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset, struct flash_flexspi_nor_data *data = dev->data; int num_sectors = size / SPI_NOR_SECTOR_SIZE; int i; + unsigned int key = 0; uint8_t *dst = memc_flexspi_get_ahb_address(data->controller, config->port, @@ -344,6 +388,10 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset, return -EINVAL; } + if (memc_flexspi_is_running_xip(data->controller)) { + key = irq_lock(); + } + if ((offset == 0) && (size == config->config.flashSize * KB(1))) { flash_flexspi_nor_write_enable(dev); flash_flexspi_nor_erase_chip(dev); @@ -359,6 +407,10 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset, } } + if (memc_flexspi_is_running_xip(data->controller)) { + irq_unlock(key); + } + #ifdef CONFIG_HAS_MCUX_CACHE DCACHE_InvalidateByRange((uint32_t) dst, size); #endif @@ -397,7 +449,8 @@ static int flash_flexspi_nor_init(const struct device *dev) return -EINVAL; } - if (memc_flexspi_set_device_config(data->controller, &config->config, + if (!memc_flexspi_is_running_xip(data->controller) && + memc_flexspi_set_device_config(data->controller, &config->config, config->port)) { LOG_ERR("Could not set device configuration"); return -EINVAL; diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index c8a30e7071d..8fa6a9fc385 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -6,3 +6,7 @@ zephyr_linker_sources_ifdef(CONFIG_MEMC_STM32_SDRAM SECTIONS memc_stm32_sdram.ld zephyr_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI memc_mcux_flexspi.c) zephyr_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_HYPERRAM memc_mcux_flexspi_hyperram.c) + +if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(memc_mcux_flexspi.c ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) +endif() diff --git a/drivers/memc/memc_mcux_flexspi.c b/drivers/memc/memc_mcux_flexspi.c index e396fae8a8e..4c88235f674 100644 --- a/drivers/memc/memc_mcux_flexspi.c +++ b/drivers/memc/memc_mcux_flexspi.c @@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(memc_flexspi, CONFIG_MEMC_LOG_LEVEL); struct memc_flexspi_config { FLEXSPI_Type *base; uint8_t *ahb_base; + bool xip; bool ahb_bufferable; bool ahb_cacheable; bool ahb_prefetch; @@ -29,6 +30,13 @@ struct memc_flexspi_data { size_t size[kFLEXSPI_PortCount]; }; +bool memc_flexspi_is_running_xip(const struct device *dev) +{ + const struct memc_flexspi_config *config = dev->config; + + return config->xip; +} + int memc_flexspi_update_lut(const struct device *dev, uint32_t index, const uint32_t *cmd, uint32_t count) { @@ -107,6 +115,12 @@ static int memc_flexspi_init(const struct device *dev) const struct memc_flexspi_config *config = dev->config; flexspi_config_t flexspi_config; + /* we should not configure the device we are running on */ + if (memc_flexspi_is_running_xip(dev)) { + LOG_DBG("XIP active on %s, skipping init", dev->name); + return 0; + } + FLEXSPI_GetDefaultConfig(&flexspi_config); flexspi_config.ahbConfig.enableAHBBufferable = config->ahb_bufferable; @@ -122,10 +136,19 @@ static int memc_flexspi_init(const struct device *dev) return 0; } +#if defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI) +#define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi)) +#elif defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI2) +#define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi2)) +#else +#define MEMC_FLEXSPI_CFG_XIP(node_id) false +#endif + #define MEMC_FLEXSPI(n) \ static const struct memc_flexspi_config \ memc_flexspi_config_##n = { \ .base = (FLEXSPI_Type *) DT_INST_REG_ADDR(n), \ + .xip = MEMC_FLEXSPI_CFG_XIP(DT_DRV_INST(n)), \ .ahb_base = (uint8_t *) DT_INST_REG_ADDR_BY_IDX(n, 1), \ .ahb_bufferable = DT_INST_PROP(n, ahb_bufferable), \ .ahb_cacheable = DT_INST_PROP(n, ahb_cacheable), \ diff --git a/drivers/memc/memc_mcux_flexspi.h b/drivers/memc/memc_mcux_flexspi.h index 6e11db8a4a7..1b86b8a78c5 100644 --- a/drivers/memc/memc_mcux_flexspi.h +++ b/drivers/memc/memc_mcux_flexspi.h @@ -8,6 +8,8 @@ #include #include +bool memc_flexspi_is_running_xip(const struct device *dev); + int memc_flexspi_update_lut(const struct device *dev, uint32_t index, const uint32_t *cmd, uint32_t count); diff --git a/soc/arm/nxp_imx/rt/soc.c b/soc/arm/nxp_imx/rt/soc.c index 2b79bec1730..d818c7a8fd7 100644 --- a/soc/arm/nxp_imx/rt/soc.c +++ b/soc/arm/nxp_imx/rt/soc.c @@ -216,7 +216,9 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_SetMux(kCLOCK_CanMux, 2); /* Set Can clock source. */ #endif -#if defined(CONFIG_MEMC_MCUX_FLEXSPI) && DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi), okay) +#if !(defined(CONFIG_CODE_FLEXSPI) || defined(CONFIG_CODE_FLEXSPI2)) && \ + defined(CONFIG_MEMC_MCUX_FLEXSPI) && \ + DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi), okay) CLOCK_DisableClock(kCLOCK_FlexSpi); CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 24); CLOCK_SetMux(kCLOCK_FlexspiMux, 3); diff --git a/west.yml b/west.yml index bcad1675d8d..35c8a10f8d4 100644 --- a/west.yml +++ b/west.yml @@ -100,7 +100,7 @@ manifest: revision: f49bd1354616fae4093bf36e5eaee43c51a55127 path: tools/net-tools - name: hal_nxp - revision: 4560b0a0106bbe47eded4d7af775998c4f6d05c0 + revision: 27a464e4885f393dc376a53d9fc8d52078848496 path: modules/hal/nxp - name: open-amp revision: de1b85a13032a2de1d8b6695ae5f800b613e739d