soc/arm/silabs_exx32: fix PM implementation - wake up using BURTC timer
- Add Gecko BURTC sys_clock driver to handle wake up from EM2,3 states - Remove custom PM policy and dependency on HAL sl_power_manager service - EM1 supported in all configurations - EM2,3 supported only if SysTick is replaced by BURTC Signed-off-by: Roman Dobrodii <rdobrodii@antmicro.com>
This commit is contained in:
parent
bdb8024df3
commit
cb14d8b099
21 changed files with 491 additions and 136 deletions
|
@ -21,6 +21,18 @@ config SOC_PART_NUMBER
|
|||
that you should not set directly. The part number selection choice defines
|
||||
the default value for this string.
|
||||
|
||||
config SOC_GECKO_SERIES2
|
||||
bool
|
||||
help
|
||||
Set if we're building for Gecko Series 2 SoC.
|
||||
This is equivalent of _SILICON_LABS_32B_SERIES_2 definition in HAL
|
||||
code.
|
||||
|
||||
config SOC_GECKO_BURTC
|
||||
bool
|
||||
help
|
||||
Set if the Back-Up Real Time Counter (BURTC) HAL module is used.
|
||||
|
||||
config SOC_GECKO_CORE
|
||||
bool
|
||||
default y
|
||||
|
@ -163,6 +175,12 @@ config SOC_GECKO_CMU
|
|||
|
||||
if SOC_GECKO_CMU
|
||||
|
||||
config CMU_NEED_LFXO
|
||||
bool
|
||||
help
|
||||
Set if LFXO oscillator should be configured and enabled, potentially
|
||||
in on-demand mode, after SoC is initialized.
|
||||
|
||||
choice
|
||||
prompt "High Frequency Clock Selection"
|
||||
default CMU_HFCLK_HFXO
|
||||
|
@ -175,6 +193,7 @@ config CMU_HFCLK_HFXO
|
|||
|
||||
config CMU_HFCLK_LFXO
|
||||
bool "External low frequency crystal oscillator"
|
||||
select CMU_NEED_LFXO
|
||||
help
|
||||
Set this option to use the external low frequency crystal oscillator
|
||||
as high frequency clock.
|
||||
|
@ -186,6 +205,37 @@ config CMU_HFCLK_HFRCO
|
|||
|
||||
endchoice
|
||||
|
||||
|
||||
choice
|
||||
prompt "BURTC Clock Selection"
|
||||
depends on SOC_GECKO_BURTC
|
||||
default CMU_BURTCCLK_LFRCO
|
||||
|
||||
config CMU_BURTCCLK_LFXO
|
||||
bool "LFXO - external low frequency crystal oscillator"
|
||||
select CMU_NEED_LFXO
|
||||
help
|
||||
Set this option to use LFXO - the external low freqency crystal oscillator
|
||||
as BURTC clock.
|
||||
Frequency is set by external crystal, typically 32.768 kHz.
|
||||
|
||||
config CMU_BURTCCLK_LFRCO
|
||||
bool "LFRCO - internal low frequency RC oscillator"
|
||||
help
|
||||
Set this option to use LFRCO - the internal low freqency RC oscillator
|
||||
as BURTC clock.
|
||||
Frequency is approximately 32.768 kHz.
|
||||
|
||||
config CMU_BURTCCLK_ULFRCO
|
||||
bool "ULFRCO - internal ultra low frequency RC oscillator"
|
||||
help
|
||||
Set this option to use ULFRCO - the external low freqency crystal oscillator
|
||||
as BURTC clock.
|
||||
Frequency is approximately 1 kHz.
|
||||
|
||||
endchoice
|
||||
|
||||
|
||||
config CMU_HFXO_FREQ
|
||||
int "External high frequency oscillator frequency"
|
||||
help
|
||||
|
|
|
@ -9,4 +9,7 @@ config SOC_GECKO_EMU
|
|||
select SOC_GECKO_CORE
|
||||
depends on PM
|
||||
|
||||
config CORTEX_M_SYSTICK
|
||||
default n if GECKO_BURTC_TIMER
|
||||
|
||||
endif
|
||||
|
|
|
@ -41,12 +41,44 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
|
|||
* @brief Initialization parameters for the external high frequency oscillator
|
||||
*/
|
||||
static CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
|
||||
#elif (defined CONFIG_CMU_HFCLK_LFXO)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMU_NEED_LFXO
|
||||
/**
|
||||
* @brief Initialization parameters for the external low frequency oscillator
|
||||
*/
|
||||
static CMU_LFXOInit_TypeDef lfxoInit = CMU_LFXOINIT_DEFAULT;
|
||||
#endif
|
||||
|
||||
static void init_lfxo(void)
|
||||
{
|
||||
/*
|
||||
* Configuring LFXO disables it, so we can do that only if it's not
|
||||
* used as a SYSCLK/HFCLK source.
|
||||
*/
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
if (CMU_ClockSelectGet(cmuClock_SYSCLK) != cmuSelect_LFXO) {
|
||||
/*
|
||||
* Check if device has LFXO configuration info in DEVINFO
|
||||
* See AN0016.2
|
||||
*/
|
||||
if ((DEVINFO->MODULEINFO & DEVINFO_MODULEINFO_LFXOCALVAL) ==
|
||||
DEVINFO_MODULEINFO_LFXOCALVAL_VALID) {
|
||||
lfxoInit.capTune =
|
||||
(DEVINFO->MODXOCAL & _DEVINFO_MODXOCAL_LFXOCAPTUNE_MASK) >>
|
||||
_DEVINFO_MODXOCAL_LFXOCAPTUNE_SHIFT;
|
||||
}
|
||||
CMU_LFXOInit(&lfxoInit);
|
||||
}
|
||||
#else
|
||||
if (CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_LFXO) {
|
||||
CMU_LFXOInit(&lfxoInit);
|
||||
CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
|
||||
}
|
||||
#endif /* _SILICON_LABS_32B_SERIES_2 */
|
||||
SystemLFXOClockSet(CONFIG_CMU_LFXO_FREQ);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CMU_NEED_LFXO */
|
||||
|
||||
/**
|
||||
* @brief Initialize the system clock
|
||||
|
@ -85,29 +117,11 @@ static ALWAYS_INLINE void clock_init(void)
|
|||
CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
|
||||
#endif /* _SILICON_LABS_32B_SERIES_2 */
|
||||
#elif (defined CONFIG_CMU_HFCLK_LFXO)
|
||||
/* LFXO should've been already brought up by init_lfxo() */
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
if (CMU_ClockSelectGet(cmuClock_SYSCLK) != cmuSelect_LFXO) {
|
||||
/*
|
||||
* Start the LFXO Oscillator as well (use by RTCC)
|
||||
* Check if device has HFXO configuration info in DEVINFO
|
||||
* See AN0016.2
|
||||
*/
|
||||
if ((DEVINFO->MODULEINFO & DEVINFO_MODULEINFO_LFXOCALVAL) ==
|
||||
DEVINFO_MODULEINFO_LFXOCALVAL_VALID) {
|
||||
lfxoInit.capTune =
|
||||
(DEVINFO->MODXOCAL & _DEVINFO_MODXOCAL_LFXOCAPTUNE_MASK) >>
|
||||
_DEVINFO_MODXOCAL_LFXOCAPTUNE_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
SystemLFXOClockSet(CONFIG_CMU_LFXO_FREQ);
|
||||
CMU_ClockSelectSet(cmuClock_SYSCLK, cmuSelect_LFXO);
|
||||
#else
|
||||
if (CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_LFXO) {
|
||||
CMU_LFXOInit(&lfxoInit);
|
||||
CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
|
||||
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_LFXO);
|
||||
}
|
||||
SystemLFXOClockSet(CONFIG_CMU_LFXO_FREQ);
|
||||
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_LFXO);
|
||||
CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
|
||||
#endif /* _SILICON_LABS_32B_SERIES_2 */
|
||||
#elif (defined CONFIG_CMU_HFCLK_HFRCO)
|
||||
|
@ -204,6 +218,10 @@ static int silabs_exx32_init(void)
|
|||
/* handle chip errata */
|
||||
CHIP_Init();
|
||||
|
||||
#ifdef CONFIG_CMU_NEED_LFXO
|
||||
init_lfxo();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOC_GECKO_DEV_INIT
|
||||
sl_device_init_dcdc();
|
||||
sl_device_init_hfxo();
|
||||
|
@ -215,7 +233,7 @@ static int silabs_exx32_init(void)
|
|||
sl_hfxo_manager_init();
|
||||
#endif
|
||||
|
||||
#else
|
||||
#else /* !CONFIG_SOC_GECKO_DEV_INIT */
|
||||
|
||||
#ifdef CONFIG_SOC_GECKO_EMU_DCDC
|
||||
dcdc_init();
|
||||
|
@ -234,7 +252,8 @@ static int silabs_exx32_init(void)
|
|||
/* Configure SWO debug output */
|
||||
swo_init();
|
||||
#endif
|
||||
#endif
|
||||
#endif /* !CONFIG_SOC_GECKO_DEV_INIT */
|
||||
|
||||
/* restore interrupt state */
|
||||
irq_unlock(oldLevel);
|
||||
return 0;
|
||||
|
|
|
@ -9,25 +9,14 @@
|
|||
#include <zephyr/pm/pm.h>
|
||||
#include <em_emu.h>
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/counter.h>
|
||||
|
||||
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
|
||||
|
||||
#ifdef CONFIG_SOC_GECKO_DEV_INIT
|
||||
#include <sl_power_manager.h>
|
||||
|
||||
static const struct device *const counter_dev = DEVICE_DT_GET(DT_NODELABEL(stimer0));
|
||||
static struct counter_alarm_cfg wakeup_cfg = {
|
||||
.callback = NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Power state map:
|
||||
* PM_STATE_RUNTIME_IDLE: EM1 Sleep
|
||||
* PM_STATE_SUSPEND_TO_IDLE: EM2 Deep Sleep
|
||||
* PM_STATE_STANDBY: EM3 Stop
|
||||
* PM_STATE_SOFT_OFF: EM4
|
||||
*/
|
||||
|
||||
/* Invoke Low Power/System Off specific Tasks */
|
||||
|
@ -37,52 +26,6 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
|
|||
|
||||
LOG_DBG("SoC entering power state %d", state);
|
||||
|
||||
#ifdef CONFIG_SOC_GECKO_DEV_INIT
|
||||
sl_power_manager_em_t energy_mode;
|
||||
|
||||
/* Save RTCC IRQ priority */
|
||||
uint32_t rtcc_prio = NVIC_GetPriority(RTCC_IRQn);
|
||||
/*
|
||||
* When this function is entered the Kernel has disabled handling interrupts
|
||||
* with priority other than 0. The Interrupt for the timer used to wake up
|
||||
* the cpu has priority equal to 1. Manually set this priority to 0 so that
|
||||
* cpu could exit sleep state.
|
||||
*
|
||||
* Note on priority value: set priority to -1 because z_arm_irq_priority_set
|
||||
* offsets the priorities by 1.
|
||||
* This function call will effectively set the priority to 0.
|
||||
*/
|
||||
z_arm_irq_priority_set(RTCC_IRQn, -1, 0);
|
||||
|
||||
switch (state) {
|
||||
|
||||
case PM_STATE_STANDBY:
|
||||
energy_mode = SL_POWER_MANAGER_EM3;
|
||||
|
||||
/* Limit sleep level to given state */
|
||||
sl_power_manager_add_em_requirement(energy_mode);
|
||||
|
||||
counter_start(counter_dev);
|
||||
counter_set_channel_alarm(counter_dev, 0, &wakeup_cfg);
|
||||
sl_power_manager_sleep();
|
||||
k_cpu_idle();
|
||||
counter_stop(counter_dev);
|
||||
|
||||
/* Remove sleep level limit */
|
||||
sl_power_manager_remove_em_requirement(energy_mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_DBG("Unsupported power state %u", state);
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_DBG("SoC leaving power state %d", state);
|
||||
|
||||
/* Restore RTCC IRQ priority */
|
||||
z_arm_irq_priority_set(RTCC_IRQn, (rtcc_prio - 1), 0);
|
||||
#else
|
||||
|
||||
/* FIXME: When this function is entered the Kernel has disabled
|
||||
* interrupts using BASEPRI register. This is incorrect as it prevents
|
||||
* waking up from any interrupt which priority is not 0. Work around the
|
||||
|
@ -105,6 +48,9 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
|
|||
case PM_STATE_STANDBY:
|
||||
EMU_EnterEM3(true);
|
||||
break;
|
||||
case PM_STATE_SOFT_OFF:
|
||||
EMU_EnterEM4();
|
||||
break;
|
||||
default:
|
||||
LOG_DBG("Unsupported power state %u", state);
|
||||
break;
|
||||
|
@ -114,8 +60,6 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
|
|||
|
||||
/* Clear PRIMASK */
|
||||
__enable_irq();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Handle SOC specific activity after Low Power Mode Exit */
|
||||
|
@ -124,37 +68,3 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
|
|||
ARG_UNUSED(state);
|
||||
ARG_UNUSED(substate_id);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SOC_GECKO_DEV_INIT) && defined(CONFIG_PM_POLICY_CUSTOM)
|
||||
/* CONFIG_PM_POLICY_CUSTOM allows us to set the next alarm to a specific number
|
||||
* of ticks in the future. This is needed for the Gecko SleepTimer to wake up
|
||||
* the device properly.
|
||||
*/
|
||||
static const struct pm_state_info pm_min_residency[] =
|
||||
PM_STATE_INFO_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0));
|
||||
struct pm_state_info pm_state_active = {PM_STATE_ACTIVE, 0, 0, 0};
|
||||
|
||||
__weak struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ARRAY_SIZE(pm_min_residency) - 1; i >= 0; i--) {
|
||||
|
||||
if ((ticks == K_TICKS_FOREVER) ||
|
||||
(ticks >= k_us_to_ticks_ceil32(
|
||||
pm_min_residency[i].min_residency_us))) {
|
||||
LOG_DBG("Selected power state %d "
|
||||
"(ticks: %d, min_residency: %u)",
|
||||
pm_min_residency[i].state, ticks,
|
||||
pm_min_residency[i].min_residency_us);
|
||||
|
||||
/* Busy waiting for 1 tick to flush UART buffer */
|
||||
k_busy_wait(k_ticks_to_us_floor32(1));
|
||||
wakeup_cfg.ticks = ticks;
|
||||
|
||||
return ((struct pm_state_info *) &pm_min_residency[i]);
|
||||
}
|
||||
}
|
||||
return (struct pm_state_info *)(&pm_state_active);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,11 +19,6 @@ config PM
|
|||
select COUNTER
|
||||
select UART_INTERRUPT_DRIVEN
|
||||
|
||||
choice PM_POLICY
|
||||
default PM_POLICY_CUSTOM
|
||||
depends on PM
|
||||
endchoice
|
||||
|
||||
source "soc/arm/silabs_exx32/efr32bg22/Kconfig.defconfig.efr32bg22"
|
||||
|
||||
endif # SOC_SERIES_EFR32BG22
|
||||
|
|
|
@ -15,6 +15,7 @@ config SOC_SERIES_EFR32BG22
|
|||
select HAS_SILABS_GECKO
|
||||
select HAS_SWO
|
||||
select SOC_FAMILY_EXX32
|
||||
select SOC_GECKO_SERIES2
|
||||
select SOC_GECKO_CMU
|
||||
select SOC_GECKO_CORE
|
||||
select SOC_GECKO_DEV_INIT
|
||||
|
|
|
@ -15,6 +15,7 @@ config SOC_SERIES_EFR32BG27
|
|||
select HAS_SILABS_GECKO
|
||||
select HAS_SWO
|
||||
select SOC_FAMILY_EXX32
|
||||
select SOC_GECKO_SERIES2
|
||||
select SOC_GECKO_CMU
|
||||
select SOC_GECKO_CORE
|
||||
select SOC_GECKO_DEV_INIT
|
||||
|
|
|
@ -12,6 +12,7 @@ config SOC_SERIES_EFR32MG21
|
|||
select CPU_HAS_FPU
|
||||
select CPU_HAS_ARM_MPU
|
||||
select SOC_FAMILY_EXX32
|
||||
select SOC_GECKO_SERIES2
|
||||
select HAS_SILABS_GECKO
|
||||
select HAS_SWO
|
||||
select SOC_GECKO_CMU
|
||||
|
|
|
@ -14,6 +14,7 @@ config SOC_SERIES_EFR32MG24
|
|||
select ARMV8_M_DSP
|
||||
select ARM_TRUSTZONE_M
|
||||
select SOC_FAMILY_EXX32
|
||||
select SOC_GECKO_SERIES2
|
||||
select HAS_SILABS_GECKO
|
||||
select HAS_SWO
|
||||
select SOC_GECKO_CMU
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue