blob: 659a1c4ad25669e6ad11060a9bf37be13ab4ae71 [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
150int hisi_test_ap_suspend_flag(unsigned int cluster)
151{
152 unsigned int val;
153
154 val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
155 val &= AP_SUSPEND_FLAG;
156 return !!val;
157}
158
159void hisi_set_cluster_pwdn_flag(unsigned int cluster,
160 unsigned int core, unsigned int value)
161{
162 unsigned int val;
163
164 hisi_cpuhotplug_lock(cluster, core);
165
166 val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
167 val = (value << (cluster << 1)) | (val & 0xFFFFFFF);
168 mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
169
170 hisi_cpuhotplug_unlock(cluster, core);
171}
172
173unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core)
174{
175 unsigned int val;
176
177 hisi_cpuhotplug_lock(cluster, core);
178 val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
179 val = val >> (16 + (cluster << 2));
180 val &= 0xF;
181 hisi_cpuhotplug_unlock(cluster, core);
182
183 return val;
184}
185
186unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core)
187{
188 unsigned int val;
189
190 hisi_cpuhotplug_lock(cluster, core);
191 val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
192 val = val >> (16 + (cluster << 2));
193 val &= 0xF;
194 hisi_cpuhotplug_unlock(cluster, core);
195
196 if (val)
197 return 0;
198 else
199 return 1;
200}
201
202void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core)
203{
204 unsigned int flag = BIT((cluster<<2) + core + 16);
205
206 hisi_cpuhotplug_lock(cluster, core);
207
208 mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag);
209
210 hisi_cpuhotplug_unlock(cluster, core);
211}
212
213void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core)
214{
215 unsigned int flag = BIT((cluster<<2) + core + 16);
216
217 hisi_cpuhotplug_lock(cluster, core);
218
219 mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag);
220
221 hisi_cpuhotplug_unlock(cluster, core);
222}
223
224int cluster_is_powered_on(unsigned int cluster)
225{
226 unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
227 int ret;
228
229 if (cluster == 0)
230 ret = val & CLUSTER0_CPUS_ONLINE_MASK;
231 else
232 ret = val & CLUSTER1_CPUS_ONLINE_MASK;
233
234 return !!ret;
235}
236
237static void *hisi_get_pdc_addr(unsigned int cluster)
238{
239 void *pdc_base_addr;
240 uintptr_t addr;
241
242 if (cluster == 0)
243 addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE);
244 else
245 addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE);
246 pdc_base_addr = (void *)addr;
247
248 return pdc_base_addr;
249}
250
251static unsigned int hisi_get_pdc_stat(unsigned int cluster)
252{
253 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
254 unsigned int val;
255
256 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET);
257
258 return val;
259}
260
261int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
262{
263 unsigned int mask = 0xf << (core * 4);
264 unsigned int pdc_stat = hisi_get_pdc_stat(cluster);
265 unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core);
266 unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster);
267
268 mask = (PDC_COREPWRSTAT_MASK & (~mask));
269 pdc_stat &= mask;
270
271 if ((boot_flag ^ cpuidle_flag) || pdc_stat)
272 return 0;
273 else
274 return 1;
275}
276
277void hisi_disable_pdc(unsigned int cluster)
278{
279 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
280
281 mmio_write_32((uintptr_t)pdc_base_addr, 0x0);
282}
283
284void hisi_enable_pdc(unsigned int cluster)
285{
286 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
287
288 mmio_write_32((uintptr_t)pdc_base_addr, 0x1);
289}
290
Haojian Zhuang26c94f62018-03-02 14:23:55 +0800291void hisi_pdc_set_intmask(void *pdc_base_addr,
292 unsigned int core,
293 enum pdc_finish_int_mask intmask)
Haojian Zhuang1b5c2252017-06-01 15:20:46 +0800294{
295 unsigned int val;
296
297 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET);
298 if (intmask == PDC_ENABLE_FINISH_INT)
299 val |= BIT(core);
300 else
301 val &= ~BIT(core);
302
303 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val);
304}
305
306static inline void hisi_pdc_set_gicmask(void *pdc_base_addr,
307 unsigned int core,
308 enum pdc_gic_mask gicmask)
309{
310 unsigned int val;
311
312 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET);
313 if (gicmask == PDC_MASK_GIC_WAKE_IRQ)
314 val |= BIT(core);
315 else
316 val &= ~BIT(core);
317
318 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val);
319}
320
321void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)
322{
323 int i;
324 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
325
326 for (i = 0; i < 4; i++)
327 hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ);
328}
329
330static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core,
331 enum pdc_gic_mask gicmask,
332 enum pdc_finish_int_mask intmask)
333{
334 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
335
336 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET,
337 BIT(core));
338}
339
340static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core,
341 enum pdc_gic_mask gicmask,
342 enum pdc_finish_int_mask intmask)
343{
344 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
345
346 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
347 BIT(core));
348}
349
350void hisi_powerup_core(unsigned int cluster, unsigned int core)
351{
352 hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
353 PDC_DISABLE_FINISH_INT);
354}
355
356void hisi_powerdn_core(unsigned int cluster, unsigned int core)
357{
358 hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
359 PDC_DISABLE_FINISH_INT);
360}
361
362void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
363{
364 hisi_ipc_pm_on_off(core, cluster, PM_ON);
365}
366
367void hisi_powerdn_cluster(unsigned int cluster, unsigned int core)
368{
369 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
370
371 hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG);
372 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
373 (0x10001 << core));
374 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
375 BIT(core));
376}
377
378void hisi_enter_core_idle(unsigned int cluster, unsigned int core)
379{
380 hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ,
381 PDC_DISABLE_FINISH_INT);
382}
383
384void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core)
385{
386 void *pdc_base_addr = hisi_get_pdc_addr(cluster);
387
388 hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE);
389 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
390 (0x10001 << core));
391 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
392 BIT(core));
393}
394
395void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
396{
397 hisi_ipc_pm_suspend(core, cluster, 0x3);
398}