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