xref: /rk3399_ARM-atf/plat/hisilicon/hikey960/hikey960_pm.c (revision 28b02e2348f92cfb702695c970b893768471392d)
1*28b02e23SHaojian Zhuang /*
2*28b02e23SHaojian Zhuang  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3*28b02e23SHaojian Zhuang  *
4*28b02e23SHaojian Zhuang  * SPDX-License-Identifier: BSD-3-Clause
5*28b02e23SHaojian Zhuang  */
6*28b02e23SHaojian Zhuang 
7*28b02e23SHaojian Zhuang #include <arch_helpers.h>
8*28b02e23SHaojian Zhuang #include <assert.h>
9*28b02e23SHaojian Zhuang #include <cci.h>
10*28b02e23SHaojian Zhuang #include <console.h>
11*28b02e23SHaojian Zhuang #include <debug.h>
12*28b02e23SHaojian Zhuang #include <gicv2.h>
13*28b02e23SHaojian Zhuang #include <hi3660.h>
14*28b02e23SHaojian Zhuang #include <hi3660_crg.h>
15*28b02e23SHaojian Zhuang #include <mmio.h>
16*28b02e23SHaojian Zhuang #include <psci.h>
17*28b02e23SHaojian Zhuang #include "drivers/pwrc/hisi_pwrc.h"
18*28b02e23SHaojian Zhuang 
19*28b02e23SHaojian Zhuang #include "hikey960_def.h"
20*28b02e23SHaojian Zhuang #include "hikey960_private.h"
21*28b02e23SHaojian Zhuang 
22*28b02e23SHaojian Zhuang #define CORE_PWR_STATE(state) \
23*28b02e23SHaojian Zhuang 	((state)->pwr_domain_state[MPIDR_AFFLVL0])
24*28b02e23SHaojian Zhuang #define CLUSTER_PWR_STATE(state) \
25*28b02e23SHaojian Zhuang 	((state)->pwr_domain_state[MPIDR_AFFLVL1])
26*28b02e23SHaojian Zhuang #define SYSTEM_PWR_STATE(state) \
27*28b02e23SHaojian Zhuang 	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
28*28b02e23SHaojian Zhuang 
29*28b02e23SHaojian Zhuang #define DMAC_GLB_REG_SEC	0x694
30*28b02e23SHaojian Zhuang #define AXI_CONF_BASE		0x820
31*28b02e23SHaojian Zhuang 
32*28b02e23SHaojian Zhuang static uintptr_t hikey960_sec_entrypoint;
33*28b02e23SHaojian Zhuang 
34*28b02e23SHaojian Zhuang static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
35*28b02e23SHaojian Zhuang {
36*28b02e23SHaojian Zhuang 	unsigned long scr;
37*28b02e23SHaojian Zhuang 	unsigned int val = 0;
38*28b02e23SHaojian Zhuang 
39*28b02e23SHaojian Zhuang 	assert(cpu_state == PLAT_MAX_RET_STATE);
40*28b02e23SHaojian Zhuang 
41*28b02e23SHaojian Zhuang 	scr = read_scr_el3();
42*28b02e23SHaojian Zhuang 
43*28b02e23SHaojian Zhuang 	/* Enable Physical IRQ and FIQ to wake the CPU*/
44*28b02e23SHaojian Zhuang 	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
45*28b02e23SHaojian Zhuang 
46*28b02e23SHaojian Zhuang 	set_retention_ticks(val);
47*28b02e23SHaojian Zhuang 	wfi();
48*28b02e23SHaojian Zhuang 	clr_retention_ticks(val);
49*28b02e23SHaojian Zhuang 
50*28b02e23SHaojian Zhuang 	/*
51*28b02e23SHaojian Zhuang 	 * Restore SCR to the original value, synchronisazion of
52*28b02e23SHaojian Zhuang 	 * scr_el3 is done by eret while el3_exit to save some
53*28b02e23SHaojian Zhuang 	 * execution cycles.
54*28b02e23SHaojian Zhuang 	 */
55*28b02e23SHaojian Zhuang 	write_scr_el3(scr);
56*28b02e23SHaojian Zhuang }
57*28b02e23SHaojian Zhuang 
58*28b02e23SHaojian Zhuang static int hikey960_pwr_domain_on(u_register_t mpidr)
59*28b02e23SHaojian Zhuang {
60*28b02e23SHaojian Zhuang 	unsigned int core = mpidr & MPIDR_CPU_MASK;
61*28b02e23SHaojian Zhuang 	unsigned int cluster =
62*28b02e23SHaojian Zhuang 		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
63*28b02e23SHaojian Zhuang 	int cluster_stat = cluster_is_powered_on(cluster);
64*28b02e23SHaojian Zhuang 
65*28b02e23SHaojian Zhuang 	hisi_set_cpu_boot_flag(cluster, core);
66*28b02e23SHaojian Zhuang 
67*28b02e23SHaojian Zhuang 	mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
68*28b02e23SHaojian Zhuang 		      hikey960_sec_entrypoint >> 2);
69*28b02e23SHaojian Zhuang 
70*28b02e23SHaojian Zhuang 	if (cluster_stat)
71*28b02e23SHaojian Zhuang 		hisi_powerup_core(cluster, core);
72*28b02e23SHaojian Zhuang 	else
73*28b02e23SHaojian Zhuang 		hisi_powerup_cluster(cluster, core);
74*28b02e23SHaojian Zhuang 
75*28b02e23SHaojian Zhuang 	return PSCI_E_SUCCESS;
76*28b02e23SHaojian Zhuang }
77*28b02e23SHaojian Zhuang 
78*28b02e23SHaojian Zhuang static void
79*28b02e23SHaojian Zhuang hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
80*28b02e23SHaojian Zhuang {
81*28b02e23SHaojian Zhuang 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
82*28b02e23SHaojian Zhuang 		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
83*28b02e23SHaojian Zhuang 
84*28b02e23SHaojian Zhuang 	gicv2_pcpu_distif_init();
85*28b02e23SHaojian Zhuang 	gicv2_cpuif_enable();
86*28b02e23SHaojian Zhuang }
87*28b02e23SHaojian Zhuang 
88*28b02e23SHaojian Zhuang void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
89*28b02e23SHaojian Zhuang {
90*28b02e23SHaojian Zhuang 	unsigned long mpidr = read_mpidr_el1();
91*28b02e23SHaojian Zhuang 	unsigned int core = mpidr & MPIDR_CPU_MASK;
92*28b02e23SHaojian Zhuang 	unsigned int cluster =
93*28b02e23SHaojian Zhuang 		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
94*28b02e23SHaojian Zhuang 
95*28b02e23SHaojian Zhuang 	clr_ex();
96*28b02e23SHaojian Zhuang 	isb();
97*28b02e23SHaojian Zhuang 	dsbsy();
98*28b02e23SHaojian Zhuang 
99*28b02e23SHaojian Zhuang 	gicv2_cpuif_disable();
100*28b02e23SHaojian Zhuang 
101*28b02e23SHaojian Zhuang 	hisi_clear_cpu_boot_flag(cluster, core);
102*28b02e23SHaojian Zhuang 	hisi_powerdn_core(cluster, core);
103*28b02e23SHaojian Zhuang 
104*28b02e23SHaojian Zhuang 	/* check if any core is powered up */
105*28b02e23SHaojian Zhuang 	if (hisi_test_pwrdn_allcores(cluster, core)) {
106*28b02e23SHaojian Zhuang 
107*28b02e23SHaojian Zhuang 		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
108*28b02e23SHaojian Zhuang 
109*28b02e23SHaojian Zhuang 		isb();
110*28b02e23SHaojian Zhuang 		dsbsy();
111*28b02e23SHaojian Zhuang 
112*28b02e23SHaojian Zhuang 		hisi_powerdn_cluster(cluster, core);
113*28b02e23SHaojian Zhuang 	}
114*28b02e23SHaojian Zhuang }
115*28b02e23SHaojian Zhuang 
116*28b02e23SHaojian Zhuang static void __dead2 hikey960_system_reset(void)
117*28b02e23SHaojian Zhuang {
118*28b02e23SHaojian Zhuang 	mmio_write_32(SCTRL_SCPEREN1_REG,
119*28b02e23SHaojian Zhuang 		      SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
120*28b02e23SHaojian Zhuang 	mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
121*28b02e23SHaojian Zhuang 	panic();
122*28b02e23SHaojian Zhuang }
123*28b02e23SHaojian Zhuang 
124*28b02e23SHaojian Zhuang int hikey960_validate_power_state(unsigned int power_state,
125*28b02e23SHaojian Zhuang 			       psci_power_state_t *req_state)
126*28b02e23SHaojian Zhuang {
127*28b02e23SHaojian Zhuang 	int pstate = psci_get_pstate_type(power_state);
128*28b02e23SHaojian Zhuang 	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
129*28b02e23SHaojian Zhuang 	int i;
130*28b02e23SHaojian Zhuang 
131*28b02e23SHaojian Zhuang 	assert(req_state);
132*28b02e23SHaojian Zhuang 
133*28b02e23SHaojian Zhuang 	if (pwr_lvl > PLAT_MAX_PWR_LVL)
134*28b02e23SHaojian Zhuang 		return PSCI_E_INVALID_PARAMS;
135*28b02e23SHaojian Zhuang 
136*28b02e23SHaojian Zhuang 	/* Sanity check the requested state */
137*28b02e23SHaojian Zhuang 	if (pstate == PSTATE_TYPE_STANDBY) {
138*28b02e23SHaojian Zhuang 		/*
139*28b02e23SHaojian Zhuang 		 * It's possible to enter standby only on power level 0
140*28b02e23SHaojian Zhuang 		 * Ignore any other power level.
141*28b02e23SHaojian Zhuang 		 */
142*28b02e23SHaojian Zhuang 		if (pwr_lvl != MPIDR_AFFLVL0)
143*28b02e23SHaojian Zhuang 			return PSCI_E_INVALID_PARAMS;
144*28b02e23SHaojian Zhuang 
145*28b02e23SHaojian Zhuang 		req_state->pwr_domain_state[MPIDR_AFFLVL0] =
146*28b02e23SHaojian Zhuang 					PLAT_MAX_RET_STATE;
147*28b02e23SHaojian Zhuang 	} else {
148*28b02e23SHaojian Zhuang 		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
149*28b02e23SHaojian Zhuang 			req_state->pwr_domain_state[i] =
150*28b02e23SHaojian Zhuang 					PLAT_MAX_OFF_STATE;
151*28b02e23SHaojian Zhuang 	}
152*28b02e23SHaojian Zhuang 
153*28b02e23SHaojian Zhuang 	/*
154*28b02e23SHaojian Zhuang 	 * We expect the 'state id' to be zero.
155*28b02e23SHaojian Zhuang 	 */
156*28b02e23SHaojian Zhuang 	if (psci_get_pstate_id(power_state))
157*28b02e23SHaojian Zhuang 		return PSCI_E_INVALID_PARAMS;
158*28b02e23SHaojian Zhuang 
159*28b02e23SHaojian Zhuang 	return PSCI_E_SUCCESS;
160*28b02e23SHaojian Zhuang }
161*28b02e23SHaojian Zhuang 
162*28b02e23SHaojian Zhuang static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
163*28b02e23SHaojian Zhuang {
164*28b02e23SHaojian Zhuang 	/*
165*28b02e23SHaojian Zhuang 	 * Check if the non secure entrypoint lies within the non
166*28b02e23SHaojian Zhuang 	 * secure DRAM.
167*28b02e23SHaojian Zhuang 	 */
168*28b02e23SHaojian Zhuang 	if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
169*28b02e23SHaojian Zhuang 		return PSCI_E_SUCCESS;
170*28b02e23SHaojian Zhuang 
171*28b02e23SHaojian Zhuang 	return PSCI_E_INVALID_ADDRESS;
172*28b02e23SHaojian Zhuang }
173*28b02e23SHaojian Zhuang 
174*28b02e23SHaojian Zhuang static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
175*28b02e23SHaojian Zhuang {
176*28b02e23SHaojian Zhuang 	u_register_t mpidr = read_mpidr_el1();
177*28b02e23SHaojian Zhuang 	unsigned int core = mpidr & MPIDR_CPU_MASK;
178*28b02e23SHaojian Zhuang 	unsigned int cluster =
179*28b02e23SHaojian Zhuang 		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
180*28b02e23SHaojian Zhuang 
181*28b02e23SHaojian Zhuang 	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
182*28b02e23SHaojian Zhuang 		return;
183*28b02e23SHaojian Zhuang 
184*28b02e23SHaojian Zhuang 	if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
185*28b02e23SHaojian Zhuang 		clr_ex();
186*28b02e23SHaojian Zhuang 		isb();
187*28b02e23SHaojian Zhuang 		dsbsy();
188*28b02e23SHaojian Zhuang 
189*28b02e23SHaojian Zhuang 		gicv2_cpuif_disable();
190*28b02e23SHaojian Zhuang 
191*28b02e23SHaojian Zhuang 		hisi_cpuidle_lock(cluster, core);
192*28b02e23SHaojian Zhuang 		hisi_set_cpuidle_flag(cluster, core);
193*28b02e23SHaojian Zhuang 		hisi_cpuidle_unlock(cluster, core);
194*28b02e23SHaojian Zhuang 
195*28b02e23SHaojian Zhuang 		mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
196*28b02e23SHaojian Zhuang 		      hikey960_sec_entrypoint >> 2);
197*28b02e23SHaojian Zhuang 
198*28b02e23SHaojian Zhuang 		hisi_enter_core_idle(cluster, core);
199*28b02e23SHaojian Zhuang 	}
200*28b02e23SHaojian Zhuang 
201*28b02e23SHaojian Zhuang 	/* Perform the common cluster specific operations */
202*28b02e23SHaojian Zhuang 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
203*28b02e23SHaojian Zhuang 		hisi_cpuidle_lock(cluster, core);
204*28b02e23SHaojian Zhuang 		hisi_disable_pdc(cluster);
205*28b02e23SHaojian Zhuang 
206*28b02e23SHaojian Zhuang 		/* check if any core is powered up */
207*28b02e23SHaojian Zhuang 		if (hisi_test_pwrdn_allcores(cluster, core)) {
208*28b02e23SHaojian Zhuang 
209*28b02e23SHaojian Zhuang 			cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
210*28b02e23SHaojian Zhuang 
211*28b02e23SHaojian Zhuang 			isb();
212*28b02e23SHaojian Zhuang 			dsbsy();
213*28b02e23SHaojian Zhuang 
214*28b02e23SHaojian Zhuang 			/* mask the pdc wakeup irq, then
215*28b02e23SHaojian Zhuang 			 * enable pdc to power down the core
216*28b02e23SHaojian Zhuang 			 */
217*28b02e23SHaojian Zhuang 			hisi_pdc_mask_cluster_wakeirq(cluster);
218*28b02e23SHaojian Zhuang 			hisi_enable_pdc(cluster);
219*28b02e23SHaojian Zhuang 
220*28b02e23SHaojian Zhuang 			hisi_cpuidle_unlock(cluster, core);
221*28b02e23SHaojian Zhuang 
222*28b02e23SHaojian Zhuang 			/* check the SR flag bit to determine
223*28b02e23SHaojian Zhuang 			 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
224*28b02e23SHaojian Zhuang 			 */
225*28b02e23SHaojian Zhuang 			if (hisi_test_ap_suspend_flag(cluster))
226*28b02e23SHaojian Zhuang 				hisi_enter_ap_suspend(cluster, core);
227*28b02e23SHaojian Zhuang 			else
228*28b02e23SHaojian Zhuang 				hisi_enter_cluster_idle(cluster, core);
229*28b02e23SHaojian Zhuang 		} else {
230*28b02e23SHaojian Zhuang 			/* enable pdc */
231*28b02e23SHaojian Zhuang 			hisi_enable_pdc(cluster);
232*28b02e23SHaojian Zhuang 			hisi_cpuidle_unlock(cluster, core);
233*28b02e23SHaojian Zhuang 		}
234*28b02e23SHaojian Zhuang 	}
235*28b02e23SHaojian Zhuang }
236*28b02e23SHaojian Zhuang 
237*28b02e23SHaojian Zhuang static void hikey960_sr_dma_reinit(void)
238*28b02e23SHaojian Zhuang {
239*28b02e23SHaojian Zhuang 	unsigned int ctr = 0;
240*28b02e23SHaojian Zhuang 
241*28b02e23SHaojian Zhuang 	mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
242*28b02e23SHaojian Zhuang 
243*28b02e23SHaojian Zhuang 	/* 1~15 channel is set non_secure */
244*28b02e23SHaojian Zhuang 	for (ctr = 1; ctr <= 15; ctr++)
245*28b02e23SHaojian Zhuang 		mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
246*28b02e23SHaojian Zhuang 			      (1 << 6) | (1 << 18));
247*28b02e23SHaojian Zhuang }
248*28b02e23SHaojian Zhuang 
249*28b02e23SHaojian Zhuang static void
250*28b02e23SHaojian Zhuang hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
251*28b02e23SHaojian Zhuang {
252*28b02e23SHaojian Zhuang 	unsigned long mpidr = read_mpidr_el1();
253*28b02e23SHaojian Zhuang 	unsigned int cluster =
254*28b02e23SHaojian Zhuang 		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
255*28b02e23SHaojian Zhuang 
256*28b02e23SHaojian Zhuang 	/* Nothing to be done on waking up from retention from CPU level */
257*28b02e23SHaojian Zhuang 	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
258*28b02e23SHaojian Zhuang 		return;
259*28b02e23SHaojian Zhuang 
260*28b02e23SHaojian Zhuang 	if (hisi_test_ap_suspend_flag(cluster)) {
261*28b02e23SHaojian Zhuang 		hikey960_sr_dma_reinit();
262*28b02e23SHaojian Zhuang 		gicv2_cpuif_enable();
263*28b02e23SHaojian Zhuang 		console_init(PL011_UART6_BASE, PL011_UART_CLK_IN_HZ,
264*28b02e23SHaojian Zhuang 			     PL011_BAUDRATE);
265*28b02e23SHaojian Zhuang 	}
266*28b02e23SHaojian Zhuang 
267*28b02e23SHaojian Zhuang 	hikey960_pwr_domain_on_finish(target_state);
268*28b02e23SHaojian Zhuang }
269*28b02e23SHaojian Zhuang 
270*28b02e23SHaojian Zhuang static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
271*28b02e23SHaojian Zhuang {
272*28b02e23SHaojian Zhuang 	int i;
273*28b02e23SHaojian Zhuang 
274*28b02e23SHaojian Zhuang 	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
275*28b02e23SHaojian Zhuang 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
276*28b02e23SHaojian Zhuang }
277*28b02e23SHaojian Zhuang 
278*28b02e23SHaojian Zhuang static const plat_psci_ops_t hikey960_psci_ops = {
279*28b02e23SHaojian Zhuang 	.cpu_standby			= hikey960_pwr_domain_standby,
280*28b02e23SHaojian Zhuang 	.pwr_domain_on			= hikey960_pwr_domain_on,
281*28b02e23SHaojian Zhuang 	.pwr_domain_on_finish		= hikey960_pwr_domain_on_finish,
282*28b02e23SHaojian Zhuang 	.pwr_domain_off			= hikey960_pwr_domain_off,
283*28b02e23SHaojian Zhuang 	.pwr_domain_suspend		= hikey960_pwr_domain_suspend,
284*28b02e23SHaojian Zhuang 	.pwr_domain_suspend_finish	= hikey960_pwr_domain_suspend_finish,
285*28b02e23SHaojian Zhuang 	.system_off			= NULL,
286*28b02e23SHaojian Zhuang 	.system_reset			= hikey960_system_reset,
287*28b02e23SHaojian Zhuang 	.validate_power_state		= hikey960_validate_power_state,
288*28b02e23SHaojian Zhuang 	.validate_ns_entrypoint		= hikey960_validate_ns_entrypoint,
289*28b02e23SHaojian Zhuang 	.get_sys_suspend_power_state	= hikey960_get_sys_suspend_power_state,
290*28b02e23SHaojian Zhuang };
291*28b02e23SHaojian Zhuang 
292*28b02e23SHaojian Zhuang int plat_setup_psci_ops(uintptr_t sec_entrypoint,
293*28b02e23SHaojian Zhuang 			const plat_psci_ops_t **psci_ops)
294*28b02e23SHaojian Zhuang {
295*28b02e23SHaojian Zhuang 	hikey960_sec_entrypoint = sec_entrypoint;
296*28b02e23SHaojian Zhuang 
297*28b02e23SHaojian Zhuang 	INFO("%s: sec_entrypoint=0x%lx\n", __func__,
298*28b02e23SHaojian Zhuang 	     (unsigned long)hikey960_sec_entrypoint);
299*28b02e23SHaojian Zhuang 
300*28b02e23SHaojian Zhuang 	/*
301*28b02e23SHaojian Zhuang 	 * Initialize PSCI ops struct
302*28b02e23SHaojian Zhuang 	 */
303*28b02e23SHaojian Zhuang 	*psci_ops = &hikey960_psci_ops;
304*28b02e23SHaojian Zhuang 	return 0;
305*28b02e23SHaojian Zhuang }
306