From 6b681bcbcc688cc6276d01bd7f22991811cec0ed Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 7 Nov 2023 09:31:12 +0100 Subject: [PATCH] soc: arm: stm32wba: add support for standby mode with ram retention Add support for STM32WBA Standby low-power mode with RAM retention. Signed-off-by: Guillaume Gautier --- .../stm32wba/Kconfig.defconfig.series | 22 +++ soc/arm/st_stm32/stm32wba/power.c | 126 +++++++++++++++--- soc/arm/st_stm32/stm32wba/soc.c | 3 +- soc/arm/st_stm32/stm32wba/soc.h | 3 + 4 files changed, 131 insertions(+), 23 deletions(-) diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series index a1099228e5f..340b62049e8 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series @@ -39,4 +39,26 @@ config ENTROPY_STM32_CLK_CHECK endif +if PM_S2RAM + +config COUNTER + default y + +config COUNTER_RTC_STM32_SUBSECONDS + default y + +config STM32_LPTIM_STDBY_TIMER + default y + +config TICKLESS_KERNEL + default y + +config COUNTER_RTC_STM32_SAVE_VALUE_BETWEEN_RESETS + default y + +config IDLE_STACK_SIZE + default 512 + +endif + endif # SOC_SERIES_STM32WBAX diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c index 89d9f5e72ed..1565c59cfc6 100644 --- a/soc/arm/st_stm32/stm32wba/power.c +++ b/soc/arm/st_stm32/stm32wba/power.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -24,7 +26,25 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); -void set_mode_stop(uint8_t substate_id) +static int stm32_power_init(void); + +static void disable_cache(void) +{ + /* Disabling ICACHE */ + LL_ICACHE_Disable(); + while (LL_ICACHE_IsEnabled() == 1U) { + } + + /* Wait until ICACHE_SR.BUSYF is cleared */ + while (LL_ICACHE_IsActiveFlag_BUSY() == 1U) { + } + + /* Wait until ICACHE_SR.BSYENDF is set */ + while (LL_ICACHE_IsActiveFlag_BSYEND() == 0U) { + } +} + +static void set_mode_stop(uint8_t substate_id) { LL_PWR_ClearFlag_STOP(); @@ -33,10 +53,7 @@ void set_mode_stop(uint8_t substate_id) /* Erratum 2.2.15: * Disabling ICACHE is required before entering stop mode */ - LL_ICACHE_Disable(); - while (LL_ICACHE_IsEnabled() == 1U) { - } - + disable_cache(); #ifdef CONFIG_BT_STM32WBA scm_setwaitstates(LP); @@ -60,35 +77,76 @@ void set_mode_stop(uint8_t substate_id) } } +#if defined(CONFIG_PM_S2RAM) +static int suspend_to_ram(void) +{ + LL_LPM_EnableDeepSleep(); + + while (LL_PWR_IsActiveFlag_ACTVOS() == 0) { + } + + /* Select mode entry : WFE or WFI and enter the CPU selected mode */ + k_cpu_idle(); + + return 0; +} + +static void set_mode_suspend_to_ram(void) +{ + /* Enable SRAM full retention */ + LL_PWR_SetSRAM1SBRetention(LL_PWR_SRAM1_SB_FULL_RETENTION); + LL_PWR_SetSRAM2SBRetention(LL_PWR_SRAM2_SB_FULL_RETENTION); + + /* Enable RTC wakeup + * This configures an internal pin that generates an event to wakeup the system + */ + LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN7); + LL_PWR_SetWakeUpPinSignal3Selection(LL_PWR_WAKEUP_PIN7); + + /* Clear flags */ + LL_PWR_ClearFlag_SB(); + LL_PWR_ClearFlag_WU(); + LL_RCC_ClearResetFlags(); + + disable_cache(); + + /* Select standby mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); + + /* Save context and enter Standby mode */ + arch_pm_s2ram_suspend(suspend_to_ram); + + /* Execution is restored at this point after wake up */ + /* Restore system clock as soon as we exit standby mode */ + sys_clock_idle_exit(); +} +#endif + /* Invoke Low Power/System Off specific Tasks */ void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: set_mode_stop(substate_id); + + /* Select mode entry : WFE or WFI and enter the CPU selected mode */ + k_cpu_idle(); + break; - case PM_STATE_STANDBY: - /* Not supported today */ - __fallthrough; +#if defined(CONFIG_PM_S2RAM) + case PM_STATE_SUSPEND_TO_RAM: + set_mode_suspend_to_ram(); + break; +#endif default: LOG_DBG("Unsupported power state %u", state); return; } - - /* Select mode entry : WFE or WFI and enter the CPU selected mode */ - k_cpu_idle(); } /* Handle SOC specific activity after Low Power Mode Exit */ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { - /* Erratum 2.2.15: - * Enable ICACHE when exiting stop mode - */ - LL_ICACHE_Enable(); - while (LL_ICACHE_IsEnabled() == 0U) { - } - #ifdef CONFIG_BT_STM32WBA if (LL_PWR_IsActiveFlag_STOP() == 1U) { scm_setup(); @@ -100,16 +158,33 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) switch (state) { case PM_STATE_SUSPEND_TO_IDLE: if (substate_id <= 2) { + /* Erratum 2.2.15: + * Enable ICACHE when exiting stop mode + */ + LL_ICACHE_SetMode(LL_ICACHE_1WAY); + LL_ICACHE_Enable(); + while (LL_ICACHE_IsEnabled() == 0U) { + } + LL_LPM_DisableSleepOnExit(); LL_LPM_EnableSleep(); } else { LOG_DBG("Unsupported power substate-id %u", substate_id); } - case PM_STATE_STANDBY: - /* To be tested */ - LL_LPM_EnableSleep(); + break; case PM_STATE_SUSPEND_TO_RAM: +#if defined(CONFIG_PM_S2RAM) + stm32wba_init(); + stm32_power_init(); + + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); +#else + LOG_DBG("Suspend to RAM needs CONFIG_PM_S2RAM to be enabled"); +#endif + break; + case PM_STATE_STANDBY: __fallthrough; case PM_STATE_SUSPEND_TO_DISK: __fallthrough; @@ -141,6 +216,15 @@ static int stm32_power_init(void) LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); +#ifdef CONFIG_DEBUG + LL_DBGMCU_EnableDBGStandbyMode(); + LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_RTC_STOP); + LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_LPTIM1_STOP); +#else + LL_DBGMCU_DisableDBGStandbyMode(); +#endif + + /* Enabling Ultra Low power mode */ LL_PWR_EnableUltraLowPowerMode(); LL_FLASH_EnableSleepPowerDown(); diff --git a/soc/arm/st_stm32/stm32wba/soc.c b/soc/arm/st_stm32/stm32wba/soc.c index b0e2a439b5a..c3f12078e8d 100644 --- a/soc/arm/st_stm32/stm32wba/soc.c +++ b/soc/arm/st_stm32/stm32wba/soc.c @@ -32,7 +32,7 @@ LOG_MODULE_REGISTER(soc); * * @return 0 */ -static int stm32wba_init(void) +int stm32wba_init(void) { /* Enable instruction cache in 1-way (direct mapped cache) */ LL_ICACHE_SetMode(LL_ICACHE_1WAY); @@ -51,7 +51,6 @@ static int stm32wba_init(void) LL_PWR_SetRegulatorSupply(LL_PWR_LDO_SUPPLY); #endif - return 0; } diff --git a/soc/arm/st_stm32/stm32wba/soc.h b/soc/arm/st_stm32/stm32wba/soc.h index ef41f7adf8a..0c337ea9e22 100644 --- a/soc/arm/st_stm32/stm32wba/soc.h +++ b/soc/arm/st_stm32/stm32wba/soc.h @@ -17,6 +17,9 @@ #include +/* function exported to the soc power.c */ +int stm32wba_init(void); + #endif /* !_ASMLANGUAGE */ #endif /* _STM32WBA_SOC_H_ */