1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2016 4 * Author: Chen-Yu Tsai <wens (at) csie.org> 5 * 6 * Based on assembly code by Marc Zyngier <marc.zyngier (at) arm.com>, 7 * which was based on code by Carl van Schaik <carl (at) ok-labs.com>. 8 */ 9 #include <config.h> 10 #include <common.h> 11 12 #include <asm/arch/cpu.h> 13 #include <asm/arch/cpucfg.h> 14 #include <asm/arch/prcm.h> 15 #include <asm/armv7.h> 16 #include <asm/gic.h> 17 #include <asm/io.h> 18 #include <asm/psci.h> 19 #include <asm/secure.h> 20 #include <asm/system.h> 21 22 #include <linux/bitops.h> 23 24 #define __irq __attribute__ ((interrupt ("IRQ"))) 25 26 #define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET) 27 #define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15) 28 29 /* 30 * R40 is different from other single cluster SoCs. 31 * 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. 35 */ 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) 39 40 static void __secure cp15_write_cntp_tval(u32 tval) 41 { 42 asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); 43 } 44 45 static void __secure cp15_write_cntp_ctl(u32 val) 46 { 47 asm volatile ("mcr p15, 0, %0, c14, c2, 1" : : "r" (val)); 48 } 49 50 static u32 __secure cp15_read_cntp_ctl(void) 51 { 52 u32 val; 53 54 asm volatile ("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); 55 56 return val; 57 } 58 59 #define ONE_MS (COUNTER_FREQUENCY / 1000) 60 61 static void __secure __mdelay(u32 ms) 62 { 63 u32 reg = ONE_MS * ms; 64 65 cp15_write_cntp_tval(reg); 66 isb(); 67 cp15_write_cntp_ctl(3); 68 69 do { 70 isb(); 71 reg = cp15_read_cntp_ctl(); 72 } while (!(reg & BIT(2))); 73 74 cp15_write_cntp_ctl(0); 75 isb(); 76 } 77 78 static void __secure clamp_release(u32 __maybe_unused *clamp) 79 { 80 #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \ 81 defined(CONFIG_MACH_SUN8I_H3) || \ 82 defined(CONFIG_MACH_SUN8I_R40) 83 u32 tmp = 0x1ff; 84 do { 85 tmp >>= 1; 86 writel(tmp, clamp); 87 } while (tmp); 88 89 __mdelay(10); 90 #endif 91 } 92 93 static void __secure clamp_set(u32 __maybe_unused *clamp) 94 { 95 #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \ 96 defined(CONFIG_MACH_SUN8I_H3) || \ 97 defined(CONFIG_MACH_SUN8I_R40) 98 writel(0xff, clamp); 99 #endif 100 } 101 102 static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on, 103 int cpu) 104 { 105 if (on) { 106 /* Release power clamp */ 107 clamp_release(clamp); 108 109 /* Clear power gating */ 110 clrbits_le32(pwroff, BIT(cpu)); 111 } else { 112 /* Set power gating */ 113 setbits_le32(pwroff, BIT(cpu)); 114 115 /* Activate power clamp */ 116 clamp_set(clamp); 117 } 118 } 119 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) 123 { 124 writel((u32)entry, 125 SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); 126 } 127 #else 128 static void __secure sunxi_set_entry_address(void *entry) 129 { 130 struct sunxi_cpucfg_reg *cpucfg = 131 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; 132 133 writel((u32)entry, &cpucfg->priv0); 134 } 135 #endif 136 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) 140 { 141 struct sunxi_cpucfg_reg *cpucfg = 142 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; 143 144 sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff, 145 on, 0); 146 } 147 #elif defined CONFIG_MACH_SUN8I_R40 148 static void __secure sunxi_cpu_set_power(int cpu, bool on) 149 { 150 struct sunxi_cpucfg_reg *cpucfg = 151 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; 152 153 sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu), 154 (void *)cpucfg + SUN8I_R40_PWROFF, 155 on, 0); 156 } 157 #else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */ 158 static void __secure sunxi_cpu_set_power(int cpu, bool on) 159 { 160 struct sunxi_prcm_reg *prcm = 161 (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; 162 163 sunxi_power_switch(&prcm->cpu_pwr_clamp[cpu], &prcm->cpu_pwroff, 164 on, cpu); 165 } 166 #endif /* CONFIG_MACH_SUN7I */ 167 168 void __secure sunxi_cpu_power_off(u32 cpuid) 169 { 170 struct sunxi_cpucfg_reg *cpucfg = 171 (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; 172 u32 cpu = cpuid & 0x3; 173 174 /* Wait for the core to enter WFI */ 175 while (1) { 176 if (readl(&cpucfg->cpu[cpu].status) & BIT(2)) 177 break; 178 __mdelay(1); 179 } 180 181 /* Assert reset on target CPU */ 182 writel(0, &cpucfg->cpu[cpu].rst); 183 184 /* Lock CPU (Disable external debug access) */ 185 clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); 186 187 /* Power down CPU */ 188 sunxi_cpu_set_power(cpuid, false); 189 190 /* Unlock CPU (Disable external debug access) */ 191 setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu)); 192 } 193 194 static u32 __secure cp15_read_scr(void) 195 { 196 u32 scr; 197 198 asm volatile ("mrc p15, 0, %0, c1, c1, 0" : "=r" (scr)); 199 200 return scr; 201 } 202 203 static void __secure cp15_write_scr(u32 scr) 204 { 205 asm volatile ("mcr p15, 0, %0, c1, c1, 0" : : "r" (scr)); 206 isb(); 207 } 208 209 /* 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 213 * and return. 214 */ 215 void __secure __irq psci_fiq_enter(void) 216 { 217 u32 scr, reg, cpu; 218 219 /* Switch to secure mode */ 220 scr = cp15_read_scr(); 221 cp15_write_scr(scr & ~BIT(0)); 222 223 /* Validate reason based on IAR and acknowledge */ 224 reg = readl(GICC_BASE + GICC_IAR); 225 226 /* Skip spurious interrupts 1022 and 1023 */ 227 if (reg == 1023 || reg == 1022) 228 goto out; 229 230 /* End of interrupt */ 231 writel(reg, GICC_BASE + GICC_EOIR); 232 dsb(); 233 234 /* Get CPU number */ 235 cpu = (reg >> 10) & 0x7; 236 237 /* Power off the CPU */ 238 sunxi_cpu_power_off(cpu); 239 240 out: 241 /* Restore security level */ 242 cp15_write_scr(scr); 243 } 244 245 int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc, 246 u32 context_id) 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 and context id */ 253 psci_save(cpu, pc, context_id); 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