1 /* 2 * Copyright (c) 2019 Microchip Technology Inc. 3 * Copyright (c) 2016 Intel Corporation. 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 8 #include <zephyr/kernel.h> 9 #include <zephyr/sys/sys_io.h> 10 #include <zephyr/sys/__assert.h> 11 #include <zephyr/pm/pm.h> 12 #include <soc.h> 13 #include <zephyr/arch/cpu.h> 14 #include <cmsis_core.h> 15 #include "device_power.h" 16 17 #include "soc_power_debug.h" 18 19 #define HTMR_0_XEC_REG_BASE \ 20 ((struct htmr_regs *)(DT_REG_ADDR(DT_NODELABEL(hibtimer0)))) 21 #define PCR_XEC_REG_BASE \ 22 ((struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr)))) 23 24 /* 25 * Deep Sleep 26 * Pros: 27 * Lower power dissipation, 48MHz PLL is off 28 * Cons: 29 * Longer wake latency. CPU start running on ring oscillator 30 * between 16 to 25 MHz. Minimum 3ms until PLL reaches lock 31 * frequency of 48MHz. 32 * 33 * Implementation Notes: 34 * We touch the Cortex-M's primary mask and base priority registers 35 * because we do not want to enter an ISR immediately upon wake. 36 * We must restore any hardware state that was modified upon sleep 37 * entry before allowing interrupts to be serviced. Zephyr arch level 38 * does not provide API's to manipulate both primary mask and base priority. 39 * 40 * DEBUG NOTES: 41 * If a JTAG/SWD debug probe is connected driving TRST# high and 42 * possibly polling the DUT then MEC1501 will not shut off its 48MHz 43 * PLL. Firmware should not disable JTAG/SWD in the EC subsystem 44 * while a probe is using the interface. This can leave the JTAG/SWD 45 * TAP controller in a state of requesting clocks preventing the PLL 46 * from being shut off. 47 */ 48 49 /* NOTE: Zephyr masks interrupts using BASEPRI before calling PM subsystem */ z_power_soc_deep_sleep(void)50static void z_power_soc_deep_sleep(void) 51 { 52 struct pcr_regs *pcr = PCR_XEC_REG_BASE; 53 struct htmr_regs *htmr0 = HTMR_0_XEC_REG_BASE; 54 uint32_t temp = 0U; 55 56 PM_DP_ENTER(); 57 58 __disable_irq(); 59 60 soc_deep_sleep_periph_save(); 61 soc_deep_sleep_wake_en(); 62 soc_deep_sleep_non_wake_en(); 63 64 /* 65 * Enable deep sleep mode in CM4 and MEC172x. 66 * Enable CM4 deep sleep and sleep signals assertion on WFI. 67 * Set MCHP Heavy sleep (PLL OFF when all CLK_REQ clear) and SLEEP_ALL 68 * to assert SLP_EN to all peripherals on WFI. 69 * Set PRIMASK = 1 so on wake the CPU will not vector to any ISR. 70 * Set BASEPRI = 0 to allow any priority to wake. 71 */ 72 SCB->SCR |= BIT(2); 73 pcr->SYS_SLP_CTRL = MCHP_PCR_SYS_SLP_HEAVY; 74 pcr->OSC_ID = pcr->SYS_SLP_CTRL; 75 #ifdef DEBUG_DEEP_SLEEP_CLK_REQ 76 soc_debug_sleep_clk_req(); 77 #endif 78 __set_BASEPRI(0); 79 __DSB(); 80 __WFI(); /* triggers sleep hardware */ 81 __NOP(); 82 __NOP(); 83 84 /* 85 * Clear SLEEP_ALL manually since we are not vectoring to an ISR until 86 * PM post ops. This de-asserts peripheral SLP_EN signals. 87 */ 88 pcr->SYS_SLP_CTRL = 0U; 89 SCB->SCR &= ~BIT(2); 90 91 /* Wait for PLL to lock with timeout */ 92 htmr0->PRLD = 0U; /* make sure its stopped */ 93 htmr0->CTRL = 0U; /* 30.5 us per tick */ 94 htmr0->PRLD = 216U; /* ~6.6 ms 2x the expected lock time */ 95 temp = htmr0->PRLD; 96 while ((pcr->OSC_ID & MCHP_PCR_OSC_ID_PLL_LOCK) == 0) { 97 temp = htmr0->PRLD; 98 if (!temp) { 99 break; 100 } 101 } 102 103 htmr0->PRLD = 0U; /* stop */ 104 105 soc_deep_sleep_non_wake_dis(); 106 soc_deep_sleep_wake_dis(); 107 soc_deep_sleep_periph_restore(); 108 109 PM_DP_EXIT(); 110 } 111 112 /* 113 * Light Sleep 114 * Pros: 115 * Fast wake response: 116 * Cons: 117 * Higher power dissipation, 48MHz PLL remains on. 118 * 119 * When the kernel calls this it has masked interrupt by setting NVIC BASEPRI 120 * equal to a value equal to the highest Zephyr ISR priority. Only NVIC 121 * exceptions will be served. 122 */ z_power_soc_sleep(void)123static void z_power_soc_sleep(void) 124 { 125 struct pcr_regs *pcr = PCR_XEC_REG_BASE; 126 127 __disable_irq(); 128 129 SCB->SCR &= ~BIT(2); 130 pcr->SYS_SLP_CTRL = MCHP_PCR_SYS_SLP_LIGHT; 131 pcr->OSC_ID = pcr->SYS_SLP_CTRL; 132 __set_BASEPRI(0); 133 __DSB(); 134 __WFI(); /* triggers sleep hardware */ 135 __NOP(); 136 __NOP(); 137 pcr->SYS_SLP_CTRL = 0U; 138 } 139 140 /* 141 * Called from pm_system_suspend(int32_t ticks) in subsys/power.c 142 * For deep sleep pm_system_suspend has executed all the driver 143 * power management call backs. 144 */ pm_state_set(enum pm_state state,uint8_t substate_id)145void pm_state_set(enum pm_state state, uint8_t substate_id) 146 { 147 ARG_UNUSED(substate_id); 148 149 switch (state) { 150 case PM_STATE_SUSPEND_TO_IDLE: 151 z_power_soc_sleep(); 152 break; 153 case PM_STATE_SUSPEND_TO_RAM: 154 z_power_soc_deep_sleep(); 155 break; 156 default: 157 break; 158 } 159 } 160 161 /* 162 * Zephyr PM code expects us to enabled interrupt at post op exit. Zephyr used 163 * arch_irq_lock() which sets BASEPRI to a non-zero value masking interrupts at 164 * >= numerical priority. MCHP z_power_soc_(deep)_sleep sets PRIMASK=1 and BASEPRI=0 165 * allowing wake from any enabled interrupt and prevents the CPU from entering any 166 * ISR on wake except for faults. We re-enable interrupts by undoing global disable 167 * and alling irq_unlock with the same value, 0 zephyr core uses. 168 */ pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)169void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) 170 { 171 __enable_irq(); 172 __ISB(); 173 irq_unlock(0); 174 } 175