Browse Source

soc: st: Add support for STOP3 on STM32U5

LPTIM is not available in STOP3 mode, so RTC needs to be used instead.
This code usese similar approach as STM32WBAx for suspend to ram.
The STOP3 is disabled by default in device tree.

Signed-off-by: Adam Berlinger <adam.berlinger@st.com>
pull/74334/head
Adam Berlinger 1 year ago committed by Anas Nashif
parent
commit
19b39406eb
  1. 4
      drivers/counter/counter_ll_stm32_rtc.c
  2. 4
      drivers/timer/Kconfig.stm32_lptim
  3. 19
      drivers/timer/stm32_lptim_timer.c
  4. 7
      dts/arm/st/u5/stm32u5.dtsi
  5. 15
      soc/st/stm32/stm32u5x/Kconfig
  6. 22
      soc/st/stm32/stm32u5x/Kconfig.defconfig
  7. 64
      soc/st/stm32/stm32u5x/power.c

4
drivers/counter/counter_ll_stm32_rtc.c

@ -185,7 +185,7 @@ static void rtc_stm32_irq_config(const struct device *dev); @@ -185,7 +185,7 @@ static void rtc_stm32_irq_config(const struct device *dev);
static int rtc_stm32_start(const struct device *dev)
{
#if defined(CONFIG_SOC_SERIES_STM32WBAX)
#if defined(CONFIG_SOC_SERIES_STM32WBAX) || defined(CONFIG_SOC_SERIES_STM32U5X)
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
const struct rtc_stm32_config *cfg = dev->config;
@ -208,7 +208,7 @@ static int rtc_stm32_start(const struct device *dev) @@ -208,7 +208,7 @@ static int rtc_stm32_start(const struct device *dev)
static int rtc_stm32_stop(const struct device *dev)
{
#if defined(CONFIG_SOC_SERIES_STM32WBAX)
#if defined(CONFIG_SOC_SERIES_STM32WBAX) || defined(CONFIG_SOC_SERIES_STM32U5X)
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
const struct rtc_stm32_config *cfg = dev->config;

4
drivers/timer/Kconfig.stm32_lptim

@ -59,16 +59,18 @@ config STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE @@ -59,16 +59,18 @@ config STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE
This options allows to override this check
config STM32_LPTIM_STDBY_TIMER
bool "Use an additional timer while entering Standby mode"
bool
default $(dt_chosen_enabled,$(DT_CHOSEN_STDBY_TIMER))
depends on COUNTER
depends on TICKLESS_KERNEL
select EXPERIMENTAL
help
Use an additional timer while entering Standby mode.
There are chips e.g. STM32WBAX family that use LPTIM as a system timer,
but LPTIM is not clocked in standby mode. These chips usually have
another timer that is not stopped, but it has lower frequency e.g.
RTC, thus it can't be used as a main system timer.
Same approach is used on STM32U5 and STOP3 mode.
Use the Standby timer for timeout (wakeup) when the system is entering
Standby state.

19
drivers/timer/stm32_lptim_timer.c

@ -204,7 +204,22 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) @@ -204,7 +204,22 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
next = pm_policy_next_state(CURRENT_CPU, ticks);
if ((next != NULL) && idle && (next->state == PM_STATE_SUSPEND_TO_RAM)) {
/* Check if STANBY or STOP3 is requested */
timeout_stdby = false;
if ((next != NULL) && idle) {
#ifdef CONFIG_PM_S2RAM
if (next->state == PM_STATE_SUSPEND_TO_RAM) {
timeout_stdby = true;
}
#endif
#ifdef CONFIG_STM32_STOP3_LP_MODE
if ((next->state == PM_STATE_SUSPEND_TO_IDLE) && (next->substate_id == 4)) {
timeout_stdby = true;
}
#endif
}
if (timeout_stdby) {
uint64_t timeout_us =
((uint64_t)ticks * USEC_PER_SEC) / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
@ -215,8 +230,6 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) @@ -215,8 +230,6 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
.flags = 0,
};
timeout_stdby = true;
/* Set the alarm using timer that runs the standby.
* Needed rump-up/setting time, lower accurency etc. should be
* included in the exit-latency in the power state definition.

7
dts/arm/st/u5/stm32u5.dtsi

@ -65,6 +65,13 @@ @@ -65,6 +65,13 @@
substate-id = <3>;
min-residency-us = <900>;
};
/omit-if-no-ref/ stop3: state3 {
compatible = "zephyr,power-state";
power-state-name = "suspend-to-idle";
substate-id = <4>;
min-residency-us = <200000>;
exit-latency-us = <130>;
};
};
};

15
soc/st/stm32/stm32u5x/Kconfig

@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
# Copyright (c) 2021 Linaro Limited
# SPDX-License-Identifier: Apache-2.0
DT_CHOSEN_STDBY_TIMER := st,lptim-stdby-timer
config SOC_SERIES_STM32U5X
select ARM
select CPU_CORTEX_M33
@ -15,3 +17,16 @@ config SOC_SERIES_STM32U5X @@ -15,3 +17,16 @@ config SOC_SERIES_STM32U5X
select HAS_STM32CUBE
select HAS_PM
select HAS_POWEROFF
config STM32_STOP3_LP_MODE
bool
default $(dt_path_enabled,/cpus/power-states/state3) && $(dt_chosen_enabled,$(DT_CHOSEN_STDBY_TIMER))
help
Enable support for STM32 STOP3 low-power mode.
Based on the Cortex-M33 Deepsleep mode combined with peripheral clock gating.
All clocks in the core domain are stopped.
The PLL, MSIS, MSIK, HSI16, and HSE oscillators are disabled.
All SRAMs and register contents are preserved.
SRAMs can be totally or partially switched off to further reduce consumption.
GPIOs are left floating and additional pull-up or pull-down can be applied
via PWR registers.

22
soc/st/stm32/stm32u5x/Kconfig.defconfig

@ -10,4 +10,26 @@ rsource "Kconfig.defconfig.stm32u5*" @@ -10,4 +10,26 @@ rsource "Kconfig.defconfig.stm32u5*"
config ROM_START_OFFSET
default 0x400 if BOOTLOADER_MCUBOOT
if STM32_STOP3_LP_MODE
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 #STM32_USE_STOP3
endif # SOC_SERIES_STM32U5X

64
soc/st/stm32/stm32u5x/power.c

@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
#include <stm32u5xx_ll_bus.h>
#include <stm32u5xx_ll_cortex.h>
#include <stm32u5xx_ll_pwr.h>
#include <stm32u5xx_ll_icache.h>
#include <stm32u5xx_ll_rcc.h>
#include <stm32u5xx_ll_system.h>
#include <clock_control/clock_stm32_ll_common.h>
@ -26,6 +27,32 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); @@ -26,6 +27,32 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_HSI
#endif
#ifdef CONFIG_STM32_STOP3_LP_MODE
static void pwr_stop3_isr(const struct device *dev)
{
ARG_UNUSED(dev);
/* Clear all wake-up flags */
LL_PWR_ClearFlag_WU();
}
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) {
}
}
#endif
void set_mode_stop(uint8_t substate_id)
{
/* ensure the proper wake-up system clock */
@ -41,6 +68,25 @@ void set_mode_stop(uint8_t substate_id) @@ -41,6 +68,25 @@ void set_mode_stop(uint8_t substate_id)
case 3: /* enter STOP2 mode */
LL_PWR_SetPowerMode(LL_PWR_STOP2_MODE);
break;
#ifdef CONFIG_STM32_STOP3_LP_MODE
case 4: /* enter STOP3 mode */
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();
disable_cache();
LL_PWR_SetPowerMode(LL_PWR_STOP3_MODE);
break;
#endif
default:
LOG_DBG("Unsupported power state substate-id %u", substate_id);
break;
@ -85,6 +131,18 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) @@ -85,6 +131,18 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
if (substate_id <= 3) {
LL_LPM_DisableSleepOnExit();
LL_LPM_EnableSleep();
#ifdef CONFIG_STM32_STOP3_LP_MODE
} else if (substate_id == 4) {
stm32_clock_control_standby_exit();
LL_ICACHE_SetMode(LL_ICACHE_1WAY);
LL_ICACHE_Enable();
while (LL_ICACHE_IsEnabled() == 0U) {
}
LL_LPM_DisableSleepOnExit();
LL_LPM_EnableSleep();
#endif
} else {
LOG_DBG("Unsupported power substate-id %u",
substate_id);
@ -118,6 +176,12 @@ static int stm32_power_init(void) @@ -118,6 +176,12 @@ static int stm32_power_init(void)
/* enable Power clock */
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR);
#ifdef CONFIG_STM32_STOP3_LP_MODE
IRQ_CONNECT(PWR_S3WU_IRQn, 0,
pwr_stop3_isr, 0, 0);
irq_enable(PWR_S3WU_IRQn);
#endif
return 0;
}

Loading…
Cancel
Save