Skip to contentSkip to conversation

ARM: shmobile: r8a73a4 SMP and CPU Hotplug prototype v2

PATCH New Magnus Damm 2 participants 7 messages May 30, 2013 – Jun 5, 2013

Subsystems (5)
lore
Share & tools
lore

Magnus Damm

author maintainer
#0 lore raw

cover ARM: shmobile: r8a73a4 SMP and CPU Hotplug prototype v2

ARM: shmobile: r8a73a4 SMP and CPU Hotplug prototype v2

[PATCH 01/05] ARM: shmobile: r8a73a4 SMP prototype v1 (CA15 x 4) [PATCH 02/05] ARM: shmobile: r8a73a4 CPU Hotplug prototype v1 (CA15 x 4) [PATCH 03/05] ARM: shmobile: r8a73a4 CA15 setup WFE as NOP [PATCH 04/05] ARM: shmobile: r8a73a4 SMP CA7 prototype (+ CA7 x 4) [PATCH 05/05] ARM: shmobile: r8a73a4 CA7 setup arch timer

Here's V2 of r8a73a4 SMP prototype support. This time support for both CA15 and CA7 is included.

It is worth noting that only prototype support for the actual SoC is included here. It is included as SMP support, but since CA7 cores perform differently compared to CA15 the system will not behave in a deterministic way unless either big.LITTLE MP patches are used to extend the scheduler or c-groups are used to separate CA15 and CA7.

All 8 cores boot up as expected but certainly needs more work.

Not-yet-Signed-off-by Magnus Damm <[email protected]>

---

Written against linux.git 7b55eab81ecbbd44e76ac14c67479b82807c261b

 arch/arm/boot/dts/r8a73a4.dtsi                |   49 ++++
 arch/arm/mach-shmobile/Makefile               |    1 
 arch/arm/mach-shmobile/board-ape6evm.c        |    1 
 arch/arm/mach-shmobile/include/mach/r8a73a4.h |    1 
 arch/arm/mach-shmobile/setup-r8a73a4.c        |    1 
 arch/arm/mach-shmobile/smp-r8a73a4.c          |  274 ++++++++++++++++++++++++-
 6 files changed, 321 insertions(+), 6 deletions(-)
author maintainer
#1 lore raw

PATCH 1/5 ARM: shmobile: r8a73a4 SMP prototype v1 (CA15 x 4)

From: Magnus Damm <[email protected]>

Add SMP prototype support for r8a73a4 by enabling 4 x Cortex-A15. This patch only adds support for booting, see the incremental patch for CPU Hotplug.

Needs a rewrite to support more generic handling of CPU core power domains. Not ready for merge.

Not-yet-Signed-off-by Magnus Damm <[email protected]>

---

Developed and tested on top of v3.10-rc2

 arch/arm/boot/dts/r8a73a4.dtsi                |   21 +++++
 arch/arm/mach-shmobile/Makefile               |    1 
 arch/arm/mach-shmobile/board-ape6evm.c        |    1 
 arch/arm/mach-shmobile/include/mach/r8a73a4.h |    1 
 arch/arm/mach-shmobile/setup-r8a73a4.c        |    1 
 arch/arm/mach-shmobile/smp-r8a73a4.c          |   89 +++++++++++++++++++++++++
 6 files changed, 114 insertions(+)
arch/arm/boot/dts/r8a73a4.dtsi +21 -0
@@ -25,6 +25,27 @@
 			reg = <0>;
 			clock-frequency = <1500000000>;
 		};
+
+		cpu1: cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <1>;
+			clock-frequency = <1500000000>;
+		};
+
+		cpu2: cpu at 2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <2>;
+			clock-frequency = <1500000000>;
+		};
+
+		cpu3: cpu at 3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <3>;
+			clock-frequency = <1500000000>;
+		};
 	};
 
 	gic: interrupt-controller at f1001000 {
arch/arm/mach-shmobile/Makefile +1 -0
@@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_EMEV2)	+= setup-emev2.
 # SMP objects
 smp-y				:= platsmp.o headsmp.o
 smp-$(CONFIG_ARCH_SH73A0)	+= smp-sh73a0.o headsmp-scu.o
+smp-$(CONFIG_ARCH_R8A73A4)	+= smp-r8a73a4.o
 smp-$(CONFIG_ARCH_R8A7779)	+= smp-r8a7779.o headsmp-scu.o
 smp-$(CONFIG_ARCH_EMEV2)	+= smp-emev2.o headsmp-scu.o
 
