diff mbox

[RESEND,2/3] ARM: Meson6: Add SMP support for Amlogic Meson6

Message ID 1415982353-9293-3-git-send-email-carlo@caione.org (mailing list archive)
State New, archived
Headers show

Commit Message

Carlo Caione Nov. 14, 2014, 4:25 p.m. UTC
Amlogic Meson6 is a dual core Cortex-A9. This patch adds the logic to
boot up the second CPU.

Signed-off-by: Carlo Caione <carlo@caione.org>
---
 arch/arm/mach-meson/Kconfig   |  1 +
 arch/arm/mach-meson/Makefile  |  1 +
 arch/arm/mach-meson/headsmp.S |  7 ++++
 arch/arm/mach-meson/platsmp.c | 80 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 89 insertions(+)
 create mode 100644 arch/arm/mach-meson/headsmp.S
 create mode 100644 arch/arm/mach-meson/platsmp.c

Comments

Arnd Bergmann Nov. 24, 2014, 3:20 p.m. UTC | #1
On Friday 14 November 2014, Carlo Caione wrote:

> +static void __iomem *cpucfg_membase;
> +static void __iomem *scu_membase;

I don't think you need a global scu_membase variable, you use it only in
one function.

> +static DEFINE_SPINLOCK(cpu_lock);
> +
> +extern void meson_secondary_startup(void);

Better put the extern declaration into a header file.

> +static void __init meson6_smp_prepare_cpus(unsigned int max_cpus)
> +{
> +	struct device_node *node;
> +
> +	node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
> +	if (!node) {
> +		pr_err("Missing Meson6 SCU node\n");
> +		return;
> +	}
> +
> +	scu_membase = of_iomap(node, 0);
> +	if (!scu_membase) {
> +		pr_err("Couln't map Meson6 SCU registers\n");
> +		return;
> +	}
> +
> +	node = of_find_compatible_node(NULL, NULL, "amlogic,meson6-cpuconfig");
> +	if (!node) {
> +		pr_err("Missing Meson6 CPU config node\n");
> +		return;
> +	}

I'm not sure about the "amlogic,meson6-cpuconfig" device node. Since this
is just an 8-byte register range, I suspect it's actually part of a larger
device, so you should better represent that instead. We can now have
early "syscon" devices (in linux-next I think), so you could instead make
this a device that is compatible with "syscon" and have the smp code
look that up and apply an appropriate offset. Do you have an idea of
which device this is part of?

	Arnd
diff mbox

Patch

diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index 2c1154e..4e96de4 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -2,6 +2,7 @@  menuconfig ARCH_MESON
 	bool "Amlogic Meson SoCs" if ARCH_MULTI_V7
 	select GENERIC_IRQ_CHIP
 	select ARM_GIC
+	select HAVE_ARM_SCU if SMP
 
 if ARCH_MESON
 
diff --git a/arch/arm/mach-meson/Makefile b/arch/arm/mach-meson/Makefile
index 9d7380e..4691966 100644
--- a/arch/arm/mach-meson/Makefile
+++ b/arch/arm/mach-meson/Makefile
@@ -1 +1,2 @@ 
 obj-$(CONFIG_ARCH_MESON) += meson.o
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o
diff --git a/arch/arm/mach-meson/headsmp.S b/arch/arm/mach-meson/headsmp.S
new file mode 100644
index 0000000..3347d88
--- /dev/null
+++ b/arch/arm/mach-meson/headsmp.S
@@ -0,0 +1,7 @@ 
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ENTRY(meson_secondary_startup)
+        bl	v7_invalidate_l1
+        b       secondary_startup
+ENDPROC(meson_secondary_startup)
diff --git a/arch/arm/mach-meson/platsmp.c b/arch/arm/mach-meson/platsmp.c
new file mode 100644
index 0000000..3d4d0cd
--- /dev/null
+++ b/arch/arm/mach-meson/platsmp.c
@@ -0,0 +1,80 @@ 
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
+#include <asm/cacheflush.h>
+
+#define MESON_CPU_CONTROL_REG		0x0
+#define MESON_CPU1_CONTROL_ADDR_REG	0x4
+
+#define MESON_CPU_CONTROL_ID(cpu)	((1 << (cpu)) | 1)
+
+static void __iomem *cpucfg_membase;
+static void __iomem *scu_membase;
+
+static DEFINE_SPINLOCK(cpu_lock);
+
+extern void meson_secondary_startup(void);
+
+static void __init meson6_smp_prepare_cpus(unsigned int max_cpus)
+{
+	struct device_node *node;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+	if (!node) {
+		pr_err("Missing Meson6 SCU node\n");
+		return;
+	}
+
+	scu_membase = of_iomap(node, 0);
+	if (!scu_membase) {
+		pr_err("Couln't map Meson6 SCU registers\n");
+		return;
+	}
+
+	node = of_find_compatible_node(NULL, NULL, "amlogic,meson6-cpuconfig");
+	if (!node) {
+		pr_err("Missing Meson6 CPU config node\n");
+		return;
+	}
+
+	cpucfg_membase = of_iomap(node, 0);
+	if (!cpucfg_membase) {
+		pr_err("Couldn't map Meson6 CPU config registers\n");
+		return;
+	}
+
+	scu_enable(scu_membase);
+}
+
+static int meson6_smp_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	if (!cpucfg_membase)
+		return -EFAULT;
+
+	spin_lock(&cpu_lock);
+
+	writel(virt_to_phys(meson_secondary_startup), cpucfg_membase +
+		MESON_CPU1_CONTROL_ADDR_REG);
+	writel(MESON_CPU_CONTROL_ID(cpu), cpucfg_membase +
+		MESON_CPU_CONTROL_REG);
+
+	smp_wmb();
+
+	dsb_sev();
+
+	spin_unlock(&cpu_lock);
+
+	return 0;
+}
+
+static struct smp_operations meson6_smp_ops __initdata = {
+	.smp_prepare_cpus	= meson6_smp_prepare_cpus,
+	.smp_boot_secondary	= meson6_smp_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(meson6_smp, "amlogic,meson6-smp", &meson6_smp_ops);