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 "device_power.h"
14
15 #define ADC_0_XEC_REG_BASE \
16 ((struct adc_regs *)(DT_REG_ADDR(DT_NODELABEL(adc0))))
17 #define ECIA_XEC_REG_BASE \
18 ((struct ecia_named_regs *)(DT_REG_ADDR(DT_NODELABEL(ecia))))
19 #define ECS_XEC_REG_BASE \
20 ((struct ecs_regs *)(DT_REG_ADDR(DT_NODELABEL(ecs))))
21 #define PECI_XEC_REG_BASE \
22 ((struct peci_regs *)(DT_REG_ADDR(DT_NODELABEL(peci0))))
23 #define PCR_XEC_REG_BASE \
24 ((struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr))))
25 #define TFDP_0_XEC_REG_BASE \
26 ((struct tfdp_regs *)(DT_REG_ADDR(DT_NODELABEL(tfdp0))))
27 #define UART_0_XEC_REG_BASE \
28 ((struct uart_regs *)(DT_REG_ADDR(DT_NODELABEL(uart0))))
29 #define UART_1_XEC_REG_BASE \
30 ((struct uart_regs *)(DT_REG_ADDR(DT_NODELABEL(uart1))))
31 #define VBATR_XEC_REG_BASE \
32 ((struct vbatr_regs *)(DT_REG_ADDR_BY_NAME(DT_NODELABEL(pcr), vbatr)))
33 #define VBATM_XEC_BASE_ADDR \
34 ((uintptr_t)(DT_REG_ADDR(DT_NODELABEL(bbram))))
35
36 #define BTMR16_0_ADDR DT_REG_ADDR(DT_NODELABEL(timer0))
37 #define BTMR16_1_ADDR DT_REG_ADDR(DT_NODELABEL(timer1))
38 #define BTMR16_2_ADDR DT_REG_ADDR(DT_NODELABEL(timer2))
39 #define BTMR16_3_ADDR DT_REG_ADDR(DT_NODELABEL(timer3))
40 #define BTMR32_0_ADDR DT_REG_ADDR(DT_NODELABEL(timer4))
41 #define BTMR32_1_ADDR DT_REG_ADDR(DT_NODELABEL(timer5))
42 #define VBATM_XEC_ADDR DT_REG_ADDR(DT_NODELABEL(vbr))
43
44 #ifdef DEBUG_DEEP_SLEEP_CLK_REQ
soc_debug_sleep_clk_req(void)45 void soc_debug_sleep_clk_req(void)
46 {
47 struct ecs_regs *ecs = ECS_XEC_REG_BASE;
48 struct pcr_regs *pcr = PCR_XEC_REG_BASE;
49 uintptr_t vbm_addr = VBATM_XEC_BASE_ADDR;
50
51 /* Save status to debug LPM been blocked */
52 for (int i = 0; i < 5; i++) {
53 sys_write32(pcr->CLK_REQ[i], vbm_addr);
54 vbm_addr += 4;
55 }
56
57 sys_write32(pcr->SYS_SLP_CTRL, vbm_addr);
58 vbm_addr += 4;
59 sys_write32(ecs->SLP_STS_MIRROR, vbm_addr);
60 }
61 #endif
62
63 /*
64 * Allow peripherals connected to external masters to wake the PLL but not
65 * the EC. Once the peripheral has serviced the external master the PLL
66 * will be turned back off. For example, if the eSPI master requests eSPI
67 * configuration information or state of virtual wires the EC doesn't need
68 * to be involved. The hardware can power on the PLL long enough to service
69 * the request and then turn the PLL back off. The SMBus and I2C peripherals
70 * in slave mode can also make use of this feature.
71 */
soc_deep_sleep_non_wake_en(void)72 void soc_deep_sleep_non_wake_en(void)
73 {
74 #ifdef CONFIG_ESPI
75 struct ecia_named_regs *regs = ECIA_XEC_REG_BASE;
76
77 regs->GIRQ22.SRC = UINT32_MAX;
78 regs->GIRQ22.EN_SET = MCHP_ESPI_WK_CLK_GIRQ_BIT;
79 #endif
80 }
81
soc_deep_sleep_non_wake_dis(void)82 void soc_deep_sleep_non_wake_dis(void)
83 {
84 #ifdef CONFIG_ESPI
85 struct ecia_named_regs *regs = ECIA_XEC_REG_BASE;
86
87 regs->GIRQ22.EN_CLR = UINT32_MAX;
88 regs->GIRQ22.SRC = UINT32_MAX;
89 #endif
90 }
91
92 /* When MEC172x drivers are power-aware this should be move there */
soc_deep_sleep_wake_en(void)93 void soc_deep_sleep_wake_en(void)
94 {
95 #if defined(CONFIG_KSCAN) || \
96 (!defined(CONFIG_PM_DEVICE) && DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay))
97 struct ecia_named_regs *regs = ECIA_XEC_REG_BASE;
98 #if defined(CONFIG_KSCAN)
99 /* Enable PLL wake via KSCAN */
100 regs->GIRQ21.SRC = MCHP_KEYSCAN_GIRQ_BIT;
101 regs->GIRQ21.EN_SET = MCHP_KEYSCAN_GIRQ_BIT;
102 #endif
103 #if !defined(CONFIG_PM_DEVICE) && DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay)
104 /* Enable PS2_0B_WK */
105 regs->GIRQ21.SRC = MCHP_PS2_0_PORT0B_WK_GIRQ_BIT;
106 regs->GIRQ21.EN_SET = MCHP_PS2_0_PORT0B_WK_GIRQ_BIT;
107 #endif
108 #endif
109 }
110
soc_deep_sleep_wake_dis(void)111 void soc_deep_sleep_wake_dis(void)
112 {
113 #if !defined(CONFIG_PM_DEVICE) && DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay)
114 struct ecia_named_regs *regs = ECIA_XEC_REG_BASE;
115
116 /* Enable PS2_0B_WK */
117 regs->GIRQ21.EN_CLR = MCHP_PS2_0_PORT0B_WK_GIRQ_BIT;
118 regs->GIRQ21.SRC = MCHP_PS2_0_PORT0B_WK_GIRQ_BIT;
119 #endif
120 }
121
122
123 /* Variables used to save various HW state */
124 #ifdef DEEP_SLEEP_PERIPH_SAVE_RESTORE
125
126 const struct ds_timer_info ds_timer_tbl[NUM_DS_TIMER_ENTRIES] = {
127 {
128 (uintptr_t)(BTMR16_0_ADDR + MCHP_BTMR_CTRL_OFS),
129 MCHP_BTMR_CTRL_HALT, 0
130 },
131 {
132 (uintptr_t)(BTMR16_1_ADDR + MCHP_BTMR_CTRL_OFS),
133 MCHP_BTMR_CTRL_HALT, 0
134 },
135 {
136 (uintptr_t)(BTMR16_2_ADDR + MCHP_BTMR_CTRL_OFS),
137 MCHP_BTMR_CTRL_HALT, 0
138 },
139 {
140 (uintptr_t)(BTMR16_3_ADDR + MCHP_BTMR_CTRL_OFS),
141 MCHP_BTMR_CTRL_HALT, 0
142 },
143 {
144 (uintptr_t)(BTMR32_0_ADDR + MCHP_BTMR_CTRL_OFS),
145 MCHP_BTMR_CTRL_HALT, 0
146 },
147 {
148 (uintptr_t)(BTMR32_1_ADDR + MCHP_BTMR_CTRL_OFS),
149 MCHP_BTMR_CTRL_HALT, 0
150 },
151 };
152
153 static struct ds_dev_info ds_ctx;
154
deep_sleep_save_ecs(void)155 static void deep_sleep_save_ecs(void)
156 {
157 struct ecs_regs *regs = ECS_XEC_REG_BASE;
158
159 ds_ctx.ecs[0] = regs->ETM_CTRL;
160 ds_ctx.ecs[1] = regs->DEBUG_CTRL;
161 #ifdef DEEP_SLEEP_JTAG
162 regs->ETM_CTRL = 0;
163 regs->DEBUG_CTRL = 0x00;
164 #endif
165 }
166
167 #ifdef DEEP_SLEEP_UART_SAVE_RESTORE
deep_sleep_save_uarts(void)168 static void deep_sleep_save_uarts(void)
169 {
170 struct uart_regs *regs = UART_0_XEC_REG_BASE;
171
172 ds_ctx.uart_info[0] = regs->ACTV;
173 if (ds_ctx.uart_info[0]) {
174 while ((regs->LSR & MCHP_UART_LSR_TEMT) == 0) {
175 }
176 }
177 regs->ACTV = 0;
178
179 regs = UART_1_XEC_REG_BASE;
180 ds_ctx.uart_info[1] = regs->ACTV;
181 if (ds_ctx.uart_info[1]) {
182 while ((regs->LSR & MCHP_UART_LSR_TEMT) == 0) {
183 }
184 }
185 regs->ACTV = 0;
186 }
187 #endif
188
deep_sleep_save_timers(void)189 static void deep_sleep_save_timers(void)
190 {
191 const struct ds_timer_info *p;
192 uint32_t i;
193
194 p = &ds_timer_tbl[0];
195 for (i = 0; i < NUM_DS_TIMER_ENTRIES; i++) {
196 ds_ctx.timers[i] = sys_read32(p->addr);
197 if (p->stop_mask) {
198 sys_write32(ds_ctx.timers[i] | p->stop_mask, p->addr);
199 } else {
200 sys_write32(0, p->addr);
201 }
202 p++;
203 }
204 }
205
deep_sleep_restore_ecs(void)206 static void deep_sleep_restore_ecs(void)
207 {
208 #ifdef DEEP_SLEEP_JTAG
209 struct ecs_regs *regs = ECS_XEC_REG_BASE;
210
211 regs->ETM_CTRL = ds_ctx.ecs[0];
212 regs->DEBUG_CTRL = ds_ctx.ecs[1];
213 #endif
214 }
215
216 #ifdef DEEP_SLEEP_UART_SAVE_RESTORE
deep_sleep_restore_uarts(void)217 static void deep_sleep_restore_uarts(void)
218 {
219 struct uart_regs *regs0 = UART_0_XEC_REG_BASE;
220 struct uart_regs *regs1 = UART_1_XEC_REG_BASE;
221
222 regs0->ACTV = ds_ctx.uart_info[0];
223 regs1->ACTV = ds_ctx.uart_info[1];
224 }
225 #endif
226
deep_sleep_restore_timers(void)227 static void deep_sleep_restore_timers(void)
228 {
229 const struct ds_timer_info *p;
230 uint32_t i, temp;
231
232 p = &ds_timer_tbl[0];
233 for (i = 0; i < NUM_DS_TIMER_ENTRIES; i++) {
234 if (p->stop_mask) {
235 temp = sys_read32(p->addr) & ~(p->stop_mask);
236 sys_write32(temp, p->addr);
237 } else {
238 sys_write32(ds_ctx.timers[i] & ~p->restore_mask,
239 p->addr);
240 }
241 p++;
242 }
243 }
244
245 #ifdef DEEP_SLEEP_PERIPH_SAVE_RESTORE_EXTENDED
246
deep_sleep_save_blocks(void)247 static void deep_sleep_save_blocks(void)
248 {
249 struct tfdp_regs *tfdp = TFDP_0_XEC_REG_BASE;
250 struct ecs_regs *ecs = ECS_XEC_REG_BASE;
251 #ifdef CONFIG_ADC
252 struct adc_regs *adc0 = ADC_0_XEC_REG_BASE;
253
254 /* ADC deactivate */
255 adc0->CONTROL &= ~(MCHP_ADC_CTRL_ACTV);
256 #endif
257
258 #ifdef CONFIG_PECI
259 struct peci_regs *peci = PECI_XEC_REG_BASE;
260
261 ds_ctx.peci_info.peci_ctrl = peci->CONTROL;
262 ds_ctx.peci_info.peci_dis = ecs->PECI_DIS;
263 ecs->PECI_DIS |= MCHP_ECS_PECI_DISABLE;
264 #endif
265
266 #ifdef CONFIG_I2C
267 for (size_t n = 0; n < MCHP_I2C_SMB_INSTANCES; n++) {
268 uint32_t addr = MCHP_I2C_SMB_BASE_ADDR(n) +
269 MCHP_I2C_SMB_CFG_OFS;
270 uint32_t regval = sys_read32(addr);
271
272 ds_ctx.smb_info[n] = regval;
273 sys_write32(regval & ~(MCHP_I2C_SMB_CFG_ENAB), addr);
274 }
275 #endif
276
277 /* Disable comparator if enabled */
278 if (ecs->CMP_CTRL & BIT(0)) {
279 ds_ctx.comp_en = 1;
280 ecs->CMP_CTRL &= ~(MCHP_ECS_ACC_EN0);
281 }
282
283 #if defined(CONFIG_TACH_XEC) || defined(CONFIG_PWM_XEC)
284 struct pcr_regs *pcr = PCR_XEC_REG_BASE;
285
286 /* This low-speed clock derived from the 48MHz clock domain is used as
287 * a time base for PWMs and TACHs
288 * Set SLOW_CLOCK_DIVIDE = CLKOFF to save additional power
289 */
290 ds_ctx.slwclk_info = pcr->SLOW_CLK_CTRL;
291 pcr->SLOW_CLK_CTRL &= (~MCHP_PCR_SLOW_CLK_CTRL_100KHZ &
292 MCHP_PCR_SLOW_CLK_CTRL_MASK);
293 #endif
294
295 /* TFDP HW block is not expose to any Zephyr subsystem */
296 if (tfdp->CTRL & MCHP_TFDP_CTRL_EN) {
297 ds_ctx.tfdp_en = 1;
298 tfdp->CTRL &= ~MCHP_TFDP_CTRL_EN;
299 }
300
301 /* Port 80 TODO Do we need to do anything? MEC172x BDP does not
302 * include a timer so it should de-assert its CLK_REQ in response
303 * to SLP_EN 0->1.
304 */
305 }
306
deep_sleep_restore_blocks(void)307 static void deep_sleep_restore_blocks(void)
308 {
309 struct tfdp_regs *tfdp = TFDP_0_XEC_REG_BASE;
310 struct ecs_regs *ecs = ECS_XEC_REG_BASE;
311 #ifdef CONFIG_ADC
312 struct adc_regs *adc0 = ADC_0_XEC_REG_BASE;
313
314 adc0->CONTROL |= MCHP_ADC_CTRL_ACTV;
315 #endif
316
317 #ifdef CONFIG_PECI
318 struct peci_regs *peci = PECI_XEC_REG_BASE;
319
320 ecs->PECI_DIS = ds_ctx.peci_info.peci_dis;
321 peci->CONTROL = ds_ctx.peci_info.peci_ctrl;
322 #endif
323
324 #ifdef CONFIG_I2C
325 for (size_t n = 0; n < MCHP_I2C_SMB_INSTANCES; n++) {
326 uint32_t addr = MCHP_I2C_SMB_BASE_ADDR(n) +
327 MCHP_I2C_SMB_CFG_OFS;
328
329 sys_write32(ds_ctx.smb_info[n], addr);
330 }
331 #endif
332 /* Restore comparator control values */
333 if (ds_ctx.comp_en) {
334 ecs->CMP_CTRL |= MCHP_ECS_ACC_EN0;
335 }
336
337 #if defined(CONFIG_TACH_XEC) || defined(CONFIG_PWM_XEC)
338 struct pcr_regs *pcr = PCR_XEC_REG_BASE;
339
340 /* Restore slow clock control */
341 pcr->SLOW_CLK_CTRL = ds_ctx.slwclk_info;
342 #endif
343
344 /* TFDP HW block is not expose to any Zephyr subsystem */
345 if (ds_ctx.tfdp_en) {
346 tfdp->CTRL |= MCHP_TFDP_CTRL_EN;
347 }
348 }
349 #endif /* DEEP_SLEEP_PERIPH_SAVE_RESTORE_EXTENDED */
350
soc_deep_sleep_periph_save(void)351 void soc_deep_sleep_periph_save(void)
352 {
353 #ifdef DEEP_SLEEP_PERIPH_SAVE_RESTORE_EXTENDED
354 deep_sleep_save_blocks();
355 #endif
356 deep_sleep_save_ecs();
357 deep_sleep_save_timers();
358 #ifdef DEEP_SLEEP_UART_SAVE_RESTORE
359 deep_sleep_save_uarts();
360 #endif
361 }
362
soc_deep_sleep_periph_restore(void)363 void soc_deep_sleep_periph_restore(void)
364 {
365 deep_sleep_restore_ecs();
366 #ifdef DEEP_SLEEP_UART_SAVE_RESTORE
367 deep_sleep_restore_uarts();
368 #endif
369 deep_sleep_restore_timers();
370 #ifdef DEEP_SLEEP_PERIPH_SAVE_RESTORE_EXTENDED
371 deep_sleep_restore_blocks();
372 #endif
373 }
374
375 #else
376
soc_deep_sleep_periph_save(void)377 void soc_deep_sleep_periph_save(void)
378 {
379 }
380
soc_deep_sleep_periph_restore(void)381 void soc_deep_sleep_periph_restore(void)
382 {
383 }
384
385 #endif /* DEEP_SLEEP_PERIPH_SAVE_RESTORE */
386