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)50 static 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)123 static 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)145 void 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)169 void 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