xref: /rk3399_ARM-atf/plat/imx/imx8m/imx8mq/imx8mq_psci.c (revision 81136819928e373f7753b88d81fa5c11700b11e1)
1*81136819SBai Ping /*
2*81136819SBai Ping  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3*81136819SBai Ping  *
4*81136819SBai Ping  * SPDX-License-Identifier: BSD-3-Clause
5*81136819SBai Ping  */
6*81136819SBai Ping 
7*81136819SBai Ping #include <arch.h>
8*81136819SBai Ping #include <arch_helpers.h>
9*81136819SBai Ping #include <debug.h>
10*81136819SBai Ping #include <gpc.h>
11*81136819SBai Ping #include <stdbool.h>
12*81136819SBai Ping #include <plat_imx8.h>
13*81136819SBai Ping #include <psci.h>
14*81136819SBai Ping #include <mmio.h>
15*81136819SBai Ping 
16*81136819SBai Ping #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
17*81136819SBai Ping #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
18*81136819SBai Ping #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
19*81136819SBai Ping 
20*81136819SBai Ping int imx_pwr_domain_on(u_register_t mpidr)
21*81136819SBai Ping {
22*81136819SBai Ping 	unsigned int core_id;
23*81136819SBai Ping 	uint64_t base_addr = BL31_BASE;
24*81136819SBai Ping 
25*81136819SBai Ping 	core_id = MPIDR_AFFLVL0_VAL(mpidr);
26*81136819SBai Ping 
27*81136819SBai Ping 	/* set the secure entrypoint */
28*81136819SBai Ping 	imx_set_cpu_secure_entry(core_id, base_addr);
29*81136819SBai Ping 	/* power up the core */
30*81136819SBai Ping 	imx_set_cpu_pwr_on(core_id);
31*81136819SBai Ping 
32*81136819SBai Ping 	return PSCI_E_SUCCESS;
33*81136819SBai Ping }
34*81136819SBai Ping 
35*81136819SBai Ping void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
36*81136819SBai Ping {
37*81136819SBai Ping 	/* program the GIC per cpu dist and rdist interface */
38*81136819SBai Ping 	plat_gic_pcpu_init();
39*81136819SBai Ping 	/* enable the GICv3 cpu interface */
40*81136819SBai Ping 	plat_gic_cpuif_enable();
41*81136819SBai Ping }
42*81136819SBai Ping 
43*81136819SBai Ping void imx_pwr_domain_off(const psci_power_state_t *target_state)
44*81136819SBai Ping {
45*81136819SBai Ping 	uint64_t mpidr = read_mpidr_el1();
46*81136819SBai Ping 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
47*81136819SBai Ping 
48*81136819SBai Ping 	/* disable the GIC cpu interface first */
49*81136819SBai Ping 	plat_gic_cpuif_disable();
50*81136819SBai Ping 	/* config the core for power down */
51*81136819SBai Ping 	imx_set_cpu_pwr_off(core_id);
52*81136819SBai Ping }
53*81136819SBai Ping 
54*81136819SBai Ping int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
55*81136819SBai Ping {
56*81136819SBai Ping 	/* The non-secure entrypoint should be in RAM space */
57*81136819SBai Ping 	if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET)
58*81136819SBai Ping 		return PSCI_E_INVALID_PARAMS;
59*81136819SBai Ping 
60*81136819SBai Ping 	return PSCI_E_SUCCESS;
61*81136819SBai Ping }
62*81136819SBai Ping 
63*81136819SBai Ping int imx_validate_power_state(unsigned int power_state,
64*81136819SBai Ping 			 psci_power_state_t *req_state)
65*81136819SBai Ping {
66*81136819SBai Ping 	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
67*81136819SBai Ping 	int pwr_type = psci_get_pstate_type(power_state);
68*81136819SBai Ping 	int state_id = psci_get_pstate_id(power_state);
69*81136819SBai Ping 
70*81136819SBai Ping 	if (pwr_lvl > PLAT_MAX_PWR_LVL)
71*81136819SBai Ping 		return PSCI_E_INVALID_PARAMS;
72*81136819SBai Ping 
73*81136819SBai Ping 	if (pwr_type == PSTATE_TYPE_STANDBY) {
74*81136819SBai Ping 		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
75*81136819SBai Ping 		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
76*81136819SBai Ping 	}
77*81136819SBai Ping 
78*81136819SBai Ping 	if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
79*81136819SBai Ping 		CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
80*81136819SBai Ping 		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
81*81136819SBai Ping 	}
82*81136819SBai Ping 
83*81136819SBai Ping 	return PSCI_E_SUCCESS;
84*81136819SBai Ping }
85*81136819SBai Ping 
86*81136819SBai Ping void imx_cpu_standby(plat_local_state_t cpu_state)
87*81136819SBai Ping {
88*81136819SBai Ping 	dsb();
89*81136819SBai Ping 	write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
90*81136819SBai Ping 	isb();
91*81136819SBai Ping 
92*81136819SBai Ping 	wfi();
93*81136819SBai Ping 
94*81136819SBai Ping 	write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
95*81136819SBai Ping 	isb();
96*81136819SBai Ping }
97*81136819SBai Ping 
98*81136819SBai Ping void imx_domain_suspend(const psci_power_state_t *target_state)
99*81136819SBai Ping {
100*81136819SBai Ping 	uint64_t base_addr = BL31_BASE;
101*81136819SBai Ping 	uint64_t mpidr = read_mpidr_el1();
102*81136819SBai Ping 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
103*81136819SBai Ping 
104*81136819SBai Ping 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
105*81136819SBai Ping 		/* disable the cpu interface */
106*81136819SBai Ping 		plat_gic_cpuif_disable();
107*81136819SBai Ping 		imx_set_cpu_secure_entry(core_id, base_addr);
108*81136819SBai Ping 		imx_set_cpu_lpm(core_id, true);
109*81136819SBai Ping 	} else {
110*81136819SBai Ping 		dsb();
111*81136819SBai Ping 		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
112*81136819SBai Ping 		isb();
113*81136819SBai Ping 	}
114*81136819SBai Ping 
115*81136819SBai Ping 	if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
116*81136819SBai Ping 		imx_set_cluster_powerdown(core_id, true);
117*81136819SBai Ping 	else
118*81136819SBai Ping 		imx_set_cluster_standby(true);
119*81136819SBai Ping 
120*81136819SBai Ping 	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
121*81136819SBai Ping 		imx_set_sys_lpm(true);
122*81136819SBai Ping 	}
123*81136819SBai Ping }
124*81136819SBai Ping 
125*81136819SBai Ping void imx_domain_suspend_finish(const psci_power_state_t *target_state)
126*81136819SBai Ping {
127*81136819SBai Ping 	uint64_t mpidr = read_mpidr_el1();
128*81136819SBai Ping 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
129*81136819SBai Ping 
130*81136819SBai Ping 	/* check the system level status */
131*81136819SBai Ping 	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
132*81136819SBai Ping 		imx_set_sys_lpm(false);
133*81136819SBai Ping 		imx_clear_rbc_count();
134*81136819SBai Ping 	}
135*81136819SBai Ping 
136*81136819SBai Ping 	/* check the cluster level power status */
137*81136819SBai Ping 	if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
138*81136819SBai Ping 		imx_set_cluster_powerdown(core_id, false);
139*81136819SBai Ping 	else
140*81136819SBai Ping 		imx_set_cluster_standby(false);
141*81136819SBai Ping 
142*81136819SBai Ping 	/* check the core level power status */
143*81136819SBai Ping 	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
144*81136819SBai Ping 		/* clear the core lpm setting */
145*81136819SBai Ping 		imx_set_cpu_lpm(core_id, false);
146*81136819SBai Ping 		/* enable the gic cpu interface */
147*81136819SBai Ping 		plat_gic_cpuif_enable();
148*81136819SBai Ping 	} else {
149*81136819SBai Ping 		write_scr_el3(read_scr_el3() & (~0x4));
150*81136819SBai Ping 		isb();
151*81136819SBai Ping 	}
152*81136819SBai Ping }
153*81136819SBai Ping 
154*81136819SBai Ping void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
155*81136819SBai Ping {
156*81136819SBai Ping 	unsigned int i;
157*81136819SBai Ping 
158*81136819SBai Ping 	for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
159*81136819SBai Ping 		req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
160*81136819SBai Ping 
161*81136819SBai Ping 	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
162*81136819SBai Ping }
163*81136819SBai Ping 
164*81136819SBai Ping void __dead2 imx_system_reset(void)
165*81136819SBai Ping {
166*81136819SBai Ping 	uintptr_t wdog_base = IMX_WDOG_BASE;
167*81136819SBai Ping 	unsigned int val;
168*81136819SBai Ping 
169*81136819SBai Ping 	/* WDOG_B reset */
170*81136819SBai Ping 	val = mmio_read_16(wdog_base);
171*81136819SBai Ping #ifdef IMX_WDOG_B_RESET
172*81136819SBai Ping 	val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE |
173*81136819SBai Ping 		WDOG_WCR_WDT | WDOG_WCR_SRS;
174*81136819SBai Ping #else
175*81136819SBai Ping 	val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS;
176*81136819SBai Ping #endif
177*81136819SBai Ping 	mmio_write_16(wdog_base, val);
178*81136819SBai Ping 
179*81136819SBai Ping 	mmio_write_16(wdog_base + WDOG_WSR, 0x5555);
180*81136819SBai Ping 	mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa);
181*81136819SBai Ping 	while (1)
182*81136819SBai Ping 		;
183*81136819SBai Ping }
184*81136819SBai Ping 
185*81136819SBai Ping 
186*81136819SBai Ping 
187*81136819SBai Ping void __dead2 imx_system_off(void)
188*81136819SBai Ping {
189*81136819SBai Ping 	mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV |
190*81136819SBai Ping 			SNVS_LPCR_DP_EN | SNVS_LPCR_TOP);
191*81136819SBai Ping 
192*81136819SBai Ping 	while (1)
193*81136819SBai Ping 		;
194*81136819SBai Ping }
195*81136819SBai Ping 
196*81136819SBai Ping void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
197*81136819SBai Ping {
198*81136819SBai Ping 	if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
199*81136819SBai Ping 		imx_set_rbc_count();
200*81136819SBai Ping 
201*81136819SBai Ping 	while (1)
202*81136819SBai Ping 		wfi();
203*81136819SBai Ping }
204*81136819SBai Ping 
205*81136819SBai Ping static const plat_psci_ops_t imx_plat_psci_ops = {
206*81136819SBai Ping 	.pwr_domain_on = imx_pwr_domain_on,
207*81136819SBai Ping 	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
208*81136819SBai Ping 	.pwr_domain_off = imx_pwr_domain_off,
209*81136819SBai Ping 	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
210*81136819SBai Ping 	.validate_power_state = imx_validate_power_state,
211*81136819SBai Ping 	.cpu_standby = imx_cpu_standby,
212*81136819SBai Ping 	.pwr_domain_suspend = imx_domain_suspend,
213*81136819SBai Ping 	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
214*81136819SBai Ping 	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
215*81136819SBai Ping 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
216*81136819SBai Ping 	.system_reset = imx_system_reset,
217*81136819SBai Ping 	.system_off = imx_system_off,
218*81136819SBai Ping };
219*81136819SBai Ping 
220*81136819SBai Ping /* export the platform specific psci ops */
221*81136819SBai Ping int plat_setup_psci_ops(uintptr_t sec_entrypoint,
222*81136819SBai Ping 			const plat_psci_ops_t **psci_ops)
223*81136819SBai Ping {
224*81136819SBai Ping 	imx_mailbox_init(sec_entrypoint);
225*81136819SBai Ping 	/* sec_entrypoint is used for warm reset */
226*81136819SBai Ping 	*psci_ops = &imx_plat_psci_ops;
227*81136819SBai Ping 
228*81136819SBai Ping 	return 0;
229*81136819SBai Ping }
230