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