• 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 <assert.h>
8 
9 #include <platform_def.h>
10 
11 #include <arch_helpers.h>
12 #include <lib/mmio.h>
13 #include <plat/common/platform.h>
14 
15 #include <../hikey960_def.h>
16 #include <hisi_ipc.h>
17 #include "hisi_pwrc.h"
18 
19 
20 /* resource lock api */
21 #define RES0_LOCK_BASE		(SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE))
22 #define RES1_LOCK_BASE		(SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE))
23 #define RES2_LOCK_BASE		(SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE))
24 
25 #define LOCK_BIT			(0x1 << 28)
26 #define LOCK_ID_MASK			(0x7u << 29)
27 #define CPUIDLE_LOCK_ID(core)		(0x6 - (core))
28 #define LOCK_UNLOCK_OFFSET		0x4
29 #define LOCK_STAT_OFFSET		0x8
30 
31 #define CLUSTER0_CPUS_ONLINE_MASK	(0xF << 16)
32 #define	CLUSTER1_CPUS_ONLINE_MASK	(0xF << 20)
33 
34 /* cpu hotplug flag api */
35 #define SCTRL_BASE			(SOC_ACPU_SCTRL_BASE_ADDR)
36 #define REG_SCBAKDATA3_OFFSET		(SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE))
37 #define REG_SCBAKDATA8_OFFSET		(SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE))
38 #define REG_SCBAKDATA9_OFFSET		(SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE))
39 
40 #define CPUIDLE_FLAG_REG(cluster) \
41 			((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \
42 			 REG_SCBAKDATA9_OFFSET)
43 #define CLUSTER_IDLE_BIT				BIT(8)
44 #define CLUSTER_IDLE_MASK		(CLUSTER_IDLE_BIT | 0x0F)
45 
46 #define AP_SUSPEND_FLAG			(1 << 16)
47 
48 #define CLUSTER_PWDN_IDLE		(0<<28)
49 #define CLUSTER_PWDN_HOTPLUG		(1<<28)
50 #define CLUSTER_PWDN_SR			(2<<28)
51 
52 #define CLUSTER0_PDC_OFFSET			0x260
53 #define CLUSTER1_PDC_OFFSET			0x300
54 
55 #define PDC_EN_OFFSET				0x0
56 #define PDC_COREPWRINTEN_OFFSET		0x4
57 #define PDC_COREPWRINTSTAT_OFFSET	0x8
58 #define PDC_COREGICMASK_OFFSET		0xc
59 #define PDC_COREPOWERUP_OFFSET		0x10
60 #define PDC_COREPOWERDN_OFFSET		0x14
61 #define PDC_COREPOWERSTAT_OFFSET	0x18
62 
63 #define PDC_COREPWRSTAT_MASK   (0XFFFF)
64 
65 enum pdc_gic_mask {
66 	PDC_MASK_GIC_WAKE_IRQ,
67 	PDC_UNMASK_GIC_WAKE_IRQ
68 };
69 
70 enum pdc_finish_int_mask {
71 	PDC_DISABLE_FINISH_INT,
72 	PDC_ENABLE_FINISH_INT
73 };
74 
hisi_resource_lock(unsigned int lockid,unsigned int offset)75 static void hisi_resource_lock(unsigned int lockid, unsigned int offset)
76 {
77 	unsigned int lock_id = (lockid << 29);
78 	unsigned int lock_val =  lock_id | LOCK_BIT;
79 	unsigned int lock_state;
80 
81 	do {
82 		mmio_write_32(offset, lock_val);
83 		lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset);
84 	} while ((lock_state & LOCK_ID_MASK) != lock_id);
85 }
86 
hisi_resource_unlock(unsigned int lockid,unsigned int offset)87 static void hisi_resource_unlock(unsigned int lockid, unsigned int offset)
88 {
89 	unsigned int lock_val = (lockid << 29) | LOCK_BIT;
90 
91 	mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val);
92 }
93 
94 
hisi_cpuhotplug_lock(unsigned int cluster,unsigned int core)95 static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core)
96 {
97 	unsigned int lock_id;
98 
99 	lock_id = (cluster << 2) + core;
100 
101 	hisi_resource_lock(lock_id, RES2_LOCK_BASE);
102 }
103 
hisi_cpuhotplug_unlock(unsigned int cluster,unsigned int core)104 static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core)
105 {
106 	unsigned int lock_id;
107 
108 	lock_id = (cluster << 2) + core;
109 
110 	hisi_resource_unlock(lock_id, RES2_LOCK_BASE);
111 }
112 
113 /* get the resource lock */
hisi_cpuidle_lock(unsigned int cluster,unsigned int core)114 void hisi_cpuidle_lock(unsigned int cluster, unsigned int core)
115 {
116 	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
117 
118 	hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset);
119 }
120 
121 /* release the resource lock */
hisi_cpuidle_unlock(unsigned int cluster,unsigned int core)122 void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core)
123 {
124 	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
125 
126 	hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset);
127 }
128 
hisi_get_cpuidle_flag(unsigned int cluster)129 unsigned int hisi_get_cpuidle_flag(unsigned int cluster)
130 {
131 	unsigned int val;
132 
133 	val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
134 	val &= 0xF;
135 
136 	return val;
137 }
138 
hisi_set_cpuidle_flag(unsigned int cluster,unsigned int core)139 void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
140 {
141 	mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
142 }
143 
hisi_clear_cpuidle_flag(unsigned int cluster,unsigned int core)144 void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
145 {
146 	mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
147 
148 }
149 
hisi_test_ap_suspend_flag(void)150 int hisi_test_ap_suspend_flag(void)
151 {
152 	unsigned int val1;
153 	unsigned int val2;
154 
155 	val1 = mmio_read_32(CPUIDLE_FLAG_REG(0));
156 	val1 &= AP_SUSPEND_FLAG;
157 
158 	val2 = mmio_read_32(CPUIDLE_FLAG_REG(1));
159 	val2 &= AP_SUSPEND_FLAG;
160 
161 	val1 |= val2;
162 	return (val1 != 0);
163 }
164 
hisi_set_cluster_pwdn_flag(unsigned int cluster,unsigned int core,unsigned int value)165 void hisi_set_cluster_pwdn_flag(unsigned int cluster,
166 				unsigned int core, unsigned int value)
167 {
168 	unsigned int val;
169 
170 	hisi_cpuhotplug_lock(cluster, core);
171 
172 	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
173 	val &= ~(0x3U << ((2 * cluster) + 28));
174 	val |= (value << (2 * cluster));
175 	mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
176 
177 	hisi_cpuhotplug_unlock(cluster, core);
178 }
179 
hisi_get_cpu_boot_flag(unsigned int cluster,unsigned int core)180 unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core)
181 {
182 	unsigned int val;
183 
184 	hisi_cpuhotplug_lock(cluster, core);
185 	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
186 	val = val >> (16 + (cluster << 2));
187 	val &= 0xF;
188 	hisi_cpuhotplug_unlock(cluster, core);
189 
190 	return val;
191 }
192 
hisi_test_cpu_down(unsigned int cluster,unsigned int core)193 unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core)
194 {
195 	unsigned int val;
196 
197 	hisi_cpuhotplug_lock(cluster, core);
198 	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
199 	val = val >> (16 + (cluster << 2));
200 	val &= 0xF;
201 	hisi_cpuhotplug_unlock(cluster, core);
202 
203 	if (val)
204 		return 0;
205 	else
206 		return 1;
207 }
208 
hisi_set_cpu_boot_flag(unsigned int cluster,unsigned int core)209 void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core)
210 {
211 	unsigned int flag = BIT((cluster<<2) + core + 16);
212 
213 	hisi_cpuhotplug_lock(cluster, core);
214 
215 	mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag);
216 
217 	hisi_cpuhotplug_unlock(cluster, core);
218 }
219 
hisi_clear_cpu_boot_flag(unsigned int cluster,unsigned int core)220 void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core)
221 {
222 	unsigned int flag = BIT((cluster<<2) + core + 16);
223 
224 	hisi_cpuhotplug_lock(cluster, core);
225 
226 	mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag);
227 
228 	hisi_cpuhotplug_unlock(cluster, core);
229 }
230 
cluster_is_powered_on(unsigned int cluster)231 int cluster_is_powered_on(unsigned int cluster)
232 {
233 	unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
234 	int ret;
235 
236 	if (cluster == 0)
237 		ret = val & CLUSTER0_CPUS_ONLINE_MASK;
238 	else
239 		ret = val & CLUSTER1_CPUS_ONLINE_MASK;
240 
241 	return !!ret;
242 }
243 
hisi_get_pdc_addr(unsigned int cluster)244 static void *hisi_get_pdc_addr(unsigned int cluster)
245 {
246 	void *pdc_base_addr;
247 	uintptr_t addr;
248 
249 	if (cluster == 0)
250 		addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE);
251 	else
252 		addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE);
253 	pdc_base_addr = (void *)addr;
254 
255 	return pdc_base_addr;
256 }
257 
hisi_get_pdc_stat(unsigned int cluster)258 static unsigned int hisi_get_pdc_stat(unsigned int cluster)
259 {
260 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
261 	unsigned int val;
262 
263 	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET);
264 
265 	return val;
266 }
267 
check_hotplug(unsigned int cluster,unsigned int boot_flag)268 static int check_hotplug(unsigned int cluster, unsigned int boot_flag)
269 {
270 	unsigned int mask = 0xF;
271 
272 	if (hisi_test_ap_suspend_flag() ||
273 	    ((boot_flag & mask) == mask))
274 		return 0;
275 
276 	return 1;
277 }
278 
hisi_test_pwrdn_allcores(unsigned int cluster,unsigned int core)279 int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
280 {
281 	unsigned int mask = 0xf << (core * 4);
282 	unsigned int pdc_stat = hisi_get_pdc_stat(cluster);
283 	unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core);
284 	unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster);
285 
286 	mask = (PDC_COREPWRSTAT_MASK & (~mask));
287 	pdc_stat &= mask;
288 
289 	if ((boot_flag ^ cpuidle_flag) || pdc_stat ||
290 	    check_hotplug(cluster, boot_flag))
291 		return 0;
292 	else
293 		return 1;
294 }
295 
hisi_disable_pdc(unsigned int cluster)296 void hisi_disable_pdc(unsigned int cluster)
297 {
298 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
299 
300 	mmio_write_32((uintptr_t)pdc_base_addr, 0x0);
301 }
302 
hisi_enable_pdc(unsigned int cluster)303 void hisi_enable_pdc(unsigned int cluster)
304 {
305 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
306 
307 	mmio_write_32((uintptr_t)pdc_base_addr, 0x1);
308 }
309 
hisi_pdc_set_intmask(void * pdc_base_addr,unsigned int core,enum pdc_finish_int_mask intmask)310 void hisi_pdc_set_intmask(void *pdc_base_addr,
311 			unsigned int core,
312 			enum pdc_finish_int_mask intmask)
313 {
314 	unsigned int val;
315 
316 	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET);
317 	if (intmask == PDC_ENABLE_FINISH_INT)
318 		val |= BIT(core);
319 	else
320 		val &= ~BIT(core);
321 
322 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val);
323 }
324 
hisi_pdc_set_gicmask(void * pdc_base_addr,unsigned int core,enum pdc_gic_mask gicmask)325 static inline void hisi_pdc_set_gicmask(void *pdc_base_addr,
326 					unsigned int core,
327 					enum pdc_gic_mask gicmask)
328 {
329 	unsigned int val;
330 
331 	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET);
332 	if (gicmask == PDC_MASK_GIC_WAKE_IRQ)
333 		val |= BIT(core);
334 	else
335 		val &= ~BIT(core);
336 
337 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val);
338 }
339 
hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)340 void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)
341 {
342 	int i;
343 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
344 
345 	for (i = 0; i < 4; i++)
346 		hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ);
347 }
348 
hisi_pdc_powerup_core(unsigned int cluster,unsigned int core,enum pdc_gic_mask gicmask,enum pdc_finish_int_mask intmask)349 static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core,
350 				  enum pdc_gic_mask gicmask,
351 				  enum pdc_finish_int_mask intmask)
352 {
353 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
354 
355 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET,
356 		      BIT(core));
357 }
358 
hisi_pdc_powerdn_core(unsigned int cluster,unsigned int core,enum pdc_gic_mask gicmask,enum pdc_finish_int_mask intmask)359 static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core,
360 				  enum pdc_gic_mask gicmask,
361 				  enum pdc_finish_int_mask intmask)
362 {
363 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
364 
365 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
366 		      BIT(core));
367 }
368 
hisi_powerup_core(unsigned int cluster,unsigned int core)369 void hisi_powerup_core(unsigned int cluster, unsigned int core)
370 {
371 	hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
372 			      PDC_DISABLE_FINISH_INT);
373 }
374 
hisi_powerdn_core(unsigned int cluster,unsigned int core)375 void hisi_powerdn_core(unsigned int cluster, unsigned int core)
376 {
377 	hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
378 			      PDC_DISABLE_FINISH_INT);
379 }
380 
hisi_powerup_cluster(unsigned int cluster,unsigned int core)381 void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
382 {
383 	hisi_ipc_pm_on_off(core, cluster, PM_ON);
384 }
385 
hisi_powerdn_cluster(unsigned int cluster,unsigned int core)386 void hisi_powerdn_cluster(unsigned int cluster, unsigned int core)
387 {
388 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
389 
390 	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG);
391 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
392 		      (0x10001 << core));
393 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
394 		      BIT(core));
395 }
396 
hisi_enter_core_idle(unsigned int cluster,unsigned int core)397 void hisi_enter_core_idle(unsigned int cluster, unsigned int core)
398 {
399 	hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ,
400 			      PDC_DISABLE_FINISH_INT);
401 }
402 
hisi_enter_cluster_idle(unsigned int cluster,unsigned int core)403 void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core)
404 {
405 	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
406 
407 	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE);
408 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
409 		      (0x10001 << core));
410 	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
411 		      BIT(core));
412 }
413 
hisi_enter_ap_suspend(unsigned int cluster,unsigned int core)414 void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
415 {
416 	hisi_ipc_pm_suspend(core, cluster, 0x3);
417 }
418