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