linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: sebastian.hesselbarth@gmail.com (Sebastian Hesselbarth)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 2/2] ARM: berlin: add SMP support
Date: Thu, 20 Mar 2014 21:39:46 +0100	[thread overview]
Message-ID: <1395347986-30203-3-git-send-email-sebastian.hesselbarth@gmail.com> (raw)
In-Reply-To: <1395347986-30203-1-git-send-email-sebastian.hesselbarth@gmail.com>

This adds SMP support to Marvell Berlin2 SoCs. Secondary CPUs boot into
BootROM, wait for interrupt, and read SW generic register 1 with actual
boot code address. Synchronization by holding pen is copied from
plat-versatile and mach-prima2.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
---
 arch/arm/mach-berlin/Kconfig   |   1 +
 arch/arm/mach-berlin/Makefile  |   1 +
 arch/arm/mach-berlin/berlin.c  |   3 +
 arch/arm/mach-berlin/common.h  |  18 ++++++
 arch/arm/mach-berlin/headsmp.S |  43 +++++++++++++
 arch/arm/mach-berlin/platsmp.c | 139 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 205 insertions(+)
 create mode 100644 arch/arm/mach-berlin/common.h
 create mode 100644 arch/arm/mach-berlin/headsmp.S
 create mode 100644 arch/arm/mach-berlin/platsmp.c

diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig
index 7a02d222c378..eecec99c3096 100644
--- a/arch/arm/mach-berlin/Kconfig
+++ b/arch/arm/mach-berlin/Kconfig
@@ -15,6 +15,7 @@ config MACH_BERLIN_BG2
 	bool "Marvell Armada 1500 (BG2)"
 	select CACHE_L2X0
 	select CPU_PJ4B
+	select HAVE_ARM_SCU if SMP
 	select HAVE_ARM_TWD if SMP
 	select HAVE_SMP
 
diff --git a/arch/arm/mach-berlin/Makefile b/arch/arm/mach-berlin/Makefile
index ab69fe956f49..e11b1b0be4dd 100644
--- a/arch/arm/mach-berlin/Makefile
+++ b/arch/arm/mach-berlin/Makefile
@@ -1 +1,2 @@
 obj-y += berlin.o
