diff --git a/boards/st/stm32f746g_disco/stm32f746g_disco.dts b/boards/st/stm32f746g_disco/stm32f746g_disco.dts index 6250c4e8e80d..c48d7258eab9 100644 --- a/boards/st/stm32f746g_disco/stm32f746g_disco.dts +++ b/boards/st/stm32f746g_disco/stm32f746g_disco.dts @@ -185,6 +185,7 @@ zephyr_udc0: &usbotg_fs { &quadspi_bk1_io0_pd11 &quadspi_bk1_io1_pd12 &quadspi_bk1_io2_pe2 &quadspi_bk1_io3_pd13>; pinctrl-names = "default"; + flash-id = <1>; /* One quad NOR : single flash mode */ status = "okay"; n25q128a1: qspi-nor-flash@90000000 { diff --git a/boards/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts b/boards/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts index 8f27eb0f8365..528a8ed04b06 100644 --- a/boards/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts +++ b/boards/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts @@ -20,7 +20,6 @@ zephyr,shell-uart = &usart1; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,flash-controller = &mt25ql512ab1; }; sdram2: sdram@d0000000 { @@ -31,6 +30,14 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>; }; + quad_nor: memory@90000000 { + compatible = "zephyr,memory-region"; + reg = <0x90000000 DT_SIZE_K(800)>; /* size of the slot partition */ + zephyr,memory-region = "EXTMEM"; + /* The ATTR_MPU_EXTMEM attribut causing a MPU FAULT */ + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; + leds { green_led_1:led_1 { status = "okay"; @@ -111,6 +118,19 @@ #address-cells = <1>; #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(60)>; + }; + + scratch_partition: partition@1f000 { + label = "image-scratch"; + reg = <0x0001f000 DT_SIZE_K(2)>; + }; /* Set 2KB of storage at the end of first 1MB flash */ storage_partition: partition@ff800 { label = "storage"; diff --git a/boards/st/stm32h750b_dk/stm32h750b_dk.dts b/boards/st/stm32h750b_dk/stm32h750b_dk.dts index 7cd328e90dbd..3d8bf439815e 100644 --- a/boards/st/stm32h750b_dk/stm32h750b_dk.dts +++ b/boards/st/stm32h750b_dk/stm32h750b_dk.dts @@ -18,7 +18,6 @@ zephyr,shell-uart = &usart3; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,flash-controller = &mt25ql512ab1; }; sdram2: sdram@d0000000 { @@ -29,6 +28,14 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>; }; + quad_nor: memory@90000000 { + compatible = "zephyr,memory-region"; + reg = <0x90000000 DT_SIZE_K(800)>; /* size of the slot partition */ + zephyr,memory-region = "EXTMEM"; + /* The ATTR_MPU_EXTMEM attribut causing a MPU FAULT */ + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; + leds { compatible = "gpio-leds"; red_led: led_1 { @@ -92,6 +99,33 @@ status = "okay"; }; +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(60)>; + }; + + scratch_partition: partition@1f000 { + label = "image-scratch"; + reg = <0x0001f000 DT_SIZE_K(2)>; + }; + storage_partition: partition@1f800 { + label = "storage"; + reg = <0x0001f800 DT_SIZE_K(2)>; + }; + + }; +}; + &quadspi { pinctrl-names = "default"; pinctrl-0 = <&quadspi_clk_pf10 &quadspi_bk1_ncs_pg6 @@ -99,7 +133,7 @@ &quadspi_bk1_io2_pf7 &quadspi_bk1_io3_pf6 &quadspi_bk2_io0_ph2 &quadspi_bk2_io1_ph3 &quadspi_bk2_io2_pg9 &quadspi_bk2_io3_pg14>; - flash-id = <1>; + status = "okay"; mt25ql512ab1: qspi-nor-flash-1@90000000 { diff --git a/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts b/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts index 1567585b2fd5..879c09d5c93f 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_K(800)>; /* size of the slot partition */ + 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/boards/st/stm32l496g_disco/stm32l496g_disco.dts b/boards/st/stm32l496g_disco/stm32l496g_disco.dts index e2a70f6163d5..b16e74ab9910 100644 --- a/boards/st/stm32l496g_disco/stm32l496g_disco.dts +++ b/boards/st/stm32l496g_disco/stm32l496g_disco.dts @@ -208,5 +208,15 @@ zephyr_udc0: &usbotg_fs { status = "okay"; spi-bus-width = <4>; writeoc = "PP_1_4_4"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + reg = <0x00000000 DT_SIZE_M(8)>; + }; + }; }; }; diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index e4d78e5ce603..e15b291820bc 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -672,6 +672,16 @@ __unused static int set_up_plls(void) { #if defined(STM32_PLL_ENABLED) || defined(STM32_PLL2_ENABLED) || defined(STM32_PLL3_ENABLED) + + /* + * Skip if PLL1 is already configured by the McuBoot + * with ext NOR in MemMapped : application running in external NOR in XiP + * has not necessarily the CONFIG_STM32_MEMMAP + */ + if (LL_RCC_PLL1_IsReady()) { + return 0; + } + int r; uint32_t vco_input_range; uint32_t vco_output_range; diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index a452ab8b98d0..d431b76cbe19 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 diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 030dc8bd1563..ba5e842c38a8 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -975,11 +975,150 @@ 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) + : 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; + 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 enable memory mapped", ret); + return -EIO; + } + + LOG_DBG("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); +} + +/* 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 */ + /* * 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) @@ -1009,6 +1148,17 @@ 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)) { + /* If the Flash is in MemoryMapped mode, abort it and continue */ + LOG_DBG("MemoryMap : disable before erase"); + if (stm32_ospi_abort_memmap(dev) != 0) { + LOG_ERR("MemoryMap not aborted correctly"); + return -EIO; + } + } +#endif /* CONFIG_STM32_MEMMAP */ + OSPI_RegularCmdTypeDef cmd_erase = { .OperationType = HAL_OSPI_OPTYPE_COMMON_CFG, .FlashId = HAL_OSPI_FLASH_ID_1, @@ -1023,9 +1173,9 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, 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,6 +1284,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, } +end_erase: ospi_unlock_thread(dev); return ret; @@ -1158,6 +1309,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; + } + } + 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), + 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) { @@ -1226,7 +1396,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) { @@ -1246,6 +1419,28 @@ 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)) { + /* 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); + 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); @@ -1910,6 +2105,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 @@ -2289,9 +2494,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/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 326c1129a363..b4c0c40b144e 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -385,6 +385,58 @@ static bool qspi_address_is_valid(const struct device *dev, off_t addr, return (addr >= 0) && ((uint64_t)addr + (uint64_t)size <= flash_size); } +#ifdef CONFIG_STM32_MEMMAP +/* Function to return true if the quad-NOR flash is in MemoryMapped else false */ +static bool qspi_is_memorymap(const struct device *dev) +{ + struct flash_stm32_qspi_data *dev_data = dev->data; + + return ((READ_BIT(dev_data->hqspi.Instance->CCR, + QUADSPI_CCR_FMODE) == QUADSPI_CCR_FMODE) ? + true : false); +} + + +/* Function to configure the memmapped mode */ +static int qspi_set_memorymap(const struct device *dev) +{ + HAL_StatusTypeDef ret; + struct flash_stm32_qspi_data *dev_data = dev->data; + QSPI_CommandTypeDef s_command = {0}; + QSPI_MemoryMappedTypeDef s_memmap_cfg; + + /* Reading sequence */ + s_command.Instruction = SPI_NOR_CMD_4READ; /* 0x6B also supported */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.DataMode = QSPI_DATA_4_LINES; +#ifdef CONFIG_SOC_SERIES_STM32H7X + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.DummyCycles = SPI_NOR_DUMMY_RD_QUAD; /* less than 10 is too short */ +#elif CONFIG_SOC_SERIES_STM32F7X + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.DummyCycles = 10;/* other value than 10 is too short */ +#else + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.DummyCycles = 6;/* other value than 6 is too short */ +#endif /* CONFIG_SOC_SERIES_STM32H7X */ + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + + /* Enable the memory-mapping */ + s_memmap_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_memmap_cfg.TimeOutPeriod = 0; + + ret = HAL_QSPI_MemoryMapped(&dev_data->hqspi, &s_command, &s_memmap_cfg); + if (ret != HAL_OK) { + LOG_ERR("%d: Failed to set memory map", ret); + return -EIO; + } + + return 0; +} +#endif /* CONFIG_STM32_MEMMAP */ + static int flash_stm32_qspi_read(const struct device *dev, off_t addr, void *data, size_t size) { @@ -401,6 +453,15 @@ static int flash_stm32_qspi_read(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + if (qspi_is_memorymap(dev)) { + LOG_DBG("MemoryMapped Read offset: 0x%lx, len: %zu", + (long)(STM32_QSPI_BASE_ADDRESS + addr), size); + memcpy(data, (uint8_t *)STM32_QSPI_BASE_ADDRESS + addr, size); + + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ QSPI_CommandTypeDef cmd = { .Instruction = SPI_NOR_CMD_READ, .Address = addr, @@ -460,6 +521,16 @@ static int flash_stm32_qspi_write(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + if (qspi_is_memorymap(dev)) { + LOG_DBG("MemoryMapped Write offset: 0x%lx, len: %zu", + (long)(STM32_QSPI_BASE_ADDRESS + addr), size); + memcpy((uint8_t *)STM32_QSPI_BASE_ADDRESS + addr, data, size); + + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + QSPI_CommandTypeDef cmd_write_en = { .Instruction = SPI_NOR_CMD_WREN, .InstructionMode = QSPI_INSTRUCTION_1_LINE, @@ -541,6 +612,13 @@ static int flash_stm32_qspi_erase(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + if (qspi_is_memorymap(dev)) { + LOG_INF("MemoryMapped : cannot erase"); + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + QSPI_CommandTypeDef cmd_write_en = { .Instruction = SPI_NOR_CMD_WREN, .InstructionMode = QSPI_INSTRUCTION_1_LINE, @@ -913,6 +991,7 @@ static int qspi_write_status_register(const struct device *dev, uint8_t reg_num, return qspi_write_access(dev, &cmd, regs_p, size); } +/* Function send a Write Enable and wait it is effective. */ static int qspi_write_enable(const struct device *dev) { uint8_t reg; @@ -1188,6 +1267,17 @@ static int flash_stm32_qspi_init(const struct device *dev) return ret; } + +#ifdef CONFIG_STM32_MEMMAP + /* If MemoryMapped then configure skip init */ + if (qspi_is_memorymap(dev)) { + LOG_INF("NOR init'd in MemMapped mode\n"); + /* Force HAL instance in correct state */ + dev_data->hqspi.State = HAL_QSPI_STATE_BUSY_MEM_MAPPED; + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + #if STM32_QSPI_RESET_GPIO flash_stm32_qspi_gpio_reset(dev); #endif @@ -1281,14 +1371,29 @@ static int flash_stm32_qspi_init(const struct device *dev) /* Give a bit position from 0 to 31 to the HAL init minus 1 for the DCR1 reg */ dev_data->hqspi.Init.FlashSize = find_lsb_set(dev_cfg->flash_size) - 2; +#if !DT_NODE_HAS_PROP(DT_NODELABEL(quadspi), flash_id) && defined(QUADSPI_CR_DFM) + /* + * When the DTS has NO FlashID, it means Dual Flash + * Even in DUAL flash config, the SDFP is read from one single quad-NOR + * else the magic nb is wrong (0x46465353) + * That means that the Dual Flash config is set after the SFDP sequence + */ + dev_data->hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + dev_data->hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE; + dev_data->hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + /* Set Dual Flash Mode only on MemoryMapped */ + dev_data->hqspi.Init.FlashID = QSPI_FLASH_ID_1; +#endif /* ! flash_id */ + HAL_QSPI_Init(&dev_data->hqspi); -#if DT_NODE_HAS_PROP(DT_NODELABEL(quadspi), flash_id) +#if DT_NODE_HAS_PROP(DT_NODELABEL(quadspi), flash_id) && defined(QUADSPI_CR_DFM) uint8_t qspi_flash_id = DT_PROP(DT_NODELABEL(quadspi), flash_id); HAL_QSPI_SetFlashID(&dev_data->hqspi, (qspi_flash_id - 1) << QUADSPI_CR_FSEL_Pos); -#endif +#endif /* flash_id */ + /* Initialize semaphores */ k_sem_init(&dev_data->sem, 1, 1); k_sem_init(&dev_data->sync, 0, 1); @@ -1367,9 +1472,35 @@ static int flash_stm32_qspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ - LOG_INF("NOR quad-flash at 0x%lx (0x%x bytes)", +#ifdef CONFIG_STM32_MEMMAP + +#if !DT_NODE_HAS_PROP(DT_NODELABEL(quadspi), flash_id) && defined(QUADSPI_CR_DFM) + /* + * When the DTS has NO FlashID, it means Dual Flash + * Force Dual Flash mode now, after the SFDP sequence which is reading + * one quad-NOR only + */ + MODIFY_REG(dev_data->hqspi.Instance->CR, (QUADSPI_CR_DFM), QSPI_DUALFLASH_ENABLE); + LOG_DBG("Dual Flash Mode"); +#endif /* !flash_id */ + + +#endif /* CONFIG_STM32_MEMMAP */ + +#ifdef CONFIG_STM32_MEMMAP + ret = qspi_set_memorymap(dev); + if (ret != 0) { + LOG_ERR("Error (%d): setting NOR in MemoryMapped mode", ret); + return -EINVAL; + } + LOG_DBG("NOR quad-flash in MemoryMapped mode at 0x%lx (0x%x bytes)", (long)(STM32_QSPI_BASE_ADDRESS), dev_cfg->flash_size); +#else + LOG_DBG("NOR quad-flash at 0x%lx (0x%x bytes)", + (long)(STM32_QSPI_BASE_ADDRESS), + dev_cfg->flash_size); +#endif /* CONFIG_STM32_MEMMAP */ return 0; } @@ -1465,4 +1596,4 @@ static void flash_stm32_qspi_irq_config_func(const struct device *dev) irq_enable(DT_IRQN(STM32_QSPI_NODE)); } -#endif +#endif /* compat st_stm32_qspi_nor */ diff --git a/drivers/flash/spi_nor.h b/drivers/flash/spi_nor.h index 5f38c98289f8..23f6124eb288 100644 --- a/drivers/flash/spi_nor.h +++ b/drivers/flash/spi_nor.h @@ -60,6 +60,9 @@ #define SPI_NOR_CMD_PP_1_1_4_4B 0x34 /* Quad Page program (1-1-4) 4 Byte Address */ #define SPI_NOR_CMD_PP_1_4_4_4B 0x3e /* Quad Page program (1-4-4) 4 Byte Address */ +#define SPI_NOR_CMD_RD_VOL_CFG 0x85 /* Read Volatile configuration register */ +#define SPI_NOR_CMD_WR_VOL_CFG 0x81 /* Write Volatile configuration register */ + /* Flash octal opcodes */ #define SPI_NOR_OCMD_SE 0x21DE /* Octal Sector erase */ #define SPI_NOR_OCMD_CE 0xC738 /* Octal Chip erase */ @@ -94,6 +97,7 @@ /* Flash Dummy Cycles values */ #define SPI_NOR_DUMMY_RD 8U +#define SPI_NOR_DUMMY_RD_QUAD 10U #define SPI_NOR_DUMMY_RD_OCTAL 6U #define SPI_NOR_DUMMY_RD_OCTAL_DTR 6U #define SPI_NOR_DUMMY_REG_OCTAL 4U diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 600f959b4fd8..f6535c844427 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -46,9 +46,9 @@ quadspi_memory: memory@90000000 { compatible = "zephyr,memory-region", "mmio-sram"; - reg = <0x90000000 DT_SIZE_M(256)>; + reg = <0x90000000 DT_SIZE_M(16)>; zephyr,memory-region = "QSPI"; - zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )>; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; }; clocks { diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 95c5590a8716..37136b50b453 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -47,7 +47,7 @@ ext_memory: memory@90000000 { compatible = "zephyr,memory-region"; - reg = <0x90000000 DT_SIZE_M(256)>; /* max addressable area */ + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ zephyr,memory-region = "EXTMEM"; zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )>; }; diff --git a/dts/bindings/qspi/st,stm32-qspi.yaml b/dts/bindings/qspi/st,stm32-qspi.yaml index 04aa6e4d0208..cea2f66a70eb 100644 --- a/dts/bindings/qspi/st,stm32-qspi.yaml +++ b/dts/bindings/qspi/st,stm32-qspi.yaml @@ -66,5 +66,7 @@ properties: QSPI GPIO banks (defined as 'quadspi_bk[12]' in pinctrl property) to communicate with flash memory. + When NOT set, it means Dual Flash Mode. + For example flash-id = <2>; 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 000000000000..eac2504a7850 --- /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/stm32f746g_disco.conf b/samples/application_development/code_relocation_nocopy/boards/stm32f746g_disco.conf new file mode 100644 index 000000000000..abbcc320bb35 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/stm32f746g_disco.conf @@ -0,0 +1,5 @@ +CONFIG_FLASH=y +CONFIG_STM32_MEMMAP=y + +CONFIG_LOG=y +CONFIG_FLASH_LOG_LEVEL_DBG=y diff --git a/samples/application_development/code_relocation_nocopy/boards/stm32h747i_disco.conf b/samples/application_development/code_relocation_nocopy/boards/stm32h747i_disco.conf new file mode 100644 index 000000000000..abbcc320bb35 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/stm32h747i_disco.conf @@ -0,0 +1,5 @@ +CONFIG_FLASH=y +CONFIG_STM32_MEMMAP=y + +CONFIG_LOG=y +CONFIG_FLASH_LOG_LEVEL_DBG=y diff --git a/samples/application_development/code_relocation_nocopy/boards/stm32h750b_dk.conf b/samples/application_development/code_relocation_nocopy/boards/stm32h750b_dk.conf new file mode 100644 index 000000000000..eac2504a7850 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/stm32h750b_dk.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 000000000000..eac2504a7850 --- /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/boards/stm32l496g_disco.conf b/samples/application_development/code_relocation_nocopy/boards/stm32l496g_disco.conf new file mode 100644 index 000000000000..eac2504a7850 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/stm32l496g_disco.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 7ead7f6bae48..7d4e3a964fc3 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,20 @@ #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. */ + +#define EXTFLASH_NODE DT_INST(0, st_stm32_qspi_nor) +#define EXTFLASH_ADDR DT_REG_ADDR(DT_INST(0, st_stm32_qspi_nor)) +#define EXTFLASH_SIZE DT_REG_ADDR_BY_IDX(DT_INST(0, st_stm32_qspi_nor), 1) + #else /*