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