From: Hauke Mehrtens Date: Wed, 2 Dec 2015 15:23:08 +0000 (+0000) Subject: bcm53xx: update SMP patches X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=73e17aa5995b25afe7dd99a1c3297d879fdb57f8;p=openwrt%2Fsvn-archive%2Farchive.git bcm53xx: update SMP patches Broadcom submitted new SMP patches for this SoC to upstream Linux, add them to OpenWrt. Signed-off-by: Hauke Mehrtens SVN-Revision: 47687 --- diff --git a/target/linux/bcm53xx/patches-4.1/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.1/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch deleted file mode 100644 index 5e3bd7793d..0000000000 --- a/target/linux/bcm53xx/patches-4.1/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch +++ /dev/null @@ -1,635 +0,0 @@ -From a0ad1511d5805b95ac4c454d7904c670a1696055 Mon Sep 17 00:00:00 2001 -From: Kapil Hali -Date: Wed, 14 Oct 2015 13:47:00 -0400 -Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom NSP - -Add SMP support for Broadcom's Northstar Plus SoC, -cpu enable method and pen_release procedures. This -changes also consolidates iProc family's - BCM NSP -and BCM Kona, SMP handling in a common file. - -Northstar Plus SoC is based on ARM Cortex-A9 -revision r3p0 which requires configuration for ARM -Errata 764369 for SMP. This change adds the needed -configuration option. - -Signed-off-by: Kapil Hali ---- - arch/arm/mach-bcm/Makefile | 2 +- - arch/arm/mach-bcm/bcm_nsp.h | 19 +++ - arch/arm/mach-bcm/headsmp.S | 37 +++++ - arch/arm/mach-bcm/kona_smp.c | 202 --------------------------- - arch/arm/mach-bcm/platsmp.c | 326 +++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 383 insertions(+), 203 deletions(-) - create mode 100644 arch/arm/mach-bcm/bcm_nsp.h - create mode 100644 arch/arm/mach-bcm/headsmp.S - delete mode 100644 arch/arm/mach-bcm/kona_smp.c - create mode 100644 arch/arm/mach-bcm/platsmp.c - ---- a/arch/arm/mach-bcm/Makefile -+++ b/arch/arm/mach-bcm/Makefile -@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc - obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o - - # BCM281XX and BCM21664 SMP support --obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o -+obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o - - # BCM281XX and BCM21664 L2 cache control - obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o ---- /dev/null -+++ b/arch/arm/mach-bcm/bcm_nsp.h -@@ -0,0 +1,19 @@ -+/* -+ * Copyright (C) 2015 Broadcom Corporation -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __BCM_NSP_H -+#define __BCM_NSP_H -+ -+extern void nsp_secondary_startup(void); -+ -+#endif /* __BCM_NSP_H */ ---- /dev/null -+++ b/arch/arm/mach-bcm/headsmp.S -@@ -0,0 +1,37 @@ -+/* -+ * Copyright (C) 2015 Broadcom Corporation -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+ -+/* -+ * iProc specific entry point for secondary CPUs. This provides -+ * a "holding pen" into which all secondary cores are held until -+ * we are ready for them to initialise. -+ */ -+ENTRY(nsp_secondary_startup) -+ 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 -+ -+ b secondary_startup -+ -+1: .long . -+ .long pen_release -+ -+ENDPROC(nsp_secondary_startup) ---- a/arch/arm/mach-bcm/kona_smp.c -+++ /dev/null -@@ -1,202 +0,0 @@ --/* -- * Copyright (C) 2014 Broadcom Corporation -- * Copyright 2014 Linaro Limited -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License as -- * published by the Free Software Foundation version 2. -- * -- * This program is distributed "as is" WITHOUT ANY WARRANTY of any -- * kind, whether express or implied; without even the implied warranty -- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- */ -- --#include --#include --#include --#include --#include -- --#include --#include --#include -- --/* Size of mapped Cortex A9 SCU address space */ --#define CORTEX_A9_SCU_SIZE 0x58 -- --#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ --#define BOOT_ADDR_CPUID_MASK 0x3 -- --/* Name of device node property defining secondary boot register location */ --#define OF_SECONDARY_BOOT "secondary-boot-reg" -- --/* I/O address of register used to coordinate secondary core startup */ --static u32 secondary_boot; -- --/* -- * Enable the Cortex A9 Snoop Control Unit -- * -- * By the time this is called we already know there are multiple -- * cores present. We assume we're running on a Cortex A9 processor, -- * so any trouble getting the base address register or getting the -- * SCU base is a problem. -- * -- * Return 0 if successful or an error code otherwise. -- */ --static int __init scu_a9_enable(void) --{ -- unsigned long config_base; -- void __iomem *scu_base; -- -- if (!scu_a9_has_base()) { -- pr_err("no configuration base address register!\n"); -- return -ENXIO; -- } -- -- /* Config base address register value is zero for uniprocessor */ -- config_base = scu_a9_get_base(); -- if (!config_base) { -- pr_err("hardware reports only one core\n"); -- return -ENOENT; -- } -- -- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); -- if (!scu_base) { -- pr_err("failed to remap config base (%lu/%u) for SCU\n", -- config_base, CORTEX_A9_SCU_SIZE); -- return -ENOMEM; -- } -- -- scu_enable(scu_base); -- -- iounmap(scu_base); /* That's the last we'll need of this */ -- -- return 0; --} -- --static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) --{ -- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; -- struct device_node *node; -- int ret; -- -- BUG_ON(secondary_boot); /* We're called only once */ -- -- /* -- * This function is only called via smp_ops->smp_prepare_cpu(). -- * That only happens if a "/cpus" device tree node exists -- * and has an "enable-method" property that selects the SMP -- * operations defined herein. -- */ -- node = of_find_node_by_path("/cpus"); -- BUG_ON(!node); -- -- /* -- * Our secondary enable method requires a "secondary-boot-reg" -- * property to specify a register address used to request the -- * ROM code boot a secondary code. If we have any trouble -- * getting this we fall back to uniprocessor mode. -- */ -- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { -- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", -- node->name); -- ret = -ENOENT; /* Arrange to disable SMP */ -- goto out; -- } -- -- /* -- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is -- * returned, the SoC reported a uniprocessor configuration. -- * We bail on any other error. -- */ -- ret = scu_a9_enable(); --out: -- of_node_put(node); -- if (ret) { -- /* Update the CPU present map to reflect uniprocessor mode */ -- BUG_ON(ret != -ENOENT); -- pr_warn("disabling SMP\n"); -- init_cpu_present(&only_cpu_0); -- } --} -- --/* -- * The ROM code has the secondary cores looping, waiting for an event. -- * When an event occurs each core examines the bottom two bits of the -- * secondary boot register. When a core finds those bits contain its -- * own core id, it performs initialization, including computing its boot -- * address by clearing the boot register value's bottom two bits. The -- * core signals that it is beginning its execution by writing its boot -- * address back to the secondary boot register, and finally jumps to -- * that address. -- * -- * So to start a core executing we need to: -- * - Encode the (hardware) CPU id with the bottom bits of the secondary -- * start address. -- * - Write that value into the secondary boot register. -- * - Generate an event to wake up the secondary CPU(s). -- * - Wait for the secondary boot register to be re-written, which -- * indicates the secondary core has started. -- */ --static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) --{ -- void __iomem *boot_reg; -- phys_addr_t boot_func; -- u64 start_clock; -- u32 cpu_id; -- u32 boot_val; -- bool timeout = false; -- -- cpu_id = cpu_logical_map(cpu); -- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { -- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); -- return -EINVAL; -- } -- -- if (!secondary_boot) { -- pr_err("required secondary boot register not specified\n"); -- return -EINVAL; -- } -- -- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); -- if (!boot_reg) { -- pr_err("unable to map boot register for cpu %u\n", cpu_id); -- return -ENOSYS; -- } -- -- /* -- * Secondary cores will start in secondary_startup(), -- * defined in "arch/arm/kernel/head.S" -- */ -- boot_func = virt_to_phys(secondary_startup); -- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); -- BUG_ON(boot_func > (phys_addr_t)U32_MAX); -- -- /* The core to start is encoded in the low bits */ -- boot_val = (u32)boot_func | cpu_id; -- writel_relaxed(boot_val, boot_reg); -- -- sev(); -- -- /* The low bits will be cleared once the core has started */ -- start_clock = local_clock(); -- while (!timeout && readl_relaxed(boot_reg) == boot_val) -- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; -- -- iounmap(boot_reg); -- -- if (!timeout) -- return 0; -- -- pr_err("timeout waiting for cpu %u to start\n", cpu_id); -- -- return -ENOSYS; --} -- --static struct smp_operations bcm_smp_ops __initdata = { -- .smp_prepare_cpus = bcm_smp_prepare_cpus, -- .smp_boot_secondary = bcm_boot_secondary, --}; --CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", -- &bcm_smp_ops); ---- /dev/null -+++ b/arch/arm/mach-bcm/platsmp.c -@@ -0,0 +1,326 @@ -+/* -+ * Copyright (C) 2014-2015 Broadcom Corporation -+ * Copyright 2014 Linaro Limited -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "bcm_nsp.h" -+ -+/* Size of mapped Cortex A9 SCU address space */ -+#define CORTEX_A9_SCU_SIZE 0x58 -+ -+#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ -+#define BOOT_ADDR_CPUID_MASK 0x3 -+ -+/* Name of device node property defining secondary boot register location */ -+#define OF_SECONDARY_BOOT "secondary-boot-reg" -+ -+/* I/O address of register used to coordinate secondary core startup */ -+static u32 secondary_boot; -+ -+static DEFINE_SPINLOCK(boot_lock); -+ -+/* -+ * 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; -+ /* -+ * Ensure write to pen_release is visible to the other cores, -+ * here - primary core -+ */ -+ smp_wmb(); -+ sync_cache_w(&pen_release); -+} -+ -+/* -+ * Enable the Cortex A9 Snoop Control Unit -+ * -+ * By the time this is called we already know there are multiple -+ * cores present. We assume we're running on a Cortex A9 processor, -+ * so any trouble getting the base address register or getting the -+ * SCU base is a problem. -+ * -+ * Return 0 if successful or an error code otherwise. -+ */ -+static int __init scu_a9_enable(void) -+{ -+ unsigned long config_base; -+ void __iomem *scu_base; -+ -+ if (!scu_a9_has_base()) { -+ pr_err("no configuration base address register!\n"); -+ return -ENXIO; -+ } -+ -+ /* Config base address register value is zero for uniprocessor */ -+ config_base = scu_a9_get_base(); -+ if (!config_base) { -+ pr_err("hardware reports only one core\n"); -+ return -ENOENT; -+ } -+ -+ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); -+ if (!scu_base) { -+ pr_err("failed to remap config base (%lu/%u) for SCU\n", -+ config_base, CORTEX_A9_SCU_SIZE); -+ return -ENOMEM; -+ } -+ -+ scu_enable(scu_base); -+ -+ iounmap(scu_base); /* That's the last we'll need of this */ -+ -+ return 0; -+} -+ -+static int nsp_write_lut(void (*secondary_startup) (void)) -+{ -+ void __iomem *sku_rom_lut; -+ phys_addr_t secondary_startup_phy; -+ -+ if (!secondary_boot) { -+ pr_warn("required secondary boot register not specified\n"); -+ return -EINVAL; -+ } -+ -+ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot, -+ sizeof(secondary_boot)); -+ if (!sku_rom_lut) { -+ pr_warn("unable to ioremap SKU-ROM LUT register\n"); -+ return -ENOMEM; -+ } -+ -+ secondary_startup_phy = virt_to_phys(secondary_startup); -+ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); -+ -+ writel_relaxed(secondary_startup_phy, sku_rom_lut); -+ /* -+ * Ensure the write is visible to the secondary core. -+ */ -+ smp_wmb(); -+ -+ iounmap(sku_rom_lut); -+ -+ return 0; -+} -+ -+static void nsp_secondary_init(unsigned int cpu) -+{ -+ /* -+ * Let the primary cpu know we are out of holding pen. -+ */ -+ write_pen_release(-1); -+ -+ /* -+ * Synchronise with the boot thread. -+ */ -+ spin_lock(&boot_lock); -+ spin_unlock(&boot_lock); -+} -+ -+static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) -+{ -+ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; -+ struct device_node *node; -+ int ret; -+ -+ BUG_ON(secondary_boot); /* We're called only once */ -+ -+ /* -+ * This function is only called via smp_ops->smp_prepare_cpu(). -+ * That only happens if a "/cpus" device tree node exists -+ * and has an "enable-method" property that selects the SMP -+ * operations defined herein. -+ */ -+ node = of_find_node_by_path("/cpus"); -+ BUG_ON(!node); -+ -+ /* -+ * Our secondary enable method requires a "secondary-boot-reg" -+ * property to specify a register address used to request the -+ * ROM code boot a secondary core. If we have any trouble -+ * getting this we fall back to uniprocessor mode. -+ */ -+ if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { -+ pr_warn("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", -+ node->name); -+ ret = -ENOENT; /* Arrange to disable SMP */ -+ goto out; -+ } -+ -+ /* -+ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is -+ * returned, the SoC reported a uniprocessor configuration. -+ * We bail on any other error. -+ */ -+ ret = scu_a9_enable(); -+out: -+ of_node_put(node); -+ if (ret) { -+ /* Update the CPU present map to reflect uniprocessor mode */ -+ pr_warn("disabling SMP\n"); -+ init_cpu_present(&only_cpu_0); -+ } -+} -+ -+/* -+ * The ROM code has the secondary cores looping, waiting for an event. -+ * When an event occurs each core examines the bottom two bits of the -+ * secondary boot register. When a core finds those bits contain its -+ * own core id, it performs initialization, including computing its boot -+ * address by clearing the boot register value's bottom two bits. The -+ * core signals that it is beginning its execution by writing its boot -+ * address back to the secondary boot register, and finally jumps to -+ * that address. -+ * -+ * So to start a core executing we need to: -+ * - Encode the (hardware) CPU id with the bottom bits of the secondary -+ * start address. -+ * - Write that value into the secondary boot register. -+ * - Generate an event to wake up the secondary CPU(s). -+ * - Wait for the secondary boot register to be re-written, which -+ * indicates the secondary core has started. -+ */ -+static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) -+{ -+ void __iomem *boot_reg; -+ phys_addr_t boot_func; -+ u64 start_clock; -+ u32 cpu_id; -+ u32 boot_val; -+ bool timeout = false; -+ -+ cpu_id = cpu_logical_map(cpu); -+ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { -+ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); -+ return -EINVAL; -+ } -+ -+ if (!secondary_boot) { -+ pr_err("required secondary boot register not specified\n"); -+ return -EINVAL; -+ } -+ -+ boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); -+ if (!boot_reg) { -+ pr_err("unable to map boot register for cpu %u\n", cpu_id); -+ return -ENOMEM; -+ } -+ -+ /* -+ * Secondary cores will start in secondary_startup(), -+ * defined in "arch/arm/kernel/head.S" -+ */ -+ boot_func = virt_to_phys(secondary_startup); -+ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); -+ BUG_ON(boot_func > (phys_addr_t)U32_MAX); -+ -+ /* The core to start is encoded in the low bits */ -+ boot_val = (u32)boot_func | cpu_id; -+ writel_relaxed(boot_val, boot_reg); -+ -+ sev(); -+ -+ /* The low bits will be cleared once the core has started */ -+ start_clock = local_clock(); -+ while (!timeout && readl_relaxed(boot_reg) == boot_val) -+ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; -+ -+ iounmap(boot_reg); -+ -+ if (!timeout) -+ return 0; -+ -+ pr_err("timeout waiting for cpu %u to start\n", cpu_id); -+ -+ return -ENXIO; -+} -+ -+static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) -+{ -+ unsigned long timeout; -+ int ret; -+ -+ /* -+ * After wake up, secondary core branches to the startup -+ * address programmed at SKU ROM LUT location. -+ */ -+ ret = nsp_write_lut(nsp_secondary_startup); -+ if (ret) { -+ pr_err("unable to write startup addr to SKU ROM LUT\n"); -+ goto out; -+ } -+ -+ /* -+ * The secondary processor is waiting to be released from -+ * the holding pen - release it, then wait for it to flag -+ * that it has been released by resetting pen_release. -+ */ -+ spin_lock(&boot_lock); -+ -+ write_pen_release(cpu_logical_map(cpu)); -+ /* -+ * Send an Event to wake up the secondary core which is in -+ * WFE state. Updated pen_release should also be visible to -+ * the secondary core. -+ */ -+ dsb_sev(); -+ -+ timeout = jiffies + (1 * HZ); -+ while (time_before(jiffies, timeout)) { -+ /* Make sure loads on other CPU is visible */ -+ smp_rmb(); -+ if (pen_release == -1) -+ break; -+ -+ udelay(10); -+ } -+ -+ spin_unlock(&boot_lock); -+ -+ ret = pen_release != -1 ? -ENXIO : 0; -+ -+out: -+ return ret; -+} -+ -+static struct smp_operations bcm_smp_ops __initdata = { -+ .smp_prepare_cpus = bcm_smp_prepare_cpus, -+ .smp_boot_secondary = kona_boot_secondary, -+}; -+CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", -+ &bcm_smp_ops); -+ -+struct smp_operations nsp_smp_ops __initdata = { -+ .smp_prepare_cpus = bcm_smp_prepare_cpus, -+ .smp_secondary_init = nsp_secondary_init, -+ .smp_boot_secondary = nsp_boot_secondary, -+}; -+CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.1/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.1/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch new file mode 100644 index 0000000000..ce002a29da --- /dev/null +++ b/target/linux/bcm53xx/patches-4.1/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch @@ -0,0 +1,69 @@ +From 204b9dbd7c4bd5a223fd104b9cba56c12fe04add Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Wed, 19 Aug 2015 13:42:23 -0400 +Subject: [PATCH 130/134] dt-bindings: add SMP enable-method for Broadcom NSP + +Add a compatible string "brcm,bcm-nsp-smp" for Broadcom's +Northstar Plus CPU to the 32-bit ARM CPU device tree binding +documentation file and create a new binding documentation for +Northstar Plus CPU. + +Signed-off-by: Kapil Hali +--- + .../bindings/arm/bcm/brcm,nsp-cpu-method.txt | 39 ++++++++++++++++++++++ + Documentation/devicetree/bindings/arm/cpus.txt | 1 + + 2 files changed, 40 insertions(+) + create mode 100644 Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt +@@ -0,0 +1,39 @@ ++Broadcom Northstar Plus SoC CPU Enable Method ++--------------------------------------------- ++This binding defines the enable method used for starting secondary ++CPUs in the following Broadcom SoCs: ++ BCM58522, BCM58525, BCM58535, BCM58622, BCM58623, BCM58625, BCM88312 ++ ++The enable method is specified by defining the following required ++properties in the "cpus" device tree node: ++ - enable-method = "brcm,bcm-nsp-smp"; ++ - secondary-boot-reg = <...>; ++ ++The secondary-boot-reg property is a u32 value that specifies the ++physical address of the register which should hold the common ++entry point for a secondary CPU. This entry is cpu node specific ++and should be added per cpu. E.g., in case of NSP (BCM58625) which ++is a dual core CPU SoC, this entry should be added to cpu1 node. ++ ++ ++Example: ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm-nsp-smp"; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ next-level-cache = <&L2>; ++ reg = <0>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ next-level-cache = <&L2>; ++ reg = <1>; ++ secondary-boot-reg = <0xffff042c>; ++ }; ++ }; +--- a/Documentation/devicetree/bindings/arm/cpus.txt ++++ b/Documentation/devicetree/bindings/arm/cpus.txt +@@ -189,6 +189,7 @@ nodes to be present and contain the prop + can be one of: + "allwinner,sun6i-a31" + "arm,psci" ++ "brcm,bcm-nsp-smp" + "brcm,brahma-b15" + "marvell,armada-375-smp" + "marvell,armada-380-smp" diff --git a/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch deleted file mode 100644 index a23aa5df36..0000000000 --- a/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch +++ /dev/null @@ -1,49 +0,0 @@ -From ddbf0ad85be06948dd214c7beb7b315ef2749e65 Mon Sep 17 00:00:00 2001 -From: Jon Mason -Date: Thu, 15 Oct 2015 14:14:10 -0400 -Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom 4708 - -ARM: BCM: Add SMP support for Broadcom 4708 - -Add SMP support for Broadcom's 4708 SoCs. - -Signed-off-by: Jon Mason ---- - arch/arm/boot/dts/bcm4708.dtsi | 2 ++ - arch/arm/mach-bcm/Kconfig | 2 ++ - arch/arm/mach-bcm/Makefile | 3 +++ - 3 files changed, 7 insertions(+) - ---- a/arch/arm/boot/dts/bcm4708.dtsi -+++ b/arch/arm/boot/dts/bcm4708.dtsi -@@ -15,6 +15,8 @@ - cpus { - #address-cells = <1>; - #size-cells = <0>; -+ enable-method = "brcm,bcm-nsp-smp"; -+ secondary-boot-reg = <0xffff0400>; - - cpu@0 { - device_type = "cpu"; ---- a/arch/arm/mach-bcm/Kconfig -+++ b/arch/arm/mach-bcm/Kconfig -@@ -41,6 +41,7 @@ config ARCH_BCM_5301X - select ARM_ERRATA_754322 - select ARM_ERRATA_775420 - select ARM_ERRATA_764369 if SMP -+ select HAVE_SMP - - help - Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. ---- a/arch/arm/mach-bcm/Makefile -+++ b/arch/arm/mach-bcm/Makefile -@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2 - - # BCM5301X - obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o -+ifeq ($(CONFIG_ARCH_BCM_5301X),y) -+obj-$(CONFIG_SMP) += headsmp.o platsmp.o -+endif - - # BCM63XXx - obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o diff --git a/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch b/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch new file mode 100644 index 0000000000..7a48a13e64 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch @@ -0,0 +1,206 @@ +From 8622d6da5d95293d474c156612fd819fdaf542ec Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Wed, 25 Nov 2015 08:58:53 -0500 +Subject: [PATCH 131/134] ARM: BCM: Clean up SMP support for Broadcom Kona + +These changes cleans up SMP implementaion for Broadcom's +Kona SoC which are required for handling SMP for iProc +family of SoCs at a single place for BCM NSP and BCM Kona. + +Signed-off-by: Kapil Hali +--- + arch/arm/boot/dts/bcm11351.dtsi | 2 +- + arch/arm/boot/dts/bcm21664.dtsi | 2 +- + arch/arm/mach-bcm/kona_smp.c | 82 +++++++++++++++++++++++++++-------------- + 3 files changed, 56 insertions(+), 30 deletions(-) + +--- a/arch/arm/boot/dts/bcm11351.dtsi ++++ b/arch/arm/boot/dts/bcm11351.dtsi +@@ -31,7 +31,6 @@ + #address-cells = <1>; + #size-cells = <0>; + enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x3500417c>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +41,7 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ secondary-boot-reg = <0x3500417c>; + reg = <1>; + }; + }; +--- a/arch/arm/boot/dts/bcm21664.dtsi ++++ b/arch/arm/boot/dts/bcm21664.dtsi +@@ -31,7 +31,6 @@ + #address-cells = <1>; + #size-cells = <0>; + enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x35004178>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +41,7 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ secondary-boot-reg = <0x35004178>; + reg = <1>; + }; + }; +--- a/arch/arm/mach-bcm/kona_smp.c ++++ b/arch/arm/mach-bcm/kona_smp.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2014 Broadcom Corporation ++ * Copyright (C) 2014-2015 Broadcom Corporation + * Copyright 2014 Linaro Limited + * + * This program is free software; you can redistribute it and/or +@@ -30,9 +30,10 @@ + + /* Name of device node property defining secondary boot register location */ + #define OF_SECONDARY_BOOT "secondary-boot-reg" ++#define MPIDR_CPUID_BITMASK 0x3 + + /* I/O address of register used to coordinate secondary core startup */ +-static u32 secondary_boot; ++static u32 secondary_boot_addr; + + /* + * Enable the Cortex A9 Snoop Control Unit +@@ -78,44 +79,68 @@ static int __init scu_a9_enable(void) + static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) + { + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; +- struct device_node *node; ++ struct device_node *cpus_node = NULL; ++ struct device_node *cpu_node = NULL; + int ret; + +- BUG_ON(secondary_boot); /* We're called only once */ +- + /* + * This function is only called via smp_ops->smp_prepare_cpu(). + * That only happens if a "/cpus" device tree node exists + * and has an "enable-method" property that selects the SMP + * operations defined herein. + */ +- node = of_find_node_by_path("/cpus"); +- BUG_ON(!node); +- +- /* +- * Our secondary enable method requires a "secondary-boot-reg" +- * property to specify a register address used to request the +- * ROM code boot a secondary code. If we have any trouble +- * getting this we fall back to uniprocessor mode. +- */ +- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { +- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", +- node->name); +- ret = -ENOENT; /* Arrange to disable SMP */ +- goto out; ++ cpus_node = of_find_node_by_path("/cpus"); ++ if (!cpus_node) ++ return; ++ ++ for_each_child_of_node(cpus_node, cpu_node) { ++ u32 cpuid; ++ ++ if (of_node_cmp(cpu_node->type, "cpu")) ++ continue; ++ ++ if (of_property_read_u32(cpu_node, "reg", &cpuid)) { ++ pr_debug("%s: missing reg property\n", ++ cpu_node->full_name); ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ /* ++ * "secondary-boot-reg" property should be defined only ++ * for secondary cpu ++ */ ++ if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { ++ /* ++ * Our secondary enable method requires a ++ * "secondary-boot-reg" property to specify a register ++ * address used to request the ROM code boot a secondary ++ * core. If we have any trouble getting this we fall ++ * back to uniprocessor mode. ++ */ ++ if (of_property_read_u32(cpu_node, ++ OF_SECONDARY_BOOT, ++ &secondary_boot_addr)) { ++ pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", ++ cpu_node->name); ++ ret = -ENOENT; ++ goto out; ++ } ++ } + } + + /* +- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is ++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is + * returned, the SoC reported a uniprocessor configuration. + * We bail on any other error. + */ + ret = scu_a9_enable(); + out: +- of_node_put(node); ++ of_node_put(cpu_node); ++ of_node_put(cpus_node); ++ + if (ret) { + /* Update the CPU present map to reflect uniprocessor mode */ +- BUG_ON(ret != -ENOENT); + pr_warn("disabling SMP\n"); + init_cpu_present(&only_cpu_0); + } +@@ -139,7 +164,7 @@ out: + * - Wait for the secondary boot register to be re-written, which + * indicates the secondary core has started. + */ +-static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) ++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) + { + void __iomem *boot_reg; + phys_addr_t boot_func; +@@ -154,15 +179,16 @@ static int bcm_boot_secondary(unsigned i + return -EINVAL; + } + +- if (!secondary_boot) { ++ if (!secondary_boot_addr) { + pr_err("required secondary boot register not specified\n"); + return -EINVAL; + } + +- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); ++ boot_reg = ioremap_nocache( ++ (phys_addr_t)secondary_boot_addr, sizeof(u32)); + if (!boot_reg) { + pr_err("unable to map boot register for cpu %u\n", cpu_id); +- return -ENOSYS; ++ return -ENOMEM; + } + + /* +@@ -191,12 +217,12 @@ static int bcm_boot_secondary(unsigned i + + pr_err("timeout waiting for cpu %u to start\n", cpu_id); + +- return -ENOSYS; ++ return -ENXIO; + } + + static struct smp_operations bcm_smp_ops __initdata = { + .smp_prepare_cpus = bcm_smp_prepare_cpus, +- .smp_boot_secondary = bcm_boot_secondary, ++ .smp_boot_secondary = kona_boot_secondary, + }; + CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", + &bcm_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.1/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.1/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch new file mode 100644 index 0000000000..14a1da1eb5 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.1/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch @@ -0,0 +1,560 @@ +From e99fb6d01cddf38cffc11655aba4a96a981d604e Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Wed, 25 Nov 2015 13:25:55 -0500 +Subject: [PATCH 133/134] ARM: BCM: Add SMP support for Broadcom NSP + +Add SMP support for Broadcom's Northstar Plus SoC +cpu enable method. This changes also consolidates +iProc family's - BCM NSP and BCM Kona, platform +SMP handling in a common file. + +Northstar Plus SoC is based on ARM Cortex-A9 +revision r3p0 which requires configuration for ARM +Errata 764369 for SMP. This change adds the needed +configuration option. + +Signed-off-by: Kapil Hali +--- + arch/arm/mach-bcm/Kconfig | 2 + + arch/arm/mach-bcm/Makefile | 8 +- + arch/arm/mach-bcm/kona_smp.c | 228 ---------------------------------- + arch/arm/mach-bcm/platsmp.c | 290 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 298 insertions(+), 230 deletions(-) + delete mode 100644 arch/arm/mach-bcm/kona_smp.c + create mode 100644 arch/arm/mach-bcm/platsmp.c + +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc + obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o + + # BCM281XX and BCM21664 SMP support +-obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o ++obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o + + # BCM281XX and BCM21664 L2 cache control + obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o +--- a/arch/arm/mach-bcm/kona_smp.c ++++ /dev/null +@@ -1,228 +0,0 @@ +-/* +- * Copyright (C) 2014-2015 Broadcom Corporation +- * Copyright 2014 Linaro Limited +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation version 2. +- * +- * This program is distributed "as is" WITHOUT ANY WARRANTY of any +- * kind, whether express or implied; without even the implied warranty +- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-/* Size of mapped Cortex A9 SCU address space */ +-#define CORTEX_A9_SCU_SIZE 0x58 +- +-#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ +-#define BOOT_ADDR_CPUID_MASK 0x3 +- +-/* Name of device node property defining secondary boot register location */ +-#define OF_SECONDARY_BOOT "secondary-boot-reg" +-#define MPIDR_CPUID_BITMASK 0x3 +- +-/* I/O address of register used to coordinate secondary core startup */ +-static u32 secondary_boot_addr; +- +-/* +- * Enable the Cortex A9 Snoop Control Unit +- * +- * By the time this is called we already know there are multiple +- * cores present. We assume we're running on a Cortex A9 processor, +- * so any trouble getting the base address register or getting the +- * SCU base is a problem. +- * +- * Return 0 if successful or an error code otherwise. +- */ +-static int __init scu_a9_enable(void) +-{ +- unsigned long config_base; +- void __iomem *scu_base; +- +- if (!scu_a9_has_base()) { +- pr_err("no configuration base address register!\n"); +- return -ENXIO; +- } +- +- /* Config base address register value is zero for uniprocessor */ +- config_base = scu_a9_get_base(); +- if (!config_base) { +- pr_err("hardware reports only one core\n"); +- return -ENOENT; +- } +- +- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); +- if (!scu_base) { +- pr_err("failed to remap config base (%lu/%u) for SCU\n", +- config_base, CORTEX_A9_SCU_SIZE); +- return -ENOMEM; +- } +- +- scu_enable(scu_base); +- +- iounmap(scu_base); /* That's the last we'll need of this */ +- +- return 0; +-} +- +-static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) +-{ +- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; +- struct device_node *cpus_node = NULL; +- struct device_node *cpu_node = NULL; +- int ret; +- +- /* +- * This function is only called via smp_ops->smp_prepare_cpu(). +- * That only happens if a "/cpus" device tree node exists +- * and has an "enable-method" property that selects the SMP +- * operations defined herein. +- */ +- cpus_node = of_find_node_by_path("/cpus"); +- if (!cpus_node) +- return; +- +- for_each_child_of_node(cpus_node, cpu_node) { +- u32 cpuid; +- +- if (of_node_cmp(cpu_node->type, "cpu")) +- continue; +- +- if (of_property_read_u32(cpu_node, "reg", &cpuid)) { +- pr_debug("%s: missing reg property\n", +- cpu_node->full_name); +- ret = -ENOENT; +- goto out; +- } +- +- /* +- * "secondary-boot-reg" property should be defined only +- * for secondary cpu +- */ +- if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { +- /* +- * Our secondary enable method requires a +- * "secondary-boot-reg" property to specify a register +- * address used to request the ROM code boot a secondary +- * core. If we have any trouble getting this we fall +- * back to uniprocessor mode. +- */ +- if (of_property_read_u32(cpu_node, +- OF_SECONDARY_BOOT, +- &secondary_boot_addr)) { +- pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", +- cpu_node->name); +- ret = -ENOENT; +- goto out; +- } +- } +- } +- +- /* +- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is +- * returned, the SoC reported a uniprocessor configuration. +- * We bail on any other error. +- */ +- ret = scu_a9_enable(); +-out: +- of_node_put(cpu_node); +- of_node_put(cpus_node); +- +- if (ret) { +- /* Update the CPU present map to reflect uniprocessor mode */ +- pr_warn("disabling SMP\n"); +- init_cpu_present(&only_cpu_0); +- } +-} +- +-/* +- * The ROM code has the secondary cores looping, waiting for an event. +- * When an event occurs each core examines the bottom two bits of the +- * secondary boot register. When a core finds those bits contain its +- * own core id, it performs initialization, including computing its boot +- * address by clearing the boot register value's bottom two bits. The +- * core signals that it is beginning its execution by writing its boot +- * address back to the secondary boot register, and finally jumps to +- * that address. +- * +- * So to start a core executing we need to: +- * - Encode the (hardware) CPU id with the bottom bits of the secondary +- * start address. +- * - Write that value into the secondary boot register. +- * - Generate an event to wake up the secondary CPU(s). +- * - Wait for the secondary boot register to be re-written, which +- * indicates the secondary core has started. +- */ +-static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) +-{ +- void __iomem *boot_reg; +- phys_addr_t boot_func; +- u64 start_clock; +- u32 cpu_id; +- u32 boot_val; +- bool timeout = false; +- +- cpu_id = cpu_logical_map(cpu); +- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { +- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); +- return -EINVAL; +- } +- +- if (!secondary_boot_addr) { +- pr_err("required secondary boot register not specified\n"); +- return -EINVAL; +- } +- +- boot_reg = ioremap_nocache( +- (phys_addr_t)secondary_boot_addr, sizeof(u32)); +- if (!boot_reg) { +- pr_err("unable to map boot register for cpu %u\n", cpu_id); +- return -ENOMEM; +- } +- +- /* +- * Secondary cores will start in secondary_startup(), +- * defined in "arch/arm/kernel/head.S" +- */ +- boot_func = virt_to_phys(secondary_startup); +- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); +- BUG_ON(boot_func > (phys_addr_t)U32_MAX); +- +- /* The core to start is encoded in the low bits */ +- boot_val = (u32)boot_func | cpu_id; +- writel_relaxed(boot_val, boot_reg); +- +- sev(); +- +- /* The low bits will be cleared once the core has started */ +- start_clock = local_clock(); +- while (!timeout && readl_relaxed(boot_reg) == boot_val) +- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; +- +- iounmap(boot_reg); +- +- if (!timeout) +- return 0; +- +- pr_err("timeout waiting for cpu %u to start\n", cpu_id); +- +- return -ENXIO; +-} +- +-static struct smp_operations bcm_smp_ops __initdata = { +- .smp_prepare_cpus = bcm_smp_prepare_cpus, +- .smp_boot_secondary = kona_boot_secondary, +-}; +-CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", +- &bcm_smp_ops); +--- /dev/null ++++ b/arch/arm/mach-bcm/platsmp.c +@@ -0,0 +1,290 @@ ++/* ++ * Copyright (C) 2014-2015 Broadcom Corporation ++ * Copyright 2014 Linaro Limited ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Size of mapped Cortex A9 SCU address space */ ++#define CORTEX_A9_SCU_SIZE 0x58 ++ ++#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ ++#define BOOT_ADDR_CPUID_MASK 0x3 ++ ++/* Name of device node property defining secondary boot register location */ ++#define OF_SECONDARY_BOOT "secondary-boot-reg" ++#define MPIDR_CPUID_BITMASK 0x3 ++ ++/* I/O address of register used to coordinate secondary core startup */ ++static u32 secondary_boot_addr; ++ ++/* ++ * Enable the Cortex A9 Snoop Control Unit ++ * ++ * By the time this is called we already know there are multiple ++ * cores present. We assume we're running on a Cortex A9 processor, ++ * so any trouble getting the base address register or getting the ++ * SCU base is a problem. ++ * ++ * Return 0 if successful or an error code otherwise. ++ */ ++static int __init scu_a9_enable(void) ++{ ++ unsigned long config_base; ++ void __iomem *scu_base; ++ ++ if (!scu_a9_has_base()) { ++ pr_err("no configuration base address register!\n"); ++ return -ENXIO; ++ } ++ ++ /* Config base address register value is zero for uniprocessor */ ++ config_base = scu_a9_get_base(); ++ if (!config_base) { ++ pr_err("hardware reports only one core\n"); ++ return -ENOENT; ++ } ++ ++ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); ++ if (!scu_base) { ++ pr_err("failed to remap config base (%lu/%u) for SCU\n", ++ config_base, CORTEX_A9_SCU_SIZE); ++ return -ENOMEM; ++ } ++ ++ scu_enable(scu_base); ++ ++ iounmap(scu_base); /* That's the last we'll need of this */ ++ ++ return 0; ++} ++ ++static int nsp_write_lut(void) ++{ ++ void __iomem *sku_rom_lut; ++ phys_addr_t secondary_startup_phy; ++ ++ if (!secondary_boot_addr) { ++ pr_warn("required secondary boot register not specified\n"); ++ return -EINVAL; ++ } ++ ++ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot_addr, ++ sizeof(secondary_boot_addr)); ++ if (!sku_rom_lut) { ++ pr_warn("unable to ioremap SKU-ROM LUT register\n"); ++ return -ENOMEM; ++ } ++ ++ secondary_startup_phy = virt_to_phys(secondary_startup); ++ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); ++ ++ writel_relaxed(secondary_startup_phy, sku_rom_lut); ++ ++ /* Ensure the write is visible to the secondary core */ ++ smp_wmb(); ++ ++ iounmap(sku_rom_lut); ++ ++ return 0; ++} ++ ++static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) ++{ ++ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; ++ struct device_node *cpus_node = NULL; ++ struct device_node *cpu_node = NULL; ++ int ret; ++ ++ /* ++ * This function is only called via smp_ops->smp_prepare_cpu(). ++ * That only happens if a "/cpus" device tree node exists ++ * and has an "enable-method" property that selects the SMP ++ * operations defined herein. ++ */ ++ cpus_node = of_find_node_by_path("/cpus"); ++ if (!cpus_node) ++ return; ++ ++ for_each_child_of_node(cpus_node, cpu_node) { ++ u32 cpuid; ++ ++ if (of_node_cmp(cpu_node->type, "cpu")) ++ continue; ++ ++ if (of_property_read_u32(cpu_node, "reg", &cpuid)) { ++ pr_debug("%s: missing reg property\n", ++ cpu_node->full_name); ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ /* ++ * "secondary-boot-reg" property should be defined only ++ * for secondary cpu ++ */ ++ if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { ++ /* ++ * Our secondary enable method requires a ++ * "secondary-boot-reg" property to specify a register ++ * address used to request the ROM code boot a secondary ++ * core. If we have any trouble getting this we fall ++ * back to uniprocessor mode. ++ */ ++ if (of_property_read_u32(cpu_node, ++ OF_SECONDARY_BOOT, ++ &secondary_boot_addr)) { ++ pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", ++ cpu_node->name); ++ ret = -ENOENT; ++ goto out; ++ } ++ } ++ } ++ ++ /* ++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is ++ * returned, the SoC reported a uniprocessor configuration. ++ * We bail on any other error. ++ */ ++ ret = scu_a9_enable(); ++out: ++ of_node_put(cpu_node); ++ of_node_put(cpus_node); ++ ++ if (ret) { ++ /* Update the CPU present map to reflect uniprocessor mode */ ++ pr_warn("disabling SMP\n"); ++ init_cpu_present(&only_cpu_0); ++ } ++} ++ ++/* ++ * The ROM code has the secondary cores looping, waiting for an event. ++ * When an event occurs each core examines the bottom two bits of the ++ * secondary boot register. When a core finds those bits contain its ++ * own core id, it performs initialization, including computing its boot ++ * address by clearing the boot register value's bottom two bits. The ++ * core signals that it is beginning its execution by writing its boot ++ * address back to the secondary boot register, and finally jumps to ++ * that address. ++ * ++ * So to start a core executing we need to: ++ * - Encode the (hardware) CPU id with the bottom bits of the secondary ++ * start address. ++ * - Write that value into the secondary boot register. ++ * - Generate an event to wake up the secondary CPU(s). ++ * - Wait for the secondary boot register to be re-written, which ++ * indicates the secondary core has started. ++ */ ++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) ++{ ++ void __iomem *boot_reg; ++ phys_addr_t boot_func; ++ u64 start_clock; ++ u32 cpu_id; ++ u32 boot_val; ++ bool timeout = false; ++ ++ cpu_id = cpu_logical_map(cpu); ++ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { ++ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); ++ return -EINVAL; ++ } ++ ++ if (!secondary_boot_addr) { ++ pr_err("required secondary boot register not specified\n"); ++ return -EINVAL; ++ } ++ ++ boot_reg = ioremap_nocache( ++ (phys_addr_t)secondary_boot_addr, sizeof(u32)); ++ if (!boot_reg) { ++ pr_err("unable to map boot register for cpu %u\n", cpu_id); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Secondary cores will start in secondary_startup(), ++ * defined in "arch/arm/kernel/head.S" ++ */ ++ boot_func = virt_to_phys(secondary_startup); ++ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); ++ BUG_ON(boot_func > (phys_addr_t)U32_MAX); ++ ++ /* The core to start is encoded in the low bits */ ++ boot_val = (u32)boot_func | cpu_id; ++ writel_relaxed(boot_val, boot_reg); ++ ++ sev(); ++ ++ /* The low bits will be cleared once the core has started */ ++ start_clock = local_clock(); ++ while (!timeout && readl_relaxed(boot_reg) == boot_val) ++ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; ++ ++ iounmap(boot_reg); ++ ++ if (!timeout) ++ return 0; ++ ++ pr_err("timeout waiting for cpu %u to start\n", cpu_id); ++ ++ return -ENXIO; ++} ++ ++static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) ++{ ++ int ret; ++ ++ /* ++ * After wake up, secondary core branches to the startup ++ * address programmed at SKU ROM LUT location. ++ */ ++ ret = nsp_write_lut(); ++ if (ret) { ++ pr_err("unable to write startup addr to SKU ROM LUT\n"); ++ goto out; ++ } ++ ++ /* Send a CPU wakeup interrupt to the secondary core */ ++ arch_send_wakeup_ipi_mask(cpumask_of(cpu)); ++ ++out: ++ return ret; ++} ++ ++static struct smp_operations bcm_smp_ops __initdata = { ++ .smp_prepare_cpus = bcm_smp_prepare_cpus, ++ .smp_boot_secondary = kona_boot_secondary, ++}; ++CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", ++ &bcm_smp_ops); ++ ++struct smp_operations nsp_smp_ops __initdata = { ++ .smp_prepare_cpus = bcm_smp_prepare_cpus, ++ .smp_boot_secondary = nsp_boot_secondary, ++}; ++CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.1/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.1/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch new file mode 100644 index 0000000000..5ff1c3526f --- /dev/null +++ b/target/linux/bcm53xx/patches-4.1/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch @@ -0,0 +1,57 @@ +From 16e1bf7dde22ee22a331aabf824cc31a6794a4cb Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 14:09:10 -0400 +Subject: [PATCH 134/134] ARM: BCM: Add SMP support for Broadcom 4708 + +Add SMP support for Broadcom's 4708 SoCs. + +Signed-off-by: Jon Mason +Acked-by: Hauke Mehrtens +Tested-by: Hauke Mehrtens +Signed-off-by: Kapil Hali +--- + arch/arm/boot/dts/bcm4708.dtsi | 2 ++ + arch/arm/mach-bcm/Kconfig | 1 + + arch/arm/mach-bcm/Makefile | 3 +++ + 3 files changed, 6 insertions(+) + +--- a/arch/arm/boot/dts/bcm4708.dtsi ++++ b/arch/arm/boot/dts/bcm4708.dtsi +@@ -15,6 +15,7 @@ + cpus { + #address-cells = <1>; + #size-cells = <0>; ++ enable-method = "brcm,bcm-nsp-smp"; + + cpu@0 { + device_type = "cpu"; +@@ -27,6 +28,7 @@ + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; ++ secondary-boot-reg = <0xffff0400>; + reg = <0x1>; + }; + }; +--- a/arch/arm/mach-bcm/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -41,6 +41,7 @@ config ARCH_BCM_5301X + select ARM_ERRATA_754322 + select ARM_ERRATA_775420 + select ARM_ERRATA_764369 if SMP ++ select HAVE_SMP + + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2 + + # BCM5301X + obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o ++ifeq ($(CONFIG_ARCH_BCM_5301X),y) ++obj-$(CONFIG_SMP) += platsmp.o ++endif + + # BCM63XXx + obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o diff --git a/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch deleted file mode 100644 index 5e3bd7793d..0000000000 --- a/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch +++ /dev/null @@ -1,635 +0,0 @@ -From a0ad1511d5805b95ac4c454d7904c670a1696055 Mon Sep 17 00:00:00 2001 -From: Kapil Hali -Date: Wed, 14 Oct 2015 13:47:00 -0400 -Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom NSP - -Add SMP support for Broadcom's Northstar Plus SoC, -cpu enable method and pen_release procedures. This -changes also consolidates iProc family's - BCM NSP -and BCM Kona, SMP handling in a common file. - -Northstar Plus SoC is based on ARM Cortex-A9 -revision r3p0 which requires configuration for ARM -Errata 764369 for SMP. This change adds the needed -configuration option. - -Signed-off-by: Kapil Hali ---- - arch/arm/mach-bcm/Makefile | 2 +- - arch/arm/mach-bcm/bcm_nsp.h | 19 +++ - arch/arm/mach-bcm/headsmp.S | 37 +++++ - arch/arm/mach-bcm/kona_smp.c | 202 --------------------------- - arch/arm/mach-bcm/platsmp.c | 326 +++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 383 insertions(+), 203 deletions(-) - create mode 100644 arch/arm/mach-bcm/bcm_nsp.h - create mode 100644 arch/arm/mach-bcm/headsmp.S - delete mode 100644 arch/arm/mach-bcm/kona_smp.c - create mode 100644 arch/arm/mach-bcm/platsmp.c - ---- a/arch/arm/mach-bcm/Makefile -+++ b/arch/arm/mach-bcm/Makefile -@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc - obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o - - # BCM281XX and BCM21664 SMP support --obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o -+obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o - - # BCM281XX and BCM21664 L2 cache control - obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o ---- /dev/null -+++ b/arch/arm/mach-bcm/bcm_nsp.h -@@ -0,0 +1,19 @@ -+/* -+ * Copyright (C) 2015 Broadcom Corporation -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __BCM_NSP_H -+#define __BCM_NSP_H -+ -+extern void nsp_secondary_startup(void); -+ -+#endif /* __BCM_NSP_H */ ---- /dev/null -+++ b/arch/arm/mach-bcm/headsmp.S -@@ -0,0 +1,37 @@ -+/* -+ * Copyright (C) 2015 Broadcom Corporation -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+ -+/* -+ * iProc specific entry point for secondary CPUs. This provides -+ * a "holding pen" into which all secondary cores are held until -+ * we are ready for them to initialise. -+ */ -+ENTRY(nsp_secondary_startup) -+ 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 -+ -+ b secondary_startup -+ -+1: .long . -+ .long pen_release -+ -+ENDPROC(nsp_secondary_startup) ---- a/arch/arm/mach-bcm/kona_smp.c -+++ /dev/null -@@ -1,202 +0,0 @@ --/* -- * Copyright (C) 2014 Broadcom Corporation -- * Copyright 2014 Linaro Limited -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License as -- * published by the Free Software Foundation version 2. -- * -- * This program is distributed "as is" WITHOUT ANY WARRANTY of any -- * kind, whether express or implied; without even the implied warranty -- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- */ -- --#include --#include --#include --#include --#include -- --#include --#include --#include -- --/* Size of mapped Cortex A9 SCU address space */ --#define CORTEX_A9_SCU_SIZE 0x58 -- --#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ --#define BOOT_ADDR_CPUID_MASK 0x3 -- --/* Name of device node property defining secondary boot register location */ --#define OF_SECONDARY_BOOT "secondary-boot-reg" -- --/* I/O address of register used to coordinate secondary core startup */ --static u32 secondary_boot; -- --/* -- * Enable the Cortex A9 Snoop Control Unit -- * -- * By the time this is called we already know there are multiple -- * cores present. We assume we're running on a Cortex A9 processor, -- * so any trouble getting the base address register or getting the -- * SCU base is a problem. -- * -- * Return 0 if successful or an error code otherwise. -- */ --static int __init scu_a9_enable(void) --{ -- unsigned long config_base; -- void __iomem *scu_base; -- -- if (!scu_a9_has_base()) { -- pr_err("no configuration base address register!\n"); -- return -ENXIO; -- } -- -- /* Config base address register value is zero for uniprocessor */ -- config_base = scu_a9_get_base(); -- if (!config_base) { -- pr_err("hardware reports only one core\n"); -- return -ENOENT; -- } -- -- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); -- if (!scu_base) { -- pr_err("failed to remap config base (%lu/%u) for SCU\n", -- config_base, CORTEX_A9_SCU_SIZE); -- return -ENOMEM; -- } -- -- scu_enable(scu_base); -- -- iounmap(scu_base); /* That's the last we'll need of this */ -- -- return 0; --} -- --static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) --{ -- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; -- struct device_node *node; -- int ret; -- -- BUG_ON(secondary_boot); /* We're called only once */ -- -- /* -- * This function is only called via smp_ops->smp_prepare_cpu(). -- * That only happens if a "/cpus" device tree node exists -- * and has an "enable-method" property that selects the SMP -- * operations defined herein. -- */ -- node = of_find_node_by_path("/cpus"); -- BUG_ON(!node); -- -- /* -- * Our secondary enable method requires a "secondary-boot-reg" -- * property to specify a register address used to request the -- * ROM code boot a secondary code. If we have any trouble -- * getting this we fall back to uniprocessor mode. -- */ -- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { -- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", -- node->name); -- ret = -ENOENT; /* Arrange to disable SMP */ -- goto out; -- } -- -- /* -- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is -- * returned, the SoC reported a uniprocessor configuration. -- * We bail on any other error. -- */ -- ret = scu_a9_enable(); --out: -- of_node_put(node); -- if (ret) { -- /* Update the CPU present map to reflect uniprocessor mode */ -- BUG_ON(ret != -ENOENT); -- pr_warn("disabling SMP\n"); -- init_cpu_present(&only_cpu_0); -- } --} -- --/* -- * The ROM code has the secondary cores looping, waiting for an event. -- * When an event occurs each core examines the bottom two bits of the -- * secondary boot register. When a core finds those bits contain its -- * own core id, it performs initialization, including computing its boot -- * address by clearing the boot register value's bottom two bits. The -- * core signals that it is beginning its execution by writing its boot -- * address back to the secondary boot register, and finally jumps to -- * that address. -- * -- * So to start a core executing we need to: -- * - Encode the (hardware) CPU id with the bottom bits of the secondary -- * start address. -- * - Write that value into the secondary boot register. -- * - Generate an event to wake up the secondary CPU(s). -- * - Wait for the secondary boot register to be re-written, which -- * indicates the secondary core has started. -- */ --static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) --{ -- void __iomem *boot_reg; -- phys_addr_t boot_func; -- u64 start_clock; -- u32 cpu_id; -- u32 boot_val; -- bool timeout = false; -- -- cpu_id = cpu_logical_map(cpu); -- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { -- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); -- return -EINVAL; -- } -- -- if (!secondary_boot) { -- pr_err("required secondary boot register not specified\n"); -- return -EINVAL; -- } -- -- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); -- if (!boot_reg) { -- pr_err("unable to map boot register for cpu %u\n", cpu_id); -- return -ENOSYS; -- } -- -- /* -- * Secondary cores will start in secondary_startup(), -- * defined in "arch/arm/kernel/head.S" -- */ -- boot_func = virt_to_phys(secondary_startup); -- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); -- BUG_ON(boot_func > (phys_addr_t)U32_MAX); -- -- /* The core to start is encoded in the low bits */ -- boot_val = (u32)boot_func | cpu_id; -- writel_relaxed(boot_val, boot_reg); -- -- sev(); -- -- /* The low bits will be cleared once the core has started */ -- start_clock = local_clock(); -- while (!timeout && readl_relaxed(boot_reg) == boot_val) -- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; -- -- iounmap(boot_reg); -- -- if (!timeout) -- return 0; -- -- pr_err("timeout waiting for cpu %u to start\n", cpu_id); -- -- return -ENOSYS; --} -- --static struct smp_operations bcm_smp_ops __initdata = { -- .smp_prepare_cpus = bcm_smp_prepare_cpus, -- .smp_boot_secondary = bcm_boot_secondary, --}; --CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", -- &bcm_smp_ops); ---- /dev/null -+++ b/arch/arm/mach-bcm/platsmp.c -@@ -0,0 +1,326 @@ -+/* -+ * Copyright (C) 2014-2015 Broadcom Corporation -+ * Copyright 2014 Linaro Limited -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation version 2. -+ * -+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any -+ * kind, whether express or implied; without even the implied warranty -+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "bcm_nsp.h" -+ -+/* Size of mapped Cortex A9 SCU address space */ -+#define CORTEX_A9_SCU_SIZE 0x58 -+ -+#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ -+#define BOOT_ADDR_CPUID_MASK 0x3 -+ -+/* Name of device node property defining secondary boot register location */ -+#define OF_SECONDARY_BOOT "secondary-boot-reg" -+ -+/* I/O address of register used to coordinate secondary core startup */ -+static u32 secondary_boot; -+ -+static DEFINE_SPINLOCK(boot_lock); -+ -+/* -+ * 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; -+ /* -+ * Ensure write to pen_release is visible to the other cores, -+ * here - primary core -+ */ -+ smp_wmb(); -+ sync_cache_w(&pen_release); -+} -+ -+/* -+ * Enable the Cortex A9 Snoop Control Unit -+ * -+ * By the time this is called we already know there are multiple -+ * cores present. We assume we're running on a Cortex A9 processor, -+ * so any trouble getting the base address register or getting the -+ * SCU base is a problem. -+ * -+ * Return 0 if successful or an error code otherwise. -+ */ -+static int __init scu_a9_enable(void) -+{ -+ unsigned long config_base; -+ void __iomem *scu_base; -+ -+ if (!scu_a9_has_base()) { -+ pr_err("no configuration base address register!\n"); -+ return -ENXIO; -+ } -+ -+ /* Config base address register value is zero for uniprocessor */ -+ config_base = scu_a9_get_base(); -+ if (!config_base) { -+ pr_err("hardware reports only one core\n"); -+ return -ENOENT; -+ } -+ -+ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); -+ if (!scu_base) { -+ pr_err("failed to remap config base (%lu/%u) for SCU\n", -+ config_base, CORTEX_A9_SCU_SIZE); -+ return -ENOMEM; -+ } -+ -+ scu_enable(scu_base); -+ -+ iounmap(scu_base); /* That's the last we'll need of this */ -+ -+ return 0; -+} -+ -+static int nsp_write_lut(void (*secondary_startup) (void)) -+{ -+ void __iomem *sku_rom_lut; -+ phys_addr_t secondary_startup_phy; -+ -+ if (!secondary_boot) { -+ pr_warn("required secondary boot register not specified\n"); -+ return -EINVAL; -+ } -+ -+ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot, -+ sizeof(secondary_boot)); -+ if (!sku_rom_lut) { -+ pr_warn("unable to ioremap SKU-ROM LUT register\n"); -+ return -ENOMEM; -+ } -+ -+ secondary_startup_phy = virt_to_phys(secondary_startup); -+ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); -+ -+ writel_relaxed(secondary_startup_phy, sku_rom_lut); -+ /* -+ * Ensure the write is visible to the secondary core. -+ */ -+ smp_wmb(); -+ -+ iounmap(sku_rom_lut); -+ -+ return 0; -+} -+ -+static void nsp_secondary_init(unsigned int cpu) -+{ -+ /* -+ * Let the primary cpu know we are out of holding pen. -+ */ -+ write_pen_release(-1); -+ -+ /* -+ * Synchronise with the boot thread. -+ */ -+ spin_lock(&boot_lock); -+ spin_unlock(&boot_lock); -+} -+ -+static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) -+{ -+ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; -+ struct device_node *node; -+ int ret; -+ -+ BUG_ON(secondary_boot); /* We're called only once */ -+ -+ /* -+ * This function is only called via smp_ops->smp_prepare_cpu(). -+ * That only happens if a "/cpus" device tree node exists -+ * and has an "enable-method" property that selects the SMP -+ * operations defined herein. -+ */ -+ node = of_find_node_by_path("/cpus"); -+ BUG_ON(!node); -+ -+ /* -+ * Our secondary enable method requires a "secondary-boot-reg" -+ * property to specify a register address used to request the -+ * ROM code boot a secondary core. If we have any trouble -+ * getting this we fall back to uniprocessor mode. -+ */ -+ if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { -+ pr_warn("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", -+ node->name); -+ ret = -ENOENT; /* Arrange to disable SMP */ -+ goto out; -+ } -+ -+ /* -+ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is -+ * returned, the SoC reported a uniprocessor configuration. -+ * We bail on any other error. -+ */ -+ ret = scu_a9_enable(); -+out: -+ of_node_put(node); -+ if (ret) { -+ /* Update the CPU present map to reflect uniprocessor mode */ -+ pr_warn("disabling SMP\n"); -+ init_cpu_present(&only_cpu_0); -+ } -+} -+ -+/* -+ * The ROM code has the secondary cores looping, waiting for an event. -+ * When an event occurs each core examines the bottom two bits of the -+ * secondary boot register. When a core finds those bits contain its -+ * own core id, it performs initialization, including computing its boot -+ * address by clearing the boot register value's bottom two bits. The -+ * core signals that it is beginning its execution by writing its boot -+ * address back to the secondary boot register, and finally jumps to -+ * that address. -+ * -+ * So to start a core executing we need to: -+ * - Encode the (hardware) CPU id with the bottom bits of the secondary -+ * start address. -+ * - Write that value into the secondary boot register. -+ * - Generate an event to wake up the secondary CPU(s). -+ * - Wait for the secondary boot register to be re-written, which -+ * indicates the secondary core has started. -+ */ -+static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) -+{ -+ void __iomem *boot_reg; -+ phys_addr_t boot_func; -+ u64 start_clock; -+ u32 cpu_id; -+ u32 boot_val; -+ bool timeout = false; -+ -+ cpu_id = cpu_logical_map(cpu); -+ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { -+ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); -+ return -EINVAL; -+ } -+ -+ if (!secondary_boot) { -+ pr_err("required secondary boot register not specified\n"); -+ return -EINVAL; -+ } -+ -+ boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); -+ if (!boot_reg) { -+ pr_err("unable to map boot register for cpu %u\n", cpu_id); -+ return -ENOMEM; -+ } -+ -+ /* -+ * Secondary cores will start in secondary_startup(), -+ * defined in "arch/arm/kernel/head.S" -+ */ -+ boot_func = virt_to_phys(secondary_startup); -+ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); -+ BUG_ON(boot_func > (phys_addr_t)U32_MAX); -+ -+ /* The core to start is encoded in the low bits */ -+ boot_val = (u32)boot_func | cpu_id; -+ writel_relaxed(boot_val, boot_reg); -+ -+ sev(); -+ -+ /* The low bits will be cleared once the core has started */ -+ start_clock = local_clock(); -+ while (!timeout && readl_relaxed(boot_reg) == boot_val) -+ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; -+ -+ iounmap(boot_reg); -+ -+ if (!timeout) -+ return 0; -+ -+ pr_err("timeout waiting for cpu %u to start\n", cpu_id); -+ -+ return -ENXIO; -+} -+ -+static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) -+{ -+ unsigned long timeout; -+ int ret; -+ -+ /* -+ * After wake up, secondary core branches to the startup -+ * address programmed at SKU ROM LUT location. -+ */ -+ ret = nsp_write_lut(nsp_secondary_startup); -+ if (ret) { -+ pr_err("unable to write startup addr to SKU ROM LUT\n"); -+ goto out; -+ } -+ -+ /* -+ * The secondary processor is waiting to be released from -+ * the holding pen - release it, then wait for it to flag -+ * that it has been released by resetting pen_release. -+ */ -+ spin_lock(&boot_lock); -+ -+ write_pen_release(cpu_logical_map(cpu)); -+ /* -+ * Send an Event to wake up the secondary core which is in -+ * WFE state. Updated pen_release should also be visible to -+ * the secondary core. -+ */ -+ dsb_sev(); -+ -+ timeout = jiffies + (1 * HZ); -+ while (time_before(jiffies, timeout)) { -+ /* Make sure loads on other CPU is visible */ -+ smp_rmb(); -+ if (pen_release == -1) -+ break; -+ -+ udelay(10); -+ } -+ -+ spin_unlock(&boot_lock); -+ -+ ret = pen_release != -1 ? -ENXIO : 0; -+ -+out: -+ return ret; -+} -+ -+static struct smp_operations bcm_smp_ops __initdata = { -+ .smp_prepare_cpus = bcm_smp_prepare_cpus, -+ .smp_boot_secondary = kona_boot_secondary, -+}; -+CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", -+ &bcm_smp_ops); -+ -+struct smp_operations nsp_smp_ops __initdata = { -+ .smp_prepare_cpus = bcm_smp_prepare_cpus, -+ .smp_secondary_init = nsp_secondary_init, -+ .smp_boot_secondary = nsp_boot_secondary, -+}; -+CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.3/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.3/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch new file mode 100644 index 0000000000..1de37b0132 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/130-dt-bindings-add-SMP-enable-method-for-Broadcom-NSP.patch @@ -0,0 +1,69 @@ +From 204b9dbd7c4bd5a223fd104b9cba56c12fe04add Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Wed, 19 Aug 2015 13:42:23 -0400 +Subject: [PATCH 130/134] dt-bindings: add SMP enable-method for Broadcom NSP + +Add a compatible string "brcm,bcm-nsp-smp" for Broadcom's +Northstar Plus CPU to the 32-bit ARM CPU device tree binding +documentation file and create a new binding documentation for +Northstar Plus CPU. + +Signed-off-by: Kapil Hali +--- + .../bindings/arm/bcm/brcm,nsp-cpu-method.txt | 39 ++++++++++++++++++++++ + Documentation/devicetree/bindings/arm/cpus.txt | 1 + + 2 files changed, 40 insertions(+) + create mode 100644 Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/arm/bcm/brcm,nsp-cpu-method.txt +@@ -0,0 +1,39 @@ ++Broadcom Northstar Plus SoC CPU Enable Method ++--------------------------------------------- ++This binding defines the enable method used for starting secondary ++CPUs in the following Broadcom SoCs: ++ BCM58522, BCM58525, BCM58535, BCM58622, BCM58623, BCM58625, BCM88312 ++ ++The enable method is specified by defining the following required ++properties in the "cpus" device tree node: ++ - enable-method = "brcm,bcm-nsp-smp"; ++ - secondary-boot-reg = <...>; ++ ++The secondary-boot-reg property is a u32 value that specifies the ++physical address of the register which should hold the common ++entry point for a secondary CPU. This entry is cpu node specific ++and should be added per cpu. E.g., in case of NSP (BCM58625) which ++is a dual core CPU SoC, this entry should be added to cpu1 node. ++ ++ ++Example: ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm-nsp-smp"; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ next-level-cache = <&L2>; ++ reg = <0>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ next-level-cache = <&L2>; ++ reg = <1>; ++ secondary-boot-reg = <0xffff042c>; ++ }; ++ }; +--- a/Documentation/devicetree/bindings/arm/cpus.txt ++++ b/Documentation/devicetree/bindings/arm/cpus.txt +@@ -190,6 +190,7 @@ nodes to be present and contain the prop + "allwinner,sun6i-a31" + "allwinner,sun8i-a23" + "arm,psci" ++ "brcm,bcm-nsp-smp" + "brcm,brahma-b15" + "marvell,armada-375-smp" + "marvell,armada-380-smp" diff --git a/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch deleted file mode 100644 index ec07be5277..0000000000 --- a/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch +++ /dev/null @@ -1,49 +0,0 @@ -From ddbf0ad85be06948dd214c7beb7b315ef2749e65 Mon Sep 17 00:00:00 2001 -From: Jon Mason -Date: Thu, 15 Oct 2015 14:14:10 -0400 -Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom 4708 - -ARM: BCM: Add SMP support for Broadcom 4708 - -Add SMP support for Broadcom's 4708 SoCs. - -Signed-off-by: Jon Mason ---- - arch/arm/boot/dts/bcm4708.dtsi | 2 ++ - arch/arm/mach-bcm/Kconfig | 2 ++ - arch/arm/mach-bcm/Makefile | 3 +++ - 3 files changed, 7 insertions(+) - ---- a/arch/arm/boot/dts/bcm4708.dtsi -+++ b/arch/arm/boot/dts/bcm4708.dtsi -@@ -15,6 +15,8 @@ - cpus { - #address-cells = <1>; - #size-cells = <0>; -+ enable-method = "brcm,bcm-nsp-smp"; -+ secondary-boot-reg = <0xffff0400>; - - cpu@0 { - device_type = "cpu"; ---- a/arch/arm/mach-bcm/Kconfig -+++ b/arch/arm/mach-bcm/Kconfig -@@ -41,6 +41,7 @@ config ARCH_BCM_5301X - select ARM_ERRATA_754322 - select ARM_ERRATA_775420 - select ARM_ERRATA_764369 if SMP -+ select HAVE_SMP - - help - Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. ---- a/arch/arm/mach-bcm/Makefile -+++ b/arch/arm/mach-bcm/Makefile -@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2 - - # BCM5301X - obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o -+ifeq ($(CONFIG_ARCH_BCM_5301X),y) -+obj-$(CONFIG_SMP) += headsmp.o platsmp.o -+endif - - # BCM63XXx - ifeq ($(CONFIG_ARCH_BCM_63XX),y) diff --git a/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch b/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch new file mode 100644 index 0000000000..7a48a13e64 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch @@ -0,0 +1,206 @@ +From 8622d6da5d95293d474c156612fd819fdaf542ec Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Wed, 25 Nov 2015 08:58:53 -0500 +Subject: [PATCH 131/134] ARM: BCM: Clean up SMP support for Broadcom Kona + +These changes cleans up SMP implementaion for Broadcom's +Kona SoC which are required for handling SMP for iProc +family of SoCs at a single place for BCM NSP and BCM Kona. + +Signed-off-by: Kapil Hali +--- + arch/arm/boot/dts/bcm11351.dtsi | 2 +- + arch/arm/boot/dts/bcm21664.dtsi | 2 +- + arch/arm/mach-bcm/kona_smp.c | 82 +++++++++++++++++++++++++++-------------- + 3 files changed, 56 insertions(+), 30 deletions(-) + +--- a/arch/arm/boot/dts/bcm11351.dtsi ++++ b/arch/arm/boot/dts/bcm11351.dtsi +@@ -31,7 +31,6 @@ + #address-cells = <1>; + #size-cells = <0>; + enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x3500417c>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +41,7 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ secondary-boot-reg = <0x3500417c>; + reg = <1>; + }; + }; +--- a/arch/arm/boot/dts/bcm21664.dtsi ++++ b/arch/arm/boot/dts/bcm21664.dtsi +@@ -31,7 +31,6 @@ + #address-cells = <1>; + #size-cells = <0>; + enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x35004178>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +41,7 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ secondary-boot-reg = <0x35004178>; + reg = <1>; + }; + }; +--- a/arch/arm/mach-bcm/kona_smp.c ++++ b/arch/arm/mach-bcm/kona_smp.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2014 Broadcom Corporation ++ * Copyright (C) 2014-2015 Broadcom Corporation + * Copyright 2014 Linaro Limited + * + * This program is free software; you can redistribute it and/or +@@ -30,9 +30,10 @@ + + /* Name of device node property defining secondary boot register location */ + #define OF_SECONDARY_BOOT "secondary-boot-reg" ++#define MPIDR_CPUID_BITMASK 0x3 + + /* I/O address of register used to coordinate secondary core startup */ +-static u32 secondary_boot; ++static u32 secondary_boot_addr; + + /* + * Enable the Cortex A9 Snoop Control Unit +@@ -78,44 +79,68 @@ static int __init scu_a9_enable(void) + static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) + { + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; +- struct device_node *node; ++ struct device_node *cpus_node = NULL; ++ struct device_node *cpu_node = NULL; + int ret; + +- BUG_ON(secondary_boot); /* We're called only once */ +- + /* + * This function is only called via smp_ops->smp_prepare_cpu(). + * That only happens if a "/cpus" device tree node exists + * and has an "enable-method" property that selects the SMP + * operations defined herein. + */ +- node = of_find_node_by_path("/cpus"); +- BUG_ON(!node); +- +- /* +- * Our secondary enable method requires a "secondary-boot-reg" +- * property to specify a register address used to request the +- * ROM code boot a secondary code. If we have any trouble +- * getting this we fall back to uniprocessor mode. +- */ +- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) { +- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", +- node->name); +- ret = -ENOENT; /* Arrange to disable SMP */ +- goto out; ++ cpus_node = of_find_node_by_path("/cpus"); ++ if (!cpus_node) ++ return; ++ ++ for_each_child_of_node(cpus_node, cpu_node) { ++ u32 cpuid; ++ ++ if (of_node_cmp(cpu_node->type, "cpu")) ++ continue; ++ ++ if (of_property_read_u32(cpu_node, "reg", &cpuid)) { ++ pr_debug("%s: missing reg property\n", ++ cpu_node->full_name); ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ /* ++ * "secondary-boot-reg" property should be defined only ++ * for secondary cpu ++ */ ++ if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { ++ /* ++ * Our secondary enable method requires a ++ * "secondary-boot-reg" property to specify a register ++ * address used to request the ROM code boot a secondary ++ * core. If we have any trouble getting this we fall ++ * back to uniprocessor mode. ++ */ ++ if (of_property_read_u32(cpu_node, ++ OF_SECONDARY_BOOT, ++ &secondary_boot_addr)) { ++ pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", ++ cpu_node->name); ++ ret = -ENOENT; ++ goto out; ++ } ++ } + } + + /* +- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is ++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is + * returned, the SoC reported a uniprocessor configuration. + * We bail on any other error. + */ + ret = scu_a9_enable(); + out: +- of_node_put(node); ++ of_node_put(cpu_node); ++ of_node_put(cpus_node); ++ + if (ret) { + /* Update the CPU present map to reflect uniprocessor mode */ +- BUG_ON(ret != -ENOENT); + pr_warn("disabling SMP\n"); + init_cpu_present(&only_cpu_0); + } +@@ -139,7 +164,7 @@ out: + * - Wait for the secondary boot register to be re-written, which + * indicates the secondary core has started. + */ +-static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) ++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) + { + void __iomem *boot_reg; + phys_addr_t boot_func; +@@ -154,15 +179,16 @@ static int bcm_boot_secondary(unsigned i + return -EINVAL; + } + +- if (!secondary_boot) { ++ if (!secondary_boot_addr) { + pr_err("required secondary boot register not specified\n"); + return -EINVAL; + } + +- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); ++ boot_reg = ioremap_nocache( ++ (phys_addr_t)secondary_boot_addr, sizeof(u32)); + if (!boot_reg) { + pr_err("unable to map boot register for cpu %u\n", cpu_id); +- return -ENOSYS; ++ return -ENOMEM; + } + + /* +@@ -191,12 +217,12 @@ static int bcm_boot_secondary(unsigned i + + pr_err("timeout waiting for cpu %u to start\n", cpu_id); + +- return -ENOSYS; ++ return -ENXIO; + } + + static struct smp_operations bcm_smp_ops __initdata = { + .smp_prepare_cpus = bcm_smp_prepare_cpus, +- .smp_boot_secondary = bcm_boot_secondary, ++ .smp_boot_secondary = kona_boot_secondary, + }; + CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", + &bcm_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.3/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.3/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch new file mode 100644 index 0000000000..14a1da1eb5 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch @@ -0,0 +1,560 @@ +From e99fb6d01cddf38cffc11655aba4a96a981d604e Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Wed, 25 Nov 2015 13:25:55 -0500 +Subject: [PATCH 133/134] ARM: BCM: Add SMP support for Broadcom NSP + +Add SMP support for Broadcom's Northstar Plus SoC +cpu enable method. This changes also consolidates +iProc family's - BCM NSP and BCM Kona, platform +SMP handling in a common file. + +Northstar Plus SoC is based on ARM Cortex-A9 +revision r3p0 which requires configuration for ARM +Errata 764369 for SMP. This change adds the needed +configuration option. + +Signed-off-by: Kapil Hali +--- + arch/arm/mach-bcm/Kconfig | 2 + + arch/arm/mach-bcm/Makefile | 8 +- + arch/arm/mach-bcm/kona_smp.c | 228 ---------------------------------- + arch/arm/mach-bcm/platsmp.c | 290 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 298 insertions(+), 230 deletions(-) + delete mode 100644 arch/arm/mach-bcm/kona_smp.c + create mode 100644 arch/arm/mach-bcm/platsmp.c + +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc + obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o + + # BCM281XX and BCM21664 SMP support +-obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o ++obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o + + # BCM281XX and BCM21664 L2 cache control + obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o +--- a/arch/arm/mach-bcm/kona_smp.c ++++ /dev/null +@@ -1,228 +0,0 @@ +-/* +- * Copyright (C) 2014-2015 Broadcom Corporation +- * Copyright 2014 Linaro Limited +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation version 2. +- * +- * This program is distributed "as is" WITHOUT ANY WARRANTY of any +- * kind, whether express or implied; without even the implied warranty +- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-/* Size of mapped Cortex A9 SCU address space */ +-#define CORTEX_A9_SCU_SIZE 0x58 +- +-#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ +-#define BOOT_ADDR_CPUID_MASK 0x3 +- +-/* Name of device node property defining secondary boot register location */ +-#define OF_SECONDARY_BOOT "secondary-boot-reg" +-#define MPIDR_CPUID_BITMASK 0x3 +- +-/* I/O address of register used to coordinate secondary core startup */ +-static u32 secondary_boot_addr; +- +-/* +- * Enable the Cortex A9 Snoop Control Unit +- * +- * By the time this is called we already know there are multiple +- * cores present. We assume we're running on a Cortex A9 processor, +- * so any trouble getting the base address register or getting the +- * SCU base is a problem. +- * +- * Return 0 if successful or an error code otherwise. +- */ +-static int __init scu_a9_enable(void) +-{ +- unsigned long config_base; +- void __iomem *scu_base; +- +- if (!scu_a9_has_base()) { +- pr_err("no configuration base address register!\n"); +- return -ENXIO; +- } +- +- /* Config base address register value is zero for uniprocessor */ +- config_base = scu_a9_get_base(); +- if (!config_base) { +- pr_err("hardware reports only one core\n"); +- return -ENOENT; +- } +- +- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); +- if (!scu_base) { +- pr_err("failed to remap config base (%lu/%u) for SCU\n", +- config_base, CORTEX_A9_SCU_SIZE); +- return -ENOMEM; +- } +- +- scu_enable(scu_base); +- +- iounmap(scu_base); /* That's the last we'll need of this */ +- +- return 0; +-} +- +-static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) +-{ +- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; +- struct device_node *cpus_node = NULL; +- struct device_node *cpu_node = NULL; +- int ret; +- +- /* +- * This function is only called via smp_ops->smp_prepare_cpu(). +- * That only happens if a "/cpus" device tree node exists +- * and has an "enable-method" property that selects the SMP +- * operations defined herein. +- */ +- cpus_node = of_find_node_by_path("/cpus"); +- if (!cpus_node) +- return; +- +- for_each_child_of_node(cpus_node, cpu_node) { +- u32 cpuid; +- +- if (of_node_cmp(cpu_node->type, "cpu")) +- continue; +- +- if (of_property_read_u32(cpu_node, "reg", &cpuid)) { +- pr_debug("%s: missing reg property\n", +- cpu_node->full_name); +- ret = -ENOENT; +- goto out; +- } +- +- /* +- * "secondary-boot-reg" property should be defined only +- * for secondary cpu +- */ +- if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { +- /* +- * Our secondary enable method requires a +- * "secondary-boot-reg" property to specify a register +- * address used to request the ROM code boot a secondary +- * core. If we have any trouble getting this we fall +- * back to uniprocessor mode. +- */ +- if (of_property_read_u32(cpu_node, +- OF_SECONDARY_BOOT, +- &secondary_boot_addr)) { +- pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", +- cpu_node->name); +- ret = -ENOENT; +- goto out; +- } +- } +- } +- +- /* +- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is +- * returned, the SoC reported a uniprocessor configuration. +- * We bail on any other error. +- */ +- ret = scu_a9_enable(); +-out: +- of_node_put(cpu_node); +- of_node_put(cpus_node); +- +- if (ret) { +- /* Update the CPU present map to reflect uniprocessor mode */ +- pr_warn("disabling SMP\n"); +- init_cpu_present(&only_cpu_0); +- } +-} +- +-/* +- * The ROM code has the secondary cores looping, waiting for an event. +- * When an event occurs each core examines the bottom two bits of the +- * secondary boot register. When a core finds those bits contain its +- * own core id, it performs initialization, including computing its boot +- * address by clearing the boot register value's bottom two bits. The +- * core signals that it is beginning its execution by writing its boot +- * address back to the secondary boot register, and finally jumps to +- * that address. +- * +- * So to start a core executing we need to: +- * - Encode the (hardware) CPU id with the bottom bits of the secondary +- * start address. +- * - Write that value into the secondary boot register. +- * - Generate an event to wake up the secondary CPU(s). +- * - Wait for the secondary boot register to be re-written, which +- * indicates the secondary core has started. +- */ +-static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) +-{ +- void __iomem *boot_reg; +- phys_addr_t boot_func; +- u64 start_clock; +- u32 cpu_id; +- u32 boot_val; +- bool timeout = false; +- +- cpu_id = cpu_logical_map(cpu); +- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { +- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); +- return -EINVAL; +- } +- +- if (!secondary_boot_addr) { +- pr_err("required secondary boot register not specified\n"); +- return -EINVAL; +- } +- +- boot_reg = ioremap_nocache( +- (phys_addr_t)secondary_boot_addr, sizeof(u32)); +- if (!boot_reg) { +- pr_err("unable to map boot register for cpu %u\n", cpu_id); +- return -ENOMEM; +- } +- +- /* +- * Secondary cores will start in secondary_startup(), +- * defined in "arch/arm/kernel/head.S" +- */ +- boot_func = virt_to_phys(secondary_startup); +- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); +- BUG_ON(boot_func > (phys_addr_t)U32_MAX); +- +- /* The core to start is encoded in the low bits */ +- boot_val = (u32)boot_func | cpu_id; +- writel_relaxed(boot_val, boot_reg); +- +- sev(); +- +- /* The low bits will be cleared once the core has started */ +- start_clock = local_clock(); +- while (!timeout && readl_relaxed(boot_reg) == boot_val) +- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; +- +- iounmap(boot_reg); +- +- if (!timeout) +- return 0; +- +- pr_err("timeout waiting for cpu %u to start\n", cpu_id); +- +- return -ENXIO; +-} +- +-static struct smp_operations bcm_smp_ops __initdata = { +- .smp_prepare_cpus = bcm_smp_prepare_cpus, +- .smp_boot_secondary = kona_boot_secondary, +-}; +-CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", +- &bcm_smp_ops); +--- /dev/null ++++ b/arch/arm/mach-bcm/platsmp.c +@@ -0,0 +1,290 @@ ++/* ++ * Copyright (C) 2014-2015 Broadcom Corporation ++ * Copyright 2014 Linaro Limited ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Size of mapped Cortex A9 SCU address space */ ++#define CORTEX_A9_SCU_SIZE 0x58 ++ ++#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ ++#define BOOT_ADDR_CPUID_MASK 0x3 ++ ++/* Name of device node property defining secondary boot register location */ ++#define OF_SECONDARY_BOOT "secondary-boot-reg" ++#define MPIDR_CPUID_BITMASK 0x3 ++ ++/* I/O address of register used to coordinate secondary core startup */ ++static u32 secondary_boot_addr; ++ ++/* ++ * Enable the Cortex A9 Snoop Control Unit ++ * ++ * By the time this is called we already know there are multiple ++ * cores present. We assume we're running on a Cortex A9 processor, ++ * so any trouble getting the base address register or getting the ++ * SCU base is a problem. ++ * ++ * Return 0 if successful or an error code otherwise. ++ */ ++static int __init scu_a9_enable(void) ++{ ++ unsigned long config_base; ++ void __iomem *scu_base; ++ ++ if (!scu_a9_has_base()) { ++ pr_err("no configuration base address register!\n"); ++ return -ENXIO; ++ } ++ ++ /* Config base address register value is zero for uniprocessor */ ++ config_base = scu_a9_get_base(); ++ if (!config_base) { ++ pr_err("hardware reports only one core\n"); ++ return -ENOENT; ++ } ++ ++ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); ++ if (!scu_base) { ++ pr_err("failed to remap config base (%lu/%u) for SCU\n", ++ config_base, CORTEX_A9_SCU_SIZE); ++ return -ENOMEM; ++ } ++ ++ scu_enable(scu_base); ++ ++ iounmap(scu_base); /* That's the last we'll need of this */ ++ ++ return 0; ++} ++ ++static int nsp_write_lut(void) ++{ ++ void __iomem *sku_rom_lut; ++ phys_addr_t secondary_startup_phy; ++ ++ if (!secondary_boot_addr) { ++ pr_warn("required secondary boot register not specified\n"); ++ return -EINVAL; ++ } ++ ++ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot_addr, ++ sizeof(secondary_boot_addr)); ++ if (!sku_rom_lut) { ++ pr_warn("unable to ioremap SKU-ROM LUT register\n"); ++ return -ENOMEM; ++ } ++ ++ secondary_startup_phy = virt_to_phys(secondary_startup); ++ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); ++ ++ writel_relaxed(secondary_startup_phy, sku_rom_lut); ++ ++ /* Ensure the write is visible to the secondary core */ ++ smp_wmb(); ++ ++ iounmap(sku_rom_lut); ++ ++ return 0; ++} ++ ++static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) ++{ ++ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; ++ struct device_node *cpus_node = NULL; ++ struct device_node *cpu_node = NULL; ++ int ret; ++ ++ /* ++ * This function is only called via smp_ops->smp_prepare_cpu(). ++ * That only happens if a "/cpus" device tree node exists ++ * and has an "enable-method" property that selects the SMP ++ * operations defined herein. ++ */ ++ cpus_node = of_find_node_by_path("/cpus"); ++ if (!cpus_node) ++ return; ++ ++ for_each_child_of_node(cpus_node, cpu_node) { ++ u32 cpuid; ++ ++ if (of_node_cmp(cpu_node->type, "cpu")) ++ continue; ++ ++ if (of_property_read_u32(cpu_node, "reg", &cpuid)) { ++ pr_debug("%s: missing reg property\n", ++ cpu_node->full_name); ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ /* ++ * "secondary-boot-reg" property should be defined only ++ * for secondary cpu ++ */ ++ if ((cpuid & MPIDR_CPUID_BITMASK) == 1) { ++ /* ++ * Our secondary enable method requires a ++ * "secondary-boot-reg" property to specify a register ++ * address used to request the ROM code boot a secondary ++ * core. If we have any trouble getting this we fall ++ * back to uniprocessor mode. ++ */ ++ if (of_property_read_u32(cpu_node, ++ OF_SECONDARY_BOOT, ++ &secondary_boot_addr)) { ++ pr_warn("%s: no" OF_SECONDARY_BOOT "property\n", ++ cpu_node->name); ++ ret = -ENOENT; ++ goto out; ++ } ++ } ++ } ++ ++ /* ++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is ++ * returned, the SoC reported a uniprocessor configuration. ++ * We bail on any other error. ++ */ ++ ret = scu_a9_enable(); ++out: ++ of_node_put(cpu_node); ++ of_node_put(cpus_node); ++ ++ if (ret) { ++ /* Update the CPU present map to reflect uniprocessor mode */ ++ pr_warn("disabling SMP\n"); ++ init_cpu_present(&only_cpu_0); ++ } ++} ++ ++/* ++ * The ROM code has the secondary cores looping, waiting for an event. ++ * When an event occurs each core examines the bottom two bits of the ++ * secondary boot register. When a core finds those bits contain its ++ * own core id, it performs initialization, including computing its boot ++ * address by clearing the boot register value's bottom two bits. The ++ * core signals that it is beginning its execution by writing its boot ++ * address back to the secondary boot register, and finally jumps to ++ * that address. ++ * ++ * So to start a core executing we need to: ++ * - Encode the (hardware) CPU id with the bottom bits of the secondary ++ * start address. ++ * - Write that value into the secondary boot register. ++ * - Generate an event to wake up the secondary CPU(s). ++ * - Wait for the secondary boot register to be re-written, which ++ * indicates the secondary core has started. ++ */ ++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) ++{ ++ void __iomem *boot_reg; ++ phys_addr_t boot_func; ++ u64 start_clock; ++ u32 cpu_id; ++ u32 boot_val; ++ bool timeout = false; ++ ++ cpu_id = cpu_logical_map(cpu); ++ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { ++ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); ++ return -EINVAL; ++ } ++ ++ if (!secondary_boot_addr) { ++ pr_err("required secondary boot register not specified\n"); ++ return -EINVAL; ++ } ++ ++ boot_reg = ioremap_nocache( ++ (phys_addr_t)secondary_boot_addr, sizeof(u32)); ++ if (!boot_reg) { ++ pr_err("unable to map boot register for cpu %u\n", cpu_id); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Secondary cores will start in secondary_startup(), ++ * defined in "arch/arm/kernel/head.S" ++ */ ++ boot_func = virt_to_phys(secondary_startup); ++ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); ++ BUG_ON(boot_func > (phys_addr_t)U32_MAX); ++ ++ /* The core to start is encoded in the low bits */ ++ boot_val = (u32)boot_func | cpu_id; ++ writel_relaxed(boot_val, boot_reg); ++ ++ sev(); ++ ++ /* The low bits will be cleared once the core has started */ ++ start_clock = local_clock(); ++ while (!timeout && readl_relaxed(boot_reg) == boot_val) ++ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; ++ ++ iounmap(boot_reg); ++ ++ if (!timeout) ++ return 0; ++ ++ pr_err("timeout waiting for cpu %u to start\n", cpu_id); ++ ++ return -ENXIO; ++} ++ ++static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) ++{ ++ int ret; ++ ++ /* ++ * After wake up, secondary core branches to the startup ++ * address programmed at SKU ROM LUT location. ++ */ ++ ret = nsp_write_lut(); ++ if (ret) { ++ pr_err("unable to write startup addr to SKU ROM LUT\n"); ++ goto out; ++ } ++ ++ /* Send a CPU wakeup interrupt to the secondary core */ ++ arch_send_wakeup_ipi_mask(cpumask_of(cpu)); ++ ++out: ++ return ret; ++} ++ ++static struct smp_operations bcm_smp_ops __initdata = { ++ .smp_prepare_cpus = bcm_smp_prepare_cpus, ++ .smp_boot_secondary = kona_boot_secondary, ++}; ++CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", ++ &bcm_smp_ops); ++ ++struct smp_operations nsp_smp_ops __initdata = { ++ .smp_prepare_cpus = bcm_smp_prepare_cpus, ++ .smp_boot_secondary = nsp_boot_secondary, ++}; ++CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); diff --git a/target/linux/bcm53xx/patches-4.3/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.3/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch new file mode 100644 index 0000000000..9260190a34 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.3/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch @@ -0,0 +1,57 @@ +From 16e1bf7dde22ee22a331aabf824cc31a6794a4cb Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Thu, 15 Oct 2015 14:09:10 -0400 +Subject: [PATCH 134/134] ARM: BCM: Add SMP support for Broadcom 4708 + +Add SMP support for Broadcom's 4708 SoCs. + +Signed-off-by: Jon Mason +Acked-by: Hauke Mehrtens +Tested-by: Hauke Mehrtens +Signed-off-by: Kapil Hali +--- + arch/arm/boot/dts/bcm4708.dtsi | 2 ++ + arch/arm/mach-bcm/Kconfig | 1 + + arch/arm/mach-bcm/Makefile | 3 +++ + 3 files changed, 6 insertions(+) + +--- a/arch/arm/boot/dts/bcm4708.dtsi ++++ b/arch/arm/boot/dts/bcm4708.dtsi +@@ -15,6 +15,7 @@ + cpus { + #address-cells = <1>; + #size-cells = <0>; ++ enable-method = "brcm,bcm-nsp-smp"; + + cpu@0 { + device_type = "cpu"; +@@ -27,6 +28,7 @@ + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; ++ secondary-boot-reg = <0xffff0400>; + reg = <0x1>; + }; + }; +--- a/arch/arm/mach-bcm/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -41,6 +41,7 @@ config ARCH_BCM_5301X + select ARM_ERRATA_754322 + select ARM_ERRATA_775420 + select ARM_ERRATA_764369 if SMP ++ select HAVE_SMP + + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2 + + # BCM5301X + obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o ++ifeq ($(CONFIG_ARCH_BCM_5301X),y) ++obj-$(CONFIG_SMP) += platsmp.o ++endif + + # BCM63XXx + ifeq ($(CONFIG_ARCH_BCM_63XX),y)