1 /*
2  * Copyright 2021-2024 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <inttypes.h>
7 #include <lib/libc/errno.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <common/debug.h>
13 #include <drivers/scmi.h>
14 #include <lib/mmio.h>
15 #include <lib/utils_def.h>
16 #include <platform_def.h>
17 #include <scmi.h>
18 
19 #include <upower_api.h>
20 
21 #define POWER_STATE_ON	(0 << 30)
22 #define POWER_STATE_OFF	(1 << 30)
23 
24 extern bool is_lpav_owned_by_apd(void);
25 
26 enum {
27 	PS0 = 0,
28 	PS1 = 1,
29 	PS2 = 2,
30 	PS3 = 3,
31 	PS4 = 4,
32 	PS5 = 5,
33 	PS6 = 6,
34 	PS7 = 7,
35 	PS8 = 8,
36 	PS9 = 9,
37 	PS10 = 10,
38 	PS11 = 11,
39 	PS12 = 12,
40 	PS13 = 13,
41 	PS14 = 14,
42 	PS15 = 15,
43 	PS16 = 16,
44 	PS17 = 17,
45 	PS18 = 18,
46 	PS19 = 19,
47 };
48 
49 #define SRAM_DMA1		BIT(6)
50 #define SRAM_FLEXSPI2		BIT(7)
51 #define SRAM_USB0		BIT(10)
52 #define SRAM_USDHC0		BIT(11)
53 #define SRAM_USDHC1		BIT(12)
54 #define SRAM_USDHC2_USB1	BIT(13)
55 #define SRAM_DCNANO		GENMASK_32(18, 17)
56 #define SRAM_EPDC		GENMASK_32(20, 19)
57 #define SRAM_DMA2		BIT(21)
58 #define SRAM_GPU2D		GENMASK_32(23, 22)
59 #define SRAM_GPU3D		GENMASK_32(25, 24)
60 #define SRAM_HIFI4		BIT(26)
61 #define SRAM_ISI_BUFFER		BIT(27)
62 #define SRAM_MIPI_CSI_FIFO	BIT(28)
63 #define SRAM_MIPI_DSI_FIFO	BIT(29)
64 #define SRAM_PXP		BIT(30)
65 
66 #define SRAM_DMA0		BIT_64(33)
67 #define SRAM_FLEXCAN		BIT_64(34)
68 #define SRAM_FLEXSPI0		BIT_64(35)
69 #define SRAM_FLEXSPI1		BIT_64(36)
70 
71 struct psw {
72 	char *name;
73 	uint32_t reg;
74 	int power_state;
75 	uint32_t count;
76 	int flags;
77 };
78 
79 #define ALWAYS_ON BIT(0)
80 
81 static struct psw imx8ulp_psw[] = {
82 	[PS6] = { .name = "PS6", .reg = PS6, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
83 	[PS7] = { .name = "PS7", .reg = PS7, .power_state = POWER_STATE_OFF },
84 	[PS8] = { .name = "PS8", .reg = PS8, .power_state = POWER_STATE_OFF },
85 	[PS13] = { .name = "PS13", .reg = PS13, .power_state = POWER_STATE_OFF },
86 	[PS14] = { .name = "PS14", .reg = PS14, .flags = ALWAYS_ON, .power_state = POWER_STATE_OFF },
87 	[PS15] = { .name = "PS15", .reg = PS15, .power_state = POWER_STATE_OFF },
88 	[PS16] = { .name = "PS16", .reg = PS16, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
89 };
90 
91 struct power_domain {
92 	char *name;
93 	uint32_t reg;
94 	uint32_t psw_parent;
95 	uint32_t sram_parent;
96 	uint64_t bits;
97 	uint32_t power_state;
98 	bool lpav; /* belong to lpav domain */
99 	uint32_t sw_rst_reg; /* pcc sw reset reg offset */
100 };
101 
102 /* The Rich OS need flow the macro */
103 #define IMX8ULP_PD_DMA1		0
104 #define IMX8ULP_PD_FLEXSPI2	1
105 #define IMX8ULP_PD_USB0		2
106 #define IMX8ULP_PD_USDHC0	3
107 #define IMX8ULP_PD_USDHC1	4
108 #define IMX8ULP_PD_USDHC2_USB1	5
109 #define IMX8ULP_PD_DCNANO	6
110 #define IMX8ULP_PD_EPDC		7
111 #define IMX8ULP_PD_DMA2		8
112 #define IMX8ULP_PD_GPU2D	9
113 #define IMX8ULP_PD_GPU3D	10
114 #define IMX8ULP_PD_HIFI4	11
115 #define IMX8ULP_PD_ISI		12
116 #define IMX8ULP_PD_MIPI_CSI	13
117 #define IMX8ULP_PD_MIPI_DSI	14
118 #define IMX8ULP_PD_PXP		15
119 
120 #define IMX8ULP_PD_PS6		16
121 #define IMX8ULP_PD_PS7		17
122 #define IMX8ULP_PD_PS8		18
123 #define IMX8ULP_PD_PS13		19
124 #define IMX8ULP_PD_PS14		20
125 #define IMX8ULP_PD_PS15		21
126 #define IMX8ULP_PD_PS16		22
127 #define IMX8ULP_PD_MAX		23
128 
129 /* LPAV peripheral PCC */
130 #define PCC_GPU2D	(IMX_PCC5_BASE + 0xf0)
131 #define PCC_GPU3D	(IMX_PCC5_BASE + 0xf4)
132 #define PCC_EPDC	(IMX_PCC5_BASE + 0xcc)
133 #define PCC_CSI		(IMX_PCC5_BASE + 0xbc)
134 #define PCC_PXP		(IMX_PCC5_BASE + 0xd0)
135 
136 #define PCC_SW_RST	BIT(28)
137 
138 #define PWR_DOMAIN(_name, _reg, _psw_parent, _sram_parent, \
139 		   _bits, _state, _lpav, _rst_reg) \
140 	{ \
141 		.name = _name, \
142 		.reg = _reg, \
143 		.psw_parent = _psw_parent, \
144 		.sram_parent = _sram_parent, \
145 		.bits = _bits, \
146 		.power_state = _state, \
147 		.lpav = _lpav, \
148 		.sw_rst_reg = _rst_reg, \
149 	}
150 
151 static struct power_domain scmi_power_domains[] = {
152 	PWR_DOMAIN("DMA1", IMX8ULP_PD_DMA1, PS6, PS6, SRAM_DMA1, POWER_STATE_OFF, false, 0U),
153 	PWR_DOMAIN("FLEXSPI2", IMX8ULP_PD_FLEXSPI2, PS6, PS6, SRAM_FLEXSPI2, POWER_STATE_OFF, false, 0U),
154 	PWR_DOMAIN("USB0", IMX8ULP_PD_USB0, PS6, PS6, SRAM_USB0, POWER_STATE_OFF, false, 0U),
155 	PWR_DOMAIN("USDHC0", IMX8ULP_PD_USDHC0, PS6, PS6, SRAM_USDHC0, POWER_STATE_OFF, false, 0U),
156 	PWR_DOMAIN("USDHC1", IMX8ULP_PD_USDHC1, PS6, PS6, SRAM_USDHC1, POWER_STATE_OFF, false, 0U),
157 	PWR_DOMAIN("USDHC2_USB1", IMX8ULP_PD_USDHC2_USB1, PS6, PS6, SRAM_USDHC2_USB1, POWER_STATE_OFF, false, 0U),
158 	PWR_DOMAIN("DCNano", IMX8ULP_PD_DCNANO, PS16, PS16, SRAM_DCNANO, POWER_STATE_OFF, true, 0U),
159 	PWR_DOMAIN("EPDC", IMX8ULP_PD_EPDC, PS13, PS13, SRAM_EPDC, POWER_STATE_OFF, true, PCC_EPDC),
160 	PWR_DOMAIN("DMA2", IMX8ULP_PD_DMA2, PS16, PS16, SRAM_DMA2, POWER_STATE_OFF, true, 0U),
161 	PWR_DOMAIN("GPU2D", IMX8ULP_PD_GPU2D, PS16, PS16, SRAM_GPU2D, POWER_STATE_OFF, true, PCC_GPU2D),
162 	PWR_DOMAIN("GPU3D", IMX8ULP_PD_GPU3D, PS7, PS7, SRAM_GPU3D, POWER_STATE_OFF, true, PCC_GPU3D),
163 	PWR_DOMAIN("HIFI4", IMX8ULP_PD_HIFI4, PS8, PS8, SRAM_HIFI4, POWER_STATE_OFF, true, 0U),
164 	PWR_DOMAIN("ISI", IMX8ULP_PD_ISI, PS16, PS16, SRAM_ISI_BUFFER, POWER_STATE_OFF, true, 0U),
165 	PWR_DOMAIN("MIPI_CSI", IMX8ULP_PD_MIPI_CSI, PS15, PS16, SRAM_MIPI_CSI_FIFO, POWER_STATE_OFF, true, PCC_CSI),
166 	PWR_DOMAIN("MIPI_DSI", IMX8ULP_PD_MIPI_DSI, PS14, PS16, SRAM_MIPI_DSI_FIFO, POWER_STATE_OFF, true, 0U),
167 	PWR_DOMAIN("PXP", IMX8ULP_PD_PXP, PS13, PS13, SRAM_PXP | SRAM_EPDC, POWER_STATE_OFF, true, PCC_PXP)
168 };
169 
plat_scmi_pd_count(unsigned int agent_id __unused)170 size_t plat_scmi_pd_count(unsigned int agent_id __unused)
171 {
172 	return ARRAY_SIZE(scmi_power_domains);
173 }
174 
plat_scmi_pd_get_name(unsigned int agent_id __unused,unsigned int pd_id)175 const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
176 				  unsigned int pd_id)
177 {
178 	if (pd_id >= IMX8ULP_PD_PS6) {
179 		return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].name;
180 	}
181 
182 	return scmi_power_domains[pd_id].name;
183 }
184 
plat_scmi_pd_get_state(unsigned int agent_id __unused,unsigned int pd_id __unused)185 unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
186 				    unsigned int pd_id __unused)
187 {
188 	if (pd_id >= IMX8ULP_PD_PS6) {
189 		return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].power_state;
190 	}
191 
192 	return scmi_power_domains[pd_id].power_state;
193 }
194 
195 extern void upower_wait_resp(void);
upwr_pwm_power(const uint32_t swton[],const uint32_t memon[],bool on)196 int upwr_pwm_power(const uint32_t swton[], const uint32_t memon[], bool on)
197 {
198 	int ret_val;
199 	int ret;
200 
201 	if (on == true) {
202 		ret = upwr_pwm_power_on(swton, memon, NULL);
203 	} else {
204 		ret = upwr_pwm_power_off(swton, memon, NULL);
205 	}
206 
207 	if (ret != 0U) {
208 		WARN("%s failed: ret: %d, state: %x\n", __func__, ret, on);
209 		return ret;
210 	}
211 
212 	upower_wait_resp();
213 
214 	ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000);
215 	if (ret != UPWR_REQ_OK) {
216 		WARN("Failure %d, %s\n", ret, __func__);
217 		if (ret == UPWR_REQ_BUSY) {
218 			return -EBUSY;
219 		} else {
220 			return -EINVAL;
221 		}
222 	}
223 
224 	return 0;
225 }
226 
plat_scmi_pd_psw(unsigned int index,unsigned int state)227 int32_t plat_scmi_pd_psw(unsigned int index, unsigned int state)
228 {
229 	uint32_t psw_parent = scmi_power_domains[index].psw_parent;
230 	uint32_t sram_parent = scmi_power_domains[index].sram_parent;
231 	uint64_t swt;
232 	bool on;
233 	int ret = 0;
234 
235 	if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) != 0U &&
236 	    (imx8ulp_psw[sram_parent].flags & ALWAYS_ON) != 0U) {
237 		return 0;
238 	}
239 
240 	on = (state == POWER_STATE_ON) ? true : false;
241 
242 	if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) == 0U) {
243 		swt = 1 << imx8ulp_psw[psw_parent].reg;
244 		if (imx8ulp_psw[psw_parent].count == 0U) {
245 			if (on == false) {
246 				WARN("off PSW[%d] that already in off state\n", psw_parent);
247 				ret = -EACCES;
248 			} else {
249 				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
250 				imx8ulp_psw[psw_parent].count++;
251 			}
252 		} else {
253 			if (on == true) {
254 				imx8ulp_psw[psw_parent].count++;
255 			} else {
256 				imx8ulp_psw[psw_parent].count--;
257 			}
258 
259 			if (imx8ulp_psw[psw_parent].count == 0U) {
260 				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
261 			}
262 		}
263 	}
264 
265 	if (!(imx8ulp_psw[sram_parent].flags & ALWAYS_ON) && (psw_parent != sram_parent)) {
266 		swt = 1 << imx8ulp_psw[sram_parent].reg;
267 		if (imx8ulp_psw[sram_parent].count == 0U) {
268 			if (on == false) {
269 				WARN("off PSW[%d] that already in off state\n", sram_parent);
270 				ret = -EACCES;
271 			} else {
272 				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
273 				imx8ulp_psw[sram_parent].count++;
274 			}
275 		} else {
276 			if (on == true) {
277 				imx8ulp_psw[sram_parent].count++;
278 			} else {
279 				imx8ulp_psw[sram_parent].count--;
280 			}
281 
282 			if (imx8ulp_psw[sram_parent].count == 0U) {
283 				ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
284 			}
285 		}
286 	}
287 
288 	return ret;
289 }
290 
pd_allow_power_off(unsigned int pd_id)291 bool pd_allow_power_off(unsigned int pd_id)
292 {
293 	if (scmi_power_domains[pd_id].lpav) {
294 		if (!is_lpav_owned_by_apd()) {
295 			return false;
296 		}
297 	}
298 
299 	return true;
300 }
301 
assert_pcc_reset(unsigned int pcc)302 void assert_pcc_reset(unsigned int pcc)
303 {
304 	/* if sw_rst_reg is valid, assert the pcc reset */
305 	if (pcc != 0U) {
306 		mmio_clrbits_32(pcc, PCC_SW_RST);
307 	}
308 }
309 
plat_scmi_pd_set_state(unsigned int agent_id __unused,unsigned int flags,unsigned int pd_id,unsigned int state)310 int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
311 			       unsigned int flags,
312 			       unsigned int pd_id,
313 			       unsigned int state)
314 {
315 	unsigned int ps_idx;
316 	uint64_t mem;
317 	bool on;
318 	int ret;
319 
320 	if (flags != 0U || pd_id >= IMX8ULP_PD_PS6) {
321 		return SCMI_NOT_SUPPORTED;
322 	}
323 
324 	ps_idx = 0;
325 	while (ps_idx < IMX8ULP_PD_PS6 && scmi_power_domains[ps_idx].reg != pd_id) {
326 		ps_idx++;
327 	}
328 
329 	if (ps_idx == IMX8ULP_PD_PS6) {
330 		return SCMI_NOT_FOUND;
331 	}
332 
333 	if (state == scmi_power_domains[ps_idx].power_state) {
334 		return SCMI_SUCCESS;
335 	}
336 
337 	mem = scmi_power_domains[ps_idx].bits;
338 	on = (state == POWER_STATE_ON ? true : false);
339 	if (on == true) {
340 		/* Assert pcc sw reset if necessary */
341 		assert_pcc_reset(scmi_power_domains[ps_idx].sw_rst_reg);
342 
343 		ret = plat_scmi_pd_psw(ps_idx, state);
344 		if (ret != 0U) {
345 			return SCMI_DENIED;
346 		}
347 
348 		ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
349 		if (ret != 0U) {
350 			return SCMI_DENIED;
351 		}
352 	} else {
353 		if (!pd_allow_power_off(ps_idx)) {
354 			return SCMI_DENIED;
355 		}
356 
357 		ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
358 		if (ret != 0U) {
359 			return SCMI_DENIED;
360 		}
361 
362 		ret = plat_scmi_pd_psw(ps_idx, state);
363 		if (ret != 0U) {
364 			return SCMI_DENIED;
365 		}
366 	}
367 
368 	scmi_power_domains[pd_id].power_state = state;
369 
370 	return SCMI_SUCCESS;
371 }
372