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 <scott.worley@microchip.com>
This commit is contained in:
Scott Worley 2021-05-26 18:12:18 -04:00 committed by Anas Nashif
commit a10ce7561f
2 changed files with 19 additions and 3 deletions

View file

@ -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 */
}

View file

@ -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;
}
}