From a10ce7561f26406cf4a8745a36164a8e8dc7e5a9 Mon Sep 17 00:00:00 2001 From: Scott Worley Date: Wed, 26 May 2021 18:12:18 -0400 Subject: [PATCH] soc: mchp: Deep sleep exit sequence update Zephyr kernel masks interrupts before calling the SoC PM sleep entry point. On the Cortex-Mx family this prevents wake from peripheral interrupts. The SoC PM layer requires interrupts to wake the SoC and must prevent the CPU from vectoring to an interrup until PM exit. The SoC does this by setting ARM NVIC PRIMASK to 1 and BASEPRI to 0. On return to the kernel SoC sets PRIMASK to 0 allowing ISR's to fire. In addition the MEC HW only clears its peripheral sleep enables if the CPU vectors to an ISR. On wake we clear the MEC PCR sleep control register which clears all the peripheral sleep enables so peripherals will be active before exiting the SoC PM layer. Signed-off-by: Scott Worley --- soc/arm/microchip_mec/mec1501/device_power.c | 7 +++++++ soc/arm/microchip_mec/mec1501/power.c | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/soc/arm/microchip_mec/mec1501/device_power.c b/soc/arm/microchip_mec/mec1501/device_power.c index 11f321123f4..37df97c65f3 100644 --- a/soc/arm/microchip_mec/mec1501/device_power.c +++ b/soc/arm/microchip_mec/mec1501/device_power.c @@ -53,8 +53,15 @@ void soc_deep_sleep_enable(void) PCR_REGS->SYS_SLP_CTRL = MCHP_PCR_SYS_SLP_HEAVY; } +/* + * Clear PCR Sleep control sleep all causing HW to de-assert all peripheral + * SLP_EN signals. HW will does this automatically only if it vectors to an + * ISR after wake. We are masking ISR's from running until we restore + * peripheral state therefore we force HW to de-assert the SLP_EN signals. + */ void soc_deep_sleep_disable(void) { + PCR_REGS->SYS_SLP_CTRL = 0U; SCB->SCR &= ~(1ul << 2); /* disable Cortex-M4 SLEEPDEEP */ } diff --git a/soc/arm/microchip_mec/mec1501/power.c b/soc/arm/microchip_mec/mec1501/power.c index 7902a64ba53..af4f2abf01c 100644 --- a/soc/arm/microchip_mec/mec1501/power.c +++ b/soc/arm/microchip_mec/mec1501/power.c @@ -115,16 +115,25 @@ void pm_power_state_set(struct pm_state_info info) } } +/* + * Zephyr PM code expects us to enabled interrupts at post op exit. Zephyr used + * arch_irq_lock() which sets BASEPRI to a non-zero value masking all interrupts + * preventing wake. MCHP z_power_soc_(deep)_sleep sets PRIMASK=1 and BASEPRI=0 + * allowing wake from any enabled interrupt and prevents the CPU from entering + * an ISR on wake except for faults. We re-enable interrupts by setting PRIMASK + * to 0. + */ void pm_power_state_exit_post_ops(struct pm_state_info info) { switch (info.state) { case PM_STATE_SUSPEND_TO_IDLE: - __enable_irq(); - break; case PM_STATE_SUSPEND_TO_RAM: - __enable_irq(); + __set_PRIMASK(0); + __ISB(); break; + default: + irq_unlock(0); break; } }