xref: /rk3399_ARM-atf/plat/imx/imx8m/imx8m_psci_common.c (revision 9eb1bb63e1d51dd85402227f7d904ae004ef49d9)
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 
155e8837b0aSJacky Bai void __dead2 imx_system_reset(void)
156e8837b0aSJacky Bai {
157e8837b0aSJacky Bai 	uintptr_t wdog_base = IMX_WDOG_BASE;
158e8837b0aSJacky Bai 	unsigned int val;
159e8837b0aSJacky Bai 
160e8837b0aSJacky Bai 	/* WDOG_B reset */
161e8837b0aSJacky Bai 	val = mmio_read_16(wdog_base);
162e8837b0aSJacky Bai #ifdef IMX_WDOG_B_RESET
163e8837b0aSJacky Bai 	val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE |
164e8837b0aSJacky Bai 		WDOG_WCR_WDT | WDOG_WCR_SRS;
165e8837b0aSJacky Bai #else
166e8837b0aSJacky Bai 	val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS;
167e8837b0aSJacky Bai #endif
168e8837b0aSJacky Bai 	mmio_write_16(wdog_base, val);
169e8837b0aSJacky Bai 
170e8837b0aSJacky Bai 	mmio_write_16(wdog_base + WDOG_WSR, 0x5555);
171e8837b0aSJacky Bai 	mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa);
172e8837b0aSJacky Bai 	while (1)
173e8837b0aSJacky Bai 		;
174e8837b0aSJacky Bai }
175e8837b0aSJacky Bai 
176e8837b0aSJacky Bai void __dead2 imx_system_off(void)
177e8837b0aSJacky Bai {
178e8837b0aSJacky Bai 	mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV |
179e8837b0aSJacky Bai 			SNVS_LPCR_DP_EN | SNVS_LPCR_TOP);
180e8837b0aSJacky Bai 
181e8837b0aSJacky Bai 	while (1)
182e8837b0aSJacky Bai 		;
183e8837b0aSJacky Bai }
184e8837b0aSJacky Bai 
185e8837b0aSJacky Bai void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
186e8837b0aSJacky Bai {
187e8837b0aSJacky Bai 	/*
188e8837b0aSJacky Bai 	 * before enter WAIT or STOP mode with PLAT(SCU) power down,
189e8837b0aSJacky Bai 	 * rbc count need to be enabled to make sure PLAT is
190e8837b0aSJacky Bai 	 * power down successfully even if the the wakeup IRQ is pending
191e8837b0aSJacky Bai 	 * early before the power down sequence. the RBC counter is
192e8837b0aSJacky Bai 	 * drived by the 32K OSC, so delay 30us to make sure the counter
193e8837b0aSJacky Bai 	 * is really running.
194e8837b0aSJacky Bai 	 */
195*9eb1bb63SJacky Bai 	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
196e8837b0aSJacky Bai 		imx_set_rbc_count();
197e8837b0aSJacky Bai 		udelay(30);
198e8837b0aSJacky Bai 	}
199e8837b0aSJacky Bai 
200e8837b0aSJacky Bai 	while (1)
201e8837b0aSJacky Bai 		wfi();
202e8837b0aSJacky Bai }
203