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/system.h> 21 22 #include <linux/bitops.h> 23 24 #define __secure __attribute__ ((section ("._secure.text"))) 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 (CONFIG_TIMER_CLK_FREQ / 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 at target CPU stack top */ 213 writel(pc, psci_get_cpu_stack_top(cpu)); 214 DSB; 215 216 /* Set secondary core power on PC */ 217 writel((u32)&psci_cpu_entry, &cpucfg->priv0); 218 219 /* Assert reset on target CPU */ 220 writel(0, &cpucfg->cpu[cpu].rst); 221 222 /* Invalidate L1 cache */ 223 clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu)); 224 225 /* Lock CPU (Disable external debug access) */ 226 clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); 227 228 /* Power up target CPU */ 229 sunxi_cpu_set_power(cpu, true); 230 231 /* De-assert reset on target CPU */ 232 writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst); 233 234 /* Unlock CPU (Disable external debug access) */ 235 setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); 236 237 return ARM_PSCI_RET_SUCCESS; 238 } 239 240 void __secure psci_cpu_off(void) 241 { 242 psci_cpu_off_common(); 243 244 /* Ask CPU0 via SGI15 to pull the rug... */ 245 writel(BIT(16) | 15, GICD_BASE + GICD_SGIR); 246 DSB; 247 248 /* Wait to be turned off */ 249 while (1) 250 wfi(); 251 } 252 253 void __secure sunxi_gic_init(void) 254 { 255 u32 reg; 256 257 /* SGI15 as Group-0 */ 258 clrbits_le32(GICD_BASE + GICD_IGROUPRn, BIT(15)); 259 260 /* Set SGI15 priority to 0 */ 261 writeb(0, GICD_BASE + GICD_IPRIORITYRn + 15); 262 263 /* Be cool with non-secure */ 264 writel(0xff, GICC_BASE + GICC_PMR); 265 266 /* Switch FIQEn on */ 267 setbits_le32(GICC_BASE + GICC_CTLR, BIT(3)); 268 269 reg = cp15_read_scr(); 270 reg |= BIT(2); /* Enable FIQ in monitor mode */ 271 reg &= ~BIT(0); /* Secure mode */ 272 cp15_write_scr(reg); 273 } 274