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