]> git.sur5r.net Git - u-boot/blob - arch/arm/cpu/armv7/sunxi/psci.c
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / arch / arm / cpu / armv7 / sunxi / psci.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2016
4  * Author: Chen-Yu Tsai <wens@csie.org>
5  *
6  * Based on assembly code by Marc Zyngier <marc.zyngier@arm.com>,
7  * which was based on code by Carl van Schaik <carl@ok-labs.com>.
8  */
9 #include <config.h>
10 #include <common.h>
11
12 #include <asm/arch/cpu.h>
13 #include <asm/arch/cpucfg.h>
14 #include <asm/arch/prcm.h>
15 #include <asm/armv7.h>
16 #include <asm/gic.h>
17 #include <asm/io.h>
18 #include <asm/psci.h>
19 #include <asm/secure.h>
20 #include <asm/system.h>
21
22 #include <linux/bitops.h>
23
24 #define __irq           __attribute__ ((interrupt ("IRQ")))
25
26 #define GICD_BASE       (SUNXI_GIC400_BASE + GIC_DIST_OFFSET)
27 #define GICC_BASE       (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
28
29 /*
30  * R40 is different from other single cluster SoCs.
31  *
32  * The power clamps are located in the unused space after the per-core
33  * reset controls for core 3. The secondary core entry address register
34  * is in the SRAM controller address range.
35  */
36 #define SUN8I_R40_PWROFF                        (0x110)
37 #define SUN8I_R40_PWR_CLAMP(cpu)                (0x120 + (cpu) * 0x4)
38 #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0         (0xbc)
39
40 static void __secure cp15_write_cntp_tval(u32 tval)
41 {
42         asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
43 }
44
45 static void __secure cp15_write_cntp_ctl(u32 val)
46 {
47         asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
48 }
49
50 static u32 __secure cp15_read_cntp_ctl(void)
51 {
52         u32 val;
53
54         asm volatile ("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
55
56         return val;
57 }
58
59 #define ONE_MS (COUNTER_FREQUENCY / 1000)
60
61 static void __secure __mdelay(u32 ms)
62 {
63         u32 reg = ONE_MS * ms;
64
65         cp15_write_cntp_tval(reg);
66         isb();
67         cp15_write_cntp_ctl(3);
68
69         do {
70                 isb();
71                 reg = cp15_read_cntp_ctl();
72         } while (!(reg & BIT(2)));
73
74         cp15_write_cntp_ctl(0);
75         isb();
76 }
77
78 static void __secure clamp_release(u32 __maybe_unused *clamp)
79 {
80 #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
81         defined(CONFIG_MACH_SUN8I_H3) || \
82         defined(CONFIG_MACH_SUN8I_R40)
83         u32 tmp = 0x1ff;
84         do {
85                 tmp >>= 1;
86                 writel(tmp, clamp);
87         } while (tmp);
88
89         __mdelay(10);
90 #endif
91 }
92
93 static void __secure clamp_set(u32 __maybe_unused *clamp)
94 {
95 #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
96         defined(CONFIG_MACH_SUN8I_H3) || \
97         defined(CONFIG_MACH_SUN8I_R40)
98         writel(0xff, clamp);
99 #endif
100 }
101
102 static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on,
103                                         int cpu)
104 {
105         if (on) {
106                 /* Release power clamp */
107                 clamp_release(clamp);
108
109                 /* Clear power gating */
110                 clrbits_le32(pwroff, BIT(cpu));
111         } else {
112                 /* Set power gating */
113                 setbits_le32(pwroff, BIT(cpu));
114
115                 /* Activate power clamp */
116                 clamp_set(clamp);
117         }
118 }
119
120 #ifdef CONFIG_MACH_SUN8I_R40
121 /* secondary core entry address is programmed differently on R40 */
122 static void __secure sunxi_set_entry_address(void *entry)
123 {
124         writel((u32)entry,
125                SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
126 }
127 #else
128 static void __secure sunxi_set_entry_address(void *entry)
129 {
130         struct sunxi_cpucfg_reg *cpucfg =
131                 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
132
133         writel((u32)entry, &cpucfg->priv0);
134 }
135 #endif
136
137 #ifdef CONFIG_MACH_SUN7I
138 /* sun7i (A20) is different from other single cluster SoCs */
139 static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool on)
140 {
141         struct sunxi_cpucfg_reg *cpucfg =
142                 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
143
144         sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff,
145                            on, 0);
146 }
147 #elif defined CONFIG_MACH_SUN8I_R40
148 static void __secure sunxi_cpu_set_power(int cpu, bool on)
149 {
150         struct sunxi_cpucfg_reg *cpucfg =
151                 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
152
153         sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu),
154                            (void *)cpucfg + SUN8I_R40_PWROFF,
155                            on, 0);
156 }
157 #else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */
158 static void __secure sunxi_cpu_set_power(int cpu, bool on)
159 {
160         struct sunxi_prcm_reg *prcm =
161                 (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
162
163         sunxi_power_switch(&prcm->cpu_pwr_clamp[cpu], &prcm->cpu_pwroff,
164                            on, cpu);
165 }
166 #endif /* CONFIG_MACH_SUN7I */
167
168 void __secure sunxi_cpu_power_off(u32 cpuid)
169 {
170         struct sunxi_cpucfg_reg *cpucfg =
171                 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
172         u32 cpu = cpuid & 0x3;
173
174         /* Wait for the core to enter WFI */
175         while (1) {
176                 if (readl(&cpucfg->cpu[cpu].status) & BIT(2))
177                         break;
178                 __mdelay(1);
179         }
180
181         /* Assert reset on target CPU */
182         writel(0, &cpucfg->cpu[cpu].rst);
183
184         /* Lock CPU (Disable external debug access) */
185         clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
186
187         /* Power down CPU */
188         sunxi_cpu_set_power(cpuid, false);
189
190         /* Unlock CPU (Disable external debug access) */
191         setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
192 }
193
194 static u32 __secure cp15_read_scr(void)
195 {
196         u32 scr;
197
198         asm volatile ("mrc p15, 0, %0, c1, c1, 0" : "=r" (scr));
199
200         return scr;
201 }
202
203 static void __secure cp15_write_scr(u32 scr)
204 {
205         asm volatile ("mcr p15, 0, %0, c1, c1, 0" : : "r" (scr));
206         isb();
207 }
208
209 /*
210  * Although this is an FIQ handler, the FIQ is processed in monitor mode,
211  * which means there's no FIQ banked registers. This is the same as IRQ
212  * mode, so use the IRQ attribute to ask the compiler to handler entry
213  * and return.
214  */
215 void __secure __irq psci_fiq_enter(void)
216 {
217         u32 scr, reg, cpu;
218
219         /* Switch to secure mode */
220         scr = cp15_read_scr();
221         cp15_write_scr(scr & ~BIT(0));
222
223         /* Validate reason based on IAR and acknowledge */
224         reg = readl(GICC_BASE + GICC_IAR);
225
226         /* Skip spurious interrupts 1022 and 1023 */
227         if (reg == 1023 || reg == 1022)
228                 goto out;
229
230         /* End of interrupt */
231         writel(reg, GICC_BASE + GICC_EOIR);
232         dsb();
233
234         /* Get CPU number */
235         cpu = (reg >> 10) & 0x7;
236
237         /* Power off the CPU */
238         sunxi_cpu_power_off(cpu);
239
240 out:
241         /* Restore security level */
242         cp15_write_scr(scr);
243 }
244
245 int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc)
246 {
247         struct sunxi_cpucfg_reg *cpucfg =
248                 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
249         u32 cpu = (mpidr & 0x3);
250
251         /* store target PC */
252         psci_save_target_pc(cpu, pc);
253
254         /* Set secondary core power on PC */
255         sunxi_set_entry_address(&psci_cpu_entry);
256
257         /* Assert reset on target CPU */
258         writel(0, &cpucfg->cpu[cpu].rst);
259
260         /* Invalidate L1 cache */
261         clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
262
263         /* Lock CPU (Disable external debug access) */
264         clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
265
266         /* Power up target CPU */
267         sunxi_cpu_set_power(cpu, true);
268
269         /* De-assert reset on target CPU */
270         writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
271
272         /* Unlock CPU (Disable external debug access) */
273         setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
274
275         return ARM_PSCI_RET_SUCCESS;
276 }
277
278 void __secure psci_cpu_off(void)
279 {
280         psci_cpu_off_common();
281
282         /* Ask CPU0 via SGI15 to pull the rug... */
283         writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
284         dsb();
285
286         /* Wait to be turned off */
287         while (1)
288                 wfi();
289 }
290
291 void __secure psci_arch_init(void)
292 {
293         u32 reg;
294
295         /* SGI15 as Group-0 */
296         clrbits_le32(GICD_BASE + GICD_IGROUPRn, BIT(15));
297
298         /* Set SGI15 priority to 0 */
299         writeb(0, GICD_BASE + GICD_IPRIORITYRn + 15);
300
301         /* Be cool with non-secure */
302         writel(0xff, GICC_BASE + GICC_PMR);
303
304         /* Switch FIQEn on */
305         setbits_le32(GICC_BASE + GICC_CTLR, BIT(3));
306
307         reg = cp15_read_scr();
308         reg |= BIT(2);  /* Enable FIQ in monitor mode */
309         reg &= ~BIT(0); /* Secure mode */
310         cp15_write_scr(reg);
311 }