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>
This commit is contained in:
parent
2c88cc08b3
commit
19b39406eb
7 changed files with 129 additions and 6 deletions
|
@ -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)
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
|||
.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.
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|||
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|||
#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)
|
|||
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)
|
|||
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)
|
|||
/* 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…
Add table
Add a link
Reference in a new issue