Home | History | Annotate | Download | only in sunxi
      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