soc: stm23u5: Provide power implementation

Provide power modes implementation for u5 socs.
For now STOP3 mode is not implemented as this mode is not
compatible with LPTIM activation and hence cannot be used
as a workable suspend to idle state using LPTIM as kernel
tick source.

Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
This commit is contained in:
Erwan Gouriou 2021-09-13 17:05:18 +02:00 committed by Christopher Friedt
commit 997e4584ce
3 changed files with 160 additions and 0 deletions

View file

@ -4,3 +4,7 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers)
zephyr_sources(
soc.c
)
zephyr_sources_ifdef(CONFIG_PM
power.c
)

View file

@ -10,4 +10,7 @@ source "soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5*"
config SOC_SERIES
default "stm32u5"
config STM32_LPTIM_TIMER
default y if PM
endif # SOC_SERIES_STM32U5X

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2021 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <pm/pm.h>
#include <soc.h>
#include <init.h>
#include <stm32u5xx_ll_utils.h>
#include <stm32u5xx_ll_bus.h>
#include <stm32u5xx_ll_cortex.h>
#include <stm32u5xx_ll_pwr.h>
#include <stm32u5xx_ll_rcc.h>
#include <stm32u5xx_ll_system.h>
#include <clock_control/clock_stm32_ll_common.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
/* select MSI as wake-up system clock if configured, HSI otherwise */
#if STM32_SYSCLK_SRC_MSI
#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_MSI
#else
#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_HSI
#endif
void set_mode_stop(uint8_t substate_id)
{
/* ensure the proper wake-up system clock */
LL_RCC_SetClkAfterWakeFromStop(RCC_STOP_WAKEUPCLOCK_SELECTED);
switch (substate_id) {
case 1: /* enter STOP0 mode */
LL_PWR_SetPowerMode(LL_PWR_STOP0_MODE);
break;
case 2: /* enter STOP1 mode */
LL_PWR_SetPowerMode(LL_PWR_STOP1_MODE);
break;
case 3: /* enter STOP2 mode */
LL_PWR_SetPowerMode(LL_PWR_STOP2_MODE);
break;
default:
LOG_DBG("Unsupported power state substate-id %u", substate_id);
break;
}
}
void set_mode_standby(uint8_t substate_id)
{
ARG_UNUSED(substate_id);
/* Select standby mode */
LL_PWR_SetPowerMode(LL_PWR_STANDBY_MODE);
}
void set_mode_shutdown(uint8_t substate_id)
{
ARG_UNUSED(substate_id);
/* Select shutdown mode */
LL_PWR_SetPowerMode(LL_PWR_SHUTDOWN_MODE);
}
/* Invoke Low Power/System Off specific Tasks */
__weak void pm_power_state_set(struct pm_state_info info)
{
switch (info.state) {
case PM_STATE_SUSPEND_TO_IDLE:
set_mode_stop(info.substate_id);
break;
case PM_STATE_STANDBY:
/* To be tested */
set_mode_standby(info.substate_id);
break;
case PM_STATE_SOFT_OFF:
set_mode_shutdown(info.substate_id);
break;
/* Following states are not supported */
case PM_STATE_RUNTIME_IDLE:
__fallthrough;
case PM_STATE_ACTIVE:
__fallthrough;
case PM_STATE_SUSPEND_TO_RAM:
__fallthrough;
case PM_STATE_SUSPEND_TO_DISK:
LOG_DBG("Unsupported power state %u", info.state);
return;
}
/* Set SLEEPDEEP bit of Cortex System Control Register */
LL_LPM_EnableDeepSleep();
/* Select mode entry : WFE or WFI and enter the CPU selected mode */
k_cpu_idle();
}
/* Handle SOC specific activity after Low Power Mode Exit */
__weak void pm_power_state_exit_post_ops(struct pm_state_info info)
{
switch (info.state) {
case PM_STATE_SUSPEND_TO_IDLE:
if (info.substate_id <= 3) {
LL_LPM_DisableSleepOnExit();
LL_LPM_EnableSleep();
} else {
LOG_DBG("Unsupported power substate-id %u",
info.substate_id);
}
case PM_STATE_STANDBY:
/* To be tested */
LL_LPM_EnableSleep();
case PM_STATE_SOFT_OFF:
/* We should not get there */
__fallthrough;
case PM_STATE_ACTIVE:
__fallthrough;
case PM_STATE_SUSPEND_TO_RAM:
__fallthrough;
case PM_STATE_SUSPEND_TO_DISK:
__fallthrough;
default:
LOG_DBG("Unsupported power state %u", info.state);
break;
}
/* need to restore the clock */
stm32_clock_control_init(NULL);
/*
* System is now in active mode.
* Reenable interrupts which were disabled
* when OS started idling code.
*/
irq_unlock(0);
}
/* Initialize STM32 Power */
static int stm32_power_init(const struct device *dev)
{
ARG_UNUSED(dev);
/* enable Power clock */
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR);
#ifdef CONFIG_DEBUG
/* Enable the Debug Module during all and any Low power mode */
LL_DBGMCU_EnableDBGStopMode();
#endif /* CONFIG_DEBUG */
return 0;
}
SYS_INIT(stm32_power_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);