1
2
3
4
5
6
7
8
9#include <config.h>
10#include <common.h>
11#include <asm/cache.h>
12
13#include <asm/arch/cpu.h>
14#include <asm/arch/cpucfg.h>
15#include <asm/arch/prcm.h>
16#include <asm/armv7.h>
17#include <asm/gic.h>
18#include <asm/io.h>
19#include <asm/psci.h>
20#include <asm/secure.h>
21#include <asm/system.h>
22
23#include <linux/bitops.h>
24
25#define __irq __attribute__ ((interrupt ("IRQ")))
26
27#define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET)
28#define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
29
30
31
32
33
34
35
36
37#define SUN8I_R40_PWROFF (0x110)
38#define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4)
39#define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
40
41static void __secure cp15_write_cntp_tval(u32 tval)
42{
43 asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
44}
45
46static void __secure cp15_write_cntp_ctl(u32 val)
47{
48 asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
49}
50
51static u32 __secure cp15_read_cntp_ctl(void)
52{
53 u32 val;
54
55 asm volatile ("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
56
57 return val;
58}
59
60#define ONE_MS (COUNTER_FREQUENCY / 1000)
61
62static void __secure __mdelay(u32 ms)
63{
64 u32 reg = ONE_MS * ms;
65
66 cp15_write_cntp_tval(reg);
67 isb();
68 cp15_write_cntp_ctl(3);
69
70 do {
71 isb();
72 reg = cp15_read_cntp_ctl();
73 } while (!(reg & BIT(2)));
74
75 cp15_write_cntp_ctl(0);
76 isb();
77}
78
79static void __secure clamp_release(u32 __maybe_unused *clamp)
80{
81#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
82 defined(CONFIG_MACH_SUN8I_H3) || \
83 defined(CONFIG_MACH_SUN8I_R40)
84 u32 tmp = 0x1ff;
85 do {
86 tmp >>= 1;
87 writel(tmp, clamp);
88 } while (tmp);
89
90 __mdelay(10);
91#endif
92}
93
94static void __secure clamp_set(u32 __maybe_unused *clamp)
95{
96#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
97 defined(CONFIG_MACH_SUN8I_H3) || \
98 defined(CONFIG_MACH_SUN8I_R40)
99 writel(0xff, clamp);
100#endif
101}
102
103static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on,
104 int cpu)
105{
106 if (on) {
107
108 clamp_release(clamp);
109
110
111 clrbits_le32(pwroff, BIT(cpu));
112 } else {
113
114 setbits_le32(pwroff, BIT(cpu));
115
116
117 clamp_set(clamp);
118 }
119}
120
121#ifdef CONFIG_MACH_SUN8I_R40
122
123static void __secure sunxi_set_entry_address(void *entry)
124{
125 writel((u32)entry,
126 SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
127}
128#else
129static void __secure sunxi_set_entry_address(void *entry)
130{
131 struct sunxi_cpucfg_reg *cpucfg =
132 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
133
134 writel((u32)entry, &cpucfg->priv0);
135}
136#endif
137
138#ifdef CONFIG_MACH_SUN7I
139
140static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool on)
141{
142 struct sunxi_cpucfg_reg *cpucfg =
143 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
144
145 sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff,
146 on, 0);
147}
148#elif defined CONFIG_MACH_SUN8I_R40
149static void __secure sunxi_cpu_set_power(int cpu, bool on)
150{
151 struct sunxi_cpucfg_reg *cpucfg =
152 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
153
154 sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu),
155 (void *)cpucfg + SUN8I_R40_PWROFF,
156 on, 0);
157}
158#else
159static void __secure sunxi_cpu_set_power(int cpu, bool on)
160{
161 struct sunxi_prcm_reg *prcm =
162 (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
163
164 sunxi_power_switch(&prcm->cpu_pwr_clamp[cpu], &prcm->cpu_pwroff,
165 on, cpu);
166}
167#endif
168
169void __secure sunxi_cpu_power_off(u32 cpuid)
170{
171 struct sunxi_cpucfg_reg *cpucfg =
172 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
173 u32 cpu = cpuid & 0x3;
174
175
176 while (1) {
177 if (readl(&cpucfg->cpu[cpu].status) & BIT(2))
178 break;
179 __mdelay(1);
180 }
181
182
183 writel(0, &cpucfg->cpu[cpu].rst);
184
185
186 clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
187
188
189 sunxi_cpu_set_power(cpuid, false);
190
191
192 setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
193}
194
195static u32 __secure cp15_read_scr(void)
196{
197 u32 scr;
198
199 asm volatile ("mrc p15, 0, %0, c1, c1, 0" : "=r" (scr));
200
201 return scr;
202}
203
204static void __secure cp15_write_scr(u32 scr)
205{
206 asm volatile ("mcr p15, 0, %0, c1, c1, 0" : : "r" (scr));
207 isb();
208}
209
210
211
212
213
214
215
216void __secure __irq psci_fiq_enter(void)
217{
218 u32 scr, reg, cpu;
219
220
221 scr = cp15_read_scr();
222 cp15_write_scr(scr & ~BIT(0));
223
224
225 reg = readl(GICC_BASE + GICC_IAR);
226
227
228 if (reg == 1023 || reg == 1022)
229 goto out;
230
231
232 writel(reg, GICC_BASE + GICC_EOIR);
233 dsb();
234
235
236 cpu = (reg >> 10) & 0x7;
237
238
239 sunxi_cpu_power_off(cpu);
240
241out:
242
243 cp15_write_scr(scr);
244}
245
246int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc,
247 u32 context_id)
248{
249 struct sunxi_cpucfg_reg *cpucfg =
250 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
251 u32 cpu = (mpidr & 0x3);
252
253
254 psci_save(cpu, pc, context_id);
255
256
257 sunxi_set_entry_address(&psci_cpu_entry);
258
259
260 writel(0, &cpucfg->cpu[cpu].rst);
261
262
263 clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
264
265
266 clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
267
268
269 sunxi_cpu_set_power(cpu, true);
270
271
272 writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
273
274
275 setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
276
277 return ARM_PSCI_RET_SUCCESS;
278}
279
280s32 __secure psci_cpu_off(void)
281{
282 psci_cpu_off_common();
283
284
285 writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
286 dsb();
287
288
289 while (1)
290 wfi();
291}
292
293void __secure psci_arch_init(void)
294{
295 u32 reg;
296
297
298 clrbits_le32(GICD_BASE + GICD_IGROUPRn, BIT(15));
299
300
301 writeb(0, GICD_BASE + GICD_IPRIORITYRn + 15);
302
303
304 writel(0xff, GICC_BASE + GICC_PMR);
305
306
307 setbits_le32(GICC_BASE + GICC_CTLR, BIT(3));
308
309 reg = cp15_read_scr();
310 reg |= BIT(2);
311 reg &= ~BIT(0);
312 cp15_write_scr(reg);
313}
314