xref: /openbmc/u-boot/arch/arm/cpu/armv7/sunxi/psci.c (revision eb5ba3ae)
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_SUN7I
122 /* sun7i (A20) is different from other single cluster SoCs */
123 static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool on)
124 {
125 	struct sunxi_cpucfg_reg *cpucfg =
126 		(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
127 
128 	sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff,
129 			   on, 0);
130 }
131 #elif defined CONFIG_MACH_SUN8I_R40
132 static void __secure sunxi_cpu_set_power(int cpu, bool on)
133 {
134 	struct sunxi_cpucfg_reg *cpucfg =
135 		(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
136 
137 	sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu),
138 			   (void *)cpucfg + SUN8I_R40_PWROFF,
139 			   on, 0);
140 }
141 #else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */
142 static void __secure sunxi_cpu_set_power(int cpu, bool on)
143 {
144 	struct sunxi_prcm_reg *prcm =
145 		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
146 
147 	sunxi_power_switch(&prcm->cpu_pwr_clamp[cpu], &prcm->cpu_pwroff,
148 			   on, cpu);
149 }
150 #endif /* CONFIG_MACH_SUN7I */
151 
152 void __secure sunxi_cpu_power_off(u32 cpuid)
153 {
154 	struct sunxi_cpucfg_reg *cpucfg =
155 		(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
156 	u32 cpu = cpuid & 0x3;
157 
158 	/* Wait for the core to enter WFI */
159 	while (1) {
160 		if (readl(&cpucfg->cpu[cpu].status) & BIT(2))
161 			break;
162 		__mdelay(1);
163 	}
164 
165 	/* Assert reset on target CPU */
166 	writel(0, &cpucfg->cpu[cpu].rst);
167 
168 	/* Lock CPU (Disable external debug access) */
169 	clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
170 
171 	/* Power down CPU */
172 	sunxi_cpu_set_power(cpuid, false);
173 
174 	/* Unlock CPU (Disable external debug access) */
175 	setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
176 }
177 
178 static u32 __secure cp15_read_scr(void)
179 {
180 	u32 scr;
181 
182 	asm volatile ("mrc p15, 0, %0, c1, c1, 0" : "=r" (scr));
183 
184 	return scr;
185 }
186 
187 static void __secure cp15_write_scr(u32 scr)
188 {
189 	asm volatile ("mcr p15, 0, %0, c1, c1, 0" : : "r" (scr));
190 	isb();
191 }
192 
193 /*
194  * Although this is an FIQ handler, the FIQ is processed in monitor mode,
195  * which means there's no FIQ banked registers. This is the same as IRQ
196  * mode, so use the IRQ attribute to ask the compiler to handler entry
197  * and return.
198  */
199 void __secure __irq psci_fiq_enter(void)
200 {
201 	u32 scr, reg, cpu;
202 
203 	/* Switch to secure mode */
204 	scr = cp15_read_scr();
205 	cp15_write_scr(scr & ~BIT(0));
206 
207 	/* Validate reason based on IAR and acknowledge */
208 	reg = readl(GICC_BASE + GICC_IAR);
209 
210 	/* Skip spurious interrupts 1022 and 1023 */
211 	if (reg == 1023 || reg == 1022)
212 		goto out;
213 
214 	/* End of interrupt */
215 	writel(reg, GICC_BASE + GICC_EOIR);
216 	dsb();
217 
218 	/* Get CPU number */
219 	cpu = (reg >> 10) & 0x7;
220 
221 	/* Power off the CPU */
222 	sunxi_cpu_power_off(cpu);
223 
224 out:
225 	/* Restore security level */
226 	cp15_write_scr(scr);
227 }
228 
229 int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc)
230 {
231 	struct sunxi_cpucfg_reg *cpucfg =
232 		(struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
233 	u32 cpu = (mpidr & 0x3);
234 
235 	/* store target PC */
236 	psci_save_target_pc(cpu, pc);
237 
238 	/* Set secondary core power on PC */
239 #ifdef CONFIG_MACH_SUN8I_R40
240 	/* secondary core entry address is programmed differently */
241 	writel((u32)&psci_cpu_entry,
242 	       SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
243 #else
244 	writel((u32)&psci_cpu_entry, &cpucfg->priv0);
245 #endif
246 
247 	/* Assert reset on target CPU */
248 	writel(0, &cpucfg->cpu[cpu].rst);
249 
250 	/* Invalidate L1 cache */
251 	clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
252 
253 	/* Lock CPU (Disable external debug access) */
254 	clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
255 
256 	/* Power up target CPU */
257 	sunxi_cpu_set_power(cpu, true);
258 
259 	/* De-assert reset on target CPU */
260 	writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
261 
262 	/* Unlock CPU (Disable external debug access) */
263 	setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
264 
265 	return ARM_PSCI_RET_SUCCESS;
266 }
267 
268 void __secure psci_cpu_off(void)
269 {
270 	psci_cpu_off_common();
271 
272 	/* Ask CPU0 via SGI15 to pull the rug... */
273 	writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
274 	dsb();
275 
276 	/* Wait to be turned off */
277 	while (1)
278 		wfi();
279 }
280 
281 void __secure psci_arch_init(void)
282 {
283 	u32 reg;
284 
285 	/* SGI15 as Group-0 */
286 	clrbits_le32(GICD_BASE + GICD_IGROUPRn, BIT(15));
287 
288 	/* Set SGI15 priority to 0 */
289 	writeb(0, GICD_BASE + GICD_IPRIORITYRn + 15);
290 
291 	/* Be cool with non-secure */
292 	writel(0xff, GICC_BASE + GICC_PMR);
293 
294 	/* Switch FIQEn on */
295 	setbits_le32(GICC_BASE + GICC_CTLR, BIT(3));
296 
297 	reg = cp15_read_scr();
298 	reg |= BIT(2);  /* Enable FIQ in monitor mode */
299 	reg &= ~BIT(0); /* Secure mode */
300 	cp15_write_scr(reg);
301 }
302