diff --git a/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts b/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts index 33093d701b78d..c2df9e5aa5af0 100644 --- a/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts +++ b/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts @@ -6,6 +6,8 @@ /dts-v1/; #include "b_u585i_iot02a-common.dtsi" +#include +#include / { model = "STMicroelectronics B-U585I-IOT02A discovery kit"; @@ -25,6 +27,14 @@ led1 = &red_led_1; sw0 = &user_button; }; + + octo_nor: memory@70000000 { + compatible = "zephyr,memory-region"; + reg = <0x70000000 DT_SIZE_M(64)>; + zephyr,memory-region = "EXTMEM"; + /* The ATTR_MPU_EXTMEM attribut causing a MPU FAULT */ + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; }; &flash0 { diff --git a/boards/st/b_u585i_iot02a/board.cmake b/boards/st/b_u585i_iot02a/board.cmake index 73320d749c616..8b9544b745b64 100644 --- a/boards/st/b_u585i_iot02a/board.cmake +++ b/boards/st/b_u585i_iot02a/board.cmake @@ -12,8 +12,13 @@ if(CONFIG_BUILD_WITH_TFM) endif() endif() -board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw") +if(CONFIG_STM32_MEMMAP) board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +board_runner_args(stm32cubeprogrammer "--hex-file=${ZEPHYR_BASE}/build/zephyr/zephyr.hex") +board_runner_args(stm32cubeprogrammer "--extload=MX25LM51245G_STM32U585I-IOT02A.stldr") +else() +board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw") +endif() board_runner_args(openocd "--tcl-port=6666") board_runner_args(openocd --cmd-pre-init "gdb_report_data_abort enable") diff --git a/boards/st/stm32h7b3i_dk/board.cmake b/boards/st/stm32h7b3i_dk/board.cmake index d13c9c0e976b1..091f1d393a26d 100644 --- a/boards/st/stm32h7b3i_dk/board.cmake +++ b/boards/st/stm32h7b3i_dk/board.cmake @@ -4,5 +4,14 @@ board_runner_args(jlink "--device=STM32H7B3LI" "--speed=4000") board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) +if(CONFIG_STM32_MEMMAP) +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +board_runner_args(stm32cubeprogrammer "--hex-file=${ZEPHYR_BASE}/build/zephyr/zephyr.hex") +board_runner_args(stm32cubeprogrammer "--extload=MX25LM51245G_STM32H7B3I-DISCO.stldr") +else() +board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw" ) +endif() + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts b/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts index 8868581770685..f05809f523ba5 100644 --- a/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts +++ b/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts @@ -59,6 +59,14 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; }; + octo_nor: memory@90000000 { + compatible = "zephyr,memory-region"; + reg = <0x90000000 DT_SIZE_M(64)>; + zephyr,memory-region = "EXTMEM"; + /* The ATTR_MPU_EXTMEM attribut causing a MPU FAULT */ + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; + transceiver0: can-phy0 { compatible = "microchip,mcp2562fd", "can-transceiver-gpio"; standby-gpios = <&gpioh 8 GPIO_ACTIVE_HIGH>; diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index e2a22fba6cf6e..e34c38e6eec71 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -978,11 +978,149 @@ 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; + + /* 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) + : 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) + ? 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; + + 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); +} + +static int stm32_ospi_abort(const struct device *dev) +{ + struct flash_stm32_ospi_data *dev_data = dev->data; + HAL_StatusTypeDef hal_ret; + + hal_ret = HAL_OSPI_Abort(&dev_data->hospi); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: OSPI abort failed", hal_ret); + return -EIO; + } + + return 0; +} +#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) @@ -1012,6 +1150,20 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, return -ENOTSUP; } + ospi_lock_thread(dev); + +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + /* Abort ongoing transfer to force CS high/BUSY deasserted */ + ret = stm32_ospi_abort(dev); + if (ret != 0) { + LOG_ERR("Failed to abort memory-mapped access before erase"); + goto end_erase; + } + } + /* Continue with Indirect Mode */ +#endif /* CONFIG_STM32_MEMMAP */ + OSPI_RegularCmdTypeDef cmd_erase = { .OperationType = HAL_OSPI_OPTYPE_COMMON_CFG, .FlashId = HAL_OSPI_FLASH_ID_1, @@ -1022,13 +1174,11 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, .SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD, }; - ospi_lock_thread(dev); - if (stm32_ospi_mem_ready(dev_data, 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) @@ -1134,9 +1284,10 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, ret = stm32_ospi_mem_ready(dev_data, dev_cfg->data_mode, dev_cfg->data_rate); } - } + goto end_erase; +end_erase: ospi_unlock_thread(dev); return ret; @@ -1146,9 +1297,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, static int flash_stm32_ospi_read(const struct device *dev, off_t addr, void *data, size_t size) { - const struct flash_stm32_ospi_config *dev_cfg = dev->config; - struct flash_stm32_ospi_data *dev_data = dev->data; - int ret; + int ret = 0; if (!ospi_address_is_valid(dev, addr, size)) { LOG_ERR("Error: address or size exceeds expected values: " @@ -1161,6 +1310,25 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr, return 0; } +#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; + } + } + /* Now in MemMapped mode : read with memcopy */ + 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); + +#else /* CONFIG_STM32_MEMMAP */ + const struct flash_stm32_ospi_config *dev_cfg = dev->config; + struct flash_stm32_ospi_data *dev_data = dev->data; + + OSPI_RegularCmdTypeDef cmd = ospi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate); if (dev_cfg->data_mode != OSPI_OPI_MODE) { @@ -1226,10 +1394,14 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr, ospi_unlock_thread(dev); +#endif /* CONFIG_STM32_MEMMAP */ 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) { @@ -1249,6 +1421,19 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, return 0; } + ospi_lock_thread(dev); + +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + /* Abort ongoing transfer to force CS high/BUSY deasserted */ + ret = stm32_ospi_abort(dev); + if (ret != 0) { + LOG_ERR("Failed to abort memory-mapped access before write"); + goto end_write; + } + } + /* Continue with Indirect Mode */ +#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); @@ -1292,7 +1477,6 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, cmd_pp.DummyCycles = 0U; LOG_DBG("OSPI: write %zu data", size); - ospi_lock_thread(dev); ret = stm32_ospi_mem_ready(dev_data, dev_cfg->data_mode, dev_cfg->data_rate); @@ -1341,7 +1525,9 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, break; } } + goto end_write; +end_write: ospi_unlock_thread(dev); return ret; @@ -1913,6 +2099,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_DBG("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 @@ -2292,9 +2488,21 @@ static int flash_stm32_ospi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ - LOG_INF("NOR octo-flash at 0x%lx (0x%x bytes)", +#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_DBG("NOR octo-flash in MemoryMapped mode at 0x%lx (0x%x bytes)", + (long)(STM32_OSPI_BASE_ADDRESS), + dev_cfg->flash_size); +#else + LOG_DBG("NOR octo-flash at 0x%lx (0x%x bytes)", (long)(STM32_OSPI_BASE_ADDRESS), dev_cfg->flash_size); +#endif /* CONFIG_STM32_MEMMAP */ return 0; } diff --git a/samples/application_development/code_relocation_nocopy/README.rst b/samples/application_development/code_relocation_nocopy/README.rst index 2e0f49f520f83..9b7ca572a0fff 100644 --- a/samples/application_development/code_relocation_nocopy/README.rst +++ b/samples/application_development/code_relocation_nocopy/README.rst @@ -39,6 +39,18 @@ to 0x90000000. :goals: build flash :compact: +STM32 b_u585i_iot02a Discovery kit instructions +*********************************************** + +The b_u585i_iot02a has 64MB of external flash attached via OSPI. It is mapped +to 0x70000000. + +.. zephyr-app-commands:: + :zephyr-app: samples/application_development/code_relocation_nocopy + :board: b_u585i_iot02a + :goals: build flash + :compact: + Execution output **************** diff --git a/samples/application_development/code_relocation_nocopy/boards/b_u585i_iot02a.conf b/samples/application_development/code_relocation_nocopy/boards/b_u585i_iot02a.conf new file mode 100644 index 0000000000000..eac2504a7850e --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/b_u585i_iot02a.conf @@ -0,0 +1,2 @@ +CONFIG_FLASH=y +CONFIG_STM32_MEMMAP=y diff --git a/samples/application_development/code_relocation_nocopy/boards/stm32h7b3i_dk.conf b/samples/application_development/code_relocation_nocopy/boards/stm32h7b3i_dk.conf new file mode 100644 index 0000000000000..eac2504a7850e --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/stm32h7b3i_dk.conf @@ -0,0 +1,2 @@ +CONFIG_FLASH=y +CONFIG_STM32_MEMMAP=y diff --git a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld index 4bf540a721100..7d4e3a964fc35 100644 --- a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld +++ b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld @@ -26,6 +26,13 @@ #define EXTFLASH_SIZE DT_PROP_OR(EXTFLASH_NODE, size_in_bytes, \ DT_PROP(EXTFLASH_NODE, size) / 8) +#elif defined(CONFIG_STM32_MEMMAP) && DT_NODE_EXISTS(DT_INST(0, st_stm32_ospi_nor)) +/* On stm32 OSPI, external flash is mapped in XIP region at address given by the reg property. */ + +#define EXTFLASH_NODE DT_INST(0, st_stm32_ospi_nor) +#define EXTFLASH_ADDR DT_REG_ADDR(DT_INST(0, st_stm32_ospi_nor)) +#define EXTFLASH_SIZE DT_REG_ADDR_BY_IDX(DT_INST(0, st_stm32_ospi_nor), 1) + #elif defined(CONFIG_STM32_MEMMAP) && DT_NODE_EXISTS(DT_INST(0, st_stm32_qspi_nor)) /* On stm32 QSPI, external flash is mapped in XIP region at address given by the reg property. */ diff --git a/samples/application_development/code_relocation_nocopy/sample.yaml b/samples/application_development/code_relocation_nocopy/sample.yaml index a583ea3b44f0f..b653213fa4d6e 100644 --- a/samples/application_development/code_relocation_nocopy/sample.yaml +++ b/samples/application_development/code_relocation_nocopy/sample.yaml @@ -7,6 +7,8 @@ tests: - qemu_cortex_m3 - nrf5340dk/nrf5340/cpuapp - stm32f769i_disco + - stm32h7b3i_dk + - b_u585i_iot02a integration_platforms: - qemu_cortex_m3 tags: linker