+obj-$(CONFIG_SMP)	+= platsmp.o headsmp.o
diff --git a/arch/arm/mach-berlin/berlin.c b/arch/arm/mach-berlin/berlin.c
index 025bcb5473eb..1bbca793174d 100644
--- a/arch/arm/mach-berlin/berlin.c
+++ b/arch/arm/mach-berlin/berlin.c
@@ -18,6 +18,8 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 
+#include "common.h"
+
 static void __init berlin_init_machine(void)
 {
 	/*
@@ -36,4 +38,5 @@ static const char * const berlin_dt_compat[] = {
 DT_MACHINE_START(BERLIN_DT, "Marvell Berlin")
 	.dt_compat	= berlin_dt_compat,
 	.init_machine	= berlin_init_machine,
+	.smp		= smp_ops(berlin_smp_ops),
 MACHINE_END
diff --git a/arch/arm/mach-berlin/common.h b/arch/arm/mach-berlin/common.h
new file mode 100644
index 000000000000..57c97669af0a
--- /dev/null
+++ b/arch/arm/mach-berlin/common.h
@@ -0,0 +1,18 @@
+/*
+ * Marvell Berlin SoCs common include.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ARCH_BERLIN_COMMON_H
+#define __ARCH_BERLIN_COMMON_H
+
+extern void berlin_secondary_startup(void);
+
+extern struct smp_operations berlin_smp_ops;
+
+#endif
diff --git a/arch/arm/mach-berlin/headsmp.S b/arch/arm/mach-berlin/headsmp.S
new file mode 100644
index 000000000000..bd187257fefd
--- /dev/null
+++ b/arch/arm/mach-berlin/headsmp.S
@@ -0,0 +1,43 @@
+/*
+ * linux/arch/arm/mach-berlin/headsmp.S
+ *
+ * Based on linux/arch/arm/mach-prima2/headsmp.S
+ *
+ * Copyright (c) 2003 ARM Limited
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+
+/*
+ * Entry point for secondary CPUs, this provides a "holding pen" into which
+ * all secondary cores are held until we're ready for them to initialise.
+ */
+ENTRY(berlin_secondary_startup)
+ ARM_BE8(setend be)
+	bl	v7_invalidate_l1
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #15
+	adr	r4, 1f
+	ldmia	r4, {r5, r6}
+	sub	r4, r4, r5
+	add	r6, r6, r4
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+ENDPROC(berlin_secondary_startup)
+
+	.align
+1:	.long	.
+	.long	pen_release
diff --git a/arch/arm/mach-berlin/platsmp.c b/arch/arm/mach-berlin/platsmp.c
new file mode 100644
index 000000000000..5c83941b0918
--- /dev/null
+++ b/arch/arm/mach-berlin/platsmp.c
@@ -0,0 +1,139 @@
+/*
+ * linux/arch/arm/mach-berlin/platsmp.c
+ *
+ * Based on linux/arch/arm/plat-versatile/platsmp.c
+ *
+ * Copyright (C) 2002 ARM Ltd.
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+#include "common.h"
+
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void write_pen_release(int val)
+{
+	pen_release = val;
+	/* write and flush pen_release to memory */
+	smp_wmb();
+	sync_cache_w(&pen_release);
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static void berlin_secondary_init(unsigned int cpu)
+{
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * This is really belt and braces; we hold unintended secondary
+	 * CPUs in the holding pen until we're ready for them.  However,
+	 * since we haven't sent them a soft interrupt, they shouldn't
+	 * be there.
+	 */
+	write_pen_release(cpu_logical_map(cpu));
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * the boot monitor to read the system wide flags register,
+	 * and branch to the address found there.
+	 */
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		/* pen_release SMP read barrier */
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
+
+static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
+{
+	struct device_node *np;
+	void __iomem *scu_base;
+	void __iomem *gpr_base;
+
+	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+	scu_base = of_iomap(np, 0);
+	of_node_put(np);
+	if (!scu_base)
+		return;
+
+	np = of_find_compatible_node(NULL, NULL, "marvell,berlin-generic-regs");
+	gpr_base = of_iomap(np, 0);
+	of_node_put(np);
+	if (!gpr_base) {
+		iounmap(scu_base);
+		return;
+	}
+
+	/*
+	 * Enable SCU and write the address of secondary startup into the
+	 * global SW generic register 1. The secondary CPU waits for an
+	 * interrupt and then branches to the address stored in the SW
+	 * generic register 1.
+	 */
+	scu_enable(scu_base);
+	writel(virt_to_phys(berlin_secondary_startup), gpr_base + 0x04);
+	iounmap(scu_base);
+	iounmap(gpr_base);
+}
+
+struct smp_operations berlin_smp_ops __initdata = {
+	.smp_prepare_cpus	= berlin_smp_prepare_cpus,
+	.smp_secondary_init	= berlin_secondary_init,
+	.smp_boot_secondary	= berlin_boot_secondary,
+};
-- 
1.9.0

  parent reply	other threads:[~2014-03-20 20:39 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-20 20:39 [PATCH 0/2] ARM: berlin: SMP support Sebastian Hesselbarth
2014-03-20 20:39 ` [PATCH 1/2] ARM: berlin: add scu and chipctrl device nodes for BG2/BG2Q Sebastian Hesselbarth
2014-03-20 23:33   ` Alexandre Belloni
2014-03-21  9:20   ` Antoine Ténart
2014-04-16 19:03   ` Sebastian Hesselbarth
2014-03-20 20:39 ` Sebastian Hesselbarth [this message]
2014-03-20 23:36   ` [PATCH 2/2] ARM: berlin: add SMP support Alexandre Belloni
2014-03-21  9:20   ` Antoine Ténart
2014-04-16 19:05   ` Sebastian Hesselbarth
2014-03-21  3:14 ` [PATCH 0/2] ARM: berlin: " Jisheng Zhang
2014-03-21  9:44   ` Ben Dooks

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1395347986-30203-3-git-send-email-sebastian.hesselbarth@gmail.com \
    --to=sebastian.hesselbarth@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).