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