xref: /rk3399_ARM-atf/plat/imx/imx8m/imx8m_psci_common.c (revision 60a0dde91bd03f4011c1d52d4d3aea8166e939a0)
1e8837b0aSJacky Bai /*
2e8837b0aSJacky Bai  * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
3e8837b0aSJacky Bai  *
4e8837b0aSJacky Bai  * SPDX-License-Identifier: BSD-3-Clause
5e8837b0aSJacky Bai  */
6e8837b0aSJacky Bai 
7e8837b0aSJacky Bai #include <stdbool.h>
8e8837b0aSJacky Bai 
9e8837b0aSJacky Bai #include <arch.h>
10e8837b0aSJacky Bai #include <arch_helpers.h>
11e8837b0aSJacky Bai #include <common/debug.h>
12e8837b0aSJacky Bai #include <drivers/delay_timer.h>
13e8837b0aSJacky Bai #include <lib/mmio.h>
14e8837b0aSJacky Bai #include <lib/psci/psci.h>
15e8837b0aSJacky Bai 
16e8837b0aSJacky Bai #include <gpc.h>
17e8837b0aSJacky Bai #include <imx8m_psci.h>
18e8837b0aSJacky Bai #include <plat_imx8.h>
19e8837b0aSJacky Bai 
20e8837b0aSJacky Bai /*
21e8837b0aSJacky Bai  * below callback functions need to be override by i.mx8mq,
22e8837b0aSJacky Bai  * for other i.mx8m soc, if no special requirement,
23e8837b0aSJacky Bai  * reuse below ones.
24e8837b0aSJacky Bai  */
25e8837b0aSJacky Bai #pragma weak imx_validate_power_state
26e8837b0aSJacky Bai #pragma weak imx_domain_suspend
27e8837b0aSJacky Bai #pragma weak imx_domain_suspend_finish
28e8837b0aSJacky Bai #pragma weak imx_get_sys_suspend_power_state
29e8837b0aSJacky Bai 
30e8837b0aSJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
31e8837b0aSJacky Bai {
32e8837b0aSJacky Bai 	/* The non-secure entrypoint should be in RAM space */
33e8837b0aSJacky Bai 	if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET)
34e8837b0aSJacky Bai 		return PSCI_E_INVALID_PARAMS;
35e8837b0aSJacky Bai 
36e8837b0aSJacky Bai 	return PSCI_E_SUCCESS;
37e8837b0aSJacky Bai }
38e8837b0aSJacky Bai 
39e8837b0aSJacky Bai int imx_pwr_domain_on(u_register_t mpidr)
40e8837b0aSJacky Bai {
41e8837b0aSJacky Bai 	unsigned int core_id;
42e8837b0aSJacky Bai 	uint64_t base_addr = BL31_BASE;
43e8837b0aSJacky Bai 
44e8837b0aSJacky Bai 	core_id = MPIDR_AFFLVL0_VAL(mpidr);
45e8837b0aSJacky Bai 
46e8837b0aSJacky Bai 	imx_set_cpu_secure_entry(core_id, base_addr);
47e8837b0aSJacky Bai 	imx_set_cpu_pwr_on(core_id);
48e8837b0aSJacky Bai 
49e8837b0aSJacky Bai 	return PSCI_E_SUCCESS;
50e8837b0aSJacky Bai }
51e8837b0aSJacky Bai 
52e8837b0aSJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
53e8837b0aSJacky Bai {
54e8837b0aSJacky Bai 	plat_gic_pcpu_init();
55e8837b0aSJacky Bai 	plat_gic_cpuif_enable();
56e8837b0aSJacky Bai }
57e8837b0aSJacky Bai 
58e8837b0aSJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state)
59e8837b0aSJacky Bai {
60e8837b0aSJacky Bai 	uint64_t mpidr = read_mpidr_el1();
61e8837b0aSJacky Bai 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
62e8837b0aSJacky Bai 
63e8837b0aSJacky Bai 	plat_gic_cpuif_disable();
64e8837b0aSJacky Bai 	imx_set_cpu_pwr_off(core_id);
65e8837b0aSJacky Bai }
66e8837b0aSJacky Bai 
67e8837b0aSJacky Bai int imx_validate_power_state(unsigned int power_state,
68e8837b0aSJacky Bai 			 psci_power_state_t *req_state)
69e8837b0aSJacky Bai {
70e8837b0aSJacky Bai 	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
71e8837b0aSJacky Bai 	int pwr_type = psci_get_pstate_type(power_state);
72e8837b0aSJacky Bai 	int state_id = psci_get_pstate_id(power_state);
73e8837b0aSJacky Bai 
74e8837b0aSJacky Bai 	if (pwr_lvl > PLAT_MAX_PWR_LVL)
75e8837b0aSJacky Bai 		return PSCI_E_INVALID_PARAMS;
76e8837b0aSJacky Bai 
77e8837b0aSJacky Bai 	if (pwr_type == PSTATE_TYPE_STANDBY) {
78e8837b0aSJacky Bai 		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
79e8837b0aSJacky Bai 		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
80e8837b0aSJacky Bai 	}
81e8837b0aSJacky Bai 
82e8837b0aSJacky Bai 	if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
83e8837b0aSJacky Bai 		CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
84e8837b0aSJacky Bai 		CLUSTER_PWR_STATE(req_state) = PLAT_WAIT_RET_STATE;
85e8837b0aSJacky Bai 	}
86e8837b0aSJacky Bai 
87e8837b0aSJacky Bai 	return PSCI_E_SUCCESS;
88e8837b0aSJacky Bai }
89e8837b0aSJacky Bai 
90e8837b0aSJacky Bai void imx_cpu_standby(plat_local_state_t cpu_state)
91e8837b0aSJacky Bai {
92e8837b0aSJacky Bai 	dsb();
93e8837b0aSJacky Bai 	write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
94e8837b0aSJacky Bai 	isb();
95e8837b0aSJacky Bai 
96e8837b0aSJacky Bai 	wfi();
97e8837b0aSJacky Bai 
98e8837b0aSJacky Bai 	write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
99e8837b0aSJacky Bai 	isb();
100e8837b0aSJacky Bai }
101e8837b0aSJacky Bai 
102e8837b0aSJacky Bai void imx_domain_suspend(const psci_power_state_t *target_state)
103e8837b0aSJacky Bai {
104e8837b0aSJacky Bai 	uint64_t base_addr = BL31_BASE;
105e8837b0aSJacky Bai 	uint64_t mpidr = read_mpidr_el1();
106e8837b0aSJacky Bai 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
107e8837b0aSJacky Bai 
108e8837b0aSJacky Bai 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
109e8837b0aSJacky Bai 		plat_gic_cpuif_disable();
110e8837b0aSJacky Bai 		imx_set_cpu_secure_entry(core_id, base_addr);
111e8837b0aSJacky Bai 		imx_set_cpu_lpm(core_id, true);
112e8837b0aSJacky Bai 	} else {
113e8837b0aSJacky Bai 		dsb();
114e8837b0aSJacky Bai 		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
115e8837b0aSJacky Bai 		isb();
116e8837b0aSJacky Bai 	}
117e8837b0aSJacky Bai 
118e8837b0aSJacky Bai 	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state)))
119e8837b0aSJacky Bai 		imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state));
120e8837b0aSJacky Bai 
121e8837b0aSJacky Bai 	if (is_local_state_off(SYSTEM_PWR_STATE(target_state)))
122e8837b0aSJacky Bai 		imx_set_sys_lpm(core_id, true);
123e8837b0aSJacky Bai }
124e8837b0aSJacky Bai 
125e8837b0aSJacky Bai void imx_domain_suspend_finish(const psci_power_state_t *target_state)
126e8837b0aSJacky Bai {
127e8837b0aSJacky Bai 	uint64_t mpidr = read_mpidr_el1();
128e8837b0aSJacky Bai 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
129e8837b0aSJacky Bai 
130e8837b0aSJacky Bai 	if (is_local_state_off(SYSTEM_PWR_STATE(target_state)))
131e8837b0aSJacky Bai 		imx_set_sys_lpm(core_id, false);
132e8837b0aSJacky Bai 
133e8837b0aSJacky Bai 	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) {
134e8837b0aSJacky Bai 		imx_clear_rbc_count();
135e8837b0aSJacky Bai 		imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN);
136e8837b0aSJacky Bai 	}
137e8837b0aSJacky Bai 
138e8837b0aSJacky Bai 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
139e8837b0aSJacky Bai 		imx_set_cpu_lpm(core_id, false);
140e8837b0aSJacky Bai 		plat_gic_cpuif_enable();
141e8837b0aSJacky Bai 	} else {
142e8837b0aSJacky Bai 		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
143e8837b0aSJacky Bai 		isb();
144e8837b0aSJacky Bai 	}
145e8837b0aSJacky Bai }
146e8837b0aSJacky Bai 
147e8837b0aSJacky Bai void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
148e8837b0aSJacky Bai {
149e8837b0aSJacky Bai 	unsigned int i;
150e8837b0aSJacky Bai 
151e8837b0aSJacky Bai 	for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
152e8837b0aSJacky Bai 		req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
153e8837b0aSJacky Bai }
154e8837b0aSJacky Bai 
155*60a0dde9SIgor Opaniuk static void __dead2 imx_wdog_restart(bool external_reset)
156e8837b0aSJacky Bai {
157e8837b0aSJacky Bai 	uintptr_t wdog_base = IMX_WDOG_BASE;
158e8837b0aSJacky Bai 	unsigned int val;
159e8837b0aSJacky Bai 
160e8837b0aSJacky Bai 	val = mmio_read_16(wdog_base);
161*60a0dde9SIgor Opaniuk 	/*
162*60a0dde9SIgor Opaniuk 	 * Common watchdog init flags, for additional details check
163*60a0dde9SIgor Opaniuk 	 * 6.6.4.1 Watchdog Control Register (WDOGx_WCR)
164*60a0dde9SIgor Opaniuk 	 *
165*60a0dde9SIgor Opaniuk 	 * Initial bit selection:
166*60a0dde9SIgor Opaniuk 	 * WDOG_WCR_WDE - Enable the watchdog.
167*60a0dde9SIgor Opaniuk 	 *
168*60a0dde9SIgor Opaniuk 	 * 0x000E mask is used to keep previous values (that could be set
169*60a0dde9SIgor Opaniuk 	 * in SPL) of WDBG and WDE/WDT (both are write-one once-only bits).
170*60a0dde9SIgor Opaniuk 	 */
171*60a0dde9SIgor Opaniuk 	val = (val & 0x000E) | WDOG_WCR_WDE;
172*60a0dde9SIgor Opaniuk 	if (external_reset) {
173*60a0dde9SIgor Opaniuk 		/*
174*60a0dde9SIgor Opaniuk 		 * To assert WDOG_B (external reset) we have
175*60a0dde9SIgor Opaniuk 		 * to set WDA bit 0 (already set in previous step).
176*60a0dde9SIgor Opaniuk 		 * SRS bits are required to be set to 1 (no effect on the
177*60a0dde9SIgor Opaniuk 		 * system).
178*60a0dde9SIgor Opaniuk 		 */
179*60a0dde9SIgor Opaniuk 		val |= WDOG_WCR_SRS;
180*60a0dde9SIgor Opaniuk 	} else {
181*60a0dde9SIgor Opaniuk 		/*
182*60a0dde9SIgor Opaniuk 		 * To assert Software Reset Signal (internal reset) we have
183*60a0dde9SIgor Opaniuk 		 * to set SRS bit to 0 (already set in previous step).
184*60a0dde9SIgor Opaniuk 		 * SRE bit is required to be set to 1 when used in
185*60a0dde9SIgor Opaniuk 		 * conjunction with the Software Reset Signal before
186*60a0dde9SIgor Opaniuk 		 * SRS asserton, otherwise SRS bit will just automatically
187*60a0dde9SIgor Opaniuk 		 * reset to 1.
188*60a0dde9SIgor Opaniuk 		 *
189*60a0dde9SIgor Opaniuk 		 * Also we set WDA to 1 (no effect on system).
190*60a0dde9SIgor Opaniuk 		 */
191*60a0dde9SIgor Opaniuk 		val |= WDOG_WCR_SRE | WDOG_WCR_WDA;
192*60a0dde9SIgor Opaniuk 	}
193*60a0dde9SIgor Opaniuk 
194e8837b0aSJacky Bai 	mmio_write_16(wdog_base, val);
195e8837b0aSJacky Bai 
196e8837b0aSJacky Bai 	mmio_write_16(wdog_base + WDOG_WSR, 0x5555);
197e8837b0aSJacky Bai 	mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa);
198e8837b0aSJacky Bai 	while (1)
199e8837b0aSJacky Bai 		;
200e8837b0aSJacky Bai }
201e8837b0aSJacky Bai 
202*60a0dde9SIgor Opaniuk void __dead2 imx_system_reset(void)
203*60a0dde9SIgor Opaniuk {
204*60a0dde9SIgor Opaniuk #ifdef IMX_WDOG_B_RESET
205*60a0dde9SIgor Opaniuk 	imx_wdog_restart(true);
206*60a0dde9SIgor Opaniuk #else
207*60a0dde9SIgor Opaniuk 	imx_wdog_restart(false);
208*60a0dde9SIgor Opaniuk #endif
209*60a0dde9SIgor Opaniuk }
210*60a0dde9SIgor Opaniuk 
211*60a0dde9SIgor Opaniuk int imx_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
212*60a0dde9SIgor Opaniuk {
213*60a0dde9SIgor Opaniuk 	imx_wdog_restart(false);
214*60a0dde9SIgor Opaniuk 
215*60a0dde9SIgor Opaniuk 	/*
216*60a0dde9SIgor Opaniuk 	 * imx_wdog_restart cannot return (as it's  a __dead function),
217*60a0dde9SIgor Opaniuk 	 * however imx_system_reset2 has to return some value according
218*60a0dde9SIgor Opaniuk 	 * to PSCI v1.1 spec.
219*60a0dde9SIgor Opaniuk 	 */
220*60a0dde9SIgor Opaniuk 	return 0;
221*60a0dde9SIgor Opaniuk }
222*60a0dde9SIgor Opaniuk 
223e8837b0aSJacky Bai void __dead2 imx_system_off(void)
224e8837b0aSJacky Bai {
225e8837b0aSJacky Bai 	mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV |
226e8837b0aSJacky Bai 			SNVS_LPCR_DP_EN | SNVS_LPCR_TOP);
227e8837b0aSJacky Bai 
228e8837b0aSJacky Bai 	while (1)
229e8837b0aSJacky Bai 		;
230e8837b0aSJacky Bai }
231e8837b0aSJacky Bai 
232e8837b0aSJacky Bai void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
233e8837b0aSJacky Bai {
234e8837b0aSJacky Bai 	/*
235e8837b0aSJacky Bai 	 * before enter WAIT or STOP mode with PLAT(SCU) power down,
236e8837b0aSJacky Bai 	 * rbc count need to be enabled to make sure PLAT is
237e8837b0aSJacky Bai 	 * power down successfully even if the the wakeup IRQ is pending
238e8837b0aSJacky Bai 	 * early before the power down sequence. the RBC counter is
239e8837b0aSJacky Bai 	 * drived by the 32K OSC, so delay 30us to make sure the counter
240e8837b0aSJacky Bai 	 * is really running.
241e8837b0aSJacky Bai 	 */
2429eb1bb63SJacky Bai 	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
243e8837b0aSJacky Bai 		imx_set_rbc_count();
244e8837b0aSJacky Bai 		udelay(30);
245e8837b0aSJacky Bai 	}
246e8837b0aSJacky Bai 
247e8837b0aSJacky Bai 	while (1)
248e8837b0aSJacky Bai 		wfi();
249e8837b0aSJacky Bai }
250