blob: 8e7e5d66359072f3802dde4f384234dcee497ab9 [file] [log] [blame]
Jacky Bai4d93d1d2020-07-02 14:39:58 +08001/*
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
Ye Li234925b2021-12-22 14:46:01 +080024extern bool is_lpav_owned_by_apd(void);
25
Jacky Bai4d93d1d2020-07-02 14:39:58 +080026enum {
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
71struct 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
81static 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
91struct 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;
Ye Li234925b2021-12-22 14:46:01 +080098 bool lpav; /* belong to lpav domain */
Jacky Bai4d93d1d2020-07-02 14:39:58 +080099 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, \
Ye Li234925b2021-12-22 14:46:01 +0800139 _bits, _state, _lpav, _rst_reg) \
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800140 { \
141 .name = _name, \
142 .reg = _reg, \
143 .psw_parent = _psw_parent, \
144 .sram_parent = _sram_parent, \
145 .bits = _bits, \
146 .power_state = _state, \
Ye Li234925b2021-12-22 14:46:01 +0800147 .lpav = _lpav, \
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800148 .sw_rst_reg = _rst_reg, \
149 }
150
151static struct power_domain scmi_power_domains[] = {
Ye Li234925b2021-12-22 14:46:01 +0800152 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)
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800168};
169
170size_t plat_scmi_pd_count(unsigned int agent_id __unused)
171{
172 return ARRAY_SIZE(scmi_power_domains);
173}
174
175const 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
185unsigned 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
195extern void upower_wait_resp(void);
196int 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
227int32_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
Ye Li234925b2021-12-22 14:46:01 +0800291bool 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
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800302void 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
310int32_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 {
Ye Li234925b2021-12-22 14:46:01 +0800353 if (!pd_allow_power_off(ps_idx)) {
354 return SCMI_DENIED;
355 }
356
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800357 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}