arch/arm/mach-shmobile/board-ape6evm.c +1 -0
@@ -87,6 +87,7 @@ static const char *ape6evm_boards_compat
 };
 
 DT_MACHINE_START(APE6EVM_DT, "ape6evm")
+	.smp		= smp_ops(r8a73a4_smp_ops),
 	.init_irq	= irqchip_init,
 	.init_time	= shmobile_timer_init,
 	.init_machine	= ape6evm_add_standard_devices,
arch/arm/mach-shmobile/include/mach/r8a73a4.h +1 -0
@@ -4,5 +4,6 @@
 void r8a73a4_add_standard_devices(void);
 void r8a73a4_clock_init(void);
 void r8a73a4_pinmux_init(void);
+extern struct smp_operations r8a73a4_smp_ops;
 
 #endif /* __ASM_R8A73A4_H__ */
arch/arm/mach-shmobile/setup-r8a73a4.c +1 -0
@@ -194,6 +194,7 @@ static const char *r8a73a4_boards_compat
 };
 
 DT_MACHINE_START(R8A73A4_DT, "Generic R8A73A4 (Flattened Device Tree)")
+	.smp		= smp_ops(r8a73a4_smp_ops),
 	.init_irq	= irqchip_init,
 	.init_machine	= r8a73a4_add_standard_devices_dt,
 	.init_time	= shmobile_timer_init,
arch/arm/mach-shmobile/smp-r8a73a4.c new file +89 -0

89 lines not on this page · raw message

#2 lore raw

PATCH 1/5 ARM: shmobile: r8a73a4 SMP prototype v1 (CA15 x 4)

Hi Magnus,

Quoted 18 lines · Magnus Damm
arch/arm/boot/dts/r8a73a4.dtsi +12 -0
@@ -25,6 +25,27 @@
 			reg = <0>;
 			clock-frequency = <1500000000>;
 		};
+
+		cpu1: cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <1>;
+			clock-frequency = <1500000000>;
+		};
+
+		cpu2: cpu at 2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <2>;

arch/arm/boot/dts/r8a73a4.dtsi line 49

Quoted 10 lines
arch/arm/boot/dts/r8a73a4.dtsi +9 -0
+			clock-frequency = <1500000000>;
+		};
+
+		cpu3: cpu at 3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <3>;
+			clock-frequency = <1500000000>;
+		};
 	};

The frequency of the EXTAL on APE6EVM machine is 26MHz, and the Generic Timers are clocked at EXTAL x1/2 (=13MHz). Do not copy-and-paste wrong clock-frequency properties currently we have, but fix cpu0 along with adding cpu1..3, please.

Furthermore you don't have (should not) to use clock-frequency property if you set up CNTFRQ to an appropriate value one by one in PATCH 05/05. --
Shinya Kuribayashi
Renesas Electronics

author maintainer
#3 lore raw

PATCH 2/5 ARM: shmobile: r8a73a4 CPU Hotplug prototype v1 (CA15 x 4)

In reply to Magnus Damm

From: Magnus Damm <[email protected]>

Add CPU Hotplug prototype support for 4 x Cortex-A15 included in r8a73a4.

Needs a rewrite to support more generic handling of CPU core power domains. Not ready for merge.

Not-yet-Signed-off-by Magnus Damm <[email protected]>

---

Developed and tested on top of v3.10-rc2, depends on "[PATCH] ARM: shmobile: r8a73a4 SMP prototype v1 (CA15 x 4)"

 arch/arm/mach-shmobile/smp-r8a73a4.c |   88 ++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)
arch/arm/mach-shmobile/smp-r8a73a4.c +88 -0
@@ -36,6 +36,8 @@
 
 #define APMU	0xe6150000
 #define CA15WUPCR 0x2010
+#define CA15PSTR 0x2040
+#define CA15CPUNCR(n) (0x2100 + (0x10 * (n))) 
 
 #define MERAM	0xe8080000
 #define CCI_BASE	0xf0190000
