xref: /rk3399_ARM-atf/plat/imx/imx8ulp/imx8ulp_psci.c (revision 891c547e9658c1827559d8da5e3b87de5a2e9f6a)
1fcd41e86SJacky Bai /*
2fcd41e86SJacky Bai  * Copyright 2021-2024 NXP
3fcd41e86SJacky Bai  *
4fcd41e86SJacky Bai  * SPDX-License-Identifier: BSD-3-Clause
5fcd41e86SJacky Bai  */
6fcd41e86SJacky Bai 
7fcd41e86SJacky Bai #include <stdbool.h>
8fcd41e86SJacky Bai 
9fcd41e86SJacky Bai #include <arch.h>
10fcd41e86SJacky Bai #include <arch_helpers.h>
11fcd41e86SJacky Bai #include <common/debug.h>
12fcd41e86SJacky Bai #include <drivers/arm/gicv3.h>
13fcd41e86SJacky Bai #include <lib/mmio.h>
14fcd41e86SJacky Bai #include <lib/psci/psci.h>
15fcd41e86SJacky Bai 
16fcd41e86SJacky Bai #include <plat_imx8.h>
17daa4478aSJacky Bai #include <upower_api.h>
18fcd41e86SJacky Bai 
19478af8d3SJacky Bai extern void cgc1_save(void);
20478af8d3SJacky Bai extern void cgc1_restore(void);
21478af8d3SJacky Bai extern void imx_apd_ctx_save(unsigned int cpu);
22478af8d3SJacky Bai extern void imx_apd_ctx_restore(unsigned int cpu);
23478af8d3SJacky Bai extern void usb_wakeup_enable(bool enable);
24478af8d3SJacky Bai 
25fcd41e86SJacky Bai static uintptr_t secure_entrypoint;
26fcd41e86SJacky Bai 
27fcd41e86SJacky Bai #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
28fcd41e86SJacky Bai #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
29fcd41e86SJacky Bai #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
30fcd41e86SJacky Bai 
31fcd41e86SJacky Bai #define RVBARADDRx(c)		(IMX_SIM1_BASE + 0x5c + 0x4 * (c))
32fcd41e86SJacky Bai #define WKPUx(c)		(IMX_SIM1_BASE + 0x3c + 0x4 * (c))
33fcd41e86SJacky Bai #define AD_COREx_LPMODE(c)	(IMX_CMC1_BASE + 0x50 + 0x4 * (c))
34fcd41e86SJacky Bai 
35daa4478aSJacky Bai #define PMIC_CFG(v, m, msk)		\
36daa4478aSJacky Bai 	{				\
37daa4478aSJacky Bai 		.volt = (v),		\
38daa4478aSJacky Bai 		.mode = (m),		\
39daa4478aSJacky Bai 		.mode_msk = (msk),	\
40daa4478aSJacky Bai 	}
41daa4478aSJacky Bai 
42daa4478aSJacky Bai #define PAD_CFG(c, r, t)		\
43daa4478aSJacky Bai 	{				\
44daa4478aSJacky Bai 		.pad_close = (c),	\
45daa4478aSJacky Bai 		.pad_reset = (r),	\
46daa4478aSJacky Bai 		.pad_tqsleep = (t)	\
47daa4478aSJacky Bai 	}
48daa4478aSJacky Bai 
49daa4478aSJacky Bai #define BIAS_CFG(m, n, p, mbias)	\
50daa4478aSJacky Bai 	{				\
51daa4478aSJacky Bai 		.dombias_cfg = {	\
52daa4478aSJacky Bai 			.mode = (m),	\
53daa4478aSJacky Bai 			.rbbn = (n),	\
54daa4478aSJacky Bai 			.rbbp = (p),	\
55daa4478aSJacky Bai 		},			\
56daa4478aSJacky Bai 		.membias_cfg = {mbias},	\
57daa4478aSJacky Bai 	}
58daa4478aSJacky Bai 
59daa4478aSJacky Bai #define SWT_BOARD(swt_on, msk)	\
60daa4478aSJacky Bai 	{			\
61daa4478aSJacky Bai 		.on = (swt_on),	\
62daa4478aSJacky Bai 		.mask = (msk),	\
63daa4478aSJacky Bai 	}
64daa4478aSJacky Bai 
65daa4478aSJacky Bai #define SWT_MEM(a, p, m)	\
66daa4478aSJacky Bai 	{			\
67daa4478aSJacky Bai 		.array = (a),	\
68daa4478aSJacky Bai 		.perif = (p),	\
69daa4478aSJacky Bai 		.mask = (m),	\
70daa4478aSJacky Bai 	}
71daa4478aSJacky Bai 
72478af8d3SJacky Bai extern void upower_wait_resp(void);
73478af8d3SJacky Bai 
74fcd41e86SJacky Bai static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry)
75fcd41e86SJacky Bai {
76fcd41e86SJacky Bai 	mmio_write_32(RVBARADDRx(cpu), entry);
77fcd41e86SJacky Bai 
78fcd41e86SJacky Bai 	/* set update bit */
79fcd41e86SJacky Bai 	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu));
80fcd41e86SJacky Bai 	/* wait for ack */
81fcd41e86SJacky Bai 	while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) {
82fcd41e86SJacky Bai 	}
83fcd41e86SJacky Bai 
84fcd41e86SJacky Bai 	/* clear update bit */
85fcd41e86SJacky Bai 	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu));
86fcd41e86SJacky Bai 	/* clear ack bit */
87fcd41e86SJacky Bai 	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu));
88fcd41e86SJacky Bai 
89fcd41e86SJacky Bai 	return 0;
90fcd41e86SJacky Bai }
91fcd41e86SJacky Bai 
92fcd41e86SJacky Bai int imx_pwr_domain_on(u_register_t mpidr)
93fcd41e86SJacky Bai {
94fcd41e86SJacky Bai 	unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
95fcd41e86SJacky Bai 
96fcd41e86SJacky Bai 	imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
97fcd41e86SJacky Bai 
98fcd41e86SJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
99fcd41e86SJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0);
100fcd41e86SJacky Bai 
101fcd41e86SJacky Bai 	/* enable wku wakeup for idle */
102fcd41e86SJacky Bai 	mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff);
103fcd41e86SJacky Bai 
104fcd41e86SJacky Bai 	return PSCI_E_SUCCESS;
105fcd41e86SJacky Bai }
106fcd41e86SJacky Bai 
107fcd41e86SJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
108fcd41e86SJacky Bai {
109fcd41e86SJacky Bai 	imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
110fcd41e86SJacky Bai 	plat_gic_pcpu_init();
111fcd41e86SJacky Bai 	plat_gic_cpuif_enable();
112fcd41e86SJacky Bai }
113fcd41e86SJacky Bai 
114fcd41e86SJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
115fcd41e86SJacky Bai {
116fcd41e86SJacky Bai 	return PSCI_E_SUCCESS;
117fcd41e86SJacky Bai }
118fcd41e86SJacky Bai 
119fcd41e86SJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state)
120fcd41e86SJacky Bai {
121fcd41e86SJacky Bai 	unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
122fcd41e86SJacky Bai 
123fcd41e86SJacky Bai 	plat_gic_cpuif_disable();
124fcd41e86SJacky Bai 
125fcd41e86SJacky Bai 	/* disable wakeup */
126fcd41e86SJacky Bai 	mmio_write_32(WKPUx(cpu), 0);
127fcd41e86SJacky Bai 
128daa4478aSJacky Bai 	/* set core power mode to PD */
129fcd41e86SJacky Bai 	mmio_write_32(AD_COREx_LPMODE(cpu), 0x3);
130fcd41e86SJacky Bai }
131478af8d3SJacky Bai 
132daa4478aSJacky Bai /* APD power mode config */
133daa4478aSJacky Bai ps_apd_pwr_mode_cfgs_t apd_pwr_mode_cfgs = {
134*891c547eSJacky Bai 	[DPD_PWR_MODE] = {
135*891c547eSJacky Bai 		.swt_board_offs = 0x180,
136*891c547eSJacky Bai 		.swt_mem_offs = 0x188,
137*891c547eSJacky Bai 		.pmic_cfg = PMIC_CFG(0x23, 0xa, 0x2),
138*891c547eSJacky Bai 		.pad_cfg = PAD_CFG(0xc, 0x0, 0x01e80a02),
139*891c547eSJacky Bai 		.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
140*891c547eSJacky Bai 	},
141*891c547eSJacky Bai 
142478af8d3SJacky Bai 	/* PD */
143478af8d3SJacky Bai 	[PD_PWR_MODE] = {
144478af8d3SJacky Bai 		.swt_board_offs = 0x170,
145478af8d3SJacky Bai 		.swt_mem_offs = 0x178,
146478af8d3SJacky Bai 		.pmic_cfg = PMIC_CFG(0x23, 0x2, 0x2),
147478af8d3SJacky Bai 		.pad_cfg = PAD_CFG(0x0, 0x0, 0x01e80a00),
148478af8d3SJacky Bai 		.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
149478af8d3SJacky Bai 	},
150478af8d3SJacky Bai 
151daa4478aSJacky Bai 	[ADMA_PWR_MODE] = {
152daa4478aSJacky Bai 		.swt_board_offs = 0x120,
153daa4478aSJacky Bai 		.swt_mem_offs = 0x128,
154daa4478aSJacky Bai 		.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
155daa4478aSJacky Bai 		.pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
156daa4478aSJacky Bai 		.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
157daa4478aSJacky Bai 	},
158daa4478aSJacky Bai 
159daa4478aSJacky Bai 	[ACT_PWR_MODE] = {
160daa4478aSJacky Bai 		.swt_board_offs = 0x110,
161daa4478aSJacky Bai 		.swt_mem_offs = 0x118,
162daa4478aSJacky Bai 		.pmic_cfg = PMIC_CFG(0x23, 0x2, 0x2),
163daa4478aSJacky Bai 		.pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
164daa4478aSJacky Bai 		.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
165daa4478aSJacky Bai 	},
166daa4478aSJacky Bai };
167daa4478aSJacky Bai 
168daa4478aSJacky Bai /* APD power switch config */
169daa4478aSJacky Bai ps_apd_swt_cfgs_t apd_swt_cfgs = {
170*891c547eSJacky Bai 	[DPD_PWR_MODE] = {
171*891c547eSJacky Bai 		.swt_board[0] = SWT_BOARD(0x00060003, 0x7c),
172*891c547eSJacky Bai 		.swt_mem[0] = SWT_MEM(0x0, 0x0, 0x1ffff),
173*891c547eSJacky Bai 		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
174*891c547eSJacky Bai 	},
175*891c547eSJacky Bai 
176478af8d3SJacky Bai 	[PD_PWR_MODE] = {
177478af8d3SJacky Bai 		.swt_board[0] = SWT_BOARD(0x00060003, 0x00001e74),
178478af8d3SJacky Bai 		.swt_mem[0] = SWT_MEM(0x00010c00, 0x0, 0x1ffff),
179478af8d3SJacky Bai 		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003f0000, 0x0),
180478af8d3SJacky Bai 	},
181478af8d3SJacky Bai 
182daa4478aSJacky Bai 	[ADMA_PWR_MODE] = {
183478af8d3SJacky Bai 		.swt_board[0] = SWT_BOARD(0x0006ff77, 0x0006ff7c),
184478af8d3SJacky Bai 		.swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
185478af8d3SJacky Bai 		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
186daa4478aSJacky Bai 	},
187daa4478aSJacky Bai 
188daa4478aSJacky Bai 	[ACT_PWR_MODE] = {
189478af8d3SJacky Bai 		.swt_board[0] = SWT_BOARD(0x0006ff77, 0x0000ff7c),
190478af8d3SJacky Bai 		.swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
191478af8d3SJacky Bai 		.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
192daa4478aSJacky Bai 	},
193daa4478aSJacky Bai };
194daa4478aSJacky Bai 
195daa4478aSJacky Bai struct ps_pwr_mode_cfg_t *pwr_sys_cfg = (struct ps_pwr_mode_cfg_t *)UPWR_DRAM_SHARED_BASE_ADDR;
196daa4478aSJacky Bai 
197daa4478aSJacky Bai void imx_set_pwr_mode_cfg(abs_pwr_mode_t mode)
198daa4478aSJacky Bai {
199daa4478aSJacky Bai 	if (mode >= NUM_PWR_MODES) {
200daa4478aSJacky Bai 		return;
201daa4478aSJacky Bai 	}
202daa4478aSJacky Bai 
203daa4478aSJacky Bai 	/* apd power mode config */
204daa4478aSJacky Bai 	memcpy(&pwr_sys_cfg->ps_apd_pwr_mode_cfg[mode], &apd_pwr_mode_cfgs[mode],
205daa4478aSJacky Bai 		 sizeof(struct ps_apd_pwr_mode_cfg_t));
206daa4478aSJacky Bai 
207daa4478aSJacky Bai 	/* apd power switch config */
208daa4478aSJacky Bai 	memcpy(&pwr_sys_cfg->ps_apd_swt_cfg[mode], &apd_swt_cfgs[mode], sizeof(swt_config_t));
209daa4478aSJacky Bai }
210daa4478aSJacky Bai 
211daa4478aSJacky Bai void imx_domain_suspend(const psci_power_state_t *target_state)
212daa4478aSJacky Bai {
213daa4478aSJacky Bai 	unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
214daa4478aSJacky Bai 
215daa4478aSJacky Bai 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
216daa4478aSJacky Bai 		plat_gic_cpuif_disable();
217daa4478aSJacky Bai 		imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
218daa4478aSJacky Bai 		/* core put into power down */
219daa4478aSJacky Bai 		mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x3);
220daa4478aSJacky Bai 		/* FIXME config wakeup interrupt in WKPU */
221daa4478aSJacky Bai 		mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
222daa4478aSJacky Bai 	} else {
223daa4478aSJacky Bai 		/* for core standby/retention mode */
224daa4478aSJacky Bai 		mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x1);
225daa4478aSJacky Bai 		mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
226daa4478aSJacky Bai 		dsb();
227daa4478aSJacky Bai 		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
228daa4478aSJacky Bai 		isb();
229daa4478aSJacky Bai 	}
230daa4478aSJacky Bai 
231478af8d3SJacky Bai 	if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) {
232daa4478aSJacky Bai 		/*
233daa4478aSJacky Bai 		 * just for sleep mode for now, need to update to
234478af8d3SJacky Bai 		 * support more modes, same for suspend finish call back.
235daa4478aSJacky Bai 		 */
236daa4478aSJacky Bai 		mmio_write_32(IMX_CMC1_BASE + 0x10, 0x1);
237daa4478aSJacky Bai 		mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1);
238478af8d3SJacky Bai 
239478af8d3SJacky Bai 	} else if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
240478af8d3SJacky Bai 		/*
241478af8d3SJacky Bai 		 * for cluster off state, put cluster into power down mode,
242478af8d3SJacky Bai 		 * config the cluster clock to be off.
243478af8d3SJacky Bai 		 */
244478af8d3SJacky Bai 		mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
245478af8d3SJacky Bai 		mmio_write_32(IMX_CMC1_BASE + 0x20, 0xf);
246daa4478aSJacky Bai 	}
247daa4478aSJacky Bai 
248daa4478aSJacky Bai 	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
249daa4478aSJacky Bai 		/*
250daa4478aSJacky Bai 		 * low power mode config info used by upower
251daa4478aSJacky Bai 		 * to do low power mode transition.
252daa4478aSJacky Bai 		 */
253daa4478aSJacky Bai 		imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
254daa4478aSJacky Bai 		imx_set_pwr_mode_cfg(ACT_PWR_MODE);
255478af8d3SJacky Bai 		imx_set_pwr_mode_cfg(PD_PWR_MODE);
256478af8d3SJacky Bai 
257478af8d3SJacky Bai 		/* clear the upower wakeup */
258478af8d3SJacky Bai 		upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
259478af8d3SJacky Bai 		upower_wait_resp();
260478af8d3SJacky Bai 
261478af8d3SJacky Bai 		/* enable the USB wakeup */
262478af8d3SJacky Bai 		usb_wakeup_enable(true);
263478af8d3SJacky Bai 
264478af8d3SJacky Bai 		/* config the WUU to enabled the wakeup source */
265478af8d3SJacky Bai 		mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
266478af8d3SJacky Bai 
267478af8d3SJacky Bai 		/* !!! clear all the pad wakeup pending event */
268478af8d3SJacky Bai 		mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
269478af8d3SJacky Bai 
270478af8d3SJacky Bai 		/* enable upower usb phy wakeup by default */
271478af8d3SJacky Bai 		mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4) | BIT(1) | BIT(0));
272478af8d3SJacky Bai 
273478af8d3SJacky Bai 		/* enabled all pad wakeup by default */
274478af8d3SJacky Bai 		mmio_write_32(IMX_WUU1_BASE + 0x8, 0xffffffff);
275478af8d3SJacky Bai 
276478af8d3SJacky Bai 		/* save the AD domain context before entering PD mode */
277478af8d3SJacky Bai 		imx_apd_ctx_save(cpu);
278daa4478aSJacky Bai 	}
279daa4478aSJacky Bai }
280daa4478aSJacky Bai 
281478af8d3SJacky Bai extern void imx8ulp_init_scmi_server(void);
282daa4478aSJacky Bai void imx_domain_suspend_finish(const psci_power_state_t *target_state)
283daa4478aSJacky Bai {
284daa4478aSJacky Bai 	unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
285daa4478aSJacky Bai 
286daa4478aSJacky Bai 	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
287478af8d3SJacky Bai 		/* restore the ap domain context */
288478af8d3SJacky Bai 		imx_apd_ctx_restore(cpu);
289478af8d3SJacky Bai 
290478af8d3SJacky Bai 		/* clear the upower wakeup */
291478af8d3SJacky Bai 		upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
292478af8d3SJacky Bai 		upower_wait_resp();
293478af8d3SJacky Bai 
294478af8d3SJacky Bai 		/* disable all pad wakeup */
295478af8d3SJacky Bai 		mmio_write_32(IMX_WUU1_BASE + 0x8, 0x0);
296478af8d3SJacky Bai 
297478af8d3SJacky Bai 		/* clear all the pad wakeup pending event */
298478af8d3SJacky Bai 		mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
299478af8d3SJacky Bai 
300478af8d3SJacky Bai 		/*
301478af8d3SJacky Bai 		 * disable the usb wakeup after resume to make sure the pending
302478af8d3SJacky Bai 		 * usb wakeup in WUU can be cleared successfully, otherwise,
303478af8d3SJacky Bai 		 * APD will resume failed in next PD mode.
304478af8d3SJacky Bai 		 */
305478af8d3SJacky Bai 		usb_wakeup_enable(false);
306478af8d3SJacky Bai 
307478af8d3SJacky Bai 		/* re-init the SCMI channel */
308478af8d3SJacky Bai 		imx8ulp_init_scmi_server();
309daa4478aSJacky Bai 	}
310daa4478aSJacky Bai 
311478af8d3SJacky Bai 	/* clear cluster's LPM setting. */
312daa4478aSJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x20, 0x0);
313daa4478aSJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x10, 0x0);
314daa4478aSJacky Bai 
315daa4478aSJacky Bai 	/* clear core's LPM setting */
316daa4478aSJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x0);
317daa4478aSJacky Bai 	mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x0);
318daa4478aSJacky Bai 
319daa4478aSJacky Bai 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
320daa4478aSJacky Bai 		imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
321daa4478aSJacky Bai 		plat_gic_cpuif_enable();
322daa4478aSJacky Bai 	} else {
323daa4478aSJacky Bai 		dsb();
324daa4478aSJacky Bai 		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
325daa4478aSJacky Bai 		isb();
326daa4478aSJacky Bai 	}
327daa4478aSJacky Bai }
328fcd41e86SJacky Bai 
329fcd41e86SJacky Bai void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
330fcd41e86SJacky Bai {
331fcd41e86SJacky Bai 	while (1) {
332fcd41e86SJacky Bai 		wfi();
333fcd41e86SJacky Bai 	}
334fcd41e86SJacky Bai }
335fcd41e86SJacky Bai 
336fcd41e86SJacky Bai void __dead2 imx8ulp_system_reset(void)
337fcd41e86SJacky Bai {
338fcd41e86SJacky Bai 	imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
339fcd41e86SJacky Bai 
340fcd41e86SJacky Bai 	/* Write invalid command to WDOG CNT to trigger reset */
341fcd41e86SJacky Bai 	mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678);
342fcd41e86SJacky Bai 
343fcd41e86SJacky Bai 	while (true) {
344fcd41e86SJacky Bai 		wfi();
345fcd41e86SJacky Bai 	}
346fcd41e86SJacky Bai }
347fcd41e86SJacky Bai 
348daa4478aSJacky Bai int imx_validate_power_state(unsigned int power_state,
349daa4478aSJacky Bai 			 psci_power_state_t *req_state)
350daa4478aSJacky Bai {
351daa4478aSJacky Bai 	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
352daa4478aSJacky Bai 	int pwr_type = psci_get_pstate_type(power_state);
353daa4478aSJacky Bai 
354daa4478aSJacky Bai 	if (pwr_lvl > PLAT_MAX_PWR_LVL) {
355daa4478aSJacky Bai 		return PSCI_E_INVALID_PARAMS;
356daa4478aSJacky Bai 	}
357daa4478aSJacky Bai 
358daa4478aSJacky Bai 	if (pwr_type == PSTATE_TYPE_STANDBY) {
359daa4478aSJacky Bai 		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
360daa4478aSJacky Bai 		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
361daa4478aSJacky Bai 	}
362daa4478aSJacky Bai 
363daa4478aSJacky Bai 	/* No power down state support */
364daa4478aSJacky Bai 	if (pwr_type == PSTATE_TYPE_POWERDOWN) {
365daa4478aSJacky Bai 		return PSCI_E_INVALID_PARAMS;
366daa4478aSJacky Bai 	}
367daa4478aSJacky Bai 
368daa4478aSJacky Bai 	return PSCI_E_SUCCESS;
369daa4478aSJacky Bai }
370daa4478aSJacky Bai 
371daa4478aSJacky Bai void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
372daa4478aSJacky Bai {
373daa4478aSJacky Bai 	unsigned int i;
374daa4478aSJacky Bai 
375daa4478aSJacky Bai 	for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) {
376daa4478aSJacky Bai 		req_state->pwr_domain_state[i] = PLAT_POWER_DOWN_OFF_STATE;
377daa4478aSJacky Bai 	}
378daa4478aSJacky Bai }
379daa4478aSJacky Bai 
380*891c547eSJacky Bai void __dead2 imx_system_off(void)
381*891c547eSJacky Bai {
382*891c547eSJacky Bai 	unsigned int i;
383*891c547eSJacky Bai 
384*891c547eSJacky Bai 	/* config the all the core into OFF mode and IRQ masked. */
385*891c547eSJacky Bai 	for (i = 0U; i < PLATFORM_CORE_COUNT; i++) {
386*891c547eSJacky Bai 		/* disable wakeup from wkpu */
387*891c547eSJacky Bai 		mmio_write_32(WKPUx(i), 0x0);
388*891c547eSJacky Bai 
389*891c547eSJacky Bai 		/* reset the core reset entry to 0x1000 */
390*891c547eSJacky Bai 		imx_pwr_set_cpu_entry(i, 0x1000);
391*891c547eSJacky Bai 
392*891c547eSJacky Bai 		/* config the core power mode to off */
393*891c547eSJacky Bai 		mmio_write_32(AD_COREx_LPMODE(i), 0x3);
394*891c547eSJacky Bai 	}
395*891c547eSJacky Bai 
396*891c547eSJacky Bai 	plat_gic_cpuif_disable();
397*891c547eSJacky Bai 
398*891c547eSJacky Bai 	/* Config the power mode info for entering DPD mode and ACT mode */
399*891c547eSJacky Bai 	imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
400*891c547eSJacky Bai 	imx_set_pwr_mode_cfg(ACT_PWR_MODE);
401*891c547eSJacky Bai 	imx_set_pwr_mode_cfg(DPD_PWR_MODE);
402*891c547eSJacky Bai 
403*891c547eSJacky Bai 	/* Set the APD domain into DPD mode */
404*891c547eSJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
405*891c547eSJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1f);
406*891c547eSJacky Bai 
407*891c547eSJacky Bai 	/* make sure no pending upower wakeup */
408*891c547eSJacky Bai 	upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
409*891c547eSJacky Bai 	upower_wait_resp();
410*891c547eSJacky Bai 
411*891c547eSJacky Bai 	/* enable the upower wakeup from wuu, act as APD boot up method  */
412*891c547eSJacky Bai 	mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
413*891c547eSJacky Bai 	mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4));
414*891c547eSJacky Bai 
415*891c547eSJacky Bai 	/* make sure no pad wakeup event is pending */
416*891c547eSJacky Bai 	mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
417*891c547eSJacky Bai 
418*891c547eSJacky Bai 	wfi();
419*891c547eSJacky Bai 
420*891c547eSJacky Bai 	ERROR("power off failed.\n");
421*891c547eSJacky Bai 	panic();
422*891c547eSJacky Bai }
423*891c547eSJacky Bai 
424fcd41e86SJacky Bai static const plat_psci_ops_t imx_plat_psci_ops = {
425fcd41e86SJacky Bai 	.pwr_domain_on = imx_pwr_domain_on,
426fcd41e86SJacky Bai 	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
427fcd41e86SJacky Bai 	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
428*891c547eSJacky Bai 	.system_off = imx_system_off,
429fcd41e86SJacky Bai 	.system_reset = imx8ulp_system_reset,
430fcd41e86SJacky Bai 	.pwr_domain_off = imx_pwr_domain_off,
431daa4478aSJacky Bai 	.pwr_domain_suspend = imx_domain_suspend,
432daa4478aSJacky Bai 	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
433daa4478aSJacky Bai 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
434daa4478aSJacky Bai 	.validate_power_state = imx_validate_power_state,
435fcd41e86SJacky Bai 	.pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
436fcd41e86SJacky Bai };
437fcd41e86SJacky Bai 
438fcd41e86SJacky Bai int plat_setup_psci_ops(uintptr_t sec_entrypoint,
439fcd41e86SJacky Bai 			const plat_psci_ops_t **psci_ops)
440fcd41e86SJacky Bai {
441fcd41e86SJacky Bai 	secure_entrypoint = sec_entrypoint;
442fcd41e86SJacky Bai 	imx_pwr_set_cpu_entry(0, sec_entrypoint);
443fcd41e86SJacky Bai 	*psci_ops = &imx_plat_psci_ops;
444fcd41e86SJacky Bai 
445fcd41e86SJacky Bai 	mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
446fcd41e86SJacky Bai 	mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff);
447fcd41e86SJacky Bai 
448fcd41e86SJacky Bai 	return 0;
449fcd41e86SJacky Bai }
450