1 // SPDX-License-Identifier: GPL-2.0
4 * Author: Chen-Yu Tsai <wens@csie.org>
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>.
12 #include <asm/arch/cpu.h>
13 #include <asm/arch/cpucfg.h>
14 #include <asm/arch/prcm.h>
15 #include <asm/armv7.h>
19 #include <asm/secure.h>
20 #include <asm/system.h>
22 #include <linux/bitops.h>
24 #define __irq __attribute__ ((interrupt ("IRQ")))
26 #define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET)
27 #define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
30 * R40 is different from other single cluster SoCs.
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.
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)
40 static void __secure cp15_write_cntp_tval(u32 tval)
42 asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
45 static void __secure cp15_write_cntp_ctl(u32 val)
47 asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
50 static u32 __secure cp15_read_cntp_ctl(void)
54 asm volatile ("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
59 #define ONE_MS (COUNTER_FREQUENCY / 1000)
61 static void __secure __mdelay(u32 ms)
63 u32 reg = ONE_MS * ms;
65 cp15_write_cntp_tval(reg);
67 cp15_write_cntp_ctl(3);
71 reg = cp15_read_cntp_ctl();
72 } while (!(reg & BIT(2)));
74 cp15_write_cntp_ctl(0);
78 static void __secure clamp_release(u32 __maybe_unused *clamp)
80 #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
81 defined(CONFIG_MACH_SUN8I_H3) || \
82 defined(CONFIG_MACH_SUN8I_R40)
93 static void __secure clamp_set(u32 __maybe_unused *clamp)
95 #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
96 defined(CONFIG_MACH_SUN8I_H3) || \
97 defined(CONFIG_MACH_SUN8I_R40)
102 static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on,
106 /* Release power clamp */
107 clamp_release(clamp);
109 /* Clear power gating */
110 clrbits_le32(pwroff, BIT(cpu));
112 /* Set power gating */
113 setbits_le32(pwroff, BIT(cpu));
115 /* Activate power clamp */
120 #ifdef CONFIG_MACH_SUN8I_R40
121 /* secondary core entry address is programmed differently on R40 */
122 static void __secure sunxi_set_entry_address(void *entry)
125 SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
128 static void __secure sunxi_set_entry_address(void *entry)
130 struct sunxi_cpucfg_reg *cpucfg =
131 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
133 writel((u32)entry, &cpucfg->priv0);
137 #ifdef CONFIG_MACH_SUN7I
138 /* sun7i (A20) is different from other single cluster SoCs */
139 static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool on)
141 struct sunxi_cpucfg_reg *cpucfg =
142 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
144 sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff,
147 #elif defined CONFIG_MACH_SUN8I_R40
148 static void __secure sunxi_cpu_set_power(int cpu, bool on)
150 struct sunxi_cpucfg_reg *cpucfg =
151 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
153 sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu),
154 (void *)cpucfg + SUN8I_R40_PWROFF,
157 #else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */
158 static void __secure sunxi_cpu_set_power(int cpu, bool on)
160 struct sunxi_prcm_reg *prcm =
161 (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
163 sunxi_power_switch(&prcm->cpu_pwr_clamp[cpu], &prcm->cpu_pwroff,
166 #endif /* CONFIG_MACH_SUN7I */
168 void __secure sunxi_cpu_power_off(u32 cpuid)
170 struct sunxi_cpucfg_reg *cpucfg =
171 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
172 u32 cpu = cpuid & 0x3;
174 /* Wait for the core to enter WFI */
176 if (readl(&cpucfg->cpu[cpu].status) & BIT(2))
181 /* Assert reset on target CPU */
182 writel(0, &cpucfg->cpu[cpu].rst);
184 /* Lock CPU (Disable external debug access) */
185 clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
188 sunxi_cpu_set_power(cpuid, false);
190 /* Unlock CPU (Disable external debug access) */
191 setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
194 static u32 __secure cp15_read_scr(void)
198 asm volatile ("mrc p15, 0, %0, c1, c1, 0" : "=r" (scr));
203 static void __secure cp15_write_scr(u32 scr)
205 asm volatile ("mcr p15, 0, %0, c1, c1, 0" : : "r" (scr));
210 * Although this is an FIQ handler, the FIQ is processed in monitor mode,
211 * which means there's no FIQ banked registers. This is the same as IRQ
212 * mode, so use the IRQ attribute to ask the compiler to handler entry
215 void __secure __irq psci_fiq_enter(void)
219 /* Switch to secure mode */
220 scr = cp15_read_scr();
221 cp15_write_scr(scr & ~BIT(0));
223 /* Validate reason based on IAR and acknowledge */
224 reg = readl(GICC_BASE + GICC_IAR);
226 /* Skip spurious interrupts 1022 and 1023 */
227 if (reg == 1023 || reg == 1022)
230 /* End of interrupt */
231 writel(reg, GICC_BASE + GICC_EOIR);
235 cpu = (reg >> 10) & 0x7;
237 /* Power off the CPU */
238 sunxi_cpu_power_off(cpu);
241 /* Restore security level */
245 int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc)
247 struct sunxi_cpucfg_reg *cpucfg =
248 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
249 u32 cpu = (mpidr & 0x3);
251 /* store target PC */
252 psci_save_target_pc(cpu, pc);
254 /* Set secondary core power on PC */
255 sunxi_set_entry_address(&psci_cpu_entry);
257 /* Assert reset on target CPU */
258 writel(0, &cpucfg->cpu[cpu].rst);
260 /* Invalidate L1 cache */
261 clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
263 /* Lock CPU (Disable external debug access) */
264 clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
266 /* Power up target CPU */
267 sunxi_cpu_set_power(cpu, true);
269 /* De-assert reset on target CPU */
270 writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
272 /* Unlock CPU (Disable external debug access) */
273 setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
275 return ARM_PSCI_RET_SUCCESS;
278 void __secure psci_cpu_off(void)
280 psci_cpu_off_common();
282 /* Ask CPU0 via SGI15 to pull the rug... */
283 writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
286 /* Wait to be turned off */
291 void __secure psci_arch_init(void)
295 /* SGI15 as Group-0 */
296 clrbits_le32(GICD_BASE + GICD_IGROUPRn, BIT(15));
298 /* Set SGI15 priority to 0 */
299 writeb(0, GICD_BASE + GICD_IPRIORITYRn + 15);
301 /* Be cool with non-secure */
302 writel(0xff, GICC_BASE + GICC_PMR);
304 /* Switch FIQEn on */
305 setbits_le32(GICC_BASE + GICC_CTLR, BIT(3));
307 reg = cp15_read_scr();
308 reg |= BIT(2); /* Enable FIQ in monitor mode */
309 reg &= ~BIT(0); /* Secure mode */