From 4830c7c11a2b8bd9acbb9dbe154161e1e2e42178 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 23 Jan 2024 10:39:22 +0100 Subject: [PATCH 1/7] drivers: flash: stm32 flash base address from the DTS node For the flash driver, the base address is the MCU internal flash address (usualyy 0x8000000). This PR gets the that address from the device tree node "st,stm32-nv-flash" instead of relying on the CONFIG_FLASH_BASE_ADDRESS which might differ when building for another flash memory. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32.c | 7 ++++--- drivers/flash/flash_stm32.h | 3 +++ drivers/flash/flash_stm32f1x.c | 6 +++--- drivers/flash/flash_stm32f2x.c | 2 +- drivers/flash/flash_stm32f4x.c | 2 +- drivers/flash/flash_stm32f7x.c | 2 +- drivers/flash/flash_stm32g0x.c | 2 +- drivers/flash/flash_stm32g4x.c | 2 +- drivers/flash/flash_stm32h7x.c | 6 +++--- drivers/flash/flash_stm32l4x.c | 2 +- drivers/flash/flash_stm32l5x.c | 2 +- drivers/flash/flash_stm32wba_fm.c | 4 ++-- drivers/flash/flash_stm32wbax.c | 2 +- drivers/flash/flash_stm32wbx.c | 2 +- 14 files changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index 36e3103c56d39..2dcf63f320893 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -157,7 +157,7 @@ static void flash_stm32_flush_caches(const struct device *dev, regs->ACR |= FLASH_ACR_DCEN; } #elif defined(CONFIG_SOC_SERIES_STM32F7X) - SCB_InvalidateDCache_by_Addr((uint32_t *)(CONFIG_FLASH_BASE_ADDRESS + SCB_InvalidateDCache_by_Addr((uint32_t *)(FLASH_STM32_BASE_ADDRESS + offset), len); #endif } @@ -178,7 +178,7 @@ static int flash_stm32_read(const struct device *dev, off_t offset, LOG_DBG("Read offset: %ld, len: %zu", (long int) offset, len); - memcpy(data, (uint8_t *) CONFIG_FLASH_BASE_ADDRESS + offset, len); + memcpy(data, (uint8_t *) FLASH_STM32_BASE_ADDRESS + offset, len); return 0; } @@ -562,7 +562,8 @@ static int stm32_flash_init(const struct device *dev) flash_stm32_sem_init(dev); - LOG_DBG("Flash initialized. BS: %zu", + LOG_DBG("Flash @0x%x initialized. BS: %zu", + FLASH_STM32_BASE_ADDRESS, flash_stm32_parameters.write_block_size); /* Check Flash configuration */ diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index e0fba89a55039..3583a1379c6cd 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -17,6 +17,9 @@ #include #endif +/* Get the base address of the flash from the DTS node */ +#define FLASH_STM32_BASE_ADDRESS DT_REG_ADDR(DT_INST(0, st_stm32_nv_flash)) + struct flash_stm32_priv { FLASH_TypeDef *regs; #if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_flash_controller), clocks) || \ diff --git a/drivers/flash/flash_stm32f1x.c b/drivers/flash/flash_stm32f1x.c index 0c54d3f69fef2..9a2c0bb4a903e 100644 --- a/drivers/flash/flash_stm32f1x.c +++ b/drivers/flash/flash_stm32f1x.c @@ -62,7 +62,7 @@ static void erase_page_begin(FLASH_TypeDef *regs, unsigned int page) { /* Set the PER bit and select the page you wish to erase */ regs->CR |= FLASH_CR_PER; - regs->AR = CONFIG_FLASH_BASE_ADDRESS + page * FLASH_PAGE_SIZE; + regs->AR = FLASH_STM32_BASE_ADDRESS + page * FLASH_PAGE_SIZE; barrier_dsync_fence_full(); @@ -99,7 +99,7 @@ static void write_disable(FLASH_TypeDef *regs) static void erase_page_begin(FLASH_TypeDef *regs, unsigned int page) { volatile flash_prg_t *page_base = (flash_prg_t *)( - CONFIG_FLASH_BASE_ADDRESS + page * FLASH_PAGE_SIZE); + FLASH_STM32_BASE_ADDRESS + page * FLASH_PAGE_SIZE); /* Enable programming in erase mode. An erase is triggered by * writing 0 to the first word of a page. */ @@ -123,7 +123,7 @@ static int write_value(const struct device *dev, off_t offset, flash_prg_t val) { volatile flash_prg_t *flash = (flash_prg_t *)( - offset + CONFIG_FLASH_BASE_ADDRESS); + offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); int rc; diff --git a/drivers/flash/flash_stm32f2x.c b/drivers/flash/flash_stm32f2x.c index f3781855f576c..a525aa8e90f0c 100644 --- a/drivers/flash/flash_stm32f2x.c +++ b/drivers/flash/flash_stm32f2x.c @@ -76,7 +76,7 @@ static int write_byte(const struct device *dev, off_t offset, uint8_t val) /* flush the register write */ tmp = regs->CR; - *((uint8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + *((uint8_t *) offset + FLASH_STM32_BASE_ADDRESS) = val; /* Wait until the BSY bit is cleared */ rc = flash_stm32_wait_flash_idle(dev); diff --git a/drivers/flash/flash_stm32f4x.c b/drivers/flash/flash_stm32f4x.c index 4261c26a58902..ddc882747ccb0 100644 --- a/drivers/flash/flash_stm32f4x.c +++ b/drivers/flash/flash_stm32f4x.c @@ -101,7 +101,7 @@ static int write_byte(const struct device *dev, off_t offset, uint8_t val) /* flush the register write */ tmp = regs->CR; - *((uint8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + *((uint8_t *) offset + FLASH_STM32_BASE_ADDRESS) = val; rc = flash_stm32_wait_flash_idle(dev); regs->CR &= (~FLASH_CR_PG); diff --git a/drivers/flash/flash_stm32f7x.c b/drivers/flash/flash_stm32f7x.c index b65bf25a07915..324b66d81979f 100644 --- a/drivers/flash/flash_stm32f7x.c +++ b/drivers/flash/flash_stm32f7x.c @@ -60,7 +60,7 @@ static int write_byte(const struct device *dev, off_t offset, uint8_t val) barrier_dsync_fence_full(); /* write the data */ - *((uint8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + *((uint8_t *) offset + FLASH_STM32_BASE_ADDRESS) = val; /* flush the register write */ barrier_dsync_fence_full(); diff --git a/drivers/flash/flash_stm32g0x.c b/drivers/flash/flash_stm32g0x.c index 41a0e1da3bf86..5c232dacc64c1 100644 --- a/drivers/flash/flash_stm32g0x.c +++ b/drivers/flash/flash_stm32g0x.c @@ -56,7 +56,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); uint32_t tmp; int rc; diff --git a/drivers/flash/flash_stm32g4x.c b/drivers/flash/flash_stm32g4x.c index 8f11e21c20e9b..631268a70c6ae 100644 --- a/drivers/flash/flash_stm32g4x.c +++ b/drivers/flash/flash_stm32g4x.c @@ -75,7 +75,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); #if defined(FLASH_STM32_DBANK) bool dcache_enabled = false; diff --git a/drivers/flash/flash_stm32h7x.c b/drivers/flash/flash_stm32h7x.c index 61394164c1bdf..271bb413194cd 100644 --- a/drivers/flash/flash_stm32h7x.c +++ b/drivers/flash/flash_stm32h7x.c @@ -307,7 +307,7 @@ static int write_ndwords(const struct device *dev, uint8_t n) { volatile uint64_t *flash = (uint64_t *)(offset - + CONFIG_FLASH_BASE_ADDRESS); + + FLASH_STM32_BASE_ADDRESS); int rc; int i; struct flash_stm32_sector_t sector = get_sector(dev, offset); @@ -451,7 +451,7 @@ static void flash_stm32h7_flush_caches(const struct device *dev, return; /* Cache not enabled */ } - SCB_InvalidateDCache_by_Addr((uint32_t *)(CONFIG_FLASH_BASE_ADDRESS + SCB_InvalidateDCache_by_Addr((uint32_t *)(FLASH_STM32_BASE_ADDRESS + offset), len); } #endif /* CONFIG_CPU_CORTEX_M7 */ @@ -574,7 +574,7 @@ static int flash_stm32h7_read(const struct device *dev, off_t offset, barrier_dsync_fence_full(); barrier_isync_fence_full(); - memcpy(data, (uint8_t *) CONFIG_FLASH_BASE_ADDRESS + offset, len); + memcpy(data, (uint8_t *) FLASH_STM32_BASE_ADDRESS + offset, len); __set_FAULTMASK(0); SCB->CCR &= ~SCB_CCR_BFHFNMIGN_Msk; diff --git a/drivers/flash/flash_stm32l4x.c b/drivers/flash/flash_stm32l4x.c index e82bf1db30392..d9b0fbbcbee22 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -69,7 +69,7 @@ static unsigned int get_page(off_t offset) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); #ifdef CONTROL_DCACHE bool dcache_enabled = false; diff --git a/drivers/flash/flash_stm32l5x.c b/drivers/flash/flash_stm32l5x.c index 5e4c096dceae8..59b649731e948 100644 --- a/drivers/flash/flash_stm32l5x.c +++ b/drivers/flash/flash_stm32l5x.c @@ -161,7 +161,7 @@ static int write_nwords(const struct device *dev, off_t offset, const uint32_t * { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); volatile uint32_t *flash = (uint32_t *)(offset - + CONFIG_FLASH_BASE_ADDRESS); + + FLASH_STM32_BASE_ADDRESS); bool full_zero = true; uint32_t tmp; int rc; diff --git a/drivers/flash/flash_stm32wba_fm.c b/drivers/flash/flash_stm32wba_fm.c index 2628f650dccfd..ff42c2643c533 100644 --- a/drivers/flash/flash_stm32wba_fm.c +++ b/drivers/flash/flash_stm32wba_fm.c @@ -93,7 +93,7 @@ static int flash_stm32_read(const struct device *dev, off_t offset, flash_stm32_sem_take(dev); - memcpy(data, (uint8_t *) CONFIG_FLASH_BASE_ADDRESS + offset, len); + memcpy(data, (uint8_t *) FLASH_STM32_BASE_ADDRESS + offset, len); flash_stm32_sem_give(dev); @@ -153,7 +153,7 @@ static int flash_stm32_write(const struct device *dev, off_t offset, LOG_DBG("Write offset: %p, len: %zu", (void *)offset, len); rc = FM_Write((uint32_t *)data, - (uint32_t *)(CONFIG_FLASH_BASE_ADDRESS + offset), + (uint32_t *)(FLASH_STM32_BASE_ADDRESS + offset), (int32_t)len/4, &cb_ptr); if (rc == 0) { k_sem_take(&flash_busy, K_FOREVER); diff --git a/drivers/flash/flash_stm32wbax.c b/drivers/flash/flash_stm32wbax.c index 0796b9a5be401..db158f71a9a27 100644 --- a/drivers/flash/flash_stm32wbax.c +++ b/drivers/flash/flash_stm32wbax.c @@ -109,7 +109,7 @@ static int write_qword(const struct device *dev, off_t offset, const uint32_t *b { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); volatile uint32_t *flash = (uint32_t *)(offset - + CONFIG_FLASH_BASE_ADDRESS); + + FLASH_STM32_BASE_ADDRESS); uint32_t tmp; int rc; diff --git a/drivers/flash/flash_stm32wbx.c b/drivers/flash/flash_stm32wbx.c index e72fddf756f75..293d9c5a54ee8 100644 --- a/drivers/flash/flash_stm32wbx.c +++ b/drivers/flash/flash_stm32wbx.c @@ -60,7 +60,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); uint32_t tmp; int ret, rc; From 3291b4cb1ce4c8325d9aaa0a7f0f9241c6440db9 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 2 Aug 2023 16:57:22 +0200 Subject: [PATCH 2/7] drivers: flash: stm32 flash driver has a Kconfig STM32_MEMMAP This CONFIG_STM32_MEMMAP is for enabling the MemoryMapped mode on external octo or quad spi memory. In this case, the flash_stm32_read is done in mem map mode the flash_stm32_erase is not available. Signed-off-by: Francois Ramu --- drivers/flash/Kconfig.stm32 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index a452ab8b98d0f..d431b76cbe19b 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -72,4 +72,11 @@ config FLASH_STM32_BLOCK_REGISTERS registers improves system security, because flash content (or protection settings) can't be changed even when exploit was found. +config STM32_MEMMAP + bool "NOR Flash in MemoryMapped for XiP" + depends on XIP + help + This option enables the XIP mode for the external NOR flash + mounted on STM32 boards. + endif # SOC_FLASH_STM32 From 44a19342c486127b7e9f296fa90bc1204c0493bd Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 1 Jun 2023 15:39:02 +0200 Subject: [PATCH 3/7] drivers: flash: stm32 ospi drivers with Memorymapped mode Enable the MemoryMapped Mode for the stm32 octoFlash driver Configure the Flash in MemoryMapped to use in XiP mode. With this mode the erase and write are not supported. Address and size are given by the DTS register property. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_ospi.c | 190 +++++++++++++++++- .../flash_controller/st,stm32-ospi-nor.yaml | 4 +- 2 files changed, 187 insertions(+), 7 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 9d2ed2412dc52..4fcc904746b68 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -36,6 +36,9 @@ LOG_MODULE_REGISTER(flash_stm32_ospi, CONFIG_FLASH_LOG_LEVEL); (_CONCAT(HAL_OSPIM_, DT_STRING_TOKEN(STM32_OSPI_NODE, prop))), \ ((default_value))) +/* Get the base address of the flash from the DTS node */ +#define STM32_OSPI_BASE_ADDRESS DT_REG_ADDR(DT_INST(0, st_stm32_ospi_nor)) + #define STM32_OSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) #define STM32_OSPI_DLYB_BYPASSED DT_PROP(STM32_OSPI_NODE, dlyb_bypass) @@ -955,11 +958,136 @@ static int stm32_ospi_mem_reset(const struct device *dev) return 0; } +#ifdef CONFIG_STM32_MEMMAP +/* Function to configure the octoflash in MemoryMapped mode */ +static int stm32_ospi_set_memorymap(const struct device *dev) +{ + HAL_StatusTypeDef ret; + const struct flash_stm32_ospi_config *dev_cfg = dev->config; + struct flash_stm32_ospi_data *dev_data = dev->data; + OSPI_RegularCmdTypeDef s_command; + OSPI_MemoryMappedTypeDef s_MemMappedCfg = {0}; + + /* Configure octoflash in MemoryMapped mode */ + if ((dev_cfg->data_mode == OSPI_SPI_MODE) && + (stm32_ospi_hal_address_size(dev) == HAL_OSPI_ADDRESS_24_BITS)) { + /* OPI mode and 3-bytes address size not supported by memory */ + LOG_ERR("OSPI_SPI_MODE in 3Bytes addressing is not supported"); + return -EIO; + } + + /* Initialize the read command */ + s_command.OperationType = HAL_OSPI_OPTYPE_READ_CFG; + s_command.FlashId = HAL_OSPI_FLASH_ID_1; + s_command.InstructionMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? ((dev_cfg->data_mode == OSPI_SPI_MODE) + ? HAL_OSPI_INSTRUCTION_1_LINE + : HAL_OSPI_INSTRUCTION_8_LINES) + : HAL_OSPI_INSTRUCTION_8_LINES; + s_command.InstructionDtrMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? HAL_OSPI_INSTRUCTION_DTR_DISABLE + : HAL_OSPI_INSTRUCTION_DTR_ENABLE; + s_command.InstructionSize = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? ((dev_cfg->data_mode == OSPI_SPI_MODE) + ? HAL_OSPI_INSTRUCTION_8_BITS + : HAL_OSPI_INSTRUCTION_16_BITS) + : HAL_OSPI_INSTRUCTION_16_BITS; + s_command.Instruction = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? ((dev_cfg->data_mode == OSPI_SPI_MODE) + ? ((stm32_ospi_hal_address_size(dev) == + HAL_OSPI_ADDRESS_24_BITS) + ? SPI_NOR_CMD_READ_FAST + : SPI_NOR_CMD_READ_FAST_4B) + : SPI_NOR_OCMD_RD) + : SPI_NOR_OCMD_DTR_RD; + s_command.AddressMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? ((dev_cfg->data_mode == OSPI_SPI_MODE) + ? HAL_OSPI_ADDRESS_1_LINE + : HAL_OSPI_ADDRESS_8_LINES) + : HAL_OSPI_ADDRESS_8_LINES; + s_command.AddressDtrMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? HAL_OSPI_ADDRESS_DTR_DISABLE + : HAL_OSPI_ADDRESS_DTR_ENABLE; + s_command.AddressSize = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? stm32_ospi_hal_address_size(dev) + : HAL_OSPI_ADDRESS_32_BITS; + s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? ((dev_cfg->data_mode == OSPI_SPI_MODE) + ? HAL_OSPI_DATA_1_LINE + : HAL_OSPI_DATA_8_LINES) + : HAL_OSPI_DATA_8_LINES; + s_command.DataDtrMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? HAL_OSPI_DATA_DTR_DISABLE + : HAL_OSPI_DATA_DTR_ENABLE; + s_command.DummyCycles = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? ((dev_cfg->data_mode == OSPI_SPI_MODE) + ? SPI_NOR_DUMMY_RD + : SPI_NOR_DUMMY_RD_OCTAL) + : SPI_NOR_DUMMY_RD_OCTAL_DTR; + s_command.DQSMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) + ? HAL_OSPI_DQS_DISABLE + : HAL_OSPI_DQS_ENABLE; + + s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + + ret = HAL_OSPI_Command(&dev_data->hospi, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); + if (ret != HAL_OK) { + LOG_ERR("%d: Failed to set memory map", ret); + return -EIO; + } + + /* Initialize the program command */ + s_command.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG; + if (dev_cfg->data_rate == OSPI_STR_TRANSFER) { + s_command.Instruction = (dev_cfg->data_mode == OSPI_SPI_MODE) + ? ((stm32_ospi_hal_address_size(dev) == + HAL_OSPI_ADDRESS_24_BITS) + ? SPI_NOR_CMD_PP + : SPI_NOR_CMD_PP_4B) + : SPI_NOR_OCMD_PAGE_PRG; + } else { + s_command.Instruction = SPI_NOR_OCMD_PAGE_PRG; + } + s_command.DQSMode = HAL_OSPI_DQS_DISABLE; + s_command.DummyCycles = 0U; + + ret = HAL_OSPI_Command(&dev_data->hospi, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); + if (ret != HAL_OK) { + LOG_ERR("%d: Failed to set memory mapped", ret); + return -EIO; + } + + /* Enable the memory-mapping */ + s_MemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE; + + ret = HAL_OSPI_MemoryMapped(&dev_data->hospi, &s_MemMappedCfg); + if (ret != HAL_OK) { + LOG_ERR("%d: Failed to set memory mapped", ret); + return -EIO; + } + + LOG_INF("MemoryMap mode enabled"); + return 0; +} + +/* Function to return true if the octoflash is in MemoryMapped else false */ +static bool stm32_ospi_is_memorymap(const struct device *dev) +{ + struct flash_stm32_ospi_data *dev_data = dev->data; + + return ((READ_BIT(dev_data->hospi.Instance->CR, + OCTOSPI_CR_FMODE) == OCTOSPI_CR_FMODE) ? + true : false); +} +#endif /* CONFIG_STM32_MEMMAP */ + /* * Function to erase the flash : chip or sector with possible OSPI/SPI and STR/DTR * to erase the complete chip (using dedicated command) : * set size >= flash size * set addr = 0 + * NOTE: cannot erase in MemoryMapped mode */ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, size_t size) @@ -989,6 +1117,13 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, return -ENOTSUP; } +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + LOG_INF("MemoryMap : cannot erase"); + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + OSPI_RegularCmdTypeDef cmd_erase = { .OperationType = HAL_OSPI_OPTYPE_COMMON_CFG, .FlashId = HAL_OSPI_FLASH_ID_1, @@ -1003,9 +1138,9 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, if (stm32_ospi_mem_ready(&dev_data->hospi, dev_cfg->data_mode, dev_cfg->data_rate) != 0) { - ospi_unlock_thread(dev); LOG_ERR("Erase failed : flash busy"); - return -EBUSY; + ret = -EBUSY; + goto end_erase; } cmd_erase.InstructionMode = (dev_cfg->data_mode == OSPI_OPI_MODE) @@ -1115,6 +1250,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, } +end_erase: ospi_unlock_thread(dev); return ret; @@ -1139,6 +1275,17 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + LOG_DBG("MemoryMapped Read offset: 0x%lx, len: %zu", + (long)(STM32_OSPI_BASE_ADDRESS + addr), + size); + memcpy(data, (uint8_t *)STM32_OSPI_BASE_ADDRESS + addr, size); + + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + OSPI_RegularCmdTypeDef cmd = ospi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate); if (dev_cfg->data_mode != OSPI_OPI_MODE) { @@ -1207,7 +1354,10 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr, return ret; } -/* Function to write the flash (page program) : with possible OSPI/SPI and STR/DTR */ +/* + * Function to write the flash (page program) : with possible OSPI/SPI and STR/DTR + * NOTE: writing in MemoryMapped mode is not guaranted + */ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, const void *data, size_t size) { @@ -1227,6 +1377,16 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + LOG_DBG("MemoryMapped Write offset: 0x%lx, len: %zu", + (long)(STM32_OSPI_BASE_ADDRESS + addr), + size); + memcpy((uint8_t *)STM32_OSPI_BASE_ADDRESS + addr, data, size); + + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ /* page program for STR or DTR mode */ OSPI_RegularCmdTypeDef cmd_pp = ospi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate); @@ -1891,6 +2051,16 @@ static int flash_stm32_ospi_init(const struct device *dev) return -ENODEV; } +#ifdef CONFIG_STM32_MEMMAP + /* If MemoryMapped then configure skip init */ + if (stm32_ospi_is_memorymap(dev)) { + LOG_INF("NOR init'd in MemMapped mode\n"); + /* Force HAL instance in correct state */ + dev_data->hospi.State = HAL_OSPI_STATE_BUSY_MEM_MAPPED; + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + #if STM32_OSPI_USE_DMA /* * DMA configuration @@ -2235,6 +2405,18 @@ static int flash_stm32_ospi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ +#ifdef CONFIG_STM32_MEMMAP + /* Now configure the octo Flash in MemoryMapped (access by address) */ + ret = stm32_ospi_set_memorymap(dev); + if (ret != 0) { + LOG_ERR("Error (%d): setting NOR in MemoryMapped mode", ret); + return -EINVAL; + } + LOG_INF("NOR in MemoryMapped mode at 0x%lx (0x%x bytes)", + (long)(STM32_OSPI_BASE_ADDRESS), + dev_cfg->flash_size); + +#endif /* CONFIG_STM32_MEMMAP */ return 0; } @@ -2300,7 +2482,7 @@ static const struct flash_stm32_ospi_config flash_stm32_ospi_cfg = { .enr = DT_CLOCKS_CELL_BY_NAME(STM32_OSPI_NODE, ospi_mgr, bits)}, #endif .irq_config = flash_stm32_ospi_irq_config_func, - .flash_size = DT_INST_PROP(0, size) / 8U, + .flash_size = DT_REG_ADDR_BY_IDX(DT_INST(0, st_stm32_ospi_nor), 1), .max_frequency = DT_INST_PROP(0, ospi_max_frequency), .data_mode = DT_INST_PROP(0, spi_bus_width), /* SPI or OPI */ .data_rate = DT_INST_PROP(0, data_rate), /* DTR or STR */ diff --git a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml index f8f84020f6a15..25dce9c076940 100644 --- a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml +++ b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml @@ -25,13 +25,11 @@ on-bus: ospi properties: reg: required: true + description: Flash Memory base address and size in bytes ospi-max-frequency: type: int required: true description: Maximum clock frequency of device's OSPI interface in Hz - size: - required: true - description: Flash Memory size in bits reset-gpios: type: phandle-array description: RESETn pin From aeed3d34ee5ffd49f60ff191a03ec6cf27d5693f Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 24 Jan 2024 12:55:47 +0100 Subject: [PATCH 4/7] drivers: flash: stm32 ospi driver aborts memmap before erase/write This change is aborting the memoryMapped mode of the octo-flash before erasing or writing the NOR. Operations are performed in command mode. Reading is always performed in MemoryMapped mode (memcopy) Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_ospi.c | 48 ++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 4fcc904746b68..83d4275fd9a07 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -998,7 +998,7 @@ static int stm32_ospi_set_memorymap(const struct device *dev) HAL_OSPI_ADDRESS_24_BITS) ? SPI_NOR_CMD_READ_FAST : SPI_NOR_CMD_READ_FAST_4B) - : SPI_NOR_OCMD_RD) + : dev_data->read_opcode) : SPI_NOR_OCMD_DTR_RD; s_command.AddressMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER) ? ((dev_cfg->data_mode == OSPI_SPI_MODE) @@ -1063,11 +1063,11 @@ static int stm32_ospi_set_memorymap(const struct device *dev) ret = HAL_OSPI_MemoryMapped(&dev_data->hospi, &s_MemMappedCfg); if (ret != HAL_OK) { - LOG_ERR("%d: Failed to set memory mapped", ret); + LOG_ERR("%d: Failed to enable memory mapped", ret); return -EIO; } - LOG_INF("MemoryMap mode enabled"); + LOG_DBG("MemoryMap mode enabled"); return 0; } @@ -1080,6 +1080,20 @@ static bool stm32_ospi_is_memorymap(const struct device *dev) OCTOSPI_CR_FMODE) == OCTOSPI_CR_FMODE) ? true : false); } + +/* Abort the Memorymapped Mode so that erasing is possible */ +static int stm32_ospi_abort_memmap(const struct device *dev) +{ + struct flash_stm32_ospi_data *dev_data = dev->data; + + if (HAL_OSPI_Abort(&dev_data->hospi) != HAL_OK) { + LOG_ERR("MemoryMap abort failed"); + return -EIO; + } + LOG_DBG("MemoryMap mode disabled"); + + return 0; +} #endif /* CONFIG_STM32_MEMMAP */ /* @@ -1119,8 +1133,12 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, #ifdef CONFIG_STM32_MEMMAP if (stm32_ospi_is_memorymap(dev)) { - LOG_INF("MemoryMap : cannot erase"); - return 0; + /* If the Flash is in MemoryMapped mode, abort it and continue */ + LOG_INF("MemoryMap : disable before erase"); + if (stm32_ospi_abort_memmap(dev) != 0) { + LOG_ERR("MemoryMap not aborted correctly"); + return -EIO; + } } #endif /* CONFIG_STM32_MEMMAP */ @@ -1276,6 +1294,14 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr, } #ifdef CONFIG_STM32_MEMMAP + /* If not MemMapped then configure it */ + if (!stm32_ospi_is_memorymap(dev)) { + if (stm32_ospi_set_memorymap(dev) != 0) { + LOG_ERR("READ failed: cannot enable MemoryMap"); + return -EIO; + } + } + LOG_INF("MemoryMap : enable before read"); if (stm32_ospi_is_memorymap(dev)) { LOG_DBG("MemoryMapped Read offset: 0x%lx, len: %zu", (long)(STM32_OSPI_BASE_ADDRESS + addr), @@ -1379,6 +1405,18 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, #ifdef CONFIG_STM32_MEMMAP if (stm32_ospi_is_memorymap(dev)) { + /* If the Flash is in MemoryMapped mode, abort it and continue */ + LOG_INF("MemoryMap : disable before write"); + if (stm32_ospi_abort_memmap(dev) != 0) { + LOG_ERR("MemoryMap not aborted correctly"); + return -EIO; + } + } + if (stm32_ospi_is_memorymap(dev)) { + /* + * If the Flash is in MemoryMapped mode, write by memcopy + * should not due to previous operation + */ LOG_DBG("MemoryMapped Write offset: 0x%lx, len: %zu", (long)(STM32_OSPI_BASE_ADDRESS + addr), size); From 5e10f8acf2b23fdbf81c0075b6b6c2e9f8754f0a Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 6 Sep 2023 15:54:25 +0200 Subject: [PATCH 5/7] soc: arm: stm32u5 device with DCACHE for writing to NOR flash Enable the DCACHE1 in INCR burt mode to allow writing to the external NOR octoFlash when in MemoryMapped mode Signed-off-by: Francois Ramu --- soc/arm/st_stm32/stm32u5/soc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/soc/arm/st_stm32/stm32u5/soc.c b/soc/arm/st_stm32/stm32u5/soc.c index d25fec9c680d5..68df79d620b5e 100644 --- a/soc/arm/st_stm32/stm32u5/soc.c +++ b/soc/arm/st_stm32/stm32u5/soc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,10 @@ static int stm32u5_init(void) LL_ICACHE_SetMode(LL_ICACHE_1WAY); LL_ICACHE_Enable(); + /* Enable data cache (master port write access) */ + LL_DCACHE_SetReadBurstType(DCACHE1, LL_DCACHE_READ_BURST_INCR); + LL_DCACHE_Enable(DCACHE1); + /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSIS */ SystemCoreClock = 4000000; From 84aca6d23b42b9f6d197545ac7e7064c997931fa Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 31 Aug 2023 14:43:44 +0200 Subject: [PATCH 6/7] boards: arm: stm32u585 disco kit for XiP on external octoflash Define the Device tree of the b_u585i_iot02a disco kit to access the external NOR octo-flash in MemoryMapped mode for XiP Signed-off-by: Francois Ramu --- boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi | 11 ++++++----- boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts | 6 +----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi index f2dd82f9ad126..1aa1d94e75550 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi @@ -131,11 +131,10 @@ stm32_lp_tick_source: &lptim1 { status = "okay"; - mx25lm51245: ospi-nor-flash@0 { + mx25lm51245: ospi-nor-flash@70000000 { compatible = "st,stm32-ospi-nor"; - reg = <0>; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits */ ospi-max-frequency = ; - size = ; /* 64 MBytes */ spi-bus-width = ; data-rate = ; four-byte-opcodes; @@ -146,8 +145,10 @@ stm32_lp_tick_source: &lptim1 { #address-cells = <1>; #size-cells = <1>; - partition@0 { - reg = <0x00000000 DT_SIZE_M(64)>; + /* put image at the offset of slot1 */ + slot1_partition:partition@100000 { + label = "image-1"; + reg = <0x00100000 DT_SIZE_K(416)>; }; }; }; diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts index f8a826b1b6ed4..42a9f89b5ce98 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts @@ -16,7 +16,6 @@ zephyr,shell-uart = &usart1; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; }; aliases { @@ -45,10 +44,7 @@ label = "image-0"; reg = <0x00010000 DT_SIZE_K(416)>; }; - slot1_partition: partition@78000 { - label = "image-1"; - reg = <0x00078000 DT_SIZE_K(416)>; - }; + scratch_partition: partition@e0000 { label = "image-scratch"; reg = <0x000e0000 DT_SIZE_K(64)>; From 2d582f4728d67766df7f70f0fdf5ce8f459490b9 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 23 Jan 2024 11:43:07 +0100 Subject: [PATCH 7/7] samples: subsys: fs_little fs on stm32u585 disco in xip Gives a sample to execute the little fs on external memory map (XiP) where the lfs1 partition is in internal mcu flash The application is built/linked/stored in the external NOR flash on slot1 partition. Signed-off-by: Francois Ramu --- .../subsys/fs/littlefs/boards/b_u585i_iot02a.conf | 2 ++ .../fs/littlefs/boards/b_u585i_iot02a.overlay | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.conf b/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.conf index c5f2188e4d31b..d906422678e6c 100644 --- a/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.conf +++ b/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.conf @@ -5,3 +5,5 @@ # CONFIG_FS_LITTLEFS_FC_HEAP_SIZE=8192 + +CONFIG_STM32_MEMMAP=y diff --git a/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.overlay b/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.overlay index b4996d707100a..311f3fce09df8 100644 --- a/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.overlay +++ b/samples/subsys/fs/littlefs/boards/b_u585i_iot02a.overlay @@ -5,6 +5,10 @@ */ / { + chosen { + zephyr,code-partition = &slot1_partition; + }; + fstab { compatible = "zephyr,fstab"; lfs1: lfs1 { @@ -21,13 +25,10 @@ }; }; -&mx25lm51245 { +&flash0 { partitions { - /delete-node/ partition; - - /* Use the whole flash for the filesystem. */ - lfs1_partition: partition@0 { - reg = <0x00000000 DT_SIZE_M(64)>; + lfs1_partition: partition@d0000 { + reg = <0x000d0000 DT_SIZE_K(64)>; }; }; };