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