From patchwork Sat Mar 23 12:57:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steffen Trumtrar X-Patchwork-Id: 2324651 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 5DA07DF215 for ; Sat, 23 Mar 2013 13:01:59 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UJO28-00073y-Ow; Sat, 23 Mar 2013 12:58:52 +0000 Received: from metis.ext.pengutronix.de ([2001:6f8:1178:4:290:27ff:fe1d:cc33]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UJO14-0006nt-GX for linux-arm-kernel@lists.infradead.org; Sat, 23 Mar 2013 12:57:49 +0000 Received: from dude.hi.pengutronix.de ([2001:6f8:1178:2:21e:67ff:fe11:9c5c]) by metis.ext.pengutronix.de with esmtp (Exim 4.72) (envelope-from ) id 1UJO12-0006Df-El; Sat, 23 Mar 2013 13:57:44 +0100 Received: from str by dude.hi.pengutronix.de with local (Exim 4.80) (envelope-from ) id 1UJO12-00054I-C4; Sat, 23 Mar 2013 13:57:44 +0100 From: Steffen Trumtrar To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 3/3] ARM: zynq: add SMP support Date: Sat, 23 Mar 2013 13:57:30 +0100 Message-Id: <1364043450-18700-4-git-send-email-s.trumtrar@pengutronix.de> X-Mailer: git-send-email 1.8.2.rc2 In-Reply-To: <1364043450-18700-1-git-send-email-s.trumtrar@pengutronix.de> References: <1364043450-18700-1-git-send-email-s.trumtrar@pengutronix.de> X-SA-Exim-Connect-IP: 2001:6f8:1178:2:21e:67ff:fe11:9c5c X-SA-Exim-Mail-From: str@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-arm-kernel@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130323_085747_044267_7E478793 X-CRM114-Status: GOOD ( 22.42 ) X-Spam-Score: -4.4 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.5 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Steffen Trumtrar , Michal Simek X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org The Zynq7000 has a CortexA9 with at least 2 cores. Add support to boot them all. To do this a trampoline is needed. At runtime the jump address and two instructions are copied to RAM by CPU0 and then executed by CPU1. Signed-off-by: Steffen Trumtrar Cc: Michal Simek --- arch/arm/boot/dts/zynq-7000.dtsi | 14 +++++ arch/arm/mach-zynq/Makefile | 2 + arch/arm/mach-zynq/common.c | 1 + arch/arm/mach-zynq/common.h | 14 +++++ arch/arm/mach-zynq/headsmp.S | 20 +++++++ arch/arm/mach-zynq/platsmp.c | 110 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 161 insertions(+) create mode 100644 arch/arm/mach-zynq/headsmp.S create mode 100644 arch/arm/mach-zynq/platsmp.c diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index c103082..258b6c9 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -15,6 +15,20 @@ / { compatible = "xlnx,zynq-7000"; + cpus { + cpu@0 { + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + clocks = <&armpll 0>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + clocks = <&armpll 0>; + }; + }; + amba { compatible = "simple-bus"; #address-cells = <1>; diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile index 397268c..906d199 100644 --- a/arch/arm/mach-zynq/Makefile +++ b/arch/arm/mach-zynq/Makefile @@ -4,3 +4,5 @@ # Common support obj-y := common.o timer.o +AFLAGS_headsmp.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SMP) += headsmp.o platsmp.o diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 1b9bb3d..4053962 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -117,6 +117,7 @@ static const char *xilinx_dt_match[] = { }; MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") + .smp = smp_ops(zynq_smp_ops), .map_io = xilinx_map_io, .init_irq = xilinx_irqchip_init, .init_machine = xilinx_init_machine, diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 8b4dbba..451d386 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -19,4 +19,18 @@ void __init xttcps_timer_init(void); +#ifdef CONFIG_SMP +extern void secondary_startup(void); +extern char secondary_trampoline, secondary_trampoline_end; +#endif + +extern struct smp_operations __initdata zynq_smp_ops; +extern void __iomem *slcr_base_addr; +extern void __iomem *scu_base; + +#define SLCR_UNLOCK_MAGIC 0xdf0d + +#define SLCR_UNLOCK 0x8 +#define SLCR_A9_CPU_RST_CTRL 0x244 + #endif diff --git a/arch/arm/mach-zynq/headsmp.S b/arch/arm/mach-zynq/headsmp.S new file mode 100644 index 0000000..145bbae --- /dev/null +++ b/arch/arm/mach-zynq/headsmp.S @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2013 Steffen Trumtrar + * + * based on mach-socfpga/headsmp.S + * + * 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 +#include + + __CPUINIT + .arch armv7-a + +ENTRY(secondary_trampoline) + ldr r0, [pc] + mov pc, r0 + +ENTRY(secondary_trampoline_end) diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c new file mode 100644 index 0000000..1ea3d4f --- /dev/null +++ b/arch/arm/mach-zynq/platsmp.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013 Steffen Trumtrar + * + * based on + * linux/arch/arm/mach-zynq/platsmp.c Copyright (C) 2011 Xilinx + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "common.h" + +#define A9_RST_MASK (1 << 0) +#define A9_CLKSTOP_MASK (1 << 4) + +static DEFINE_SPINLOCK(boot_lock); + +static void __cpuinit zynq_smp_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +static inline void zynq_set_cpu_jump(int cpu, void *jump_addr) +{ + if (jump_addr) { + int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; + + writel(virt_to_phys(jump_addr), phys_to_virt(8)); + memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); + + flush_cache_all(); + outer_flush_all(); + smp_wmb(); + } +} + +static void zynq_enable_cpu(int cpu, bool enable) +{ + writel(A9_CLKSTOP_MASK << cpu, slcr_base_addr + SLCR_A9_CPU_RST_CTRL); + writel(0, slcr_base_addr + SLCR_A9_CPU_RST_CTRL); +} + +int __cpuinit zynq_smp_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + writel(SLCR_UNLOCK_MAGIC, slcr_base_addr + SLCR_UNLOCK); + writel((A9_CLKSTOP_MASK | A9_RST_MASK) << cpu, + slcr_base_addr + SLCR_A9_CPU_RST_CTRL); + + zynq_set_cpu_jump(cpu, secondary_startup); + zynq_enable_cpu(cpu, true); + + return 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +static void __init zynq_smp_init_cpus(void) +{ + unsigned int ncores, i; + + ncores = scu_get_core_count(scu_base); + + for (i = 0; i < ncores; ++i) + set_cpu_possible(i, true); + + /* sanity check */ + if (ncores > num_possible_cpus()) { + pr_warn("zynq: no. of cores (%d) greater than configured" + "maximum of %d - clipping\n", ncores, num_possible_cpus()); + ncores = num_possible_cpus(); + } +} + +static void __init zynq_smp_prepare_cpus(unsigned int max_cpus) +{ + scu_enable(scu_base); +} + +struct smp_operations __initdata zynq_smp_ops = { + .smp_init_cpus = zynq_smp_init_cpus, + .smp_prepare_cpus = zynq_smp_prepare_cpus, + .smp_secondary_init = zynq_smp_secondary_init, + .smp_boot_secondary = zynq_smp_boot_secondary, +};