blob: e67d0b53c70d79d06e21e1b654cd6b87c1f8fced [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>
Jacky Bai2e6c8c72023-04-24 14:56:56 +080013#include <drivers/delay_timer.h>
Jacky Bai4d93d1d2020-07-02 14:39:58 +080014#include <lib/mmio.h>
15#include <lib/psci/psci.h>
16
17#include <plat_imx8.h>
Jacky Baic6fb6672023-09-18 22:08:52 +080018#include <upower_api.h>
Jacky Bai4d93d1d2020-07-02 14:39:58 +080019
Jacky Baiba997cc2021-06-25 09:47:46 +080020extern void cgc1_save(void);
21extern void cgc1_restore(void);
22extern void imx_apd_ctx_save(unsigned int cpu);
23extern void imx_apd_ctx_restore(unsigned int cpu);
24extern void usb_wakeup_enable(bool enable);
Jacky Bai5cc4c772021-10-20 11:25:30 +080025extern void upower_wait_resp(void);
26extern bool is_lpav_owned_by_apd(void);
27extern void apd_io_pad_off(void);
28extern int upower_pmic_i2c_read(uint32_t reg_addr, uint32_t *reg_val);
Jacky Baic5a923a2022-12-13 09:34:07 +080029extern void imx8ulp_init_scmi_server(void);
Jacky Baiba997cc2021-06-25 09:47:46 +080030
Jacky Bai4d93d1d2020-07-02 14:39:58 +080031static uintptr_t secure_entrypoint;
32
33#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
34#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
35#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
36
37#define RVBARADDRx(c) (IMX_SIM1_BASE + 0x5c + 0x4 * (c))
38#define WKPUx(c) (IMX_SIM1_BASE + 0x3c + 0x4 * (c))
39#define AD_COREx_LPMODE(c) (IMX_CMC1_BASE + 0x50 + 0x4 * (c))
40
Jacky Baic6fb6672023-09-18 22:08:52 +080041#define PMIC_CFG(v, m, msk) \
42 { \
43 .volt = (v), \
44 .mode = (m), \
45 .mode_msk = (msk), \
46 }
47
48#define PAD_CFG(c, r, t) \
49 { \
50 .pad_close = (c), \
51 .pad_reset = (r), \
52 .pad_tqsleep = (t) \
53 }
54
55#define BIAS_CFG(m, n, p, mbias) \
56 { \
57 .dombias_cfg = { \
58 .mode = (m), \
59 .rbbn = (n), \
60 .rbbp = (p), \
61 }, \
62 .membias_cfg = {mbias}, \
63 }
64
65#define SWT_BOARD(swt_on, msk) \
66 { \
67 .on = (swt_on), \
68 .mask = (msk), \
69 }
70
71#define SWT_MEM(a, p, m) \
72 { \
73 .array = (a), \
74 .perif = (p), \
75 .mask = (m), \
76 }
77
Jacky Bai4d93d1d2020-07-02 14:39:58 +080078static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry)
79{
80 mmio_write_32(RVBARADDRx(cpu), entry);
81
82 /* set update bit */
83 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu));
84 /* wait for ack */
85 while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) {
86 }
87
88 /* clear update bit */
89 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu));
90 /* clear ack bit */
91 mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu));
92
93 return 0;
94}
95
Jacky Bai9be87472022-08-30 15:51:06 +080096static volatile uint32_t cgc1_nicclk;
Jacky Bai4d93d1d2020-07-02 14:39:58 +080097int imx_pwr_domain_on(u_register_t mpidr)
98{
99 unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
100
101 imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
102
Jacky Bai9be87472022-08-30 15:51:06 +0800103 /* slow down the APD NIC bus clock */
104 cgc1_nicclk = mmio_read_32(IMX_CGC1_BASE + 0x34);
105 mmio_clrbits_32(IMX_CGC1_BASE + 0x34, GENMASK_32(29, 28));
106
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800107 mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
108 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0);
109
110 /* enable wku wakeup for idle */
111 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff);
112
113 return PSCI_E_SUCCESS;
114}
115
116void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
117{
118 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
119 plat_gic_pcpu_init();
120 plat_gic_cpuif_enable();
Jacky Bai9be87472022-08-30 15:51:06 +0800121
122 /* set APD NIC back to orignally setting */
123 mmio_write_32(IMX_CGC1_BASE + 0x34, cgc1_nicclk);
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800124}
125
126int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
127{
128 return PSCI_E_SUCCESS;
129}
130
131void imx_pwr_domain_off(const psci_power_state_t *target_state)
132{
133 unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
134
135 plat_gic_cpuif_disable();
136
137 /* disable wakeup */
138 mmio_write_32(WKPUx(cpu), 0);
139
Jacky Baic6fb6672023-09-18 22:08:52 +0800140 /* set core power mode to PD */
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800141 mmio_write_32(AD_COREx_LPMODE(cpu), 0x3);
142}
Jacky Baiba997cc2021-06-25 09:47:46 +0800143
Jacky Baic6fb6672023-09-18 22:08:52 +0800144/* APD power mode config */
145ps_apd_pwr_mode_cfgs_t apd_pwr_mode_cfgs = {
Jacky Bai2c87ab92023-09-18 21:53:15 +0800146 [DPD_PWR_MODE] = {
147 .swt_board_offs = 0x180,
148 .swt_mem_offs = 0x188,
Jacky Bai5cc4c772021-10-20 11:25:30 +0800149 .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
150 .pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a02),
Jacky Bai2c87ab92023-09-18 21:53:15 +0800151 .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
152 },
153
Jacky Baiba997cc2021-06-25 09:47:46 +0800154 /* PD */
155 [PD_PWR_MODE] = {
156 .swt_board_offs = 0x170,
157 .swt_mem_offs = 0x178,
Jacky Bai5cc4c772021-10-20 11:25:30 +0800158 .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
159 .pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a00),
Jacky Baiba997cc2021-06-25 09:47:46 +0800160 .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
161 },
162
Jacky Baic6fb6672023-09-18 22:08:52 +0800163 [ADMA_PWR_MODE] = {
164 .swt_board_offs = 0x120,
165 .swt_mem_offs = 0x128,
166 .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
167 .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
Jacky Bai5cc4c772021-10-20 11:25:30 +0800168 .bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0),
Jacky Baic6fb6672023-09-18 22:08:52 +0800169 },
170
171 [ACT_PWR_MODE] = {
172 .swt_board_offs = 0x110,
173 .swt_mem_offs = 0x118,
Jacky Bai5cc4c772021-10-20 11:25:30 +0800174 .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
Jacky Baic6fb6672023-09-18 22:08:52 +0800175 .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
Jacky Bai5cc4c772021-10-20 11:25:30 +0800176 .bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0),
Jacky Baic6fb6672023-09-18 22:08:52 +0800177 },
178};
179
180/* APD power switch config */
181ps_apd_swt_cfgs_t apd_swt_cfgs = {
Jacky Bai2c87ab92023-09-18 21:53:15 +0800182 [DPD_PWR_MODE] = {
Jacky Bai5cc4c772021-10-20 11:25:30 +0800183 .swt_board[0] = SWT_BOARD(0x0, 0x1fffc),
Jacky Bai2c87ab92023-09-18 21:53:15 +0800184 .swt_mem[0] = SWT_MEM(0x0, 0x0, 0x1ffff),
185 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
186 },
187
Jacky Baiba997cc2021-06-25 09:47:46 +0800188 [PD_PWR_MODE] = {
Jacky Bai5cc4c772021-10-20 11:25:30 +0800189 .swt_board[0] = SWT_BOARD(0x0, 0x00001fffc),
Jacky Baiba997cc2021-06-25 09:47:46 +0800190 .swt_mem[0] = SWT_MEM(0x00010c00, 0x0, 0x1ffff),
191 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003f0000, 0x0),
192 },
193
Jacky Baic6fb6672023-09-18 22:08:52 +0800194 [ADMA_PWR_MODE] = {
Jacky Bai5cc4c772021-10-20 11:25:30 +0800195 .swt_board[0] = SWT_BOARD(0x15f74, 0x15f74),
Jacky Baiba997cc2021-06-25 09:47:46 +0800196 .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
197 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
Jacky Baic6fb6672023-09-18 22:08:52 +0800198 },
199
200 [ACT_PWR_MODE] = {
Jacky Bai5cc4c772021-10-20 11:25:30 +0800201 .swt_board[0] = SWT_BOARD(0x15f74, 0x15f74),
Jacky Baiba997cc2021-06-25 09:47:46 +0800202 .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
203 .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
Jacky Baic6fb6672023-09-18 22:08:52 +0800204 },
205};
206
Jacky Bai5cc4c772021-10-20 11:25:30 +0800207/* PMIC config for power down, LDO1 should be OFF */
208ps_apd_pmic_reg_data_cfgs_t pd_pmic_reg_cfgs = {
209 [0] = {
210 .tag = PMIC_REG_VALID_TAG,
211 .power_mode = PD_PWR_MODE,
212 .i2c_addr = 0x30,
213 .i2c_data = 0x9c,
214 },
215 [1] = {
216 .tag = PMIC_REG_VALID_TAG,
217 .power_mode = PD_PWR_MODE,
218 .i2c_addr = 0x22,
219 .i2c_data = 0xb,
220 },
221 [2] = {
222 .tag = PMIC_REG_VALID_TAG,
223 .power_mode = ACT_PWR_MODE,
224 .i2c_addr = 0x30,
225 .i2c_data = 0x9d,
226 },
227 [3] = {
228 .tag = PMIC_REG_VALID_TAG,
229 .power_mode = ACT_PWR_MODE,
230 .i2c_addr = 0x22,
231 .i2c_data = 0x28,
232 },
233};
234
235/* PMIC config for deep power down, BUCK3 should be OFF */
236ps_apd_pmic_reg_data_cfgs_t dpd_pmic_reg_cfgs = {
237 [0] = {
238 .tag = PMIC_REG_VALID_TAG,
239 .power_mode = DPD_PWR_MODE,
240 .i2c_addr = 0x21,
241 .i2c_data = 0x78,
242 },
243 [1] = {
244 .tag = PMIC_REG_VALID_TAG,
245 .power_mode = DPD_PWR_MODE,
246 .i2c_addr = 0x30,
247 .i2c_data = 0x9c,
248 },
249 [2] = {
250 .tag = PMIC_REG_VALID_TAG,
251 .power_mode = ACT_PWR_MODE,
252 .i2c_addr = 0x21,
253 .i2c_data = 0x79,
254 },
255 [3] = {
256 .tag = PMIC_REG_VALID_TAG,
257 .power_mode = ACT_PWR_MODE,
258 .i2c_addr = 0x30,
259 .i2c_data = 0x9d,
260 },
261};
262
Jacky Baic6fb6672023-09-18 22:08:52 +0800263struct ps_pwr_mode_cfg_t *pwr_sys_cfg = (struct ps_pwr_mode_cfg_t *)UPWR_DRAM_SHARED_BASE_ADDR;
264
265void imx_set_pwr_mode_cfg(abs_pwr_mode_t mode)
266{
Jacky Bai5cc4c772021-10-20 11:25:30 +0800267 uint32_t volt;
268
Jacky Baic6fb6672023-09-18 22:08:52 +0800269 if (mode >= NUM_PWR_MODES) {
270 return;
271 }
272
273 /* apd power mode config */
274 memcpy(&pwr_sys_cfg->ps_apd_pwr_mode_cfg[mode], &apd_pwr_mode_cfgs[mode],
275 sizeof(struct ps_apd_pwr_mode_cfg_t));
276
277 /* apd power switch config */
278 memcpy(&pwr_sys_cfg->ps_apd_swt_cfg[mode], &apd_swt_cfgs[mode], sizeof(swt_config_t));
Jacky Bai5cc4c772021-10-20 11:25:30 +0800279
280 /*
281 * BUCK3 & LDO1 can only be shutdown when LPAV is owned by APD side
282 * otherwise RTD side is responsible to control them in low power mode.
283 */
284 if (is_lpav_owned_by_apd()) {
285 /* power off the BUCK3 in DPD mode */
286 if (mode == DPD_PWR_MODE) {
287 memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &dpd_pmic_reg_cfgs,
288 sizeof(ps_apd_pmic_reg_data_cfgs_t));
289 /* LDO1 should be power off in PD mode */
290 } else if (mode == PD_PWR_MODE) {
291 /* overwrite the buck3 voltage setting in active mode */
Boyan Karatotev5b940ec2025-05-15 10:00:54 +0100292 if (upower_pmic_i2c_read(0x22, &volt) != 0) {
293 panic();
294 }
Jacky Bai5cc4c772021-10-20 11:25:30 +0800295 pd_pmic_reg_cfgs[3].i2c_data = volt;
296 memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &pd_pmic_reg_cfgs,
297 sizeof(ps_apd_pmic_reg_data_cfgs_t));
298 }
299 }
Jacky Baic6fb6672023-09-18 22:08:52 +0800300}
301
302void imx_domain_suspend(const psci_power_state_t *target_state)
303{
304 unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
305
306 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
307 plat_gic_cpuif_disable();
308 imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
309 /* core put into power down */
310 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x3);
311 /* FIXME config wakeup interrupt in WKPU */
312 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
313 } else {
314 /* for core standby/retention mode */
315 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x1);
316 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
317 dsb();
318 write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
319 isb();
320 }
321
Jacky Baiba997cc2021-06-25 09:47:46 +0800322 if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) {
Jacky Baic6fb6672023-09-18 22:08:52 +0800323 /*
324 * just for sleep mode for now, need to update to
Jacky Baiba997cc2021-06-25 09:47:46 +0800325 * support more modes, same for suspend finish call back.
Jacky Baic6fb6672023-09-18 22:08:52 +0800326 */
327 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x1);
328 mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1);
Jacky Baiba997cc2021-06-25 09:47:46 +0800329
330 } else if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
331 /*
332 * for cluster off state, put cluster into power down mode,
333 * config the cluster clock to be off.
334 */
335 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
336 mmio_write_32(IMX_CMC1_BASE + 0x20, 0xf);
Jacky Baic6fb6672023-09-18 22:08:52 +0800337 }
338
Jacky Baic6fb6672023-09-18 22:08:52 +0800339 if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
340 /*
341 * low power mode config info used by upower
342 * to do low power mode transition.
343 */
344 imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
345 imx_set_pwr_mode_cfg(ACT_PWR_MODE);
Jacky Baiba997cc2021-06-25 09:47:46 +0800346 imx_set_pwr_mode_cfg(PD_PWR_MODE);
347
348 /* clear the upower wakeup */
349 upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
350 upower_wait_resp();
351
352 /* enable the USB wakeup */
353 usb_wakeup_enable(true);
354
355 /* config the WUU to enabled the wakeup source */
356 mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
357
358 /* !!! clear all the pad wakeup pending event */
359 mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
360
361 /* enable upower usb phy wakeup by default */
362 mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4) | BIT(1) | BIT(0));
363
364 /* enabled all pad wakeup by default */
365 mmio_write_32(IMX_WUU1_BASE + 0x8, 0xffffffff);
366
367 /* save the AD domain context before entering PD mode */
368 imx_apd_ctx_save(cpu);
Jacky Baic6fb6672023-09-18 22:08:52 +0800369 }
370}
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800371
Jacky Baic5a923a2022-12-13 09:34:07 +0800372#define DRAM_LPM_STATUS U(0x2802b004)
Jacky Baic6fb6672023-09-18 22:08:52 +0800373void imx_domain_suspend_finish(const psci_power_state_t *target_state)
374{
375 unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
376
377 if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
Jacky Baiba997cc2021-06-25 09:47:46 +0800378 /* restore the ap domain context */
379 imx_apd_ctx_restore(cpu);
Jacky Baic6fb6672023-09-18 22:08:52 +0800380
Jacky Baiba997cc2021-06-25 09:47:46 +0800381 /* clear the upower wakeup */
382 upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
383 upower_wait_resp();
384
385 /* disable all pad wakeup */
386 mmio_write_32(IMX_WUU1_BASE + 0x8, 0x0);
387
388 /* clear all the pad wakeup pending event */
389 mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
390
391 /*
392 * disable the usb wakeup after resume to make sure the pending
393 * usb wakeup in WUU can be cleared successfully, otherwise,
394 * APD will resume failed in next PD mode.
395 */
396 usb_wakeup_enable(false);
397
398 /* re-init the SCMI channel */
399 imx8ulp_init_scmi_server();
Jacky Baic6fb6672023-09-18 22:08:52 +0800400 }
401
Jacky Baic5a923a2022-12-13 09:34:07 +0800402 /*
403 * wait for DDR is ready when DDR is under the RTD
404 * side control for power saving
405 */
406 while (mmio_read_32(DRAM_LPM_STATUS) != 0) {
407 ;
408 }
409
Jacky Bai2e6c8c72023-04-24 14:56:56 +0800410 /*
411 * when resume from low power mode, need to delay for a while
412 * before access the CMC register.
413 */
414 udelay(5);
415
Jacky Baiba997cc2021-06-25 09:47:46 +0800416 /* clear cluster's LPM setting. */
417 mmio_write_32(IMX_CMC1_BASE + 0x20, 0x0);
418 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x0);
419
Jacky Baic6fb6672023-09-18 22:08:52 +0800420 /* clear core's LPM setting */
421 mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x0);
422 mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x0);
423
424 if (is_local_state_off(CORE_PWR_STATE(target_state))) {
425 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
426 plat_gic_cpuif_enable();
427 } else {
428 dsb();
429 write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
430 isb();
431 }
432}
433
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800434void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
435{
436 while (1) {
437 wfi();
438 }
439}
440
441void __dead2 imx8ulp_system_reset(void)
442{
443 imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
444
445 /* Write invalid command to WDOG CNT to trigger reset */
446 mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678);
447
448 while (true) {
449 wfi();
450 }
451}
452
Jacky Baic6fb6672023-09-18 22:08:52 +0800453int imx_validate_power_state(unsigned int power_state,
454 psci_power_state_t *req_state)
455{
456 int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
457 int pwr_type = psci_get_pstate_type(power_state);
458
459 if (pwr_lvl > PLAT_MAX_PWR_LVL) {
460 return PSCI_E_INVALID_PARAMS;
461 }
462
463 if (pwr_type == PSTATE_TYPE_STANDBY) {
464 CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
465 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
466 }
467
468 /* No power down state support */
469 if (pwr_type == PSTATE_TYPE_POWERDOWN) {
470 return PSCI_E_INVALID_PARAMS;
471 }
472
473 return PSCI_E_SUCCESS;
474}
475
476void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
477{
478 unsigned int i;
479
480 for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) {
481 req_state->pwr_domain_state[i] = PLAT_POWER_DOWN_OFF_STATE;
482 }
Jacky Bai2c87ab92023-09-18 21:53:15 +0800483}
484
485void __dead2 imx_system_off(void)
486{
487 unsigned int i;
488
489 /* config the all the core into OFF mode and IRQ masked. */
490 for (i = 0U; i < PLATFORM_CORE_COUNT; i++) {
491 /* disable wakeup from wkpu */
492 mmio_write_32(WKPUx(i), 0x0);
493
494 /* reset the core reset entry to 0x1000 */
495 imx_pwr_set_cpu_entry(i, 0x1000);
496
497 /* config the core power mode to off */
498 mmio_write_32(AD_COREx_LPMODE(i), 0x3);
499 }
500
501 plat_gic_cpuif_disable();
502
Jacky Bai5cc4c772021-10-20 11:25:30 +0800503 /* power off all the pad */
504 apd_io_pad_off();
505
Jacky Bai2c87ab92023-09-18 21:53:15 +0800506 /* Config the power mode info for entering DPD mode and ACT mode */
507 imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
508 imx_set_pwr_mode_cfg(ACT_PWR_MODE);
509 imx_set_pwr_mode_cfg(DPD_PWR_MODE);
510
511 /* Set the APD domain into DPD mode */
512 mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
513 mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1f);
514
515 /* make sure no pending upower wakeup */
516 upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
517 upower_wait_resp();
518
519 /* enable the upower wakeup from wuu, act as APD boot up method */
520 mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
521 mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4));
522
523 /* make sure no pad wakeup event is pending */
524 mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
525
526 wfi();
527
528 ERROR("power off failed.\n");
529 panic();
Jacky Baic6fb6672023-09-18 22:08:52 +0800530}
531
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800532static const plat_psci_ops_t imx_plat_psci_ops = {
533 .pwr_domain_on = imx_pwr_domain_on,
534 .pwr_domain_on_finish = imx_pwr_domain_on_finish,
535 .validate_ns_entrypoint = imx_validate_ns_entrypoint,
Jacky Bai2c87ab92023-09-18 21:53:15 +0800536 .system_off = imx_system_off,
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800537 .system_reset = imx8ulp_system_reset,
538 .pwr_domain_off = imx_pwr_domain_off,
Jacky Baic6fb6672023-09-18 22:08:52 +0800539 .pwr_domain_suspend = imx_domain_suspend,
540 .pwr_domain_suspend_finish = imx_domain_suspend_finish,
541 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
542 .validate_power_state = imx_validate_power_state,
Boyan Karatotevec9bfcd2024-10-08 17:34:45 +0100543 .pwr_domain_pwr_down = imx8ulp_pwr_domain_pwr_down_wfi,
Jacky Bai4d93d1d2020-07-02 14:39:58 +0800544};
545
546int plat_setup_psci_ops(uintptr_t sec_entrypoint,
547 const plat_psci_ops_t **psci_ops)
548{
549 secure_entrypoint = sec_entrypoint;
550 imx_pwr_set_cpu_entry(0, sec_entrypoint);
551 *psci_ops = &imx_plat_psci_ops;
552
553 mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
554 mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff);
555
556 return 0;
557}