blob: b2559af94b258ae64c8ecc13edb4e4cdd4f5c0cd [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
7#include <stdbool.h>
8
9#include <arch.h>
10#include <arch_helpers.h>
11#include <common/debug.h>
12#include <drivers/arm/gicv3.h>
13#include <lib/mmio.h>
14#include <lib/psci/psci.h>
15
16#include <plat_imx8.h>
Jacky Baic6fb6672023-09-18 22:08:52 +080017#include <upower_api.h>
Jacky Bai4d93d1d2020-07-02 14:39:58 +080018
Jacky Baiba997cc2021-06-25 09:47:46 +080019extern void cgc1_save(void);
20extern void cgc1_restore(void);
21extern void imx_apd_ctx_save(unsigned int cpu);
22extern void imx_apd_ctx_restore(unsigned int cpu);
23extern void usb_wakeup_enable(bool enable);
24
Jacky Bai4d93d1d2020-07-02 14:39:58 +080025static uintptr_t secure_entrypoint;
26
27#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
28#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
29#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
30
31#define RVBARADDRx(c) (IMX_SIM1_BASE + 0x5c + 0x4 * (c))
32#define WKPUx(c) (IMX_SIM1_BASE + 0x3c + 0x4 * (c))
33#define AD_COREx_LPMODE(c) (IMX_CMC1_BASE + 0x50 + 0x4 * (c))
34
Jacky Baic6fb6672023-09-18 22:08:52 +080035#define PMIC_CFG(v, m, msk) \
36 { \
37 .volt = (v), \
38 .mode = (m), \
39 .mode_msk = (msk), \
40 }
41
42#define PAD_CFG(c, r, t) \
43 { \
44 .pad_close = (c), \
45 .pad_reset = (r), \
46 .pad_tqsleep = (t) \
47 }
48
49#define BIAS_CFG(m, n, p, mbias) \
50 { \
51 .dombias_cfg = { \
52 .mode = (m), \
53 .rbbn = (n), \
54 .rbbp = (p), \
55 }, \
56 .membias_cfg = {mbias}, \
57 }
58
59#define SWT_BOARD(swt_on, msk) \
60 { \
61 .on = (swt_on), \
62 .mask = (msk), \
63 }
64
65#define SWT_MEM(a, p, m) \
66 { \
67 .array = (a), \
68 .perif = (p), \
69 .mask = (m), \
70 }
71
Jacky Baiba997cc2021-06-25 09:47:46 +080072extern void upower_wait_resp(void);
73
Jacky Bai4d93d1d2020-07-02 14:39:58 +080074static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry)
75{
76 mmio_write_32(RVBARADDRx(cpu), entry);
77
78 /* set update bit */
79 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu));
80 /* wait for ack */
81 while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) {
82 }
83
84 /* clear update bit */
85 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu));
86 /* clear ack bit */
87 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu));
88
89 return 0;
90}
91
92int imx_pwr_domain_on(u_register_t mpidr)
93{
94 unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
95
96 imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
97
98 mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
99 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0);
100
101 /* enable wku wakeup for idle */
102 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff);
103
104 return PSCI_E_SUCCESS;
105}
106
107void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
108{
109 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
110 plat_gic_pcpu_init();
111 plat_gic_cpuif_enable();
112}
113
114int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
115{
116 return PSCI_E_SUCCESS;
117}
118
119void imx_pwr_domain_off(const psci_power_state_t *target_state)
120{
121 unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
122
123 plat_gic_cpuif_disable();
124
125 /* disable wakeup */
126 mmio_write_32(WKPUx(cpu), 0);
127
Jacky Baic6fb6672023-09-18 22:08:52 +0800128 /* set core power mode to PD */
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800129 mmio_write_32(AD_COREx_LPMODE(cpu), 0x3);
130}
Jacky Baiba997cc2021-06-25 09:47:46 +0800131
Jacky Baic6fb6672023-09-18 22:08:52 +0800132/* APD power mode config */
133ps_apd_pwr_mode_cfgs_t apd_pwr_mode_cfgs = {
Jacky Bai2c87ab92023-09-18 21:53:15 +0800134 [DPD_PWR_MODE] = {
135 .swt_board_offs = 0x180,
136 .swt_mem_offs = 0x188,
137 .pmic_cfg = PMIC_CFG(0x23, 0xa, 0x2),
138 .pad_cfg = PAD_CFG(0xc, 0x0, 0x01e80a02),
139 .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
140 },
141
Jacky Baiba997cc2021-06-25 09:47:46 +0800142 /* PD */
143 [PD_PWR_MODE] = {
144 .swt_board_offs = 0x170,
145 .swt_mem_offs = 0x178,
146 .pmic_cfg = PMIC_CFG(0x23, 0x2, 0x2),
147 .pad_cfg = PAD_CFG(0x0, 0x0, 0x01e80a00),
148 .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
149 },
150
Jacky Baic6fb6672023-09-18 22:08:52 +0800151 [ADMA_PWR_MODE] = {
152 .swt_board_offs = 0x120,
153 .swt_mem_offs = 0x128,
154 .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
155 .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
156 .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
157 },
158
159 [ACT_PWR_MODE] = {
160 .swt_board_offs = 0x110,
161 .swt_mem_offs = 0x118,
162 .pmic_cfg = PMIC_CFG(0x23, 0x2, 0x2),
163 .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
164 .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
165 },
166};
167
168/* APD power switch config */
169ps_apd_swt_cfgs_t apd_swt_cfgs = {
Jacky Bai2c87ab92023-09-18 21:53:15 +0800170 [DPD_PWR_MODE] = {
171 .swt_board[0] = SWT_BOARD(0x00060003, 0x7c),
172 .swt_mem[0] = SWT_MEM(0x0, 0x0, 0x1ffff),
173 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
174 },
175
Jacky Baiba997cc2021-06-25 09:47:46 +0800176 [PD_PWR_MODE] = {
177 .swt_board[0] = SWT_BOARD(0x00060003, 0x00001e74),
178 .swt_mem[0] = SWT_MEM(0x00010c00, 0x0, 0x1ffff),
179 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003f0000, 0x0),
180 },
181
Jacky Baic6fb6672023-09-18 22:08:52 +0800182 [ADMA_PWR_MODE] = {
Jacky Baiba997cc2021-06-25 09:47:46 +0800183 .swt_board[0] = SWT_BOARD(0x0006ff77, 0x0006ff7c),
184 .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
185 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
Jacky Baic6fb6672023-09-18 22:08:52 +0800186 },
187
188 [ACT_PWR_MODE] = {
Jacky Baiba997cc2021-06-25 09:47:46 +0800189 .swt_board[0] = SWT_BOARD(0x0006ff77, 0x0000ff7c),
190 .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
191 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
Jacky Baic6fb6672023-09-18 22:08:52 +0800192 },
193};
194
195struct ps_pwr_mode_cfg_t *pwr_sys_cfg = (struct ps_pwr_mode_cfg_t *)UPWR_DRAM_SHARED_BASE_ADDR;
196
197void imx_set_pwr_mode_cfg(abs_pwr_mode_t mode)
198{
199 if (mode >= NUM_PWR_MODES) {
200 return;
201 }
202
203 /* apd power mode config */
204 memcpy(&pwr_sys_cfg->ps_apd_pwr_mode_cfg[mode], &apd_pwr_mode_cfgs[mode],
205 sizeof(struct ps_apd_pwr_mode_cfg_t));
206
207 /* apd power switch config */
208 memcpy(&pwr_sys_cfg->ps_apd_swt_cfg[mode], &apd_swt_cfgs[mode], sizeof(swt_config_t));
209}
210
211void imx_domain_suspend(const psci_power_state_t *target_state)
212{
213 unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
214
215 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
216 plat_gic_cpuif_disable();
217 imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
218 /* core put into power down */
219 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x3);
220 /* FIXME config wakeup interrupt in WKPU */
221 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
222 } else {
223 /* for core standby/retention mode */
224 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x1);
225 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
226 dsb();
227 write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
228 isb();
229 }
230
Jacky Baiba997cc2021-06-25 09:47:46 +0800231 if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) {
Jacky Baic6fb6672023-09-18 22:08:52 +0800232 /*
233 * just for sleep mode for now, need to update to
Jacky Baiba997cc2021-06-25 09:47:46 +0800234 * support more modes, same for suspend finish call back.
Jacky Baic6fb6672023-09-18 22:08:52 +0800235 */
236 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x1);
237 mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1);
Jacky Baiba997cc2021-06-25 09:47:46 +0800238
239 } else if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
240 /*
241 * for cluster off state, put cluster into power down mode,
242 * config the cluster clock to be off.
243 */
244 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
245 mmio_write_32(IMX_CMC1_BASE + 0x20, 0xf);
Jacky Baic6fb6672023-09-18 22:08:52 +0800246 }
247
Jacky Baic6fb6672023-09-18 22:08:52 +0800248 if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
249 /*
250 * low power mode config info used by upower
251 * to do low power mode transition.
252 */
253 imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
254 imx_set_pwr_mode_cfg(ACT_PWR_MODE);
Jacky Baiba997cc2021-06-25 09:47:46 +0800255 imx_set_pwr_mode_cfg(PD_PWR_MODE);
256
257 /* clear the upower wakeup */
258 upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
259 upower_wait_resp();
260
261 /* enable the USB wakeup */
262 usb_wakeup_enable(true);
263
264 /* config the WUU to enabled the wakeup source */
265 mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
266
267 /* !!! clear all the pad wakeup pending event */
268 mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
269
270 /* enable upower usb phy wakeup by default */
271 mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4) | BIT(1) | BIT(0));
272
273 /* enabled all pad wakeup by default */
274 mmio_write_32(IMX_WUU1_BASE + 0x8, 0xffffffff);
275
276 /* save the AD domain context before entering PD mode */
277 imx_apd_ctx_save(cpu);
Jacky Baic6fb6672023-09-18 22:08:52 +0800278 }
279}
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800280
Jacky Baiba997cc2021-06-25 09:47:46 +0800281extern void imx8ulp_init_scmi_server(void);
Jacky Baic6fb6672023-09-18 22:08:52 +0800282void imx_domain_suspend_finish(const psci_power_state_t *target_state)
283{
284 unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
285
286 if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
Jacky Baiba997cc2021-06-25 09:47:46 +0800287 /* restore the ap domain context */
288 imx_apd_ctx_restore(cpu);
Jacky Baic6fb6672023-09-18 22:08:52 +0800289
Jacky Baiba997cc2021-06-25 09:47:46 +0800290 /* clear the upower wakeup */
291 upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
292 upower_wait_resp();
293
294 /* disable all pad wakeup */
295 mmio_write_32(IMX_WUU1_BASE + 0x8, 0x0);
296
297 /* clear all the pad wakeup pending event */
298 mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
299
300 /*
301 * disable the usb wakeup after resume to make sure the pending
302 * usb wakeup in WUU can be cleared successfully, otherwise,
303 * APD will resume failed in next PD mode.
304 */
305 usb_wakeup_enable(false);
306
307 /* re-init the SCMI channel */
308 imx8ulp_init_scmi_server();
Jacky Baic6fb6672023-09-18 22:08:52 +0800309 }
310
Jacky Baiba997cc2021-06-25 09:47:46 +0800311 /* clear cluster's LPM setting. */
312 mmio_write_32(IMX_CMC1_BASE + 0x20, 0x0);
313 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x0);
314
Jacky Baic6fb6672023-09-18 22:08:52 +0800315 /* clear core's LPM setting */
316 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x0);
317 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x0);
318
319 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
320 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
321 plat_gic_cpuif_enable();
322 } else {
323 dsb();
324 write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
325 isb();
326 }
327}
328
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800329void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
330{
331 while (1) {
332 wfi();
333 }
334}
335
336void __dead2 imx8ulp_system_reset(void)
337{
338 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
339
340 /* Write invalid command to WDOG CNT to trigger reset */
341 mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678);
342
343 while (true) {
344 wfi();
345 }
346}
347
Jacky Baic6fb6672023-09-18 22:08:52 +0800348int imx_validate_power_state(unsigned int power_state,
349 psci_power_state_t *req_state)
350{
351 int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
352 int pwr_type = psci_get_pstate_type(power_state);
353
354 if (pwr_lvl > PLAT_MAX_PWR_LVL) {
355 return PSCI_E_INVALID_PARAMS;
356 }
357
358 if (pwr_type == PSTATE_TYPE_STANDBY) {
359 CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
360 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
361 }
362
363 /* No power down state support */
364 if (pwr_type == PSTATE_TYPE_POWERDOWN) {
365 return PSCI_E_INVALID_PARAMS;
366 }
367
368 return PSCI_E_SUCCESS;
369}
370
371void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
372{
373 unsigned int i;
374
375 for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) {
376 req_state->pwr_domain_state[i] = PLAT_POWER_DOWN_OFF_STATE;
377 }
Jacky Bai2c87ab92023-09-18 21:53:15 +0800378}
379
380void __dead2 imx_system_off(void)
381{
382 unsigned int i;
383
384 /* config the all the core into OFF mode and IRQ masked. */
385 for (i = 0U; i < PLATFORM_CORE_COUNT; i++) {
386 /* disable wakeup from wkpu */
387 mmio_write_32(WKPUx(i), 0x0);
388
389 /* reset the core reset entry to 0x1000 */
390 imx_pwr_set_cpu_entry(i, 0x1000);
391
392 /* config the core power mode to off */
393 mmio_write_32(AD_COREx_LPMODE(i), 0x3);
394 }
395
396 plat_gic_cpuif_disable();
397
398 /* Config the power mode info for entering DPD mode and ACT mode */
399 imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
400 imx_set_pwr_mode_cfg(ACT_PWR_MODE);
401 imx_set_pwr_mode_cfg(DPD_PWR_MODE);
402
403 /* Set the APD domain into DPD mode */
404 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
405 mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1f);
406
407 /* make sure no pending upower wakeup */
408 upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
409 upower_wait_resp();
410
411 /* enable the upower wakeup from wuu, act as APD boot up method */
412 mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
413 mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4));
414
415 /* make sure no pad wakeup event is pending */
416 mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
417
418 wfi();
419
420 ERROR("power off failed.\n");
421 panic();
Jacky Baic6fb6672023-09-18 22:08:52 +0800422}
423
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800424static const plat_psci_ops_t imx_plat_psci_ops = {
425 .pwr_domain_on = imx_pwr_domain_on,
426 .pwr_domain_on_finish = imx_pwr_domain_on_finish,
427 .validate_ns_entrypoint = imx_validate_ns_entrypoint,
Jacky Bai2c87ab92023-09-18 21:53:15 +0800428 .system_off = imx_system_off,
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800429 .system_reset = imx8ulp_system_reset,
430 .pwr_domain_off = imx_pwr_domain_off,
Jacky Baic6fb6672023-09-18 22:08:52 +0800431 .pwr_domain_suspend = imx_domain_suspend,
432 .pwr_domain_suspend_finish = imx_domain_suspend_finish,
433 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
434 .validate_power_state = imx_validate_power_state,
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800435 .pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
436};
437
438int plat_setup_psci_ops(uintptr_t sec_entrypoint,
439 const plat_psci_ops_t **psci_ops)
440{
441 secure_entrypoint = sec_entrypoint;
442 imx_pwr_set_cpu_entry(0, sec_entrypoint);
443 *psci_ops = &imx_plat_psci_ops;
444
445 mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
446 mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff);
447
448 return 0;
449}