soc: silabs: Fix the PRIMASK for Silabs S2 SoCs

sl_power_manager_sleep() doesn't expect the PRIMASK to be set when called.
Setting BASEPRI to 0 was moved to sl_power_manager_is_ok_to_sleep(),
this function is called after sl_power_manager_sleep() has set the PRIMASK.
Added sli_power_manager_on_wakeup() to force a clock restore before the
interrupt are handled. Added a call to retrieve the startup measurements,
reducing the early wakeup time.

Signed-off-by: Bastien Beauchamp <bastien.beauchamp@silabs.com>
This commit is contained in:
Bastien Beauchamp 2025-01-21 08:27:27 -05:00 committed by Benjamin Cabé
commit ec1a2c6f47

View file

@ -8,6 +8,8 @@
#include <zephyr/logging/log.h>
#include <zephyr/pm/pm.h>
#include <sl_power_manager.h>
#include <sl_hfxo_manager.h>
#include <sli_hfxo_manager.h>
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
@ -46,18 +48,6 @@ void pm_state_set(enum pm_state state, uint8_t substate_id)
break;
}
/* 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
* issue and disable interrupts using PRIMASK register as recommended
* by ARM.
*/
/* Set PRIMASK */
__disable_irq();
/* Set BASEPRI to 0 */
irq_unlock(0);
LOG_DBG("Entry to energy mode %d", energy_mode);
if (energy_mode == SL_POWER_MANAGER_EM4) {
@ -77,9 +67,6 @@ void pm_state_set(enum pm_state state, uint8_t substate_id)
}
LOG_DBG("Exit from energy mode %d", energy_mode);
/* Clear PRIMASK */
__enable_irq();
}
void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
@ -88,6 +75,33 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
ARG_UNUSED(substate_id);
}
/* This function is called by sl_power_manager_sleep() after it has set the PRIMASK. */
bool sl_power_manager_is_ok_to_sleep(void)
{
/* 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
* issue and disable interrupts using PRIMASK register as recommended
* by ARM.
*/
/* Set BASEPRI to 0. */
irq_unlock(0);
return true;
}
/* This function is called by sl_power_manager_sleep() right after it was woken up from WFI. */
void sli_power_manager_on_wakeup(void)
{
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
/* Handle the HFXO IRQ as soon as possible to retrieve the startup time. */
sl_hfxo_manager_irq_handler();
#endif
/* Forces a clock restore before handling interrupts. */
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
}
/**
* Some SiLabs blobs, such as RAIL, call directly into sl_power_manager, and
* for that they had to include sl_power_manager.h during build. Some of those