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