Merge branch 'master' of git://git.denx.de/u-boot-samsung
[platform/kernel/u-boot.git] / arch / arm / cpu / armv7 / sunxi / psci.c
1 /*
2  * Copyright (C) 2016
3  * Author: Chen-Yu Tsai <wens@csie.org>
4  *
5  * Based on assembly code by Marc Zyngier <marc.zyngier@arm.com>,
6  * which was based on code by Carl van Schaik <carl@ok-labs.com>.
7  *
8  * SPDX-License-Identifier:     GPL-2.0
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
30 /*
31  * R40 is different from other single cluster SoCs.
32  *
33  * The power clamps are located in the unused space after the per-core
34  * reset controls for core 3. The secondary core entry address register
35  * is in the SRAM controller address range.
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
41 static void __secure cp15_write_cntp_tval(u32 tval)
42 {
43         asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
44 }
45
46 static void __secure cp15_write_cntp_ctl(u32 val)
47 {
48         asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
49 }
50
51 static 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
62 static 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
79 static 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
94 static 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
103 static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on,
104                                         int cpu)
105 {
106         if (on) {
107                 /* Release power clamp */
108                 clamp_release(clamp);
109
110                 /* Clear power gating */
111                 clrbits_le32(pwroff, BIT(cpu));
112         } else {
113                 /* Set power gating */
114                 setbits_le32(pwroff, BIT(cpu));
115
116                 /* Activate power clamp */
117                 clamp_set(clamp);
118         }
119 }
120
121 #ifdef CONFIG_MACH_SUN8I_R40
122 /* secondary core entry address is programmed differently on R40 */
123 static 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
129 static 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 /* sun7i (A20) is different from other single cluster SoCs */
140 static 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
149 static 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 /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */
159 static 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 /* CONFIG_MACH_SUN7I */
168
169 void __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         /* Wait for the core to enter WFI */
176         while (1) {
177                 if (readl(&cpucfg->cpu[cpu].status) & BIT(2))
178                         break;
179                 __mdelay(1);
180         }
181
182         /* Assert reset on target CPU */
183         writel(0, &cpucfg->cpu[cpu].rst);
184
185         /* Lock CPU (Disable external debug access) */
186         clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
187
188         /* Power down CPU */
189         sunxi_cpu_set_power(cpuid, false);
190
191         /* Unlock CPU (Disable external debug access) */
192         setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
193 }
194
195 static 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
204 static 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  * Although this is an FIQ handler, the FIQ is processed in monitor mode,
212  * which means there's no FIQ banked registers. This is the same as IRQ
213  * mode, so use the IRQ attribute to ask the compiler to handler entry
214  * and return.
215  */
216 void __secure __irq psci_fiq_enter(void)
217 {
218         u32 scr, reg, cpu;
219
220         /* Switch to secure mode */
221         scr = cp15_read_scr();
222         cp15_write_scr(scr & ~BIT(0));
223
224         /* Validate reason based on IAR and acknowledge */
225         reg = readl(GICC_BASE + GICC_IAR);
226
227         /* Skip spurious interrupts 1022 and 1023 */
228         if (reg == 1023 || reg == 1022)
229                 goto out;
230
231         /* End of interrupt */
232         writel(reg, GICC_BASE + GICC_EOIR);
233         dsb();
234
235         /* Get CPU number */
236         cpu = (reg >> 10) & 0x7;
237
238         /* Power off the CPU */
239         sunxi_cpu_power_off(cpu);
240
241 out:
242         /* Restore security level */
243         cp15_write_scr(scr);
244 }
245
246 int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc)
247 {
248         struct sunxi_cpucfg_reg *cpucfg =
249                 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
250         u32 cpu = (mpidr & 0x3);
251
252         /* store target PC */
253         psci_save_target_pc(cpu, pc);
254
255         /* Set secondary core power on PC */
256         sunxi_set_entry_address(&psci_cpu_entry);
257
258         /* Assert reset on target CPU */
259         writel(0, &cpucfg->cpu[cpu].rst);
260
261         /* Invalidate L1 cache */
262         clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
263
264         /* Lock CPU (Disable external debug access) */
265         clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
266
267         /* Power up target CPU */
268         sunxi_cpu_set_power(cpu, true);
269
270         /* De-assert reset on target CPU */
271         writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
272
273         /* Unlock CPU (Disable external debug access) */
274         setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
275
276         return ARM_PSCI_RET_SUCCESS;
277 }
278
279 void __secure psci_cpu_off(void)
280 {
281         psci_cpu_off_common();
282
283         /* Ask CPU0 via SGI15 to pull the rug... */
284         writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
285         dsb();
286
287         /* Wait to be turned off */
288         while (1)
289                 wfi();
290 }
291
292 void __secure psci_arch_init(void)
293 {
294         u32 reg;
295
296         /* SGI15 as Group-0 */
297         clrbits_le32(GICD_BASE + GICD_IGROUPRn, BIT(15));
298
299         /* Set SGI15 priority to 0 */
300         writeb(0, GICD_BASE + GICD_IPRIORITYRn + 15);
301
302         /* Be cool with non-secure */
303         writel(0xff, GICC_BASE + GICC_PMR);
304
305         /* Switch FIQEn on */
306         setbits_le32(GICC_BASE + GICC_CTLR, BIT(3));
307
308         reg = cp15_read_scr();
309         reg |= BIT(2);  /* Enable FIQ in monitor mode */
310         reg &= ~BIT(0); /* Secure mode */
311         cp15_write_scr(reg);
312 }