diff --git a/boards/st/nucleo_wb55rg/nucleo_wb55rg.dts b/boards/st/nucleo_wb55rg/nucleo_wb55rg.dts index 8c4c56d294ee3..680c646416b15 100644 --- a/boards/st/nucleo_wb55rg/nucleo_wb55rg.dts +++ b/boards/st/nucleo_wb55rg/nucleo_wb55rg.dts @@ -10,12 +10,18 @@ #include "arduino_r3_connector.dtsi" #include + +&sram0 { + reg = <0x20000000 (DT_SIZE_K(192) - 4)>; +}; + / { model = "STMicroelectronics STM32WB55RG-NUCLEO board"; compatible = "st,stm32wb55rg-nucleo"; chosen { zephyr,console = &usart1; + zephyr,boot-mode = &boot_mode; zephyr,shell-uart = &usart1; zephyr,bt-mon-uart = &lpuart1; zephyr,bt-c2h-uart = &lpuart1; @@ -24,6 +30,27 @@ zephyr,code-partition = &slot0_partition; }; + sram_ret@2002fffc { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2002fffc 0x4>; + zephyr,memory-region = "RetainedMem"; + status = "okay"; + + retainedmem { + compatible = "zephyr,retained-ram"; + status = "okay"; + #address-cells = <1>; + #size-cells = <1>; + + boot_mode: retention@0 { + compatible = "zephyr,retention"; + status = "okay"; + reg = <0x0 0x1>; + }; + }; + }; + + leds: leds { compatible = "gpio-leds"; diff --git a/drivers/retained_mem/retained_mem_zephyr_ram.c b/drivers/retained_mem/retained_mem_zephyr_ram.c index 3410af1cbac09..f71742f41dc4c 100644 --- a/drivers/retained_mem/retained_mem_zephyr_ram.c +++ b/drivers/retained_mem/retained_mem_zephyr_ram.c @@ -33,7 +33,9 @@ static inline void zephyr_retained_mem_ram_lock_take(const struct device *dev) #ifdef CONFIG_RETAINED_MEM_MUTEXES struct zephyr_retained_mem_ram_data *data = dev->data; - k_mutex_lock(&data->lock, K_FOREVER); + if (!k_is_pre_kernel()) { + k_mutex_lock(&data->lock, K_FOREVER); + } #else ARG_UNUSED(dev); #endif @@ -44,7 +46,9 @@ static inline void zephyr_retained_mem_ram_lock_release(const struct device *dev #ifdef CONFIG_RETAINED_MEM_MUTEXES struct zephyr_retained_mem_ram_data *data = dev->data; - k_mutex_unlock(&data->lock); + if (!k_is_pre_kernel()) { + k_mutex_unlock(&data->lock); + } #else ARG_UNUSED(dev); #endif diff --git a/dts/arm/st/f0/stm32f072.dtsi b/dts/arm/st/f0/stm32f072.dtsi index c495d9af24f20..74dbbbfa30b40 100644 --- a/dts/arm/st/f0/stm32f072.dtsi +++ b/dts/arm/st/f0/stm32f072.dtsi @@ -10,6 +10,12 @@ soc { compatible = "st,stm32f072", "st,stm32f0", "simple-bus"; + rom_bootloader: rom_bootloader@1fffc800 { + compatible = "st,stm32-bootloader"; + reg = <0x1fffc800 DT_SIZE_K(12)>; + status = "okay"; + }; + can1: can@40006400 { compatible = "st,stm32-bxcan"; reg = <0x40006400 0x400>; diff --git a/dts/arm/st/f4/stm32f411.dtsi b/dts/arm/st/f4/stm32f411.dtsi index 6654d294dd175..29c20026bb7bb 100644 --- a/dts/arm/st/f4/stm32f411.dtsi +++ b/dts/arm/st/f4/stm32f411.dtsi @@ -18,6 +18,12 @@ soc { compatible = "st,stm32f411", "st,stm32f4", "simple-bus"; + rom_bootloader: rom_bootloader@1fff0000 { + compatible = "st,stm32-bootloader"; + reg = <0x1fff0000 DT_SIZE_K(29)>; + status = "okay"; + }; + spi5: spi@40015000 { compatible = "st,stm32-spi"; #address-cells = <1>; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index 5283fc9c12e3b..efc0620592dcb 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -144,6 +144,12 @@ }; soc { + rom_bootloader: rom_bootloader@1fff0000 { + compatible = "st,stm32-bootloader"; + reg = <0x1fff0000 DT_SIZE_K(28)>; + status = "okay"; + }; + flash: flash-controller@58004000 { compatible = "st,stm32-flash-controller", "st,stm32wb-flash-controller"; reg = <0x58004000 0x400>; diff --git a/dts/bindings/arm/st,stm32-bootloader.yaml b/dts/bindings/arm/st,stm32-bootloader.yaml new file mode 100644 index 0000000000000..ec1375a8bac5f --- /dev/null +++ b/dts/bindings/arm/st,stm32-bootloader.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Peter Johanson +# SPDX-License-Identifier: Apache-2.0 + +description: ST STM32 ROM Bootloader Details + +compatible: "st,stm32-bootloader" + +include: base.yaml + +properties: + reg: + required: true diff --git a/soc/st/stm32/Kconfig b/soc/st/stm32/Kconfig index 812e4fb1c889d..af1c2ad286864 100644 --- a/soc/st/stm32/Kconfig +++ b/soc/st/stm32/Kconfig @@ -38,6 +38,20 @@ config STM32_BACKUP_SRAM_INIT_PRIORITY help STM32 Backup SRAM device initialization priority. +config STM32_BOOTLOADER + bool "STM32 Bootloader Support" + depends on RETENTION_BOOT_MODE && DT_HAS_ST_STM32_BOOTLOADER_ENABLED + help + Enable support for jumping into the STM32 bootloader when the + bootmode is set. + +config STM32_BOOTLOADER_INIT_PRIORITY + int "STM32 bootloader check init priority" + default 3 + help + STM32 bootloader check initialization priority (must be higher than init + priorities for retention/retained memory drivers). + config STM32_ENABLE_DEBUG_SLEEP_STOP bool "Allow debugger attach in stop/sleep Mode" help diff --git a/soc/st/stm32/Kconfig.defconfig b/soc/st/stm32/Kconfig.defconfig index 572ebe6085437..e77b57f6b03a6 100644 --- a/soc/st/stm32/Kconfig.defconfig +++ b/soc/st/stm32/Kconfig.defconfig @@ -81,6 +81,16 @@ config CLOCK_CONTROL_INIT_PRIORITY default 1 depends on CLOCK_CONTROL +if STM32_BOOTLOADER + +config RETAINED_MEM_INIT_PRIORITY + default 1 + +config RETENTION_INIT_PRIORITY + default 2 + +endif + # Get flash configuration for NS image from dts flash partition config USE_DT_CODE_PARTITION default y if TRUSTED_EXECUTION_NONSECURE diff --git a/soc/st/stm32/common/CMakeLists.txt b/soc/st/stm32/common/CMakeLists.txt index ab854348305c9..be196a3b12ada 100644 --- a/soc/st/stm32/common/CMakeLists.txt +++ b/soc/st/stm32/common/CMakeLists.txt @@ -19,6 +19,8 @@ endif() zephyr_sources_ifdef(CONFIG_STM32_BACKUP_SRAM stm32_backup_sram.c) zephyr_linker_sources_ifdef(CONFIG_STM32_BACKUP_SRAM SECTIONS stm32_backup_sram.ld) +zephyr_sources_ifdef(CONFIG_STM32_BOOTLOADER stm32_bootloader.c) + if (NOT CONFIG_DEBUG AND CONFIG_PM) zephyr_sources_ifdef(CONFIG_DT_HAS_SWJ_CONNECTOR_ENABLED pm_debug_swj.c) endif() diff --git a/soc/st/stm32/common/stm32_bootloader.c b/soc/st/stm32/common/stm32_bootloader.c new file mode 100644 index 0000000000000..ebe891fe12e9b --- /dev/null +++ b/soc/st/stm32/common/stm32_bootloader.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 Google LLC. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_ARM_MPU) +extern void arm_core_mpu_disable(void); +#endif + +static const uint32_t bootloader = DT_REG_ADDR(DT_INST(0, st_stm32_bootloader)); +static FUNC_NORETURN void jump_to_bootloader(void) +{ + int i; + void (*jmp)(void); + + __disable_irq(); + + for (i = 0; i < ARRAY_SIZE(NVIC->ICER); i++) { + NVIC->ICER[i] = 0xFFFFFFFF; + NVIC->ICPR[i] = 0xFFFFFFFF; + } + +#if defined(CONFIG_ARM_MPU) + /* + * Needed to allow the bootloader to erase/write to flash, and the MPU + * is set up in the arch init phase. + */ + arm_core_mpu_disable(); +#endif + + /* + * Disable SysTick before jumping, to keep the bootloader happy + */ + SysTick->CTRL = 0; + + LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SYSTEMFLASH); + + jmp = (void (*)(void))(void (*)(void))(*((uint32_t *)((bootloader + 4)))); + + /* + * We need to clear a few things set by the Zephyr early startup code + */ + __set_CONTROL(0); +#if !defined(CONFIG_CPU_CORTEX_M0) + __set_BASEPRI(0); +#endif + + __set_MSP(*(uint32_t *)bootloader); + + __enable_irq(); + + jmp(); + + CODE_UNREACHABLE; +} + +static int bootloader_check_boot_init(void) +{ + if (bootmode_check(BOOT_MODE_TYPE_BOOTLOADER) > 0) { + bootmode_clear(); + jump_to_bootloader(); + } + + return 0; +} + +SYS_INIT(bootloader_check_boot_init, POST_KERNEL, CONFIG_STM32_BOOTLOADER_INIT_PRIORITY); diff --git a/subsys/retention/retention.c b/subsys/retention/retention.c index b259b19886212..da7c0de652a95 100644 --- a/subsys/retention/retention.c +++ b/subsys/retention/retention.c @@ -63,7 +63,9 @@ static inline void retention_lock_take(const struct device *dev) #ifdef CONFIG_RETENTION_MUTEXES struct retention_data *data = dev->data; - k_mutex_lock(&data->lock, K_FOREVER); + if (!k_is_pre_kernel()) { + k_mutex_lock(&data->lock, K_FOREVER); + } #else ARG_UNUSED(dev); #endif @@ -74,7 +76,9 @@ static inline void retention_lock_release(const struct device *dev) #ifdef CONFIG_RETENTION_MUTEXES struct retention_data *data = dev->data; - k_mutex_unlock(&data->lock); + if (!k_is_pre_kernel()) { + k_mutex_unlock(&data->lock); + } #else ARG_UNUSED(dev); #endif