diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 5efbcd7aa6171..8ad6f5a406ae6 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -28,6 +28,7 @@ chosen { zephyr,entropy = &rng; zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { @@ -38,6 +39,7 @@ device_type = "cpu"; compatible = "arm,cortex-m7"; reg = <0>; + cpu-power-states = <&stop>; #address-cells = <1>; #size-cells = <1>; @@ -45,6 +47,16 @@ compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; }; + }; + + + power-states { + stop: stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <400>; + exit-latency-us = <300>; + }; }; }; @@ -997,8 +1009,8 @@ #size-cells = <0>; reg = <0x40015804 0x20>; clocks = <&rcc STM32_CLOCK(APB2, 22)>; - dmas = <&dma2 1 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | - STM32_DMA_16BITS) 0>; + dmas = <&dma2 1 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; status = "disabled"; }; @@ -1008,8 +1020,8 @@ #size-cells = <0>; reg = <0x40015824 0x20>; clocks = <&rcc STM32_CLOCK(APB2, 22)>; - dmas = <&dma2 5 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | - STM32_DMA_16BITS) 0>; + dmas = <&dma2 5 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; status = "disabled"; }; }; diff --git a/soc/st/stm32/stm32f7x/CMakeLists.txt b/soc/st/stm32/stm32f7x/CMakeLists.txt index eebd281cd96be..ea800d26565a0 100644 --- a/soc/st/stm32/stm32f7x/CMakeLists.txt +++ b/soc/st/stm32/stm32f7x/CMakeLists.txt @@ -8,3 +8,7 @@ zephyr_sources( zephyr_include_directories(.) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_sources_ifdef(CONFIG_PM + power.c + ) diff --git a/soc/st/stm32/stm32f7x/Kconfig b/soc/st/stm32/stm32f7x/Kconfig index 083bbc18c0c96..56b60d72561ed 100644 --- a/soc/st/stm32/stm32f7x/Kconfig +++ b/soc/st/stm32/stm32f7x/Kconfig @@ -14,4 +14,5 @@ config SOC_SERIES_STM32F7X select HAS_STM32_FLASH_PREFETCH select CPU_HAS_ARM_MPU select HAS_SWO + select HAS_PM select SOC_EARLY_INIT_HOOK diff --git a/soc/st/stm32/stm32f7x/power.c b/soc/st/stm32/stm32f7x/power.c new file mode 100644 index 0000000000000..d5f948d4e1509 --- /dev/null +++ b/soc/st/stm32/stm32f7x/power.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Ac6 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +BUILD_ASSERT(DT_SAME_NODE(DT_CHOSEN(zephyr_cortex_m_idle_timer), DT_NODELABEL(rtc)), + "STM32Fx series needs RTC as an additional IDLE timer for power management"); + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + /* Prepare STOP mode with low-power regulator */ + LL_LPM_DisableEventOnPend(); + LL_PWR_ClearFlag_WU1(); + LL_PWR_ClearFlag_WU2(); + LL_PWR_ClearFlag_WU3(); + LL_PWR_ClearFlag_WU4(); + LL_PWR_ClearFlag_WU5(); + LL_PWR_ClearFlag_WU6(); + + /* Use low-power regulator in STOP to reduce consumption */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU); + LL_LPM_EnableDeepSleep(); + + k_cpu_idle(); + + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + /* Back to normal sleep and restore clocks after STOP */ + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); + + /* Restore the clock setup after STOP mode */ + stm32_clock_control_init(NULL); + break; + + default: + LOG_DBG("Unsupported power substate-id %u", state); + break; + } + + /* System is now active, re-enable interrupts disabled on entry */ + irq_unlock(0); +} diff --git a/soc/st/stm32/stm32f7x/soc.c b/soc/st/stm32/stm32f7x/soc.c index c0a71e39850bb..1b830a2ff8aff 100644 --- a/soc/st/stm32/stm32f7x/soc.c +++ b/soc/st/stm32/stm32f7x/soc.c @@ -16,6 +16,7 @@ #include #include +#include #include /** @@ -37,4 +38,7 @@ void soc_early_init_hook(void) /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ SystemCoreClock = 16000000; + + /* Ensure PWR peripheral clock is enabled on APB1 */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); }