1 From 55be958cd27439a58c4d9369d6fe2a1f83efdaa6 Mon Sep 17 00:00:00 2001
2 From: Kapil Hali <kapilh@broadcom.com>
3 Date: Sat, 5 Dec 2015 06:53:43 -0500
4 Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom NSP
6 Add SMP support for Broadcom's Northstar Plus SoC
7 cpu enable method. This changes also consolidates
8 iProc family's - BCM NSP and BCM Kona, platform
9 SMP handling in a common file.
11 Northstar Plus SoC is based on ARM Cortex-A9
12 revision r3p0 which requires configuration for ARM
13 Errata 764369 for SMP. This change adds the needed
16 Signed-off-by: Kapil Hali <kapilh@broadcom.com>
17 Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
19 arch/arm/mach-bcm/Kconfig | 2 +
20 arch/arm/mach-bcm/Makefile | 8 +-
21 arch/arm/mach-bcm/kona_smp.c | 228 ----------------------------------
22 arch/arm/mach-bcm/platsmp.c | 290 +++++++++++++++++++++++++++++++++++++++++++
23 4 files changed, 298 insertions(+), 230 deletions(-)
24 delete mode 100644 arch/arm/mach-bcm/kona_smp.c
25 create mode 100644 arch/arm/mach-bcm/platsmp.c
27 --- a/arch/arm/mach-bcm/Kconfig
28 +++ b/arch/arm/mach-bcm/Kconfig
29 @@ -40,6 +40,8 @@ config ARCH_BCM_NSP
31 select ARM_ERRATA_754322
32 select ARM_ERRATA_775420
33 + select ARM_ERRATA_764369 if SMP
36 Support for Broadcom Northstar Plus SoC.
37 Broadcom Northstar Plus family of SoCs are used for switching control
38 --- a/arch/arm/mach-bcm/Makefile
39 +++ b/arch/arm/mach-bcm/Makefile
41 obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
44 -obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o
45 +obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o
47 +ifeq ($(CONFIG_ARCH_BCM_NSP),y)
48 +obj-$(CONFIG_SMP) += platsmp.o
52 obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
53 @@ -23,7 +27,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
54 obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
56 # BCM281XX and BCM21664 SMP support
57 -obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o
58 +obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o
60 # BCM281XX and BCM21664 L2 cache control
61 obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
62 --- a/arch/arm/mach-bcm/kona_smp.c
66 - * Copyright (C) 2014-2015 Broadcom Corporation
67 - * Copyright 2014 Linaro Limited
69 - * This program is free software; you can redistribute it and/or
70 - * modify it under the terms of the GNU General Public License as
71 - * published by the Free Software Foundation version 2.
73 - * This program is distributed "as is" WITHOUT ANY WARRANTY of any
74 - * kind, whether express or implied; without even the implied warranty
75 - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76 - * GNU General Public License for more details.
79 -#include <linux/init.h>
80 -#include <linux/errno.h>
81 -#include <linux/io.h>
82 -#include <linux/of.h>
83 -#include <linux/sched.h>
86 -#include <asm/smp_plat.h>
87 -#include <asm/smp_scu.h>
89 -/* Size of mapped Cortex A9 SCU address space */
90 -#define CORTEX_A9_SCU_SIZE 0x58
92 -#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
93 -#define BOOT_ADDR_CPUID_MASK 0x3
95 -/* Name of device node property defining secondary boot register location */
96 -#define OF_SECONDARY_BOOT "secondary-boot-reg"
97 -#define MPIDR_CPUID_BITMASK 0x3
99 -/* I/O address of register used to coordinate secondary core startup */
100 -static u32 secondary_boot_addr;
103 - * Enable the Cortex A9 Snoop Control Unit
105 - * By the time this is called we already know there are multiple
106 - * cores present. We assume we're running on a Cortex A9 processor,
107 - * so any trouble getting the base address register or getting the
108 - * SCU base is a problem.
110 - * Return 0 if successful or an error code otherwise.
112 -static int __init scu_a9_enable(void)
114 - unsigned long config_base;
115 - void __iomem *scu_base;
117 - if (!scu_a9_has_base()) {
118 - pr_err("no configuration base address register!\n");
122 - /* Config base address register value is zero for uniprocessor */
123 - config_base = scu_a9_get_base();
124 - if (!config_base) {
125 - pr_err("hardware reports only one core\n");
129 - scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
131 - pr_err("failed to remap config base (%lu/%u) for SCU\n",
132 - config_base, CORTEX_A9_SCU_SIZE);
136 - scu_enable(scu_base);
138 - iounmap(scu_base); /* That's the last we'll need of this */
143 -static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
145 - static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
146 - struct device_node *cpus_node = NULL;
147 - struct device_node *cpu_node = NULL;
151 - * This function is only called via smp_ops->smp_prepare_cpu().
152 - * That only happens if a "/cpus" device tree node exists
153 - * and has an "enable-method" property that selects the SMP
154 - * operations defined herein.
156 - cpus_node = of_find_node_by_path("/cpus");
160 - for_each_child_of_node(cpus_node, cpu_node) {
163 - if (of_node_cmp(cpu_node->type, "cpu"))
166 - if (of_property_read_u32(cpu_node, "reg", &cpuid)) {
167 - pr_debug("%s: missing reg property\n",
168 - cpu_node->full_name);
174 - * "secondary-boot-reg" property should be defined only
175 - * for secondary cpu
177 - if ((cpuid & MPIDR_CPUID_BITMASK) == 1) {
179 - * Our secondary enable method requires a
180 - * "secondary-boot-reg" property to specify a register
181 - * address used to request the ROM code boot a secondary
182 - * core. If we have any trouble getting this we fall
183 - * back to uniprocessor mode.
185 - if (of_property_read_u32(cpu_node,
187 - &secondary_boot_addr)) {
188 - pr_warn("%s: no" OF_SECONDARY_BOOT "property\n",
197 - * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
198 - * returned, the SoC reported a uniprocessor configuration.
199 - * We bail on any other error.
201 - ret = scu_a9_enable();
203 - of_node_put(cpu_node);
204 - of_node_put(cpus_node);
207 - /* Update the CPU present map to reflect uniprocessor mode */
208 - pr_warn("disabling SMP\n");
209 - init_cpu_present(&only_cpu_0);
214 - * The ROM code has the secondary cores looping, waiting for an event.
215 - * When an event occurs each core examines the bottom two bits of the
216 - * secondary boot register. When a core finds those bits contain its
217 - * own core id, it performs initialization, including computing its boot
218 - * address by clearing the boot register value's bottom two bits. The
219 - * core signals that it is beginning its execution by writing its boot
220 - * address back to the secondary boot register, and finally jumps to
223 - * So to start a core executing we need to:
224 - * - Encode the (hardware) CPU id with the bottom bits of the secondary
226 - * - Write that value into the secondary boot register.
227 - * - Generate an event to wake up the secondary CPU(s).
228 - * - Wait for the secondary boot register to be re-written, which
229 - * indicates the secondary core has started.
231 -static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
233 - void __iomem *boot_reg;
234 - phys_addr_t boot_func;
238 - bool timeout = false;
240 - cpu_id = cpu_logical_map(cpu);
241 - if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
242 - pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
246 - if (!secondary_boot_addr) {
247 - pr_err("required secondary boot register not specified\n");
251 - boot_reg = ioremap_nocache(
252 - (phys_addr_t)secondary_boot_addr, sizeof(u32));
254 - pr_err("unable to map boot register for cpu %u\n", cpu_id);
259 - * Secondary cores will start in secondary_startup(),
260 - * defined in "arch/arm/kernel/head.S"
262 - boot_func = virt_to_phys(secondary_startup);
263 - BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
264 - BUG_ON(boot_func > (phys_addr_t)U32_MAX);
266 - /* The core to start is encoded in the low bits */
267 - boot_val = (u32)boot_func | cpu_id;
268 - writel_relaxed(boot_val, boot_reg);
272 - /* The low bits will be cleared once the core has started */
273 - start_clock = local_clock();
274 - while (!timeout && readl_relaxed(boot_reg) == boot_val)
275 - timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
282 - pr_err("timeout waiting for cpu %u to start\n", cpu_id);
287 -static struct smp_operations bcm_smp_ops __initdata = {
288 - .smp_prepare_cpus = bcm_smp_prepare_cpus,
289 - .smp_boot_secondary = kona_boot_secondary,
291 -CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
294 +++ b/arch/arm/mach-bcm/platsmp.c
297 + * Copyright (C) 2014-2015 Broadcom Corporation
298 + * Copyright 2014 Linaro Limited
300 + * This program is free software; you can redistribute it and/or
301 + * modify it under the terms of the GNU General Public License as
302 + * published by the Free Software Foundation version 2.
304 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
305 + * kind, whether express or implied; without even the implied warranty
306 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
307 + * GNU General Public License for more details.
310 +#include <linux/cpumask.h>
311 +#include <linux/delay.h>
312 +#include <linux/errno.h>
313 +#include <linux/init.h>
314 +#include <linux/io.h>
315 +#include <linux/jiffies.h>
316 +#include <linux/of.h>
317 +#include <linux/sched.h>
318 +#include <linux/smp.h>
320 +#include <asm/cacheflush.h>
321 +#include <asm/smp.h>
322 +#include <asm/smp_plat.h>
323 +#include <asm/smp_scu.h>
325 +/* Size of mapped Cortex A9 SCU address space */
326 +#define CORTEX_A9_SCU_SIZE 0x58
328 +#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
329 +#define BOOT_ADDR_CPUID_MASK 0x3
331 +/* Name of device node property defining secondary boot register location */
332 +#define OF_SECONDARY_BOOT "secondary-boot-reg"
333 +#define MPIDR_CPUID_BITMASK 0x3
335 +/* I/O address of register used to coordinate secondary core startup */
336 +static u32 secondary_boot_addr;
339 + * Enable the Cortex A9 Snoop Control Unit
341 + * By the time this is called we already know there are multiple
342 + * cores present. We assume we're running on a Cortex A9 processor,
343 + * so any trouble getting the base address register or getting the
344 + * SCU base is a problem.
346 + * Return 0 if successful or an error code otherwise.
348 +static int __init scu_a9_enable(void)
350 + unsigned long config_base;
351 + void __iomem *scu_base;
353 + if (!scu_a9_has_base()) {
354 + pr_err("no configuration base address register!\n");
358 + /* Config base address register value is zero for uniprocessor */
359 + config_base = scu_a9_get_base();
360 + if (!config_base) {
361 + pr_err("hardware reports only one core\n");
365 + scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
367 + pr_err("failed to remap config base (%lu/%u) for SCU\n",
368 + config_base, CORTEX_A9_SCU_SIZE);
372 + scu_enable(scu_base);
374 + iounmap(scu_base); /* That's the last we'll need of this */
379 +static int nsp_write_lut(void)
381 + void __iomem *sku_rom_lut;
382 + phys_addr_t secondary_startup_phy;
384 + if (!secondary_boot_addr) {
385 + pr_warn("required secondary boot register not specified\n");
389 + sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot_addr,
390 + sizeof(secondary_boot_addr));
391 + if (!sku_rom_lut) {
392 + pr_warn("unable to ioremap SKU-ROM LUT register\n");
396 + secondary_startup_phy = virt_to_phys(secondary_startup);
397 + BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX);
399 + writel_relaxed(secondary_startup_phy, sku_rom_lut);
401 + /* Ensure the write is visible to the secondary core */
404 + iounmap(sku_rom_lut);
409 +static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
411 + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
412 + struct device_node *cpus_node = NULL;
413 + struct device_node *cpu_node = NULL;
417 + * This function is only called via smp_ops->smp_prepare_cpu().
418 + * That only happens if a "/cpus" device tree node exists
419 + * and has an "enable-method" property that selects the SMP
420 + * operations defined herein.
422 + cpus_node = of_find_node_by_path("/cpus");
426 + for_each_child_of_node(cpus_node, cpu_node) {
429 + if (of_node_cmp(cpu_node->type, "cpu"))
432 + if (of_property_read_u32(cpu_node, "reg", &cpuid)) {
433 + pr_debug("%s: missing reg property\n",
434 + cpu_node->full_name);
440 + * "secondary-boot-reg" property should be defined only
441 + * for secondary cpu
443 + if ((cpuid & MPIDR_CPUID_BITMASK) == 1) {
445 + * Our secondary enable method requires a
446 + * "secondary-boot-reg" property to specify a register
447 + * address used to request the ROM code boot a secondary
448 + * core. If we have any trouble getting this we fall
449 + * back to uniprocessor mode.
451 + if (of_property_read_u32(cpu_node,
453 + &secondary_boot_addr)) {
454 + pr_warn("%s: no" OF_SECONDARY_BOOT "property\n",
463 + * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
464 + * returned, the SoC reported a uniprocessor configuration.
465 + * We bail on any other error.
467 + ret = scu_a9_enable();
469 + of_node_put(cpu_node);
470 + of_node_put(cpus_node);
473 + /* Update the CPU present map to reflect uniprocessor mode */
474 + pr_warn("disabling SMP\n");
475 + init_cpu_present(&only_cpu_0);
480 + * The ROM code has the secondary cores looping, waiting for an event.
481 + * When an event occurs each core examines the bottom two bits of the
482 + * secondary boot register. When a core finds those bits contain its
483 + * own core id, it performs initialization, including computing its boot
484 + * address by clearing the boot register value's bottom two bits. The
485 + * core signals that it is beginning its execution by writing its boot
486 + * address back to the secondary boot register, and finally jumps to
489 + * So to start a core executing we need to:
490 + * - Encode the (hardware) CPU id with the bottom bits of the secondary
492 + * - Write that value into the secondary boot register.
493 + * - Generate an event to wake up the secondary CPU(s).
494 + * - Wait for the secondary boot register to be re-written, which
495 + * indicates the secondary core has started.
497 +static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
499 + void __iomem *boot_reg;
500 + phys_addr_t boot_func;
504 + bool timeout = false;
506 + cpu_id = cpu_logical_map(cpu);
507 + if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
508 + pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
512 + if (!secondary_boot_addr) {
513 + pr_err("required secondary boot register not specified\n");
517 + boot_reg = ioremap_nocache(
518 + (phys_addr_t)secondary_boot_addr, sizeof(u32));
520 + pr_err("unable to map boot register for cpu %u\n", cpu_id);
525 + * Secondary cores will start in secondary_startup(),
526 + * defined in "arch/arm/kernel/head.S"
528 + boot_func = virt_to_phys(secondary_startup);
529 + BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
530 + BUG_ON(boot_func > (phys_addr_t)U32_MAX);
532 + /* The core to start is encoded in the low bits */
533 + boot_val = (u32)boot_func | cpu_id;
534 + writel_relaxed(boot_val, boot_reg);
538 + /* The low bits will be cleared once the core has started */
539 + start_clock = local_clock();
540 + while (!timeout && readl_relaxed(boot_reg) == boot_val)
541 + timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
548 + pr_err("timeout waiting for cpu %u to start\n", cpu_id);
553 +static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle)
558 + * After wake up, secondary core branches to the startup
559 + * address programmed at SKU ROM LUT location.
561 + ret = nsp_write_lut();
563 + pr_err("unable to write startup addr to SKU ROM LUT\n");
567 + /* Send a CPU wakeup interrupt to the secondary core */
568 + arch_send_wakeup_ipi_mask(cpumask_of(cpu));
574 +static struct smp_operations bcm_smp_ops __initdata = {
575 + .smp_prepare_cpus = bcm_smp_prepare_cpus,
576 + .smp_boot_secondary = kona_boot_secondary,
578 +CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
581 +struct smp_operations nsp_smp_ops __initdata = {
582 + .smp_prepare_cpus = bcm_smp_prepare_cpus,
583 + .smp_boot_secondary = nsp_boot_secondary,
585 +CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops);