From: Rafał Miłecki Date: Mon, 7 Dec 2015 19:20:40 +0000 (+0000) Subject: bcm53xx: use backported BCM5301X patches from stblinux soc/next X-Git-Tag: reboot~1262 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=b473cd8085ff1987e61fd283906815730a06be05;p=openwrt%2Fstaging%2Fblogic.git bcm53xx: use backported BCM5301X patches from stblinux soc/next Signed-off-by: Rafał Miłecki SVN-Revision: 47807 --- diff --git a/target/linux/bcm53xx/patches-4.4/022-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch b/target/linux/bcm53xx/patches-4.4/022-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch new file mode 100644 index 000000000000..c79cf95fd8d2 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/022-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch @@ -0,0 +1,254 @@ +From b5989f783de046577067fe356b1bb76cae07e867 Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Sat, 5 Dec 2015 06:53:41 -0500 +Subject: [PATCH] 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 +Signed-off-by: Florian Fainelli +--- + .../bindings/arm/bcm/brcm,bcm11351-cpu-method.txt | 12 ++-- + arch/arm/boot/dts/bcm11351.dtsi | 4 +- + arch/arm/boot/dts/bcm21664.dtsi | 4 +- + arch/arm/mach-bcm/kona_smp.c | 82 ++++++++++++++-------- + 4 files changed, 64 insertions(+), 38 deletions(-) + +--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351-cpu-method.txt ++++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351-cpu-method.txt +@@ -1,17 +1,17 @@ + Broadcom Kona Family CPU Enable Method + -------------------------------------- + This binding defines the enable method used for starting secondary +-CPUs in the following Broadcom SoCs: ++CPU in the following Broadcom SoCs: + BCM11130, BCM11140, BCM11351, BCM28145, BCM28155, BCM21664 + + The enable method is specified by defining the following required +-properties in the "cpus" device tree node: ++properties in the corresponding secondary "cpu" device tree node: + - enable-method = "brcm,bcm11351-cpu-method"; + - secondary-boot-reg = <...>; + + The secondary-boot-reg property is a u32 value that specifies the +-physical address of the register used to request the ROM holding pen +-code release a secondary CPU. The value written to the register is ++physical address of the register used to request the ROM code ++release a secondary CPU. The value written to the register is + formed by encoding the target CPU id into the low bits of the + physical start address it should jump to. + +@@ -19,8 +19,6 @@ Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; +- enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x3500417c>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -31,6 +29,8 @@ Example: + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ enable-method = "brcm,bcm11351-cpu-method"; ++ secondary-boot-reg = <0x3500417c>; + reg = <1>; + }; + }; +--- a/arch/arm/boot/dts/bcm11351.dtsi ++++ b/arch/arm/boot/dts/bcm11351.dtsi +@@ -30,8 +30,6 @@ + cpus { + #address-cells = <1>; + #size-cells = <0>; +- enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x3500417c>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +40,8 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ enable-method = "brcm,bcm11351-cpu-method"; ++ secondary-boot-reg = <0x3500417c>; + reg = <1>; + }; + }; +--- a/arch/arm/boot/dts/bcm21664.dtsi ++++ b/arch/arm/boot/dts/bcm21664.dtsi +@@ -30,8 +30,6 @@ + cpus { + #address-cells = <1>; + #size-cells = <0>; +- enable-method = "brcm,bcm11351-cpu-method"; +- secondary-boot-reg = <0x35004178>; + + cpu0: cpu@0 { + device_type = "cpu"; +@@ -42,6 +40,8 @@ + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; ++ enable-method = "brcm,bcm11351-cpu-method"; ++ 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 int cpu, struct task_struct *idle) + 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 int cpu, struct task_struct *idle) + + 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.4/023-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.4/023-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch new file mode 100644 index 000000000000..fb592415e9e7 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/023-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch @@ -0,0 +1,585 @@ +From 55be958cd27439a58c4d9369d6fe2a1f83efdaa6 Mon Sep 17 00:00:00 2001 +From: Kapil Hali +Date: Sat, 5 Dec 2015 06:53:43 -0500 +Subject: [PATCH] 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 +Signed-off-by: Florian Fainelli +--- + 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/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -40,6 +40,8 @@ config ARCH_BCM_NSP + select ARCH_BCM_IPROC + select ARM_ERRATA_754322 + select ARM_ERRATA_775420 ++ select ARM_ERRATA_764369 if SMP ++ select HAVE_SMP + help + Support for Broadcom Northstar Plus SoC. + Broadcom Northstar Plus family of SoCs are used for switching control +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -14,7 +14,11 @@ + obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o + + # Northstar Plus +-obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o ++obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o ++ ++ifeq ($(CONFIG_ARCH_BCM_NSP),y) ++obj-$(CONFIG_SMP) += platsmp.o ++endif + + # BCM281XX + obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o +@@ -23,7 +27,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o + 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.4/024-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.4/024-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch new file mode 100644 index 000000000000..e38b0e528f36 --- /dev/null +++ b/target/linux/bcm53xx/patches-4.4/024-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch @@ -0,0 +1,53 @@ +From af0783a87a365e87e5ee0ac0ba7e3075abc5007c Mon Sep 17 00:00:00 2001 +From: Jon Mason +Date: Sat, 5 Dec 2015 06:53:44 -0500 +Subject: [PATCH] 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 +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm4708.dtsi | 3 ++- + arch/arm/mach-bcm/Kconfig | 1 + + arch/arm/mach-bcm/Makefile | 3 +++ + 3 files changed, 6 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm4708.dtsi ++++ b/arch/arm/boot/dts/bcm4708.dtsi +@@ -27,8 +27,9 @@ + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; ++ enable-method = "brcm,bcm-nsp-smp"; ++ secondary-boot-reg = <0xffff0400>; + reg = <0x1>; + }; + }; +- + }; +--- a/arch/arm/mach-bcm/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -29,6 +29,7 @@ config ARCH_BCM_IPROC + config ARCH_BCM_CYGNUS + bool "Broadcom Cygnus Support" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC ++ select HAVE_SMP + help + Enable support for the Cygnus family, + which includes the following variants: +--- a/arch/arm/mach-bcm/Makefile ++++ b/arch/arm/mach-bcm/Makefile +@@ -43,6 +43,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2835.o + + # 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) diff --git a/target/linux/bcm53xx/patches-4.4/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch b/target/linux/bcm53xx/patches-4.4/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch deleted file mode 100644 index 7a48a13e64d2..000000000000 --- a/target/linux/bcm53xx/patches-4.4/131-ARM-BCM-Clean-up-SMP-support-for-Broadcom-Kona.patch +++ /dev/null @@ -1,206 +0,0 @@ -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.4/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.4/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch deleted file mode 100644 index 75db188ca240..000000000000 --- a/target/linux/bcm53xx/patches-4.4/133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch +++ /dev/null @@ -1,560 +0,0 @@ -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 -@@ -23,7 +23,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.4/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.4/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch deleted file mode 100644 index 3c8aed03b210..000000000000 --- a/target/linux/bcm53xx/patches-4.4/134-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch +++ /dev/null @@ -1,57 +0,0 @@ -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 -@@ -55,6 +55,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 -@@ -39,6 +39,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)