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