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