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
|
@ -50,7 +50,6 @@ static int thunderboard_init_clocks(void)
|
||||||
CMU_ClockSelectSet(cmuClock_EM01GRPBCLK, cmuSelect_HFRCODPLL);
|
CMU_ClockSelectSet(cmuClock_EM01GRPBCLK, cmuSelect_HFRCODPLL);
|
||||||
#endif
|
#endif
|
||||||
CMU_ClockSelectSet(cmuClock_EM23GRPACLK, cmuSelect_LFRCO);
|
CMU_ClockSelectSet(cmuClock_EM23GRPACLK, cmuSelect_LFRCO);
|
||||||
CMU_ClockSelectSet(cmuClock_EM4GRPACLK, cmuSelect_LFRCO);
|
|
||||||
#if defined(RTCC_PRESENT)
|
#if defined(RTCC_PRESENT)
|
||||||
CMU_ClockSelectSet(cmuClock_RTCC, cmuSelect_LFRCO);
|
CMU_ClockSelectSet(cmuClock_RTCC, cmuSelect_LFRCO);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,12 +6,17 @@ CONFIG_BOARD_EFR32BG22_BRD4184A=y
|
||||||
CONFIG_CONSOLE=y
|
CONFIG_CONSOLE=y
|
||||||
CONFIG_UART_CONSOLE=y
|
CONFIG_UART_CONSOLE=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
CONFIG_CORTEX_M_SYSTICK=y
|
|
||||||
CONFIG_GPIO=y
|
CONFIG_GPIO=y
|
||||||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=76800000
|
|
||||||
CONFIG_CMU_HFCLK_HFXO=y
|
|
||||||
CONFIG_SOC_GECKO_EMU_DCDC=y
|
CONFIG_SOC_GECKO_EMU_DCDC=y
|
||||||
CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y
|
CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y
|
||||||
CONFIG_HW_STACK_PROTECTION=y
|
CONFIG_HW_STACK_PROTECTION=y
|
||||||
CONFIG_CMU_HFCLK_HFRCO=y
|
|
||||||
CONFIG_PINCTRL=y
|
CONFIG_PINCTRL=y
|
||||||
|
|
||||||
|
# Used if SysTick is enabled, ignored for BURTC
|
||||||
|
# (BURTC uses TIMER_READS_ITS_FREQUENCY_AT_RUNTIME)
|
||||||
|
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=76800000
|
||||||
|
|
||||||
|
# Use BURTC as system clock source
|
||||||
|
CONFIG_GECKO_BURTC_TIMER=y
|
||||||
|
CONFIG_CMU_BURTCCLK_LFXO=y
|
||||||
|
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1024
|
||||||
|
|
|
@ -6,12 +6,17 @@ CONFIG_BOARD_EFR32BG27_BRD2602A=y
|
||||||
CONFIG_CONSOLE=y
|
CONFIG_CONSOLE=y
|
||||||
CONFIG_UART_CONSOLE=y
|
CONFIG_UART_CONSOLE=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
CONFIG_CORTEX_M_SYSTICK=y
|
|
||||||
CONFIG_GPIO=y
|
CONFIG_GPIO=y
|
||||||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=76800000
|
|
||||||
CONFIG_CMU_HFCLK_HFXO=y
|
|
||||||
CONFIG_SOC_GECKO_EMU_DCDC=y
|
CONFIG_SOC_GECKO_EMU_DCDC=y
|
||||||
CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y
|
CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y
|
||||||
CONFIG_HW_STACK_PROTECTION=y
|
CONFIG_HW_STACK_PROTECTION=y
|
||||||
CONFIG_CMU_HFCLK_HFRCO=y
|
|
||||||
CONFIG_PINCTRL=y
|
CONFIG_PINCTRL=y
|
||||||
|
|
||||||
|
# Used if SysTick is enabled, ignored for BURTC
|
||||||
|
# (BURTC uses TIMER_READS_ITS_FREQUENCY_AT_RUNTIME)
|
||||||
|
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=76800000
|
||||||
|
|
||||||
|
# Use BURTC as system clock source
|
||||||
|
CONFIG_GECKO_BURTC_TIMER=y
|
||||||
|
CONFIG_CMU_BURTCCLK_LFXO=y
|
||||||
|
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1024
|
||||||
|
|
|
@ -47,6 +47,10 @@
|
||||||
|
|
||||||
&cpu0 {
|
&cpu0 {
|
||||||
clock-frequency = <76800000>;
|
clock-frequency = <76800000>;
|
||||||
|
/* Enable EM1,2. This means BURTC has to be used as sys_clock
|
||||||
|
* or the system won't wake up
|
||||||
|
*/
|
||||||
|
cpu-power-states = <&pstate_em1 &pstate_em2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
&usart0 {
|
&usart0 {
|
||||||
|
@ -107,6 +111,10 @@
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&burtc0 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
&stimer0 {
|
&stimer0 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_TIMER intel_adsp_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_CC13X2_CC26X2_RTC_TIMER cc13x2_cc26x2_rtc_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_CC13X2_CC26X2_RTC_TIMER cc13x2_cc26x2_rtc_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_CORTEX_M_SYSTICK cortex_m_systick.c)
|
zephyr_library_sources_ifdef(CONFIG_CORTEX_M_SYSTICK cortex_m_systick.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_ESP32C3_SYS_TIMER esp32c3_sys_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_ESP32C3_SYS_TIMER esp32c3_sys_timer.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_GECKO_BURTC_TIMER gecko_burtc_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_HPET_TIMER hpet.c)
|
zephyr_library_sources_ifdef(CONFIG_HPET_TIMER hpet.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_ITE_IT8XXX2_TIMER ite_it8xxx2_timer.c)
|
zephyr_library_sources_ifdef(CONFIG_ITE_IT8XXX2_TIMER ite_it8xxx2_timer.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_LEON_GPTIMER leon_gptimer.c)
|
zephyr_library_sources_ifdef(CONFIG_LEON_GPTIMER leon_gptimer.c)
|
||||||
|
|
|
@ -71,6 +71,7 @@ source "drivers/timer/Kconfig.cavs"
|
||||||
source "drivers/timer/Kconfig.cc13x2_cc26x2_rtc"
|
source "drivers/timer/Kconfig.cc13x2_cc26x2_rtc"
|
||||||
source "drivers/timer/Kconfig.cortex_m_systick"
|
source "drivers/timer/Kconfig.cortex_m_systick"
|
||||||
source "drivers/timer/Kconfig.esp32c3_sys"
|
source "drivers/timer/Kconfig.esp32c3_sys"
|
||||||
|
source "drivers/timer/Kconfig.gecko"
|
||||||
source "drivers/timer/Kconfig.hpet"
|
source "drivers/timer/Kconfig.hpet"
|
||||||
source "drivers/timer/Kconfig.ite_it8xxx2"
|
source "drivers/timer/Kconfig.ite_it8xxx2"
|
||||||
source "drivers/timer/Kconfig.leon_gptimer"
|
source "drivers/timer/Kconfig.leon_gptimer"
|
||||||
|
|
33
drivers/timer/Kconfig.gecko
Normal file
33
drivers/timer/Kconfig.gecko
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Copyright (c) 2023 Antmicro <www.antmicro.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config GECKO_BURTC_TIMER
|
||||||
|
bool "SiLabs Gecko BURTC system clock driver"
|
||||||
|
depends on SOC_GECKO_SERIES2
|
||||||
|
depends on DT_HAS_SILABS_GECKO_BURTC_ENABLED
|
||||||
|
select SOC_GECKO_BURTC
|
||||||
|
select TICKLESS_CAPABLE
|
||||||
|
select TIMER_READS_ITS_FREQUENCY_AT_RUNTIME
|
||||||
|
help
|
||||||
|
If you enable this, BURTC will be used to provide hw_cycles and
|
||||||
|
kernel ticks instead of Cortex-M SysTick. You need this for system
|
||||||
|
to be able to keep track of time and wake up from EM2 & EM3 sleep
|
||||||
|
states.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
Using BURTC instead of SysTick has a large impact on kernel timing
|
||||||
|
precision.
|
||||||
|
1. You won't be able to use the usual 0.1ms-granularity tickless
|
||||||
|
scheduling. Kernel tick duration should be at least 6 BURTC clock
|
||||||
|
cycles, that is ~183 us @ 32768 Hz (LFXO, LFRCO) or
|
||||||
|
~6 ms @ 1000 Hz (ULFRCO).
|
||||||
|
2. In general, accuracy of real-time scheduling by kernel will be
|
||||||
|
degraded: all timeout-based facilities, such as timers, delayable
|
||||||
|
work, k_sleep, will issue thread wake ups less precisely than when
|
||||||
|
using SysTick timer.
|
||||||
|
3. hw_cycles granularity will be equal to 1 BURTC clock, that is
|
||||||
|
~31 us @ 32768 Hz or ~1 ms @ 1000 Hz. This reduces timing
|
||||||
|
precision of all code which relies on cycles API, e.g.
|
||||||
|
k_cycle_get_32() and similar functions.
|
||||||
|
|
||||||
|
If unsure, say 'N'.
|
237
drivers/timer/gecko_burtc_timer.c
Normal file
237
drivers/timer/gecko_burtc_timer.c
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Antmicro <www.antmicro.com>
|
||||||
|
*
|
||||||
|
* Based on:
|
||||||
|
* sam0_rtc_timer.c Copyright (c) 2018 omSquare s.r.o.
|
||||||
|
* intel_adsp_timer.c Copyright (c) 2020 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT silabs_gecko_burtc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief SiLabs Gecko BURTC-based sys_clock driver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <soc.h>
|
||||||
|
#include <zephyr/drivers/clock_control.h>
|
||||||
|
#include <zephyr/drivers/timer/system_timer.h>
|
||||||
|
#include <zephyr/drivers/pinctrl.h>
|
||||||
|
#include <zephyr/sys_clock.h>
|
||||||
|
#include <zephyr/irq.h>
|
||||||
|
#include <zephyr/spinlock.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#include "em_device.h"
|
||||||
|
#include "em_cmu.h"
|
||||||
|
#include "em_burtc.h"
|
||||||
|
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(gecko_burtc_timer);
|
||||||
|
|
||||||
|
|
||||||
|
/* Maximum time interval between timer interrupts (in hw_cycles) */
|
||||||
|
#define MAX_TIMEOUT_CYC (UINT32_MAX >> 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mininum time interval between now and IRQ firing that can be scheduled.
|
||||||
|
* The main cause for this is LFSYNC register update, which requires several
|
||||||
|
* LF clk cycles for synchronization.
|
||||||
|
* Seee e.g. "4.2.4.4.4 LFSYNC Registers" in "EFR32xG22 Reference Manual"
|
||||||
|
*/
|
||||||
|
#define MIN_DELAY_CYC (6u)
|
||||||
|
|
||||||
|
#define TIMER_IRQ (DT_INST_IRQN(0))
|
||||||
|
|
||||||
|
#if defined(CONFIG_TEST)
|
||||||
|
/* See tests/kernel/context */
|
||||||
|
const int32_t z_sys_timer_irq_for_test = TIMER_IRQ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* With CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME, that's where we
|
||||||
|
* should write hw_cycles timer clock frequency upon init
|
||||||
|
*/
|
||||||
|
extern int z_clock_hw_cycles_per_sec;
|
||||||
|
|
||||||
|
/* Number of hw_cycles clocks per 1 kernel tick */
|
||||||
|
static uint32_t g_cyc_per_tick;
|
||||||
|
|
||||||
|
/* MAX_TIMEOUT_CYC expressed as ticks */
|
||||||
|
static uint32_t g_max_timeout_ticks;
|
||||||
|
|
||||||
|
/* Value of BURTC counter when the previous kernel tick was announced */
|
||||||
|
static atomic_t g_last_count;
|
||||||
|
|
||||||
|
/* Spinlock to sync between Compare ISR and update of Compare register */
|
||||||
|
static struct k_spinlock g_lock;
|
||||||
|
|
||||||
|
|
||||||
|
static void burtc_isr(const void *arg)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(arg);
|
||||||
|
|
||||||
|
/* Clear the interrupt */
|
||||||
|
BURTC_IntClear(BURTC_IF_COMP);
|
||||||
|
|
||||||
|
uint32_t curr = BURTC_CounterGet();
|
||||||
|
|
||||||
|
/* NOTE: this is the only place where g_last_count is modified,
|
||||||
|
* so we don't need to do make the whole read-and-modify atomic, just
|
||||||
|
* writing it behind the memory barrier is enough
|
||||||
|
*/
|
||||||
|
uint32_t prev = atomic_get(&g_last_count);
|
||||||
|
|
||||||
|
/* How many ticks have we not announced since the last announcement */
|
||||||
|
uint32_t unannounced = (curr - prev) / g_cyc_per_tick;
|
||||||
|
|
||||||
|
atomic_set(&g_last_count, prev + unannounced * g_cyc_per_tick);
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
|
/* Counter value on which announcement should be made */
|
||||||
|
uint32_t next = prev + g_cyc_per_tick;
|
||||||
|
|
||||||
|
/* `next` can be too close in the future since we're trying to
|
||||||
|
* announce the very next tick - in that case we skip one and
|
||||||
|
* announce the one after it instead
|
||||||
|
*/
|
||||||
|
if ((next - curr) < MIN_DELAY_CYC) {
|
||||||
|
next += g_cyc_per_tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
BURTC_CompareSet(0, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_clock_announce(unannounced);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_clock_set_timeout(int32_t ticks, bool idle)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(idle);
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* calculate 'ticks' value that specifies which tick to announce,
|
||||||
|
* beginning from the closest upcoming one:
|
||||||
|
* 0 - announce upcoming tick itself
|
||||||
|
* 1 - skip upcoming one, but announce the one after it, etc.
|
||||||
|
*/
|
||||||
|
ticks = (ticks == K_TICKS_FOREVER) ? g_max_timeout_ticks : ticks;
|
||||||
|
ticks = CLAMP(ticks - 1, 0, g_max_timeout_ticks);
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&g_lock);
|
||||||
|
|
||||||
|
uint32_t curr = BURTC_CounterGet();
|
||||||
|
uint32_t prev = atomic_get(&g_last_count);
|
||||||
|
|
||||||
|
/* How many ticks have we not announced since the last announcement */
|
||||||
|
uint32_t unannounced = (curr - prev) / g_cyc_per_tick;
|
||||||
|
|
||||||
|
/* Which tick to announce (counting from the last announced one) */
|
||||||
|
uint32_t to_announce = unannounced + ticks + 1;
|
||||||
|
|
||||||
|
/* Force maximum interval between announcements. If we sit without
|
||||||
|
* announcements for too long, counter will roll over and we'll lose
|
||||||
|
* track of unannounced ticks.
|
||||||
|
*/
|
||||||
|
to_announce = MIN(to_announce, g_max_timeout_ticks);
|
||||||
|
|
||||||
|
/* Counter value on which announcement should be made */
|
||||||
|
uint32_t next = prev + to_announce * g_cyc_per_tick;
|
||||||
|
|
||||||
|
/* `next` can be too close in the future if we're trying to announce
|
||||||
|
* the very next tick - in that case we skip one and announce the one
|
||||||
|
* after it instead
|
||||||
|
*/
|
||||||
|
if ((next - curr) < MIN_DELAY_CYC) {
|
||||||
|
next += g_cyc_per_tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
BURTC_CompareSet(0, next);
|
||||||
|
k_spin_unlock(&g_lock, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sys_clock_elapsed(void)
|
||||||
|
{
|
||||||
|
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return (BURTC_CounterGet() - g_last_count) / g_cyc_per_tick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sys_clock_cycle_get_32(void)
|
||||||
|
{
|
||||||
|
/* API note: this function is unrelated to kernel ticks, it returns
|
||||||
|
* a value of some 32-bit hw_cycles counter which counts with
|
||||||
|
* z_clock_hw_cycles_per_sec frequency
|
||||||
|
*/
|
||||||
|
return BURTC_CounterGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int burtc_init(void)
|
||||||
|
{
|
||||||
|
uint32_t hw_clock_freq;
|
||||||
|
BURTC_Init_TypeDef init = BURTC_INIT_DEFAULT;
|
||||||
|
|
||||||
|
/* Enable clock for BURTC CSRs on APB */
|
||||||
|
CMU_ClockEnable(cmuClock_BURTC, true);
|
||||||
|
|
||||||
|
/* Configure BURTC LF clocksource according to Kconfig */
|
||||||
|
#if defined(CONFIG_CMU_BURTCCLK_LFXO)
|
||||||
|
CMU_ClockSelectSet(cmuClock_BURTC, cmuSelect_LFXO);
|
||||||
|
#elif defined(CONFIG_CMU_BURTCCLK_LFRCO)
|
||||||
|
CMU_ClockSelectSet(cmuClock_BURTC, cmuSelect_LFRCO);
|
||||||
|
#elif defined(CONFIG_CMU_BURTCCLK_ULFRCO)
|
||||||
|
CMU_ClockSelectSet(cmuClock_BURTC, cmuSelect_ULFRCO);
|
||||||
|
#else
|
||||||
|
#error "Unsupported BURTC clock specified"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Calculate timing constants and init BURTC */
|
||||||
|
hw_clock_freq = CMU_ClockFreqGet(cmuClock_BURTC);
|
||||||
|
z_clock_hw_cycles_per_sec = hw_clock_freq;
|
||||||
|
|
||||||
|
BUILD_ASSERT(CONFIG_SYS_CLOCK_TICKS_PER_SEC > 0,
|
||||||
|
"Invalid CONFIG_SYS_CLOCK_TICKS_PER_SEC value");
|
||||||
|
g_cyc_per_tick = hw_clock_freq / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
|
||||||
|
|
||||||
|
__ASSERT(g_cyc_per_tick >= MIN_DELAY_CYC,
|
||||||
|
"%u cycle-long tick is too short to be scheduled "
|
||||||
|
"(min is %u). Config: SYS_CLOCK_TICKS_PER_SEC is "
|
||||||
|
"%d and timer frequency is %u",
|
||||||
|
g_cyc_per_tick, MIN_DELAY_CYC, CONFIG_SYS_CLOCK_TICKS_PER_SEC,
|
||||||
|
hw_clock_freq);
|
||||||
|
|
||||||
|
g_max_timeout_ticks = MAX_TIMEOUT_CYC / g_cyc_per_tick;
|
||||||
|
|
||||||
|
init.clkDiv = 1;
|
||||||
|
init.start = false;
|
||||||
|
BURTC_Init(&init);
|
||||||
|
|
||||||
|
/* Enable compare match interrupt */
|
||||||
|
BURTC_IntClear(BURTC_IF_COMP);
|
||||||
|
BURTC_IntEnable(BURTC_IF_COMP);
|
||||||
|
NVIC_ClearPendingIRQ(TIMER_IRQ);
|
||||||
|
IRQ_CONNECT(TIMER_IRQ, DT_INST_IRQ(0, priority), burtc_isr, 0, 0);
|
||||||
|
irq_enable(TIMER_IRQ);
|
||||||
|
|
||||||
|
/* Start the timer and announce 1 kernel tick */
|
||||||
|
atomic_set(&g_last_count, 0);
|
||||||
|
BURTC_CompareSet(0, g_cyc_per_tick);
|
||||||
|
|
||||||
|
BURTC_SyncWait();
|
||||||
|
BURTC->CNT = 0;
|
||||||
|
BURTC_Start();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(burtc_init, PRE_KERNEL_2,
|
||||||
|
CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
|
|
@ -73,6 +73,10 @@
|
||||||
interrupts = <15 0>, <16 0>;
|
interrupts = <15 0>, <16 0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&burtc0 {
|
||||||
|
interrupts = <18 0>;
|
||||||
|
};
|
||||||
|
|
||||||
&stimer0 {
|
&stimer0 {
|
||||||
interrupts = <12 0>;
|
interrupts = <12 0>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,6 +74,10 @@
|
||||||
interrupts = <18 0>, <19 0>;
|
interrupts = <18 0>, <19 0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&burtc0 {
|
||||||
|
interrupts = <23 0>;
|
||||||
|
};
|
||||||
|
|
||||||
&stimer0 {
|
&stimer0 {
|
||||||
interrupts = <15 0>;
|
interrupts = <15 0>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,12 +17,56 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
power-states {
|
power-states {
|
||||||
standby: standby {
|
/*
|
||||||
|
* EM1 is a basic "CPU WFI idle", all high-freq clocks remain
|
||||||
|
* enabled.
|
||||||
|
*/
|
||||||
|
pstate_em1: em1 {
|
||||||
|
compatible = "zephyr,power-state";
|
||||||
|
power-state-name = "runtime-idle";
|
||||||
|
min-residency-us = <4>;
|
||||||
|
/* HFXO remains active */
|
||||||
|
exit-latency-us = <2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EM2 is a deepsleep with HF clocks disabled by HW, voltages
|
||||||
|
* scaled down, etc.
|
||||||
|
*/
|
||||||
|
pstate_em2: em2 {
|
||||||
|
compatible = "zephyr,power-state";
|
||||||
|
power-state-name = "suspend-to-idle";
|
||||||
|
min-residency-us = <260>;
|
||||||
|
exit-latency-us = <250>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EM3 seems to be exactly the same as EM2 except that
|
||||||
|
* LFXO & LFRCO should be disabled, so you must use ULFRCO
|
||||||
|
* as BURTC clock for the system to not lose track of time and
|
||||||
|
* wake up.
|
||||||
|
*/
|
||||||
|
pstate_em3: em3 {
|
||||||
compatible = "zephyr,power-state";
|
compatible = "zephyr,power-state";
|
||||||
power-state-name = "standby";
|
power-state-name = "standby";
|
||||||
min-residency-us = <50000>;
|
min-residency-us = <20000>;
|
||||||
|
exit-latency-us = <2000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EM4 does not preserve CPU or RAM state, so system runs
|
||||||
|
* through a cold boot upon wake up. BURTC can wake up the
|
||||||
|
* system from EM4 but that has to be manually configured
|
||||||
|
* by the application in BURTC registers.
|
||||||
|
*/
|
||||||
|
pstate_em4: em4 {
|
||||||
|
compatible = "zephyr,power-state";
|
||||||
|
power-state-name = "soft-off";
|
||||||
|
min-residency-us = <100000>;
|
||||||
|
exit-latency-us = <80000>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
cpus {
|
cpus {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
@ -30,7 +74,19 @@
|
||||||
device_type = "cpu";
|
device_type = "cpu";
|
||||||
compatible = "arm,cortex-m33";
|
compatible = "arm,cortex-m33";
|
||||||
reg = <0>;
|
reg = <0>;
|
||||||
cpu-power-states = <&standby>;
|
/*
|
||||||
|
* EM1 is enabled by default because it is
|
||||||
|
* unconditionally safe.
|
||||||
|
*
|
||||||
|
* EM2/3 can be enabled by the board code if proper
|
||||||
|
* timing configuration is ensured:
|
||||||
|
* - for EM2, EM3: BURTC used as sys_clock
|
||||||
|
* - for EM3: BURTC clocked from ULFRCO
|
||||||
|
* Using BURTC as sys_clock instead of SysTick
|
||||||
|
* has implications on system performance. Read
|
||||||
|
* KConfig documentation entry before enabling it.
|
||||||
|
*/
|
||||||
|
cpu-power-states = <&pstate_em1>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,6 +123,12 @@
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
burtc0: burtc@50064000 {
|
||||||
|
compatible = "silabs,gecko-burtc";
|
||||||
|
reg = <0x50064000 0x3034>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
stimer0: stimer@58000000 {
|
stimer0: stimer@58000000 {
|
||||||
compatible = "silabs,gecko-stimer";
|
compatible = "silabs,gecko-stimer";
|
||||||
reg = <0x58000000 0x3054>;
|
reg = <0x58000000 0x3054>;
|
||||||
|
|
15
dts/bindings/timer/silabs,gecko-burtc.yaml
Normal file
15
dts/bindings/timer/silabs,gecko-burtc.yaml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# Copyright (c) 2023 Antmicro <www.antmicro.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: SiLabs Gecko BURTC timer
|
||||||
|
|
||||||
|
compatible: "silabs,gecko-burtc"
|
||||||
|
|
||||||
|
include: base.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
required: true
|
|
@ -21,6 +21,18 @@ config SOC_PART_NUMBER
|
||||||
that you should not set directly. The part number selection choice defines
|
that you should not set directly. The part number selection choice defines
|
||||||
the default value for this string.
|
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
|
config SOC_GECKO_CORE
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
@ -163,6 +175,12 @@ config SOC_GECKO_CMU
|
||||||
|
|
||||||
if 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
|
choice
|
||||||
prompt "High Frequency Clock Selection"
|
prompt "High Frequency Clock Selection"
|
||||||
default CMU_HFCLK_HFXO
|
default CMU_HFCLK_HFXO
|
||||||
|
@ -175,6 +193,7 @@ config CMU_HFCLK_HFXO
|
||||||
|
|
||||||
config CMU_HFCLK_LFXO
|
config CMU_HFCLK_LFXO
|
||||||
bool "External low frequency crystal oscillator"
|
bool "External low frequency crystal oscillator"
|
||||||
|
select CMU_NEED_LFXO
|
||||||
help
|
help
|
||||||
Set this option to use the external low frequency crystal oscillator
|
Set this option to use the external low frequency crystal oscillator
|
||||||
as high frequency clock.
|
as high frequency clock.
|
||||||
|
@ -186,6 +205,37 @@ config CMU_HFCLK_HFRCO
|
||||||
|
|
||||||
endchoice
|
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
|
config CMU_HFXO_FREQ
|
||||||
int "External high frequency oscillator frequency"
|
int "External high frequency oscillator frequency"
|
||||||
help
|
help
|
||||||
|
|
|
@ -9,4 +9,7 @@ config SOC_GECKO_EMU
|
||||||
select SOC_GECKO_CORE
|
select SOC_GECKO_CORE
|
||||||
depends on PM
|
depends on PM
|
||||||
|
|
||||||
|
config CORTEX_M_SYSTICK
|
||||||
|
default n if GECKO_BURTC_TIMER
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -41,12 +41,44 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
|
||||||
* @brief Initialization parameters for the external high frequency oscillator
|
* @brief Initialization parameters for the external high frequency oscillator
|
||||||
*/
|
*/
|
||||||
static CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
|
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
|
* @brief Initialization parameters for the external low frequency oscillator
|
||||||
*/
|
*/
|
||||||
static CMU_LFXOInit_TypeDef lfxoInit = CMU_LFXOINIT_DEFAULT;
|
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
|
* @brief Initialize the system clock
|
||||||
|
@ -85,29 +117,11 @@ static ALWAYS_INLINE void clock_init(void)
|
||||||
CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
|
CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
|
||||||
#endif /* _SILICON_LABS_32B_SERIES_2 */
|
#endif /* _SILICON_LABS_32B_SERIES_2 */
|
||||||
#elif (defined CONFIG_CMU_HFCLK_LFXO)
|
#elif (defined CONFIG_CMU_HFCLK_LFXO)
|
||||||
|
/* LFXO should've been already brought up by init_lfxo() */
|
||||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||||
if (CMU_ClockSelectGet(cmuClock_SYSCLK) != cmuSelect_LFXO) {
|
CMU_ClockSelectSet(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);
|
|
||||||
#else
|
#else
|
||||||
if (CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_LFXO) {
|
CMU_ClockSelectSet(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_OscillatorEnable(cmuOsc_HFRCO, false, false);
|
CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
|
||||||
#endif /* _SILICON_LABS_32B_SERIES_2 */
|
#endif /* _SILICON_LABS_32B_SERIES_2 */
|
||||||
#elif (defined CONFIG_CMU_HFCLK_HFRCO)
|
#elif (defined CONFIG_CMU_HFCLK_HFRCO)
|
||||||
|
@ -204,6 +218,10 @@ static int silabs_exx32_init(void)
|
||||||
/* handle chip errata */
|
/* handle chip errata */
|
||||||
CHIP_Init();
|
CHIP_Init();
|
||||||
|
|
||||||
|
#ifdef CONFIG_CMU_NEED_LFXO
|
||||||
|
init_lfxo();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SOC_GECKO_DEV_INIT
|
#ifdef CONFIG_SOC_GECKO_DEV_INIT
|
||||||
sl_device_init_dcdc();
|
sl_device_init_dcdc();
|
||||||
sl_device_init_hfxo();
|
sl_device_init_hfxo();
|
||||||
|
@ -215,7 +233,7 @@ static int silabs_exx32_init(void)
|
||||||
sl_hfxo_manager_init();
|
sl_hfxo_manager_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else /* !CONFIG_SOC_GECKO_DEV_INIT */
|
||||||
|
|
||||||
#ifdef CONFIG_SOC_GECKO_EMU_DCDC
|
#ifdef CONFIG_SOC_GECKO_EMU_DCDC
|
||||||
dcdc_init();
|
dcdc_init();
|
||||||
|
@ -234,7 +252,8 @@ static int silabs_exx32_init(void)
|
||||||
/* Configure SWO debug output */
|
/* Configure SWO debug output */
|
||||||
swo_init();
|
swo_init();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif /* !CONFIG_SOC_GECKO_DEV_INIT */
|
||||||
|
|
||||||
/* restore interrupt state */
|
/* restore interrupt state */
|
||||||
irq_unlock(oldLevel);
|
irq_unlock(oldLevel);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -9,25 +9,14 @@
|
||||||
#include <zephyr/pm/pm.h>
|
#include <zephyr/pm/pm.h>
|
||||||
#include <em_emu.h>
|
#include <em_emu.h>
|
||||||
|
|
||||||
#include <zephyr/device.h>
|
|
||||||
#include <zephyr/drivers/counter.h>
|
|
||||||
|
|
||||||
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
|
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:
|
* Power state map:
|
||||||
* PM_STATE_RUNTIME_IDLE: EM1 Sleep
|
* PM_STATE_RUNTIME_IDLE: EM1 Sleep
|
||||||
* PM_STATE_SUSPEND_TO_IDLE: EM2 Deep Sleep
|
* PM_STATE_SUSPEND_TO_IDLE: EM2 Deep Sleep
|
||||||
* PM_STATE_STANDBY: EM3 Stop
|
* PM_STATE_STANDBY: EM3 Stop
|
||||||
|
* PM_STATE_SOFT_OFF: EM4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Invoke Low Power/System Off specific Tasks */
|
/* 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);
|
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
|
/* FIXME: When this function is entered the Kernel has disabled
|
||||||
* interrupts using BASEPRI register. This is incorrect as it prevents
|
* interrupts using BASEPRI register. This is incorrect as it prevents
|
||||||
* waking up from any interrupt which priority is not 0. Work around the
|
* 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:
|
case PM_STATE_STANDBY:
|
||||||
EMU_EnterEM3(true);
|
EMU_EnterEM3(true);
|
||||||
break;
|
break;
|
||||||
|
case PM_STATE_SOFT_OFF:
|
||||||
|
EMU_EnterEM4();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_DBG("Unsupported power state %u", state);
|
LOG_DBG("Unsupported power state %u", state);
|
||||||
break;
|
break;
|
||||||
|
@ -114,8 +60,6 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
|
||||||
|
|
||||||
/* Clear PRIMASK */
|
/* Clear PRIMASK */
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle SOC specific activity after Low Power Mode Exit */
|
/* 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(state);
|
||||||
ARG_UNUSED(substate_id);
|
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 COUNTER
|
||||||
select UART_INTERRUPT_DRIVEN
|
select UART_INTERRUPT_DRIVEN
|
||||||
|
|
||||||
choice PM_POLICY
|
|
||||||
default PM_POLICY_CUSTOM
|
|
||||||
depends on PM
|
|
||||||
endchoice
|
|
||||||
|
|
||||||
source "soc/arm/silabs_exx32/efr32bg22/Kconfig.defconfig.efr32bg22"
|
source "soc/arm/silabs_exx32/efr32bg22/Kconfig.defconfig.efr32bg22"
|
||||||
|
|
||||||
endif # SOC_SERIES_EFR32BG22
|
endif # SOC_SERIES_EFR32BG22
|
||||||
|
|
|
@ -15,6 +15,7 @@ config SOC_SERIES_EFR32BG22
|
||||||
select HAS_SILABS_GECKO
|
select HAS_SILABS_GECKO
|
||||||
select HAS_SWO
|
select HAS_SWO
|
||||||
select SOC_FAMILY_EXX32
|
select SOC_FAMILY_EXX32
|
||||||
|
select SOC_GECKO_SERIES2
|
||||||
select SOC_GECKO_CMU
|
select SOC_GECKO_CMU
|
||||||
select SOC_GECKO_CORE
|
select SOC_GECKO_CORE
|
||||||
select SOC_GECKO_DEV_INIT
|
select SOC_GECKO_DEV_INIT
|
||||||
|
|
|
@ -15,6 +15,7 @@ config SOC_SERIES_EFR32BG27
|
||||||
select HAS_SILABS_GECKO
|
select HAS_SILABS_GECKO
|
||||||
select HAS_SWO
|
select HAS_SWO
|
||||||
select SOC_FAMILY_EXX32
|
select SOC_FAMILY_EXX32
|
||||||
|
select SOC_GECKO_SERIES2
|
||||||
select SOC_GECKO_CMU
|
select SOC_GECKO_CMU
|
||||||
select SOC_GECKO_CORE
|
select SOC_GECKO_CORE
|
||||||
select SOC_GECKO_DEV_INIT
|
select SOC_GECKO_DEV_INIT
|
||||||
|
|
|
@ -12,6 +12,7 @@ config SOC_SERIES_EFR32MG21
|
||||||
select CPU_HAS_FPU
|
select CPU_HAS_FPU
|
||||||
select CPU_HAS_ARM_MPU
|
select CPU_HAS_ARM_MPU
|
||||||
select SOC_FAMILY_EXX32
|
select SOC_FAMILY_EXX32
|
||||||
|
select SOC_GECKO_SERIES2
|
||||||
select HAS_SILABS_GECKO
|
select HAS_SILABS_GECKO
|
||||||
select HAS_SWO
|
select HAS_SWO
|
||||||
select SOC_GECKO_CMU
|
select SOC_GECKO_CMU
|
||||||
|
|
|
@ -14,6 +14,7 @@ config SOC_SERIES_EFR32MG24
|
||||||
select ARMV8_M_DSP
|
select ARMV8_M_DSP
|
||||||
select ARM_TRUSTZONE_M
|
select ARM_TRUSTZONE_M
|
||||||
select SOC_FAMILY_EXX32
|
select SOC_FAMILY_EXX32
|
||||||
|
select SOC_GECKO_SERIES2
|
||||||
select HAS_SILABS_GECKO
|
select HAS_SILABS_GECKO
|
||||||
select HAS_SWO
|
select HAS_SWO
|
||||||
select SOC_GECKO_CMU
|
select SOC_GECKO_CMU
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue