blob: 45fcd42b409dd4ad55a997e6b4e4fb5c13e55d80 [file] [log] [blame]
Haojian Zhuang1b5c2252017-06-01 15:20:46 +08001/*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Isla Mitchelle3631462017-07-14 10:46:32 +01007#include <../hikey960_def.h>
Haojian Zhuang1b5c2252017-06-01 15:20:46 +08008#include <arch_helpers.h>
9#include <assert.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010010#include <hisi_ipc.h>
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080011#include <mmio.h>
12#include <platform.h>
13#include <platform_def.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010014
15
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080016#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
64enum pdc_gic_mask {
65 PDC_MASK_GIC_WAKE_IRQ,
66 PDC_UNMASK_GIC_WAKE_IRQ
67};
68
69enum pdc_finish_int_mask {
70 PDC_DISABLE_FINISH_INT,
71 PDC_ENABLE_FINISH_INT
72};
73
74static 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
86static 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
94static 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
103static 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 */
113void 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 */
121void 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
128unsigned 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
138void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
139{
140 mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
141}
142
143void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
144{
145 mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
146
147}
148
149int 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
158void 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
172unsigned 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
185unsigned 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
201void 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
212void 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
223int 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
236static 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
250static 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
260int 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
276void 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
283void 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
Haojian Zhuang26c94f62018-03-02 14:23:55 +0800290void hisi_pdc_set_intmask(void *pdc_base_addr,
291 unsigned int core,
292 enum pdc_finish_int_mask intmask)
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800293{
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
305static 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
320void 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
329static 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
339static 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
349void 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
355void 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
361void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
362{
363 hisi_ipc_pm_on_off(core, cluster, PM_ON);
364}
365
366void 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
377void 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
383void 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
394void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
395{
396 hisi_ipc_pm_suspend(core, cluster, 0x3);
397}