xref: /rk3399_ARM-atf/plat/imx/imx8m/imx8m_psci_common.c (revision 5864b58afc33bb639ef116074e67fc84b6ae45e8)
1e8837b0aSJacky Bai /*
2*88a26465SJacky Bai  * Copyright (c) 2018-2023, 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 
16b7abf485SJacky Bai #include <dram.h>
17e8837b0aSJacky Bai #include <gpc.h>
18e8837b0aSJacky Bai #include <imx8m_psci.h>
19e8837b0aSJacky Bai #include <plat_imx8.h>
20e8837b0aSJacky Bai 
21e8837b0aSJacky Bai /*
22e8837b0aSJacky Bai  * below callback functions need to be override by i.mx8mq,
23e8837b0aSJacky Bai  * for other i.mx8m soc, if no special requirement,
24e8837b0aSJacky Bai  * reuse below ones.
25e8837b0aSJacky Bai  */
26e8837b0aSJacky Bai #pragma weak imx_validate_power_state
27*88a26465SJacky Bai #pragma weak imx_pwr_domain_off
28e8837b0aSJacky Bai #pragma weak imx_domain_suspend
29e8837b0aSJacky Bai #pragma weak imx_domain_suspend_finish
30e8837b0aSJacky Bai #pragma weak imx_get_sys_suspend_power_state
31e8837b0aSJacky Bai 
imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)32e8837b0aSJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
33e8837b0aSJacky Bai {
34e8837b0aSJacky Bai 	/* The non-secure entrypoint should be in RAM space */
35e8837b0aSJacky Bai 	if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET)
36e8837b0aSJacky Bai 		return PSCI_E_INVALID_PARAMS;
37e8837b0aSJacky Bai 
38e8837b0aSJacky Bai 	return PSCI_E_SUCCESS;
39e8837b0aSJacky Bai }
40e8837b0aSJacky Bai 
imx_pwr_domain_on(u_register_t mpidr)41e8837b0aSJacky Bai int imx_pwr_domain_on(u_register_t mpidr)
42e8837b0aSJacky Bai {
43e8837b0aSJacky Bai 	unsigned int core_id;
445d2d3328SMarco Felsch 	uint64_t base_addr = BL31_START;
45e8837b0aSJacky Bai 
46e8837b0aSJacky Bai 	core_id = MPIDR_AFFLVL0_VAL(mpidr);
47e8837b0aSJacky Bai 
48e8837b0aSJacky Bai 	imx_set_cpu_secure_entry(core_id, base_addr);
49e8837b0aSJacky Bai 	imx_set_cpu_pwr_on(core_id);
50e8837b0aSJacky Bai 
51e8837b0aSJacky Bai 	return PSCI_E_SUCCESS;
52e8837b0aSJacky Bai }
53e8837b0aSJacky Bai 
imx_pwr_domain_on_finish(const psci_power_state_t * target_state)54e8837b0aSJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
55e8837b0aSJacky Bai {
56e8837b0aSJacky Bai 	plat_gic_pcpu_init();
57e8837b0aSJacky Bai 	plat_gic_cpuif_enable();
58e8837b0aSJacky Bai }
59e8837b0aSJacky Bai 
imx_pwr_domain_off(const psci_power_state_t * target_state)60e8837b0aSJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state)
61e8837b0aSJacky Bai {
62e8837b0aSJacky Bai 	uint64_t mpidr = read_mpidr_el1();
63e8837b0aSJacky Bai 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
64e8837b0aSJacky Bai 
65e8837b0aSJacky Bai 	plat_gic_cpuif_disable();
66e8837b0aSJacky Bai 	imx_set_cpu_pwr_off(core_id);
67e8837b0aSJacky Bai }
68e8837b0aSJacky Bai 
imx_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)69e8837b0aSJacky Bai int imx_validate_power_state(unsigned int power_state,
70e8837b0aSJacky Bai 			 psci_power_state_t *req_state)
71e8837b0aSJacky Bai {
72e8837b0aSJacky Bai 	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
73e8837b0aSJacky Bai 	int pwr_type = psci_get_pstate_type(power_state);
74e8837b0aSJacky Bai 	int state_id = psci_get_pstate_id(power_state);
75e8837b0aSJacky Bai 
76e8837b0aSJacky Bai 	if (pwr_lvl > PLAT_MAX_PWR_LVL)
77e8837b0aSJacky Bai 		return PSCI_E_INVALID_PARAMS;
78e8837b0aSJacky Bai 
79e8837b0aSJacky Bai 	if (pwr_type == PSTATE_TYPE_STANDBY) {
80e8837b0aSJacky Bai 		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
81e8837b0aSJacky Bai 		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
82e8837b0aSJacky Bai 	}
83e8837b0aSJacky Bai 
84e8837b0aSJacky Bai 	if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
85e8837b0aSJacky Bai 		CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
86e8837b0aSJacky Bai 		CLUSTER_PWR_STATE(req_state) = PLAT_WAIT_RET_STATE;
87e8837b0aSJacky Bai 	}
88e8837b0aSJacky Bai 
89e8837b0aSJacky Bai 	return PSCI_E_SUCCESS;
90e8837b0aSJacky Bai }
91e8837b0aSJacky Bai 
imx_cpu_standby(plat_local_state_t cpu_state)92e8837b0aSJacky Bai void imx_cpu_standby(plat_local_state_t cpu_state)
93e8837b0aSJacky Bai {
94e8837b0aSJacky Bai 	dsb();
95e8837b0aSJacky Bai 	write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
96e8837b0aSJacky Bai 	isb();
97e8837b0aSJacky Bai 
98e8837b0aSJacky Bai 	wfi();
99e8837b0aSJacky Bai 
100e8837b0aSJacky Bai 	write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
101e8837b0aSJacky Bai 	isb();
102e8837b0aSJacky Bai }
103e8837b0aSJacky Bai 
imx_domain_suspend(const psci_power_state_t * target_state)104e8837b0aSJacky Bai void imx_domain_suspend(const psci_power_state_t *target_state)
105e8837b0aSJacky Bai {
1065d2d3328SMarco Felsch 	uint64_t base_addr = BL31_START;
107e8837b0aSJacky Bai 	uint64_t mpidr = read_mpidr_el1();
108e8837b0aSJacky Bai 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
109e8837b0aSJacky Bai 
110e8837b0aSJacky Bai 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
111e8837b0aSJacky Bai 		plat_gic_cpuif_disable();
112e8837b0aSJacky Bai 		imx_set_cpu_secure_entry(core_id, base_addr);
113e8837b0aSJacky Bai 		imx_set_cpu_lpm(core_id, true);
114e8837b0aSJacky Bai 	} else {
115e8837b0aSJacky Bai 		dsb();
116e8837b0aSJacky Bai 		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
117e8837b0aSJacky Bai 		isb();
118e8837b0aSJacky Bai 	}
119e8837b0aSJacky Bai 
120e8837b0aSJacky Bai 	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state)))
121e8837b0aSJacky Bai 		imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state));
122e8837b0aSJacky Bai 
123b7abf485SJacky Bai 	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
124e8837b0aSJacky Bai 		imx_set_sys_lpm(core_id, true);
125b7abf485SJacky Bai 		dram_enter_retention();
12666d399e4SJacky Bai 		imx_anamix_override(true);
127b7abf485SJacky Bai 	}
128e8837b0aSJacky Bai }
129e8837b0aSJacky Bai 
imx_domain_suspend_finish(const psci_power_state_t * target_state)130e8837b0aSJacky Bai void imx_domain_suspend_finish(const psci_power_state_t *target_state)
131e8837b0aSJacky Bai {
132e8837b0aSJacky Bai 	uint64_t mpidr = read_mpidr_el1();
133e8837b0aSJacky Bai 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
134e8837b0aSJacky Bai 
135b7abf485SJacky Bai 	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
13666d399e4SJacky Bai 		imx_anamix_override(false);
137b7abf485SJacky Bai 		dram_exit_retention();
138e8837b0aSJacky Bai 		imx_set_sys_lpm(core_id, false);
139b7abf485SJacky Bai 	}
140e8837b0aSJacky Bai 
141e8837b0aSJacky Bai 	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) {
142e8837b0aSJacky Bai 		imx_clear_rbc_count();
143e8837b0aSJacky Bai 		imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN);
144e8837b0aSJacky Bai 	}
145e8837b0aSJacky Bai 
146e8837b0aSJacky Bai 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
147e8837b0aSJacky Bai 		imx_set_cpu_lpm(core_id, false);
148e8837b0aSJacky Bai 		plat_gic_cpuif_enable();
149e8837b0aSJacky Bai 	} else {
150e8837b0aSJacky Bai 		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
151e8837b0aSJacky Bai 		isb();
152e8837b0aSJacky Bai 	}
153e8837b0aSJacky Bai }
154e8837b0aSJacky Bai 
imx_get_sys_suspend_power_state(psci_power_state_t * req_state)155e8837b0aSJacky Bai void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
156e8837b0aSJacky Bai {
157e8837b0aSJacky Bai 	unsigned int i;
158e8837b0aSJacky Bai 
159e8837b0aSJacky Bai 	for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
160e8837b0aSJacky Bai 		req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
161e8837b0aSJacky Bai }
162e8837b0aSJacky Bai 
imx_wdog_restart(bool external_reset)16360a0dde9SIgor Opaniuk static void __dead2 imx_wdog_restart(bool external_reset)
164e8837b0aSJacky Bai {
165e8837b0aSJacky Bai 	uintptr_t wdog_base = IMX_WDOG_BASE;
166e8837b0aSJacky Bai 	unsigned int val;
167e8837b0aSJacky Bai 
168e8837b0aSJacky Bai 	val = mmio_read_16(wdog_base);
16960a0dde9SIgor Opaniuk 	/*
17060a0dde9SIgor Opaniuk 	 * Common watchdog init flags, for additional details check
17160a0dde9SIgor Opaniuk 	 * 6.6.4.1 Watchdog Control Register (WDOGx_WCR)
17260a0dde9SIgor Opaniuk 	 *
17360a0dde9SIgor Opaniuk 	 * Initial bit selection:
17460a0dde9SIgor Opaniuk 	 * WDOG_WCR_WDE - Enable the watchdog.
17560a0dde9SIgor Opaniuk 	 *
17660a0dde9SIgor Opaniuk 	 * 0x000E mask is used to keep previous values (that could be set
17760a0dde9SIgor Opaniuk 	 * in SPL) of WDBG and WDE/WDT (both are write-one once-only bits).
17860a0dde9SIgor Opaniuk 	 */
17960a0dde9SIgor Opaniuk 	val = (val & 0x000E) | WDOG_WCR_WDE;
18060a0dde9SIgor Opaniuk 	if (external_reset) {
18160a0dde9SIgor Opaniuk 		/*
18260a0dde9SIgor Opaniuk 		 * To assert WDOG_B (external reset) we have
18360a0dde9SIgor Opaniuk 		 * to set WDA bit 0 (already set in previous step).
18460a0dde9SIgor Opaniuk 		 * SRS bits are required to be set to 1 (no effect on the
18560a0dde9SIgor Opaniuk 		 * system).
18660a0dde9SIgor Opaniuk 		 */
18760a0dde9SIgor Opaniuk 		val |= WDOG_WCR_SRS;
18860a0dde9SIgor Opaniuk 	} else {
18960a0dde9SIgor Opaniuk 		/*
19060a0dde9SIgor Opaniuk 		 * To assert Software Reset Signal (internal reset) we have
19160a0dde9SIgor Opaniuk 		 * to set SRS bit to 0 (already set in previous step).
19260a0dde9SIgor Opaniuk 		 * SRE bit is required to be set to 1 when used in
19360a0dde9SIgor Opaniuk 		 * conjunction with the Software Reset Signal before
19460a0dde9SIgor Opaniuk 		 * SRS asserton, otherwise SRS bit will just automatically
19560a0dde9SIgor Opaniuk 		 * reset to 1.
19660a0dde9SIgor Opaniuk 		 *
19760a0dde9SIgor Opaniuk 		 * Also we set WDA to 1 (no effect on system).
19860a0dde9SIgor Opaniuk 		 */
19960a0dde9SIgor Opaniuk 		val |= WDOG_WCR_SRE | WDOG_WCR_WDA;
20060a0dde9SIgor Opaniuk 	}
20160a0dde9SIgor Opaniuk 
202e8837b0aSJacky Bai 	mmio_write_16(wdog_base, val);
203e8837b0aSJacky Bai 
204e8837b0aSJacky Bai 	mmio_write_16(wdog_base + WDOG_WSR, 0x5555);
205e8837b0aSJacky Bai 	mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa);
206e8837b0aSJacky Bai 	while (1)
207e8837b0aSJacky Bai 		;
208e8837b0aSJacky Bai }
209e8837b0aSJacky Bai 
imx_system_reset(void)21060a0dde9SIgor Opaniuk void __dead2 imx_system_reset(void)
21160a0dde9SIgor Opaniuk {
21260a0dde9SIgor Opaniuk #ifdef IMX_WDOG_B_RESET
21360a0dde9SIgor Opaniuk 	imx_wdog_restart(true);
21460a0dde9SIgor Opaniuk #else
21560a0dde9SIgor Opaniuk 	imx_wdog_restart(false);
21660a0dde9SIgor Opaniuk #endif
21760a0dde9SIgor Opaniuk }
21860a0dde9SIgor Opaniuk 
imx_system_reset2(int is_vendor,int reset_type,u_register_t cookie)21960a0dde9SIgor Opaniuk int imx_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
22060a0dde9SIgor Opaniuk {
22160a0dde9SIgor Opaniuk 	imx_wdog_restart(false);
22260a0dde9SIgor Opaniuk 
22360a0dde9SIgor Opaniuk 	/*
22460a0dde9SIgor Opaniuk 	 * imx_wdog_restart cannot return (as it's  a __dead function),
22560a0dde9SIgor Opaniuk 	 * however imx_system_reset2 has to return some value according
22660a0dde9SIgor Opaniuk 	 * to PSCI v1.1 spec.
22760a0dde9SIgor Opaniuk 	 */
22860a0dde9SIgor Opaniuk 	return 0;
22960a0dde9SIgor Opaniuk }
23060a0dde9SIgor Opaniuk 
imx_system_off(void)231e8837b0aSJacky Bai void __dead2 imx_system_off(void)
232e8837b0aSJacky Bai {
233ad6eb195SShawn Guo 	uint32_t val;
234ad6eb195SShawn Guo 
235ad6eb195SShawn Guo 	val = mmio_read_32(IMX_SNVS_BASE + SNVS_LPCR);
236ad6eb195SShawn Guo 	val |= SNVS_LPCR_SRTC_ENV | SNVS_LPCR_DP_EN | SNVS_LPCR_TOP;
237ad6eb195SShawn Guo 	mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, val);
238e8837b0aSJacky Bai 
239e8837b0aSJacky Bai 	while (1)
240e8837b0aSJacky Bai 		;
241e8837b0aSJacky Bai }
242e8837b0aSJacky Bai 
imx_pwr_domain_pwr_down_wfi(const psci_power_state_t * target_state)243e8837b0aSJacky Bai void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
244e8837b0aSJacky Bai {
245e8837b0aSJacky Bai 	/*
246e8837b0aSJacky Bai 	 * before enter WAIT or STOP mode with PLAT(SCU) power down,
247e8837b0aSJacky Bai 	 * rbc count need to be enabled to make sure PLAT is
248e8837b0aSJacky Bai 	 * power down successfully even if the the wakeup IRQ is pending
249e8837b0aSJacky Bai 	 * early before the power down sequence. the RBC counter is
250e8837b0aSJacky Bai 	 * drived by the 32K OSC, so delay 30us to make sure the counter
251e8837b0aSJacky Bai 	 * is really running.
252e8837b0aSJacky Bai 	 */
2539eb1bb63SJacky Bai 	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
254e8837b0aSJacky Bai 		imx_set_rbc_count();
255e8837b0aSJacky Bai 		udelay(30);
256e8837b0aSJacky Bai 	}
257e8837b0aSJacky Bai 
258e8837b0aSJacky Bai 	while (1)
259e8837b0aSJacky Bai 		wfi();
260e8837b0aSJacky Bai }
261