]> git.sur5r.net Git - u-boot/blob - arch/arm/cpu/armv7/sunxi/psci.c
net: fec_mxc: specify the registered eth index by dev_id
[u-boot] / 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 static void __secure cp15_write_cntp_tval(u32 tval)
31 {
32         asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
33 }
34
35 static void __secure cp15_write_cntp_ctl(u32 val)
36 {
37         asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
38 }
39
40 static 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 (COUNTER_FREQUENCY / 1000)
50
51 static 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
68 static 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
82 static 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
90 static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on,
91                                         int cpu)
92 {
93         if (on) {
94                 /* Release power clamp */
95                 clamp_release(clamp);
96
97                 /* Clear power gating */
98                 clrbits_le32(pwroff, BIT(cpu));
99         } else {
100                 /* Set power gating */
101                 setbits_le32(pwroff, BIT(cpu));
102
103                 /* Activate power clamp */
104                 clamp_set(clamp);
105         }
106 }
107
108 #ifdef CONFIG_MACH_SUN7I
109 /* sun7i (A20) is different from other single cluster SoCs */
110 static 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 /* ! CONFIG_MACH_SUN7I */
119 static 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 /* CONFIG_MACH_SUN7I */
128
129 void __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         /* Wait for the core to enter WFI */
136         while (1) {
137                 if (readl(&cpucfg->cpu[cpu].status) & BIT(2))
138                         break;
139                 __mdelay(1);
140         }
141
142         /* Assert reset on target CPU */
143         writel(0, &cpucfg->cpu[cpu].rst);
144
145         /* Lock CPU (Disable external debug access) */
146         clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
147
148         /* Power down CPU */
149         sunxi_cpu_set_power(cpuid, false);
150
151         /* Unlock CPU (Disable external debug access) */
152         setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
153 }
154
155 static 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
164 static 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  * Although this is an FIQ handler, the FIQ is processed in monitor mode,
172  * which means there's no FIQ banked registers. This is the same as IRQ
173  * mode, so use the IRQ attribute to ask the compiler to handler entry
174  * and return.
175  */
176 void __secure __irq psci_fiq_enter(void)
177 {
178         u32 scr, reg, cpu;
179
180         /* Switch to secure mode */
181         scr = cp15_read_scr();
182         cp15_write_scr(scr & ~BIT(0));
183
184         /* Validate reason based on IAR and acknowledge */
185         reg = readl(GICC_BASE + GICC_IAR);
186
187         /* Skip spurious interrupts 1022 and 1023 */
188         if (reg == 1023 || reg == 1022)
189                 goto out;
190
191         /* End of interrupt */
192         writel(reg, GICC_BASE + GICC_EOIR);
193         dsb();
194
195         /* Get CPU number */
196         cpu = (reg >> 10) & 0x7;
197
198         /* Power off the CPU */
199         sunxi_cpu_power_off(cpu);
200
201 out:
202         /* Restore security level */
203         cp15_write_scr(scr);
204 }
205
206 int __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         /* store target PC */
213         psci_save_target_pc(cpu, pc);
214
215         /* Set secondary core power on PC */
216         writel((u32)&psci_cpu_entry, &cpucfg->priv0);
217
218         /* Assert reset on target CPU */
219         writel(0, &cpucfg->cpu[cpu].rst);
220
221         /* Invalidate L1 cache */
222         clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
223
224         /* Lock CPU (Disable external debug access) */
225         clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
226
227         /* Power up target CPU */
228         sunxi_cpu_set_power(cpu, true);
229
230         /* De-assert reset on target CPU */
231         writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
232
233         /* Unlock CPU (Disable external debug access) */
234         setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
235
236         return ARM_PSCI_RET_SUCCESS;
237 }
238
239 void __secure psci_cpu_off(void)
240 {
241         psci_cpu_off_common();
242
243         /* Ask CPU0 via SGI15 to pull the rug... */
244         writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
245         dsb();
246
247         /* Wait to be turned off */
248         while (1)
249                 wfi();
250 }
251
252 void __secure psci_arch_init(void)
253 {
254         u32 reg;
255
256         /* SGI15 as Group-0 */
257         clrbits_le32(GICD_BASE + GICD_IGROUPRn, BIT(15));
258
259         /* Set SGI15 priority to 0 */
260         writeb(0, GICD_BASE + GICD_IPRIORITYRn + 15);
261
262         /* Be cool with non-secure */
263         writel(0xff, GICC_BASE + GICC_PMR);
264
265         /* Switch FIQEn on */
266         setbits_le32(GICC_BASE + GICC_CTLR, BIT(3));
267
268         reg = cp15_read_scr();
269         reg |= BIT(2);  /* Enable FIQ in monitor mode */
270         reg &= ~BIT(0); /* Secure mode */
271         cp15_write_scr(reg);
272 }