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