blob: bcf68650cd37cd6e20bdfd2d72c219e197921dfe [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
Haojian Zhuang1b5c2252017-06-01 15:20:46 +08007#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
Haojian Zhuang1b5c2252017-06-01 15:20:46 +08009#include <platform_def.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010010
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011#include <arch_helpers.h>
12#include <lib/mmio.h>
13#include <plat/common/platform.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010014
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015#include <../hikey960_def.h>
16#include <hisi_ipc.h>
Haojian Zhuang1b5c2252017-06-01 15:20:46 +080017#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 (0x7 << 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
65enum pdc_gic_mask {
66 PDC_MASK_GIC_WAKE_IRQ,
67 PDC_UNMASK_GIC_WAKE_IRQ
68};
69
70enum pdc_finish_int_mask {
71 PDC_DISABLE_FINISH_INT,
72 PDC_ENABLE_FINISH_INT
73};
74
75static 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
87static 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
95static 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
104static 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 */
114void 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 */
122void 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
129unsigned 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
139void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
140{
141 mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
142}
143
144void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
145{
146 mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
147
148}
149
Wei Yu633fc062019-04-07 11:29:28 +0800150int hisi_test_ap_suspend_flag(void)
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800151{
Wei Yu633fc062019-04-07 11:29:28 +0800152 unsigned int val1;
153 unsigned int val2;
154
155 val1 = mmio_read_32(CPUIDLE_FLAG_REG(0));
156 val1 &= AP_SUSPEND_FLAG;
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800157
Wei Yu633fc062019-04-07 11:29:28 +0800158 val2 = mmio_read_32(CPUIDLE_FLAG_REG(1));
159 val2 &= AP_SUSPEND_FLAG;
160
161 val1 |= val2;
162 return (val1 != 0);
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800163}
164
165void 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);
Wei Yu633fc062019-04-07 11:29:28 +0800173 val &= ~(0x3U << ((2 * cluster) + 28));
174 val |= (value << (2 * cluster));
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800175 mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
176
177 hisi_cpuhotplug_unlock(cluster, core);
178}
179
180unsigned 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
193unsigned 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
209void 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
220void 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
231int 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
244static 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
258static 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
Wei Yu633fc062019-04-07 11:29:28 +0800268static 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
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800279int 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
Wei Yu633fc062019-04-07 11:29:28 +0800289 if ((boot_flag ^ cpuidle_flag) || pdc_stat ||
290 check_hotplug(cluster, boot_flag))
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800291 return 0;
292 else
293 return 1;
294}
295
296void 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
303void 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
Haojian Zhuang26c94f62018-03-02 14:23:55 +0800310void hisi_pdc_set_intmask(void *pdc_base_addr,
311 unsigned int core,
312 enum pdc_finish_int_mask intmask)
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800313{
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
325static 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
340void 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
349static 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
359static 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
369void 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
375void 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
381void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
382{
383 hisi_ipc_pm_on_off(core, cluster, PM_ON);
384}
385
386void 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
397void 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
403void 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
414void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
415{
416 hisi_ipc_pm_suspend(core, cluster, 0x3);
417}