1 From a0ad1511d5805b95ac4c454d7904c670a1696055 Mon Sep 17 00:00:00 2001
2 From: Kapil Hali <kapilh@broadcom.com>
3 Date: Wed, 14 Oct 2015 13:47:00 -0400
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 and pen_release procedures. This
8 changes also consolidates iProc family's - BCM NSP
9 and BCM Kona, 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>
18 arch/arm/mach-bcm/Makefile | 2 +-
19 arch/arm/mach-bcm/bcm_nsp.h | 19 +++
20 arch/arm/mach-bcm/headsmp.S | 37 +++++
21 arch/arm/mach-bcm/kona_smp.c | 202 ---------------------------
22 arch/arm/mach-bcm/platsmp.c | 326 +++++++++++++++++++++++++++++++++++++++++++
23 5 files changed, 383 insertions(+), 203 deletions(-)
24 create mode 100644 arch/arm/mach-bcm/bcm_nsp.h
25 create mode 100644 arch/arm/mach-bcm/headsmp.S
26 delete mode 100644 arch/arm/mach-bcm/kona_smp.c
27 create mode 100644 arch/arm/mach-bcm/platsmp.c
29 --- a/arch/arm/mach-bcm/Makefile
30 +++ b/arch/arm/mach-bcm/Makefile
31 @@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc
32 obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
34 # BCM281XX and BCM21664 SMP support
35 -obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o
36 +obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o
38 # BCM281XX and BCM21664 L2 cache control
39 obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
41 +++ b/arch/arm/mach-bcm/bcm_nsp.h
44 + * Copyright (C) 2015 Broadcom Corporation
46 + * This program is free software; you can redistribute it and/or
47 + * modify it under the terms of the GNU General Public License as
48 + * published by the Free Software Foundation version 2.
50 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
51 + * kind, whether express or implied; without even the implied warranty
52 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53 + * GNU General Public License for more details.
59 +extern void nsp_secondary_startup(void);
61 +#endif /* __BCM_NSP_H */
63 +++ b/arch/arm/mach-bcm/headsmp.S
66 + * Copyright (C) 2015 Broadcom Corporation
68 + * This program is free software; you can redistribute it and/or
69 + * modify it under the terms of the GNU General Public License as
70 + * published by the Free Software Foundation version 2.
72 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
73 + * kind, whether express or implied; without even the implied warranty
74 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75 + * GNU General Public License for more details.
78 +#include <linux/linkage.h>
81 + * iProc specific entry point for secondary CPUs. This provides
82 + * a "holding pen" into which all secondary cores are held until
83 + * we are ready for them to initialise.
85 +ENTRY(nsp_secondary_startup)
86 + mrc p15, 0, r0, c0, c0, 5
101 +ENDPROC(nsp_secondary_startup)
102 --- a/arch/arm/mach-bcm/kona_smp.c
106 - * Copyright (C) 2014 Broadcom Corporation
107 - * Copyright 2014 Linaro Limited
109 - * This program is free software; you can redistribute it and/or
110 - * modify it under the terms of the GNU General Public License as
111 - * published by the Free Software Foundation version 2.
113 - * This program is distributed "as is" WITHOUT ANY WARRANTY of any
114 - * kind, whether express or implied; without even the implied warranty
115 - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
116 - * GNU General Public License for more details.
119 -#include <linux/init.h>
120 -#include <linux/errno.h>
121 -#include <linux/io.h>
122 -#include <linux/of.h>
123 -#include <linux/sched.h>
125 -#include <asm/smp.h>
126 -#include <asm/smp_plat.h>
127 -#include <asm/smp_scu.h>
129 -/* Size of mapped Cortex A9 SCU address space */
130 -#define CORTEX_A9_SCU_SIZE 0x58
132 -#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
133 -#define BOOT_ADDR_CPUID_MASK 0x3
135 -/* Name of device node property defining secondary boot register location */
136 -#define OF_SECONDARY_BOOT "secondary-boot-reg"
138 -/* I/O address of register used to coordinate secondary core startup */
139 -static u32 secondary_boot;
142 - * Enable the Cortex A9 Snoop Control Unit
144 - * By the time this is called we already know there are multiple
145 - * cores present. We assume we're running on a Cortex A9 processor,
146 - * so any trouble getting the base address register or getting the
147 - * SCU base is a problem.
149 - * Return 0 if successful or an error code otherwise.
151 -static int __init scu_a9_enable(void)
153 - unsigned long config_base;
154 - void __iomem *scu_base;
156 - if (!scu_a9_has_base()) {
157 - pr_err("no configuration base address register!\n");
161 - /* Config base address register value is zero for uniprocessor */
162 - config_base = scu_a9_get_base();
163 - if (!config_base) {
164 - pr_err("hardware reports only one core\n");
168 - scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
170 - pr_err("failed to remap config base (%lu/%u) for SCU\n",
171 - config_base, CORTEX_A9_SCU_SIZE);
175 - scu_enable(scu_base);
177 - iounmap(scu_base); /* That's the last we'll need of this */
182 -static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
184 - static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
185 - struct device_node *node;
188 - BUG_ON(secondary_boot); /* We're called only once */
191 - * This function is only called via smp_ops->smp_prepare_cpu().
192 - * That only happens if a "/cpus" device tree node exists
193 - * and has an "enable-method" property that selects the SMP
194 - * operations defined herein.
196 - node = of_find_node_by_path("/cpus");
200 - * Our secondary enable method requires a "secondary-boot-reg"
201 - * property to specify a register address used to request the
202 - * ROM code boot a secondary code. If we have any trouble
203 - * getting this we fall back to uniprocessor mode.
205 - if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
206 - pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
208 - ret = -ENOENT; /* Arrange to disable SMP */
213 - * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
214 - * returned, the SoC reported a uniprocessor configuration.
215 - * We bail on any other error.
217 - ret = scu_a9_enable();
221 - /* Update the CPU present map to reflect uniprocessor mode */
222 - BUG_ON(ret != -ENOENT);
223 - pr_warn("disabling SMP\n");
224 - init_cpu_present(&only_cpu_0);
229 - * The ROM code has the secondary cores looping, waiting for an event.
230 - * When an event occurs each core examines the bottom two bits of the
231 - * secondary boot register. When a core finds those bits contain its
232 - * own core id, it performs initialization, including computing its boot
233 - * address by clearing the boot register value's bottom two bits. The
234 - * core signals that it is beginning its execution by writing its boot
235 - * address back to the secondary boot register, and finally jumps to
238 - * So to start a core executing we need to:
239 - * - Encode the (hardware) CPU id with the bottom bits of the secondary
241 - * - Write that value into the secondary boot register.
242 - * - Generate an event to wake up the secondary CPU(s).
243 - * - Wait for the secondary boot register to be re-written, which
244 - * indicates the secondary core has started.
246 -static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle)
248 - void __iomem *boot_reg;
249 - phys_addr_t boot_func;
253 - bool timeout = false;
255 - cpu_id = cpu_logical_map(cpu);
256 - if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
257 - pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
261 - if (!secondary_boot) {
262 - pr_err("required secondary boot register not specified\n");
266 - boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
268 - pr_err("unable to map boot register for cpu %u\n", cpu_id);
273 - * Secondary cores will start in secondary_startup(),
274 - * defined in "arch/arm/kernel/head.S"
276 - boot_func = virt_to_phys(secondary_startup);
277 - BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
278 - BUG_ON(boot_func > (phys_addr_t)U32_MAX);
280 - /* The core to start is encoded in the low bits */
281 - boot_val = (u32)boot_func | cpu_id;
282 - writel_relaxed(boot_val, boot_reg);
286 - /* The low bits will be cleared once the core has started */
287 - start_clock = local_clock();
288 - while (!timeout && readl_relaxed(boot_reg) == boot_val)
289 - timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
296 - pr_err("timeout waiting for cpu %u to start\n", cpu_id);
301 -static struct smp_operations bcm_smp_ops __initdata = {
302 - .smp_prepare_cpus = bcm_smp_prepare_cpus,
303 - .smp_boot_secondary = bcm_boot_secondary,
305 -CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
308 +++ b/arch/arm/mach-bcm/platsmp.c
311 + * Copyright (C) 2014-2015 Broadcom Corporation
312 + * Copyright 2014 Linaro Limited
314 + * This program is free software; you can redistribute it and/or
315 + * modify it under the terms of the GNU General Public License as
316 + * published by the Free Software Foundation version 2.
318 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
319 + * kind, whether express or implied; without even the implied warranty
320 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
321 + * GNU General Public License for more details.
324 +#include <linux/cpumask.h>
325 +#include <linux/delay.h>
326 +#include <linux/errno.h>
327 +#include <linux/init.h>
328 +#include <linux/io.h>
329 +#include <linux/jiffies.h>
330 +#include <linux/of.h>
331 +#include <linux/sched.h>
332 +#include <linux/smp.h>
334 +#include <asm/cacheflush.h>
335 +#include <asm/smp.h>
336 +#include <asm/smp_plat.h>
337 +#include <asm/smp_scu.h>
339 +#include "bcm_nsp.h"
341 +/* Size of mapped Cortex A9 SCU address space */
342 +#define CORTEX_A9_SCU_SIZE 0x58
344 +#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
345 +#define BOOT_ADDR_CPUID_MASK 0x3
347 +/* Name of device node property defining secondary boot register location */
348 +#define OF_SECONDARY_BOOT "secondary-boot-reg"
350 +/* I/O address of register used to coordinate secondary core startup */
351 +static u32 secondary_boot;
353 +static DEFINE_SPINLOCK(boot_lock);
356 + * Write pen_release in a way that is guaranteed to be visible to all
357 + * observers, irrespective of whether they're taking part in coherency
358 + * or not. This is necessary for the hotplug code to work reliably.
360 +static void write_pen_release(int val)
364 + * Ensure write to pen_release is visible to the other cores,
365 + * here - primary core
368 + sync_cache_w(&pen_release);
372 + * Enable the Cortex A9 Snoop Control Unit
374 + * By the time this is called we already know there are multiple
375 + * cores present. We assume we're running on a Cortex A9 processor,
376 + * so any trouble getting the base address register or getting the
377 + * SCU base is a problem.
379 + * Return 0 if successful or an error code otherwise.
381 +static int __init scu_a9_enable(void)
383 + unsigned long config_base;
384 + void __iomem *scu_base;
386 + if (!scu_a9_has_base()) {
387 + pr_err("no configuration base address register!\n");
391 + /* Config base address register value is zero for uniprocessor */
392 + config_base = scu_a9_get_base();
393 + if (!config_base) {
394 + pr_err("hardware reports only one core\n");
398 + scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
400 + pr_err("failed to remap config base (%lu/%u) for SCU\n",
401 + config_base, CORTEX_A9_SCU_SIZE);
405 + scu_enable(scu_base);
407 + iounmap(scu_base); /* That's the last we'll need of this */
412 +static int nsp_write_lut(void (*secondary_startup) (void))
414 + void __iomem *sku_rom_lut;
415 + phys_addr_t secondary_startup_phy;
417 + if (!secondary_boot) {
418 + pr_warn("required secondary boot register not specified\n");
422 + sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot,
423 + sizeof(secondary_boot));
424 + if (!sku_rom_lut) {
425 + pr_warn("unable to ioremap SKU-ROM LUT register\n");
429 + secondary_startup_phy = virt_to_phys(secondary_startup);
430 + BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX);
432 + writel_relaxed(secondary_startup_phy, sku_rom_lut);
434 + * Ensure the write is visible to the secondary core.
438 + iounmap(sku_rom_lut);
443 +static void nsp_secondary_init(unsigned int cpu)
446 + * Let the primary cpu know we are out of holding pen.
448 + write_pen_release(-1);
451 + * Synchronise with the boot thread.
453 + spin_lock(&boot_lock);
454 + spin_unlock(&boot_lock);
457 +static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
459 + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
460 + struct device_node *node;
463 + BUG_ON(secondary_boot); /* We're called only once */
466 + * This function is only called via smp_ops->smp_prepare_cpu().
467 + * That only happens if a "/cpus" device tree node exists
468 + * and has an "enable-method" property that selects the SMP
469 + * operations defined herein.
471 + node = of_find_node_by_path("/cpus");
475 + * Our secondary enable method requires a "secondary-boot-reg"
476 + * property to specify a register address used to request the
477 + * ROM code boot a secondary core. If we have any trouble
478 + * getting this we fall back to uniprocessor mode.
480 + if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
481 + pr_warn("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
483 + ret = -ENOENT; /* Arrange to disable SMP */
488 + * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
489 + * returned, the SoC reported a uniprocessor configuration.
490 + * We bail on any other error.
492 + ret = scu_a9_enable();
496 + /* Update the CPU present map to reflect uniprocessor mode */
497 + pr_warn("disabling SMP\n");
498 + init_cpu_present(&only_cpu_0);
503 + * The ROM code has the secondary cores looping, waiting for an event.
504 + * When an event occurs each core examines the bottom two bits of the
505 + * secondary boot register. When a core finds those bits contain its
506 + * own core id, it performs initialization, including computing its boot
507 + * address by clearing the boot register value's bottom two bits. The
508 + * core signals that it is beginning its execution by writing its boot
509 + * address back to the secondary boot register, and finally jumps to
512 + * So to start a core executing we need to:
513 + * - Encode the (hardware) CPU id with the bottom bits of the secondary
515 + * - Write that value into the secondary boot register.
516 + * - Generate an event to wake up the secondary CPU(s).
517 + * - Wait for the secondary boot register to be re-written, which
518 + * indicates the secondary core has started.
520 +static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
522 + void __iomem *boot_reg;
523 + phys_addr_t boot_func;
527 + bool timeout = false;
529 + cpu_id = cpu_logical_map(cpu);
530 + if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
531 + pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
535 + if (!secondary_boot) {
536 + pr_err("required secondary boot register not specified\n");
540 + boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
542 + pr_err("unable to map boot register for cpu %u\n", cpu_id);
547 + * Secondary cores will start in secondary_startup(),
548 + * defined in "arch/arm/kernel/head.S"
550 + boot_func = virt_to_phys(secondary_startup);
551 + BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
552 + BUG_ON(boot_func > (phys_addr_t)U32_MAX);
554 + /* The core to start is encoded in the low bits */
555 + boot_val = (u32)boot_func | cpu_id;
556 + writel_relaxed(boot_val, boot_reg);
560 + /* The low bits will be cleared once the core has started */
561 + start_clock = local_clock();
562 + while (!timeout && readl_relaxed(boot_reg) == boot_val)
563 + timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
570 + pr_err("timeout waiting for cpu %u to start\n", cpu_id);
575 +static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle)
577 + unsigned long timeout;
581 + * After wake up, secondary core branches to the startup
582 + * address programmed at SKU ROM LUT location.
584 + ret = nsp_write_lut(nsp_secondary_startup);
586 + pr_err("unable to write startup addr to SKU ROM LUT\n");
591 + * The secondary processor is waiting to be released from
592 + * the holding pen - release it, then wait for it to flag
593 + * that it has been released by resetting pen_release.
595 + spin_lock(&boot_lock);
597 + write_pen_release(cpu_logical_map(cpu));
599 + * Send an Event to wake up the secondary core which is in
600 + * WFE state. Updated pen_release should also be visible to
601 + * the secondary core.
605 + timeout = jiffies + (1 * HZ);
606 + while (time_before(jiffies, timeout)) {
607 + /* Make sure loads on other CPU is visible */
609 + if (pen_release == -1)
615 + spin_unlock(&boot_lock);
617 + ret = pen_release != -1 ? -ENXIO : 0;
623 +static struct smp_operations bcm_smp_ops __initdata = {
624 + .smp_prepare_cpus = bcm_smp_prepare_cpus,
625 + .smp_boot_secondary = kona_boot_secondary,
627 +CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
630 +struct smp_operations nsp_smp_ops __initdata = {
631 + .smp_prepare_cpus = bcm_smp_prepare_cpus,
632 + .smp_secondary_init = nsp_secondary_init,
633 + .smp_boot_secondary = nsp_boot_secondary,
635 +CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops);