aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2018-05-25 16:59:28 -0400
committerOlof Johansson <olof@lixom.net>2018-05-25 16:59:28 -0400
commit977d29f89c743c187b8c2cba58f60e798a3e2164 (patch)
treec9d435eef4b0a1dcd45b789a944d819b29dff96a
parent68fc6c839af7da9009bf3fa9da4468c67f3ee5de (diff)
parent6961275e72a8c15cc4ebf108a81eee758480a6a2 (diff)
Merge tag 'sunxi-core-for-4.18' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into next/soc
Allwinner core changes for 4.18 The A83t, unlike the other Allwinner SoCs, cannot use PSCI because of a silicon bug. As such, we needed to have some smp_ops in order to bringup the various cores (and clusters) found on this SoC. * tag 'sunxi-core-for-4.18' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux: ARM: sun8i: smp: Add support for A83T ARM: sun9i: smp: Add is_a83t field ARM: sun9i: smp: Rename clusters's power-off ARM: shmobile: Convert file to use cntvoff ARM: sunxi: Add initialization of CNTVOFF ARM: smp: Add initialization of CNTVOFF ARM: sunxi: smp: Move assembly code into a file ARM: Allow this header to be included by assembly files Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--arch/arm/common/Makefile1
-rw-r--r--arch/arm/common/secure_cntvoff.S32
-rw-r--r--arch/arm/include/asm/secure_cntvoff.h8
-rw-r--r--arch/arm/mach-shmobile/common.h1
-rw-r--r--arch/arm/mach-shmobile/headsmp-apmu.S22
-rw-r--r--arch/arm/mach-shmobile/setup-rcar-gen2.c3
-rw-r--r--arch/arm/mach-sunxi/Kconfig2
-rw-r--r--arch/arm/mach-sunxi/Makefile2
-rw-r--r--arch/arm/mach-sunxi/headsmp.S81
-rw-r--r--arch/arm/mach-sunxi/mc_smp.c239
-rw-r--r--arch/arm/mach-sunxi/sunxi.c20
11 files changed, 291 insertions, 120 deletions
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 70b4a14ed993..1e9f7af8f70f 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DMABOUNCE) += dmabounce.o
10obj-$(CONFIG_SHARP_LOCOMO) += locomo.o 10obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
11obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o 11obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
12obj-$(CONFIG_SHARP_SCOOP) += scoop.o 12obj-$(CONFIG_SHARP_SCOOP) += scoop.o
13obj-$(CONFIG_SMP) += secure_cntvoff.o
13obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o 14obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
14obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o 15obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o
15CFLAGS_REMOVE_mcpm_entry.o = -pg 16CFLAGS_REMOVE_mcpm_entry.o = -pg
diff --git a/arch/arm/common/secure_cntvoff.S b/arch/arm/common/secure_cntvoff.S
new file mode 100644
index 000000000000..53fc7bdb6c2e
--- /dev/null
+++ b/arch/arm/common/secure_cntvoff.S
@@ -0,0 +1,32 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2014 Renesas Electronics Corporation
4 *
5 * Initialization of CNTVOFF register from secure mode
6 *
7 */
8
9#include <linux/linkage.h>
10#include <asm/assembler.h>
11
12ENTRY(secure_cntvoff_init)
13 .arch armv7-a
14 /*
15 * CNTVOFF has to be initialized either from non-secure Hypervisor
16 * mode or secure Monitor mode with SCR.NS==1. If TrustZone is enabled
17 * then it should be handled by the secure code. The CPU must implement
18 * the virtualization extensions.
19 */
20 cps #MON_MODE
21 mrc p15, 0, r1, c1, c1, 0 /* Get Secure Config */
22 orr r0, r1, #1
23 mcr p15, 0, r0, c1, c1, 0 /* Set Non Secure bit */
24 isb
25 mov r0, #0
26 mcrr p15, 4, r0, r0, c14 /* CNTVOFF = 0 */
27 isb
28 mcr p15, 0, r1, c1, c1, 0 /* Set Secure bit */
29 isb
30 cps #SVC_MODE
31 ret lr
32ENDPROC(secure_cntvoff_init)
diff --git a/arch/arm/include/asm/secure_cntvoff.h b/arch/arm/include/asm/secure_cntvoff.h
new file mode 100644
index 000000000000..1f93aee1f630
--- /dev/null
+++ b/arch/arm/include/asm/secure_cntvoff.h
@@ -0,0 +1,8 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3#ifndef __ASMARM_ARCH_CNTVOFF_H
4#define __ASMARM_ARCH_CNTVOFF_H
5
6extern void secure_cntvoff_init(void);
7
8#endif
diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h
index 43c1ac696274..2109f123bdfb 100644
--- a/arch/arm/mach-shmobile/common.h
+++ b/arch/arm/mach-shmobile/common.h
@@ -2,7 +2,6 @@
2#ifndef __ARCH_MACH_COMMON_H 2#ifndef __ARCH_MACH_COMMON_H
3#define __ARCH_MACH_COMMON_H 3#define __ARCH_MACH_COMMON_H
4 4
5extern void shmobile_init_cntvoff(void);
6extern void shmobile_init_delay(void); 5extern void shmobile_init_delay(void);
7extern void shmobile_boot_vector(void); 6extern void shmobile_boot_vector(void);
8extern unsigned long shmobile_boot_fn; 7extern unsigned long shmobile_boot_fn;
diff --git a/arch/arm/mach-shmobile/headsmp-apmu.S b/arch/arm/mach-shmobile/headsmp-apmu.S
index 5672b5849401..d49ab194766a 100644
--- a/arch/arm/mach-shmobile/headsmp-apmu.S
+++ b/arch/arm/mach-shmobile/headsmp-apmu.S
@@ -11,29 +11,9 @@
11#include <linux/linkage.h> 11#include <linux/linkage.h>
12#include <asm/assembler.h> 12#include <asm/assembler.h>
13 13
14ENTRY(shmobile_init_cntvoff)
15 /*
16 * CNTVOFF has to be initialized either from non-secure Hypervisor
17 * mode or secure Monitor mode with SCR.NS==1. If TrustZone is enabled
18 * then it should be handled by the secure code
19 */
20 cps #MON_MODE
21 mrc p15, 0, r1, c1, c1, 0 /* Get Secure Config */
22 orr r0, r1, #1
23 mcr p15, 0, r0, c1, c1, 0 /* Set Non Secure bit */
24 instr_sync
25 mov r0, #0
26 mcrr p15, 4, r0, r0, c14 /* CNTVOFF = 0 */
27 instr_sync
28 mcr p15, 0, r1, c1, c1, 0 /* Set Secure bit */
29 instr_sync
30 cps #SVC_MODE
31 ret lr
32ENDPROC(shmobile_init_cntvoff)
33
34#ifdef CONFIG_SMP 14#ifdef CONFIG_SMP
35ENTRY(shmobile_boot_apmu) 15ENTRY(shmobile_boot_apmu)
36 bl shmobile_init_cntvoff 16 bl secure_cntvoff_init
37 b secondary_startup 17 b secondary_startup
38ENDPROC(shmobile_boot_apmu) 18ENDPROC(shmobile_boot_apmu)
39#endif 19#endif
diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c
index 5561dbed7a33..4a881026d740 100644
--- a/arch/arm/mach-shmobile/setup-rcar-gen2.c
+++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c
@@ -26,6 +26,7 @@
26#include <linux/of_fdt.h> 26#include <linux/of_fdt.h>
27#include <linux/of_platform.h> 27#include <linux/of_platform.h>
28#include <asm/mach/arch.h> 28#include <asm/mach/arch.h>
29#include <asm/secure_cntvoff.h>
29#include "common.h" 30#include "common.h"
30#include "rcar-gen2.h" 31#include "rcar-gen2.h"
31 32
@@ -70,7 +71,7 @@ void __init rcar_gen2_timer_init(void)
70 void __iomem *base; 71 void __iomem *base;
71 u32 freq; 72 u32 freq;
72 73
73 shmobile_init_cntvoff(); 74 secure_cntvoff_init();
74 75
75 if (of_machine_is_compatible("renesas,r8a7745") || 76 if (of_machine_is_compatible("renesas,r8a7745") ||
76 of_machine_is_compatible("renesas,r8a7792") || 77 of_machine_is_compatible("renesas,r8a7792") ||
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index ce53ceaf4cc5..d9c8ecf88ec6 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -51,7 +51,7 @@ config MACH_SUN9I
51config ARCH_SUNXI_MC_SMP 51config ARCH_SUNXI_MC_SMP
52 bool 52 bool
53 depends on SMP 53 depends on SMP
54 default MACH_SUN9I 54 default MACH_SUN9I || MACH_SUN8I
55 select ARM_CCI400_PORT_CTRL 55 select ARM_CCI400_PORT_CTRL
56 select ARM_CPU_SUSPEND 56 select ARM_CPU_SUSPEND
57 57
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 7de9cc286d53..71429aa85143 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -1,5 +1,5 @@
1CFLAGS_mc_smp.o += -march=armv7-a 1CFLAGS_mc_smp.o += -march=armv7-a
2 2
3obj-$(CONFIG_ARCH_SUNXI) += sunxi.o 3obj-$(CONFIG_ARCH_SUNXI) += sunxi.o
4obj-$(CONFIG_ARCH_SUNXI_MC_SMP) += mc_smp.o 4obj-$(CONFIG_ARCH_SUNXI_MC_SMP) += mc_smp.o headsmp.o
5obj-$(CONFIG_SMP) += platsmp.o 5obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-sunxi/headsmp.S b/arch/arm/mach-sunxi/headsmp.S
new file mode 100644
index 000000000000..32d76be98541
--- /dev/null
+++ b/arch/arm/mach-sunxi/headsmp.S
@@ -0,0 +1,81 @@
1/* SPDX-License-Identifier: GPL-2.0
2 *
3 * Copyright (c) 2018 Chen-Yu Tsai
4 * Copyright (c) 2018 Bootlin
5 *
6 * Chen-Yu Tsai <wens@csie.org>
7 * Mylène Josserand <mylene.josserand@bootlin.com>
8 *
9 * SMP support for sunxi based systems with Cortex A7/A15
10 *
11 */
12
13#include <linux/linkage.h>
14#include <asm/assembler.h>
15#include <asm/cputype.h>
16
17ENTRY(sunxi_mc_smp_cluster_cache_enable)
18 .arch armv7-a
19 /*
20 * Enable cluster-level coherency, in preparation for turning on the MMU.
21 *
22 * Also enable regional clock gating and L2 data latency settings for
23 * Cortex-A15. These settings are from the vendor kernel.
24 */
25 mrc p15, 0, r1, c0, c0, 0
26 movw r2, #(ARM_CPU_PART_MASK & 0xffff)
27 movt r2, #(ARM_CPU_PART_MASK >> 16)
28 and r1, r1, r2
29 movw r2, #(ARM_CPU_PART_CORTEX_A15 & 0xffff)
30 movt r2, #(ARM_CPU_PART_CORTEX_A15 >> 16)
31 cmp r1, r2
32 bne not_a15
33
34 /* The following is Cortex-A15 specific */
35
36 /* ACTLR2: Enable CPU regional clock gates */
37 mrc p15, 1, r1, c15, c0, 4
38 orr r1, r1, #(0x1 << 31)
39 mcr p15, 1, r1, c15, c0, 4
40
41 /* L2ACTLR */
42 mrc p15, 1, r1, c15, c0, 0
43 /* Enable L2, GIC, and Timer regional clock gates */
44 orr r1, r1, #(0x1 << 26)
45 /* Disable clean/evict from being pushed to external */
46 orr r1, r1, #(0x1<<3)
47 mcr p15, 1, r1, c15, c0, 0
48
49 /* L2CTRL: L2 data RAM latency */
50 mrc p15, 1, r1, c9, c0, 2
51 bic r1, r1, #(0x7 << 0)
52 orr r1, r1, #(0x3 << 0)
53 mcr p15, 1, r1, c9, c0, 2
54
55 /* End of Cortex-A15 specific setup */
56 not_a15:
57
58 /* Get value of sunxi_mc_smp_first_comer */
59 adr r1, first
60 ldr r0, [r1]
61 ldr r0, [r1, r0]
62
63 /* Skip cci_enable_port_for_self if not first comer */
64 cmp r0, #0
65 bxeq lr
66 b cci_enable_port_for_self
67
68 .align 2
69 first: .word sunxi_mc_smp_first_comer - .
70ENDPROC(sunxi_mc_smp_cluster_cache_enable)
71
72ENTRY(sunxi_mc_smp_secondary_startup)
73 bl sunxi_mc_smp_cluster_cache_enable
74 bl secure_cntvoff_init
75 b secondary_startup
76ENDPROC(sunxi_mc_smp_secondary_startup)
77
78ENTRY(sunxi_mc_smp_resume)
79 bl sunxi_mc_smp_cluster_cache_enable
80 b cpu_resume
81ENDPROC(sunxi_mc_smp_resume)
diff --git a/arch/arm/mach-sunxi/mc_smp.c b/arch/arm/mach-sunxi/mc_smp.c
index c0246ec54a0a..b4037b603897 100644
--- a/arch/arm/mach-sunxi/mc_smp.c
+++ b/arch/arm/mach-sunxi/mc_smp.c
@@ -55,22 +55,35 @@
55#define CPUCFG_CX_RST_CTRL_L2_RST BIT(8) 55#define CPUCFG_CX_RST_CTRL_L2_RST BIT(8)
56#define CPUCFG_CX_RST_CTRL_CX_RST(n) BIT(4 + (n)) 56#define CPUCFG_CX_RST_CTRL_CX_RST(n) BIT(4 + (n))
57#define CPUCFG_CX_RST_CTRL_CORE_RST(n) BIT(n) 57#define CPUCFG_CX_RST_CTRL_CORE_RST(n) BIT(n)
58#define CPUCFG_CX_RST_CTRL_CORE_RST_ALL (0xf << 0)
58 59
59#define PRCM_CPU_PO_RST_CTRL(c) (0x4 + 0x4 * (c)) 60#define PRCM_CPU_PO_RST_CTRL(c) (0x4 + 0x4 * (c))
60#define PRCM_CPU_PO_RST_CTRL_CORE(n) BIT(n) 61#define PRCM_CPU_PO_RST_CTRL_CORE(n) BIT(n)
61#define PRCM_CPU_PO_RST_CTRL_CORE_ALL 0xf 62#define PRCM_CPU_PO_RST_CTRL_CORE_ALL 0xf
62#define PRCM_PWROFF_GATING_REG(c) (0x100 + 0x4 * (c)) 63#define PRCM_PWROFF_GATING_REG(c) (0x100 + 0x4 * (c))
63#define PRCM_PWROFF_GATING_REG_CLUSTER BIT(4) 64/* The power off register for clusters are different from a80 and a83t */
65#define PRCM_PWROFF_GATING_REG_CLUSTER_SUN8I BIT(0)
66#define PRCM_PWROFF_GATING_REG_CLUSTER_SUN9I BIT(4)
64#define PRCM_PWROFF_GATING_REG_CORE(n) BIT(n) 67#define PRCM_PWROFF_GATING_REG_CORE(n) BIT(n)
65#define PRCM_PWR_SWITCH_REG(c, cpu) (0x140 + 0x10 * (c) + 0x4 * (cpu)) 68#define PRCM_PWR_SWITCH_REG(c, cpu) (0x140 + 0x10 * (c) + 0x4 * (cpu))
66#define PRCM_CPU_SOFT_ENTRY_REG 0x164 69#define PRCM_CPU_SOFT_ENTRY_REG 0x164
67 70
71/* R_CPUCFG registers, specific to sun8i-a83t */
72#define R_CPUCFG_CLUSTER_PO_RST_CTRL(c) (0x30 + (c) * 0x4)
73#define R_CPUCFG_CLUSTER_PO_RST_CTRL_CORE(n) BIT(n)
74#define R_CPUCFG_CPU_SOFT_ENTRY_REG 0x01a4
75
68#define CPU0_SUPPORT_HOTPLUG_MAGIC0 0xFA50392F 76#define CPU0_SUPPORT_HOTPLUG_MAGIC0 0xFA50392F
69#define CPU0_SUPPORT_HOTPLUG_MAGIC1 0x790DCA3A 77#define CPU0_SUPPORT_HOTPLUG_MAGIC1 0x790DCA3A
70 78
71static void __iomem *cpucfg_base; 79static void __iomem *cpucfg_base;
72static void __iomem *prcm_base; 80static void __iomem *prcm_base;
73static void __iomem *sram_b_smp_base; 81static void __iomem *sram_b_smp_base;
82static void __iomem *r_cpucfg_base;
83
84extern void sunxi_mc_smp_secondary_startup(void);
85extern void sunxi_mc_smp_resume(void);
86static bool is_a83t;
74 87
75static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster) 88static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster)
76{ 89{
@@ -157,6 +170,16 @@ static int sunxi_cpu_powerup(unsigned int cpu, unsigned int cluster)
157 reg &= ~PRCM_CPU_PO_RST_CTRL_CORE(cpu); 170 reg &= ~PRCM_CPU_PO_RST_CTRL_CORE(cpu);
158 writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster)); 171 writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
159 172
173 if (is_a83t) {
174 /* assert cpu power-on reset */
175 reg = readl(r_cpucfg_base +
176 R_CPUCFG_CLUSTER_PO_RST_CTRL(cluster));
177 reg &= ~(R_CPUCFG_CLUSTER_PO_RST_CTRL_CORE(cpu));
178 writel(reg, r_cpucfg_base +
179 R_CPUCFG_CLUSTER_PO_RST_CTRL(cluster));
180 udelay(10);
181 }
182
160 /* Cortex-A7: hold L1 reset disable signal low */ 183 /* Cortex-A7: hold L1 reset disable signal low */
161 if (!sunxi_core_is_cortex_a15(cpu, cluster)) { 184 if (!sunxi_core_is_cortex_a15(cpu, cluster)) {
162 reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster)); 185 reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
@@ -180,17 +203,38 @@ static int sunxi_cpu_powerup(unsigned int cpu, unsigned int cluster)
180 /* open power switch */ 203 /* open power switch */
181 sunxi_cpu_power_switch_set(cpu, cluster, true); 204 sunxi_cpu_power_switch_set(cpu, cluster, true);
182 205
206 /* Handle A83T bit swap */
207 if (is_a83t) {
208 if (cpu == 0)
209 cpu = 4;
210 }
211
183 /* clear processor power gate */ 212 /* clear processor power gate */
184 reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster)); 213 reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
185 reg &= ~PRCM_PWROFF_GATING_REG_CORE(cpu); 214 reg &= ~PRCM_PWROFF_GATING_REG_CORE(cpu);
186 writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster)); 215 writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
187 udelay(20); 216 udelay(20);
188 217
218 /* Handle A83T bit swap */
219 if (is_a83t) {
220 if (cpu == 4)
221 cpu = 0;
222 }
223
189 /* de-assert processor power-on reset */ 224 /* de-assert processor power-on reset */
190 reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster)); 225 reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
191 reg |= PRCM_CPU_PO_RST_CTRL_CORE(cpu); 226 reg |= PRCM_CPU_PO_RST_CTRL_CORE(cpu);
192 writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster)); 227 writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
193 228
229 if (is_a83t) {
230 reg = readl(r_cpucfg_base +
231 R_CPUCFG_CLUSTER_PO_RST_CTRL(cluster));
232 reg |= R_CPUCFG_CLUSTER_PO_RST_CTRL_CORE(cpu);
233 writel(reg, r_cpucfg_base +
234 R_CPUCFG_CLUSTER_PO_RST_CTRL(cluster));
235 udelay(10);
236 }
237
194 /* de-assert all processor resets */ 238 /* de-assert all processor resets */
195 reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster)); 239 reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
196 reg |= CPUCFG_CX_RST_CTRL_DBG_RST(cpu); 240 reg |= CPUCFG_CX_RST_CTRL_DBG_RST(cpu);
@@ -212,6 +256,14 @@ static int sunxi_cluster_powerup(unsigned int cluster)
212 if (cluster >= SUNXI_NR_CLUSTERS) 256 if (cluster >= SUNXI_NR_CLUSTERS)
213 return -EINVAL; 257 return -EINVAL;
214 258
259 /* For A83T, assert cluster cores resets */
260 if (is_a83t) {
261 reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
262 reg &= ~CPUCFG_CX_RST_CTRL_CORE_RST_ALL; /* Core Reset */
263 writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
264 udelay(10);
265 }
266
215 /* assert ACINACTM */ 267 /* assert ACINACTM */
216 reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster)); 268 reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
217 reg |= CPUCFG_CX_CTRL_REG1_ACINACTM; 269 reg |= CPUCFG_CX_CTRL_REG1_ACINACTM;
@@ -222,6 +274,16 @@ static int sunxi_cluster_powerup(unsigned int cluster)
222 reg &= ~PRCM_CPU_PO_RST_CTRL_CORE_ALL; 274 reg &= ~PRCM_CPU_PO_RST_CTRL_CORE_ALL;
223 writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster)); 275 writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
224 276
277 /* assert cluster cores resets */
278 if (is_a83t) {
279 reg = readl(r_cpucfg_base +
280 R_CPUCFG_CLUSTER_PO_RST_CTRL(cluster));
281 reg &= ~CPUCFG_CX_RST_CTRL_CORE_RST_ALL;
282 writel(reg, r_cpucfg_base +
283 R_CPUCFG_CLUSTER_PO_RST_CTRL(cluster));
284 udelay(10);
285 }
286
225 /* assert cluster resets */ 287 /* assert cluster resets */
226 reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster)); 288 reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
227 reg &= ~CPUCFG_CX_RST_CTRL_DBG_SOC_RST; 289 reg &= ~CPUCFG_CX_RST_CTRL_DBG_SOC_RST;
@@ -252,7 +314,10 @@ static int sunxi_cluster_powerup(unsigned int cluster)
252 314
253 /* clear cluster power gate */ 315 /* clear cluster power gate */
254 reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster)); 316 reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
255 reg &= ~PRCM_PWROFF_GATING_REG_CLUSTER; 317 if (is_a83t)
318 reg &= ~PRCM_PWROFF_GATING_REG_CLUSTER_SUN8I;
319 else
320 reg &= ~PRCM_PWROFF_GATING_REG_CLUSTER_SUN9I;
256 writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster)); 321 writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
257 udelay(20); 322 udelay(20);
258 323
@@ -300,74 +365,7 @@ static void sunxi_cluster_cache_disable_without_axi(void)
300} 365}
301 366
302static int sunxi_mc_smp_cpu_table[SUNXI_NR_CLUSTERS][SUNXI_CPUS_PER_CLUSTER]; 367static int sunxi_mc_smp_cpu_table[SUNXI_NR_CLUSTERS][SUNXI_CPUS_PER_CLUSTER];
303static int sunxi_mc_smp_first_comer; 368int sunxi_mc_smp_first_comer;
304
305/*
306 * Enable cluster-level coherency, in preparation for turning on the MMU.
307 *
308 * Also enable regional clock gating and L2 data latency settings for
309 * Cortex-A15. These settings are from the vendor kernel.
310 */
311static void __naked sunxi_mc_smp_cluster_cache_enable(void)
312{
313 asm volatile (
314 "mrc p15, 0, r1, c0, c0, 0\n"
315 "movw r2, #" __stringify(ARM_CPU_PART_MASK & 0xffff) "\n"
316 "movt r2, #" __stringify(ARM_CPU_PART_MASK >> 16) "\n"
317 "and r1, r1, r2\n"
318 "movw r2, #" __stringify(ARM_CPU_PART_CORTEX_A15 & 0xffff) "\n"
319 "movt r2, #" __stringify(ARM_CPU_PART_CORTEX_A15 >> 16) "\n"
320 "cmp r1, r2\n"
321 "bne not_a15\n"
322
323 /* The following is Cortex-A15 specific */
324
325 /* ACTLR2: Enable CPU regional clock gates */
326 "mrc p15, 1, r1, c15, c0, 4\n"
327 "orr r1, r1, #(0x1<<31)\n"
328 "mcr p15, 1, r1, c15, c0, 4\n"
329
330 /* L2ACTLR */
331 "mrc p15, 1, r1, c15, c0, 0\n"
332 /* Enable L2, GIC, and Timer regional clock gates */
333 "orr r1, r1, #(0x1<<26)\n"
334 /* Disable clean/evict from being pushed to external */
335 "orr r1, r1, #(0x1<<3)\n"
336 "mcr p15, 1, r1, c15, c0, 0\n"
337
338 /* L2CTRL: L2 data RAM latency */
339 "mrc p15, 1, r1, c9, c0, 2\n"
340 "bic r1, r1, #(0x7<<0)\n"
341 "orr r1, r1, #(0x3<<0)\n"
342 "mcr p15, 1, r1, c9, c0, 2\n"
343
344 /* End of Cortex-A15 specific setup */
345 "not_a15:\n"
346
347 /* Get value of sunxi_mc_smp_first_comer */
348 "adr r1, first\n"
349 "ldr r0, [r1]\n"
350 "ldr r0, [r1, r0]\n"
351
352 /* Skip cci_enable_port_for_self if not first comer */
353 "cmp r0, #0\n"
354 "bxeq lr\n"
355 "b cci_enable_port_for_self\n"
356
357 ".align 2\n"
358 "first: .word sunxi_mc_smp_first_comer - .\n"
359 );
360}
361
362static void __naked sunxi_mc_smp_secondary_startup(void)
363{
364 asm volatile(
365 "bl sunxi_mc_smp_cluster_cache_enable\n"
366 "b secondary_startup"
367 /* Let compiler know about sunxi_mc_smp_cluster_cache_enable */
368 :: "i" (sunxi_mc_smp_cluster_cache_enable)
369 );
370}
371 369
372static DEFINE_SPINLOCK(boot_lock); 370static DEFINE_SPINLOCK(boot_lock);
373 371
@@ -516,7 +514,10 @@ static int sunxi_cluster_powerdown(unsigned int cluster)
516 /* gate cluster power */ 514 /* gate cluster power */
517 pr_debug("%s: gate cluster power\n", __func__); 515 pr_debug("%s: gate cluster power\n", __func__);
518 reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster)); 516 reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
519 reg |= PRCM_PWROFF_GATING_REG_CLUSTER; 517 if (is_a83t)
518 reg |= PRCM_PWROFF_GATING_REG_CLUSTER_SUN8I;
519 else
520 reg |= PRCM_PWROFF_GATING_REG_CLUSTER_SUN9I;
520 writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster)); 521 writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
521 udelay(20); 522 udelay(20);
522 523
@@ -598,8 +599,12 @@ out:
598 return !ret; 599 return !ret;
599} 600}
600 601
601static bool sunxi_mc_smp_cpu_can_disable(unsigned int __unused) 602static bool sunxi_mc_smp_cpu_can_disable(unsigned int cpu)
602{ 603{
604 /* CPU0 hotplug not handled for sun8i-a83t */
605 if (is_a83t)
606 if (cpu == 0)
607 return false;
603 return true; 608 return true;
604} 609}
605#endif 610#endif
@@ -637,16 +642,6 @@ static bool __init sunxi_mc_smp_cpu_table_init(void)
637 */ 642 */
638typedef typeof(cpu_reset) phys_reset_t; 643typedef typeof(cpu_reset) phys_reset_t;
639 644
640static void __init __naked sunxi_mc_smp_resume(void)
641{
642 asm volatile(
643 "bl sunxi_mc_smp_cluster_cache_enable\n"
644 "b cpu_resume"
645 /* Let compiler know about sunxi_mc_smp_cluster_cache_enable */
646 :: "i" (sunxi_mc_smp_cluster_cache_enable)
647 );
648}
649
650static int __init nocache_trampoline(unsigned long __unused) 645static int __init nocache_trampoline(unsigned long __unused)
651{ 646{
652 phys_reset_t phys_reset; 647 phys_reset_t phys_reset;
@@ -692,12 +687,14 @@ struct sunxi_mc_smp_nodes {
692 struct device_node *prcm_node; 687 struct device_node *prcm_node;
693 struct device_node *cpucfg_node; 688 struct device_node *cpucfg_node;
694 struct device_node *sram_node; 689 struct device_node *sram_node;
690 struct device_node *r_cpucfg_node;
695}; 691};
696 692
697/* This structure holds SoC-specific bits tied to an enable-method string. */ 693/* This structure holds SoC-specific bits tied to an enable-method string. */
698struct sunxi_mc_smp_data { 694struct sunxi_mc_smp_data {
699 const char *enable_method; 695 const char *enable_method;
700 int (*get_smp_nodes)(struct sunxi_mc_smp_nodes *nodes); 696 int (*get_smp_nodes)(struct sunxi_mc_smp_nodes *nodes);
697 bool is_a83t;
701}; 698};
702 699
703static void __init sunxi_mc_smp_put_nodes(struct sunxi_mc_smp_nodes *nodes) 700static void __init sunxi_mc_smp_put_nodes(struct sunxi_mc_smp_nodes *nodes)
@@ -705,6 +702,7 @@ static void __init sunxi_mc_smp_put_nodes(struct sunxi_mc_smp_nodes *nodes)
705 of_node_put(nodes->prcm_node); 702 of_node_put(nodes->prcm_node);
706 of_node_put(nodes->cpucfg_node); 703 of_node_put(nodes->cpucfg_node);
707 of_node_put(nodes->sram_node); 704 of_node_put(nodes->sram_node);
705 of_node_put(nodes->r_cpucfg_node);
708 memset(nodes, 0, sizeof(*nodes)); 706 memset(nodes, 0, sizeof(*nodes));
709} 707}
710 708
@@ -734,11 +732,42 @@ static int __init sun9i_a80_get_smp_nodes(struct sunxi_mc_smp_nodes *nodes)
734 return 0; 732 return 0;
735} 733}
736 734
735static int __init sun8i_a83t_get_smp_nodes(struct sunxi_mc_smp_nodes *nodes)
736{
737 nodes->prcm_node = of_find_compatible_node(NULL, NULL,
738 "allwinner,sun8i-a83t-r-ccu");
739 if (!nodes->prcm_node) {
740 pr_err("%s: PRCM not available\n", __func__);
741 return -ENODEV;
742 }
743
744 nodes->cpucfg_node = of_find_compatible_node(NULL, NULL,
745 "allwinner,sun8i-a83t-cpucfg");
746 if (!nodes->cpucfg_node) {
747 pr_err("%s: CPUCFG not available\n", __func__);
748 return -ENODEV;
749 }
750
751 nodes->r_cpucfg_node = of_find_compatible_node(NULL, NULL,
752 "allwinner,sun8i-a83t-r-cpucfg");
753 if (!nodes->r_cpucfg_node) {
754 pr_err("%s: RCPUCFG not available\n", __func__);
755 return -ENODEV;
756 }
757
758 return 0;
759}
760
737static const struct sunxi_mc_smp_data sunxi_mc_smp_data[] __initconst = { 761static const struct sunxi_mc_smp_data sunxi_mc_smp_data[] __initconst = {
738 { 762 {
739 .enable_method = "allwinner,sun9i-a80-smp", 763 .enable_method = "allwinner,sun9i-a80-smp",
740 .get_smp_nodes = sun9i_a80_get_smp_nodes, 764 .get_smp_nodes = sun9i_a80_get_smp_nodes,
741 }, 765 },
766 {
767 .enable_method = "allwinner,sun8i-a83t-smp",
768 .get_smp_nodes = sun8i_a83t_get_smp_nodes,
769 .is_a83t = true,
770 },
742}; 771};
743 772
744static int __init sunxi_mc_smp_init(void) 773static int __init sunxi_mc_smp_init(void)
@@ -746,6 +775,7 @@ static int __init sunxi_mc_smp_init(void)
746 struct sunxi_mc_smp_nodes nodes = { 0 }; 775 struct sunxi_mc_smp_nodes nodes = { 0 };
747 struct device_node *node; 776 struct device_node *node;
748 struct resource res; 777 struct resource res;
778 void __iomem *addr;
749 int i, ret; 779 int i, ret;
750 780
751 /* 781 /*
@@ -771,6 +801,8 @@ static int __init sunxi_mc_smp_init(void)
771 break; 801 break;
772 } 802 }
773 803
804 is_a83t = sunxi_mc_smp_data[i].is_a83t;
805
774 of_node_put(node); 806 of_node_put(node);
775 if (ret) 807 if (ret)
776 return -ENODEV; 808 return -ENODEV;
@@ -808,12 +840,23 @@ static int __init sunxi_mc_smp_init(void)
808 goto err_unmap_prcm; 840 goto err_unmap_prcm;
809 } 841 }
810 842
811 sram_b_smp_base = of_io_request_and_map(nodes.sram_node, 0, 843 if (is_a83t) {
812 "sunxi-mc-smp"); 844 r_cpucfg_base = of_io_request_and_map(nodes.r_cpucfg_node,
813 if (IS_ERR(sram_b_smp_base)) { 845 0, "sunxi-mc-smp");
814 ret = PTR_ERR(sram_b_smp_base); 846 if (IS_ERR(r_cpucfg_base)) {
815 pr_err("%s: failed to map secure SRAM\n", __func__); 847 ret = PTR_ERR(r_cpucfg_base);
816 goto err_unmap_release_cpucfg; 848 pr_err("%s: failed to map R-CPUCFG registers\n",
849 __func__);
850 goto err_unmap_release_cpucfg;
851 }
852 } else {
853 sram_b_smp_base = of_io_request_and_map(nodes.sram_node, 0,
854 "sunxi-mc-smp");
855 if (IS_ERR(sram_b_smp_base)) {
856 ret = PTR_ERR(sram_b_smp_base);
857 pr_err("%s: failed to map secure SRAM\n", __func__);
858 goto err_unmap_release_cpucfg;
859 }
817 } 860 }
818 861
819 /* Configure CCI-400 for boot cluster */ 862 /* Configure CCI-400 for boot cluster */
@@ -821,15 +864,18 @@ static int __init sunxi_mc_smp_init(void)
821 if (ret) { 864 if (ret) {
822 pr_err("%s: failed to configure boot cluster: %d\n", 865 pr_err("%s: failed to configure boot cluster: %d\n",
823 __func__, ret); 866 __func__, ret);
824 goto err_unmap_release_secure_sram; 867 goto err_unmap_release_sram_rcpucfg;
825 } 868 }
826 869
827 /* We don't need the device nodes anymore */ 870 /* We don't need the device nodes anymore */
828 sunxi_mc_smp_put_nodes(&nodes); 871 sunxi_mc_smp_put_nodes(&nodes);
829 872
830 /* Set the hardware entry point address */ 873 /* Set the hardware entry point address */
831 writel(__pa_symbol(sunxi_mc_smp_secondary_startup), 874 if (is_a83t)
832 prcm_base + PRCM_CPU_SOFT_ENTRY_REG); 875 addr = r_cpucfg_base + R_CPUCFG_CPU_SOFT_ENTRY_REG;
876 else
877 addr = prcm_base + PRCM_CPU_SOFT_ENTRY_REG;
878 writel(__pa_symbol(sunxi_mc_smp_secondary_startup), addr);
833 879
834 /* Actually enable multi cluster SMP */ 880 /* Actually enable multi cluster SMP */
835 smp_set_ops(&sunxi_mc_smp_smp_ops); 881 smp_set_ops(&sunxi_mc_smp_smp_ops);
@@ -838,9 +884,14 @@ static int __init sunxi_mc_smp_init(void)
838 884
839 return 0; 885 return 0;
840 886
841err_unmap_release_secure_sram: 887err_unmap_release_sram_rcpucfg:
842 iounmap(sram_b_smp_base); 888 if (is_a83t) {
843 of_address_to_resource(nodes.sram_node, 0, &res); 889 iounmap(r_cpucfg_base);
890 of_address_to_resource(nodes.r_cpucfg_node, 0, &res);
891 } else {
892 iounmap(sram_b_smp_base);
893 of_address_to_resource(nodes.sram_node, 0, &res);
894 }
844 release_mem_region(res.start, resource_size(&res)); 895 release_mem_region(res.start, resource_size(&res));
845err_unmap_release_cpucfg: 896err_unmap_release_cpucfg:
846 iounmap(cpucfg_base); 897 iounmap(cpucfg_base);
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 5e9602ce1573..de4b0e932f22 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -16,6 +16,7 @@
16#include <linux/platform_device.h> 16#include <linux/platform_device.h>
17 17
18#include <asm/mach/arch.h> 18#include <asm/mach/arch.h>
19#include <asm/secure_cntvoff.h>
19 20
20static const char * const sunxi_board_dt_compat[] = { 21static const char * const sunxi_board_dt_compat[] = {
21 "allwinner,sun4i-a10", 22 "allwinner,sun4i-a10",
@@ -62,7 +63,6 @@ MACHINE_END
62static const char * const sun8i_board_dt_compat[] = { 63static const char * const sun8i_board_dt_compat[] = {
63 "allwinner,sun8i-a23", 64 "allwinner,sun8i-a23",
64 "allwinner,sun8i-a33", 65 "allwinner,sun8i-a33",
65 "allwinner,sun8i-a83t",
66 "allwinner,sun8i-h2-plus", 66 "allwinner,sun8i-h2-plus",
67 "allwinner,sun8i-h3", 67 "allwinner,sun8i-h3",
68 "allwinner,sun8i-r40", 68 "allwinner,sun8i-r40",
@@ -75,6 +75,24 @@ DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i Family")
75 .dt_compat = sun8i_board_dt_compat, 75 .dt_compat = sun8i_board_dt_compat,
76MACHINE_END 76MACHINE_END
77 77
78static void __init sun8i_a83t_cntvoff_init(void)
79{
80#ifdef CONFIG_SMP
81 secure_cntvoff_init();
82#endif
83}
84
85static const char * const sun8i_a83t_cntvoff_board_dt_compat[] = {
86 "allwinner,sun8i-a83t",
87 NULL,
88};
89
90DT_MACHINE_START(SUN8I_A83T_CNTVOFF_DT, "Allwinner A83t board")
91 .init_early = sun8i_a83t_cntvoff_init,
92 .init_time = sun6i_timer_init,
93 .dt_compat = sun8i_a83t_cntvoff_board_dt_compat,
94MACHINE_END
95
78static const char * const sun9i_board_dt_compat[] = { 96static const char * const sun9i_board_dt_compat[] = {
79 "allwinner,sun9i-a80", 97 "allwinner,sun9i-a80",
80 NULL, 98 NULL,