@@ -83,7 +85,93 @@ static int __cpuinit r8a73a4_boot_second
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int r8a73a4_cpu_kill(unsigned int cpu)
+{
+	void __iomem *p;
+	int ret = 0;
+	int k;
+
+	/* this function is running on another CPU than the offline target,
+	 * here all we need to do is to wait for the SoC to enter sleep mode.
+	 */
+	p = ioremap_nocache(APMU, 0x3000);
+	for (k = 0; k < 1000; k++) {
+		if (((__raw_readl(p + CA15PSTR) >> (cpu * 4)) & 0x03) == 3) {
+			ret = 1;
+			break;
+		}
+
+		mdelay(1);
+	}
+	iounmap(p);
+
+	return ret;
+}
+
+/* nicked from arch/arm/mach-exynos/hotplug.c */
+static inline void cpu_enter_lowpower_a15(void)
+{
+	unsigned int v;
+
+	asm volatile(
+	"	mrc	p15, 0, %0, c1, c0, 0\n"
+	"	bic	%0, %0, %1\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	  : "=&r" (v)
+	  : "Ir" (CR_C)
+	  : "cc");
+
+	flush_cache_louis();
+
+	asm volatile(
+	/*
+	* Turn off coherency
+	*/
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	bic	%0, %0, %1\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	: "=&r" (v)
+	: "Ir" (0x40)
+	: "cc");
+
+	isb();
+	dsb();
+}
+
+static int r8a73a4_do_idle_core_standby(unsigned long unused)
+{
+	cpu_do_idle(); /* WFI triggers Core Standby */
+	return 0;
+}
+
+static void r8a73a4_cpu_die(unsigned int cpu)
+{
+	void __iomem *p;
+
+	/* hardware shutdown code running on the CPU that is being offlined */
+
+	/* select CPU shutdown mode */
+	p = ioremap_nocache(APMU, 0x3000);
+	__raw_writel(3, p + CA15CPUNCR(cpu)); /* CA15 Core Standby */
+	iounmap(p);
+
+	cpu_enter_lowpower_a15();
+	cpu_suspend(0, r8a73a4_do_idle_core_standby); /* really needed? */
+}
+
+static int r8a73a4_cpu_disable(unsigned int cpu)
+{
+	return 0; /* hotplug of any CPU is tested OK */
+}
+#endif
+
 struct smp_operations r8a73a4_smp_ops __initdata = {
 	.smp_prepare_cpus	= r8a73a4_smp_prepare_cpus,
 	.smp_boot_secondary	= r8a73a4_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_kill		= r8a73a4_cpu_kill,
+	.cpu_die		= r8a73a4_cpu_die,
+	.cpu_disable		= r8a73a4_cpu_disable,
+#endif
 };
author maintainer
#4 lore raw

PATCH 3/5 ARM: shmobile: r8a73a4 CA15 setup WFE as NOP

In reply to Magnus Damm

From: Magnus Damm <[email protected]>

Configure CA15 included in r8a73a4 to treat WFE as NOP.

This works around hardware issue found in APE6, needed for CA7 cluster to work together with CA15 cluster.

Not-yet-Signed-off-by Magnus Damm <[email protected]>

---

 arch/arm/mach-shmobile/smp-r8a73a4.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
arch/arm/mach-shmobile/smp-r8a73a4.c +24 -0
@@ -45,6 +45,20 @@
 #define CCI_SNOOP	0x0000
 #define CCI_STATUS	0x000c
 
+static inline void r8a73a4_execute_wfe_as_nop(void)
+{
+	unsigned int v;
+
+	/* set bit 7 in ACTLR */
+	asm volatile(
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	orr	%0, %0, #0x40\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	  : "=&r" (v)
+	  :
+	  : "cc");
+}
+
 static void __init r8a73a4_smp_prepare_cpus(unsigned int max_cpus)
 {
 	u32 bar;
@@ -71,6 +85,8 @@ static void __init r8a73a4_smp_prepare_c
 	while (__raw_readl(p + CCI_STATUS))
 		/* wait for pending bit low */;
 	iounmap(p);
+
+	r8a73a4_execute_wfe_as_nop();
 }
 
 static int __cpuinit r8a73a4_boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -85,6 +101,13 @@ static int __cpuinit r8a73a4_boot_second
 	return 0;
 }
 
+static void __cpuinit r8a73a4_secondary_init(unsigned int cpu)
+{
+	/* CA15 need SW workaround */
+	if (cpu_logical_map(cpu) < 4)
+		r8a73a4_execute_wfe_as_nop();
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 static int r8a73a4_cpu_kill(unsigned int cpu)
 {
@@ -169,6 +192,7 @@ static int r8a73a4_cpu_disable(unsigned
 struct smp_operations r8a73a4_smp_ops __initdata = {
 	.smp_prepare_cpus	= r8a73a4_smp_prepare_cpus,
 	.smp_boot_secondary	= r8a73a4_boot_secondary,
+	.smp_secondary_init	= r8a73a4_secondary_init,
 #ifdef CONFIG_HOTPLUG_CPU
 	.cpu_kill		= r8a73a4_cpu_kill,
 	.cpu_die		= r8a73a4_cpu_die,
author maintainer
#5 lore raw

PATCH 4/5 ARM: shmobile: r8a73a4 SMP CA7 prototype (+ CA7 x 4)

In reply to Magnus Damm

From: Magnus Damm <[email protected]>

Prototype code to enable 4 x CA7 found in r8a73a4.

To test on APE6EVM boot with maxcpus=4 and use CPU Hotplug for boot and shut down. Not ready for merge.

Not-yet-Signed-off-by Magnus Damm <[email protected]>

---

 arch/arm/boot/dts/r8a73a4.dtsi       |   28 ++++++++++++++++++++++++++
 arch/arm/mach-shmobile/smp-r8a73a4.c |   36 +++++++++++++++++++++++++++++-----
 2 files changed, 59 insertions(+), 5 deletions(-)
arch/arm/boot/dts/r8a73a4.dtsi +28 -0
@@ -46,6 +46,34 @@
 			reg = <3>;
 			clock-frequency = <1500000000>;
 		};
+
+		cpu4: cpu at 4 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x100>;
+			clock-frequency = <1000000000>; 
+		};
+
+		cpu5: cpu at 5 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x101>;
+			clock-frequency = <1000000000>; 
+		};
+
+		cpu6: cpu at 6 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x102>;
+			clock-frequency = <1000000000>; 
+		};
+
+		cpu7: cpu at 7 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x103>;
+			clock-frequency = <1000000000>; 
+		};
 	};
 
 	gic: interrupt-controller at f1001000 {
arch/arm/mach-shmobile/smp-r8a73a4.c +31 -5
@@ -31,17 +31,22 @@
 #include <asm/smp_plat.h>
 
 #define SYSC	0xe6180000
+#define CA7BAR	0x4020
 #define CA15BAR	0x6020
 #define RESCNT	0x801c
 
 #define APMU	0xe6150000
+#define CA7WUPCR 0x1010
 #define CA15WUPCR 0x2010
+#define CA7PSTR	0x1040
 #define CA15PSTR 0x2040
+#define CA7CPUNCR(n) (0x1100 + (0x10 * (n))) 
 #define CA15CPUNCR(n) (0x2100 + (0x10 * (n))) 
 
 #define MERAM	0xe8080000
 #define CCI_BASE	0xf0190000
 #define CCI_SLAVE3	0x4000
+#define CCI_SLAVE4	0x5000
 #define CCI_SNOOP	0x0000
 #define CCI_STATUS	0x000c
 
@@ -75,13 +80,16 @@ static void __init r8a73a4_smp_prepare_c
 	p = ioremap_nocache(SYSC, 0x9000);
 	bar = (MERAM >> 8) & 0xfffffc00;
 	__raw_writel(bar, p + CA15BAR);
+	__raw_writel(bar, p + CA7BAR);
 	__raw_writel(bar | 0x10, p + CA15BAR);
+	__raw_writel(bar | 0x10, p + CA7BAR);
 	__raw_writel(__raw_readl(p + RESCNT) & ~(1 << 10), p + RESCNT);
 	iounmap(p);
 
 	/* enable snoop and DVM */
 	p = ioremap_nocache(CCI_BASE, 0x8000);
 	__raw_writel(3, p + CCI_SLAVE3 + CCI_SNOOP);	/* ca15 */
+	__raw_writel(3, p + CCI_SLAVE4 + CCI_SNOOP);	/* ca7 */
 	while (__raw_readl(p + CCI_STATUS))
 		/* wait for pending bit low */;
 	iounmap(p);
@@ -92,10 +100,14 @@ static void __init r8a73a4_smp_prepare_c
 static int __cpuinit r8a73a4_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
 	void __iomem *p;
+	int cluster_cpu = cpu_logical_map(cpu) & 3;
 
 	/* wake up CPU core */
 	p = ioremap_nocache(APMU, 0x3000);
-	__raw_writel(1 << (cpu_logical_map(cpu) & 3), p + CA15WUPCR);
+	if (cpu_logical_map(cpu) < 4) 
+		__raw_writel(1 << cluster_cpu, p + CA15WUPCR);
+	else
+		__raw_writel(1 << cluster_cpu, p + CA7WUPCR);
 	iounmap(p);
 
 	return 0;
@@ -112,6 +124,7 @@ static void __cpuinit r8a73a4_secondary_
 static int r8a73a4_cpu_kill(unsigned int cpu)
 {
 	void __iomem *p;
+	int offs;
 	int ret = 0;
 	int k;
 
@@ -120,9 +133,18 @@ static int r8a73a4_cpu_kill(unsigned int
 	 */
 	p = ioremap_nocache(APMU, 0x3000);
 	for (k = 0; k < 1000; k++) {
-		if (((__raw_readl(p + CA15PSTR) >> (cpu * 4)) & 0x03) == 3) {
-			ret = 1;
-			break;
+		if (cpu < 4) { /* CA15 Core Standby */
+			offs = cpu * 4;
+			if (((__raw_readl(p + CA15PSTR) >> offs) & 0x03) == 3) {
+				ret = 1;
+				break;
+			}
+		} else { /* CA7 Core Standby */
+			offs = (cpu - 4) * 4;
+			if (((__raw_readl(p + CA7PSTR) >> offs) & 0x03) == 3) {
+				ret = 1;
+				break;
+			}
 		}
 
 		mdelay(1);
@@ -176,7 +198,11 @@ static void r8a73a4_cpu_die(unsigned int
 
 	/* select CPU shutdown mode */
 	p = ioremap_nocache(APMU, 0x3000);
-	__raw_writel(3, p + CA15CPUNCR(cpu)); /* CA15 Core Standby */
+	if (cpu < 4)
+		__raw_writel(3, p + CA15CPUNCR(cpu)); /* CA15 Core Standby */
+	else
+		__raw_writel(3, p + CA7CPUNCR(cpu - 4)); /* CA7 Core Standby */
+
 	iounmap(p);
 
 	cpu_enter_lowpower_a15();
author maintainer
#6 lore raw

PATCH 5/5 ARM: shmobile: r8a73a4 CA7 setup arch timer

In reply to Magnus Damm

From: Magnus Damm <[email protected]>

Setup the CA7 arch timer in r8a73a4 at boot up. Thanks to Kevin Bracey at Renesas Mobile for initial implementation.

We need to discuss if some of this can be moved into the common arch timer driver or not. It may also need to be shared with R-Car H2. So this is not ready for merge.

Without this patch the interrupt count for the per-cpu arch timers for CA7 are stuck at zero.

Not-yet-Signed-off-by Magnus Damm <[email protected]>

---

 arch/arm/mach-shmobile/smp-r8a73a4.c |   37 +++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)
arch/arm/mach-shmobile/smp-r8a73a4.c +36 -1
@@ -50,6 +50,8 @@
 #define CCI_SNOOP	0x0000
 #define CCI_STATUS	0x000c
 
+#define CNTFID0	0xe6080020
+
 static inline void r8a73a4_execute_wfe_as_nop(void)
 {
 	unsigned int v;
@@ -64,6 +66,32 @@ static inline void r8a73a4_execute_wfe_a
 	  : "cc");
 }
 
+static u32 r8a73a4_arch_freq;
+
+static inline void r8a73a4_reset_arch_timer(void)
+{
+	/* Program CNTFRQ from the frequency table */
+	asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (r8a73a4_arch_freq));
+
+	/* CNTVOFF has to be initialized either from non-secure Hypervisor
+	 * mode or secure Monitor mode with SCR.NS==1. If TrustZone is enabled
+	 * then it should be handled by the secure code
+	 */
+	asm volatile(
+	"cps	0x16				@ Monitor mode"
+	"mrc	p15, 0, r1, c1, c1, 0"
+	"orr	r0, r1, #1			@ Set SCR.NS (non-secure)"
+	"mcr	p15, 0, r0, c1, c1, 0"
+	"isb"
+	"mov	r0, #0"
+	"mcrr	p15, 4, r0, r0, c14		@ CNTVOFF"
+	"isb"
+	"mcr	p15, 0, r1, c1, c1, 0		@ Restore SCR"
+	"isb"
+	"cps	0x13				@ Back to SVC mode"
+	: : : "r0", "r1");
+}
+
 static void __init r8a73a4_smp_prepare_cpus(unsigned int max_cpus)
 {
 	u32 bar;
@@ -94,6 +122,11 @@ static void __init r8a73a4_smp_prepare_c
 		/* wait for pending bit low */;
 	iounmap(p);
 
+	/* Retrieve frequency to be able to later program CNTFRQ */
+	p = ioremap_nocache(CNTFID0, 16);
+	r8a73a4_arch_freq = __raw_readl(p);
+	iounmap(p);
+
 	r8a73a4_execute_wfe_as_nop();
 }
 
@@ -115,9 +148,11 @@ static int __cpuinit r8a73a4_boot_second
 
 static void __cpuinit r8a73a4_secondary_init(unsigned int cpu)
 {
-	/* CA15 need SW workaround */
+	/* CA15 and CA7 need SW workaround */
 	if (cpu_logical_map(cpu) < 4)
 		r8a73a4_execute_wfe_as_nop();
+	else
+		r8a73a4_reset_arch_timer();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU