blob: f82144a4e63116e46ae4606b3ea04f36f4059bb3 [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
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
62enum pdc_gic_mask {
63 PDC_MASK_GIC_WAKE_IRQ,
64 PDC_UNMASK_GIC_WAKE_IRQ
65};
66
67enum pdc_finish_int_mask {
68 PDC_DISABLE_FINISH_INT,
69 PDC_ENABLE_FINISH_INT
70};
71
72static 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
84static 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
92static 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
101static 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 */
111void 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 */
119void 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
126unsigned 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
136void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
137{
138 mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
139}
140
141void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
142{
143 mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
144
145}
146
147int 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
156void 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
170unsigned 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
183unsigned 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
199void 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
210void 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
221int 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
234static 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
248static 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
258int 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
274void 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
281void 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
288static 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
303static 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
318void 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
327static 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
337static 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
347void 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
353void 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
359void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
360{
361 hisi_ipc_pm_on_off(core, cluster, PM_ON);
362}
363
364void 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
375void 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
381void 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
392void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
393{
394 hisi_ipc_pm_suspend(core, cluster, 0x3);
395}