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