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