aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS8
-rw-r--r--arch/arm/configs/bcm_defconfig1
-rw-r--r--arch/arm/configs/multi_v7_defconfig1
-rw-r--r--arch/arm/mach-bcm/Kconfig34
-rw-r--r--arch/arm/mach-bcm/Makefile8
-rw-r--r--arch/arm/mach-bcm/brcmstb.c28
-rw-r--r--arch/arm/mach-bcm/brcmstb.h19
-rw-r--r--arch/arm/mach-bcm/headsmp-brcmstb.S33
-rw-r--r--arch/arm/mach-bcm/kona_smp.c202
-rw-r--r--arch/arm/mach-bcm/platsmp-brcmstb.c363
10 files changed, 694 insertions, 3 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index fb784e03db0d..5d3b0ccaa90a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1978,6 +1978,14 @@ F: arch/arm/mach-bcm/bcm_5301x.c
1978F: arch/arm/boot/dts/bcm5301x.dtsi 1978F: arch/arm/boot/dts/bcm5301x.dtsi
1979F: arch/arm/boot/dts/bcm470* 1979F: arch/arm/boot/dts/bcm470*
1980 1980
1981BROADCOM BCM7XXX ARM ARCHITECTURE
1982M: Marc Carino <marc.ceeeee@gmail.com>
1983M: Brian Norris <computersforpeace@gmail.com>
1984L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
1985S: Maintained
1986F: arch/arm/mach-bcm/*brcmstb*
1987F: arch/arm/boot/dts/bcm7*.dts*
1988
1981BROADCOM TG3 GIGABIT ETHERNET DRIVER 1989BROADCOM TG3 GIGABIT ETHERNET DRIVER
1982M: Nithin Nayak Sujir <nsujir@broadcom.com> 1990M: Nithin Nayak Sujir <nsujir@broadcom.com>
1983M: Michael Chan <mchan@broadcom.com> 1991M: Michael Chan <mchan@broadcom.com>
diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig
index 4bf72264b175..fbebcbce1e8c 100644
--- a/arch/arm/configs/bcm_defconfig
+++ b/arch/arm/configs/bcm_defconfig
@@ -27,6 +27,7 @@ CONFIG_PARTITION_ADVANCED=y
27CONFIG_ARCH_BCM=y 27CONFIG_ARCH_BCM=y
28CONFIG_ARCH_BCM_MOBILE=y 28CONFIG_ARCH_BCM_MOBILE=y
29CONFIG_ARM_THUMBEE=y 29CONFIG_ARM_THUMBEE=y
30CONFIG_SMP=y
30CONFIG_PREEMPT=y 31CONFIG_PREEMPT=y
31CONFIG_AEABI=y 32CONFIG_AEABI=y
32# CONFIG_COMPACTION is not set 33# CONFIG_COMPACTION is not set
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index f70ea2116fec..3332a4231684 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -19,6 +19,7 @@ CONFIG_MACH_DOVE=y
19CONFIG_ARCH_BCM=y 19CONFIG_ARCH_BCM=y
20CONFIG_ARCH_BCM_MOBILE=y 20CONFIG_ARCH_BCM_MOBILE=y
21CONFIG_ARCH_BCM_5301X=y 21CONFIG_ARCH_BCM_5301X=y
22CONFIG_ARCH_BRCMSTB=y
22CONFIG_ARCH_BERLIN=y 23CONFIG_ARCH_BERLIN=y
23CONFIG_MACH_BERLIN_BG2=y 24CONFIG_MACH_BERLIN_BG2=y
24CONFIG_MACH_BERLIN_BG2CD=y 25CONFIG_MACH_BERLIN_BG2CD=y
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 41c839167e87..fc938005ad39 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -9,7 +9,6 @@ config ARCH_BCM_MOBILE
9 bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 9 bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
10 select ARCH_REQUIRE_GPIOLIB 10 select ARCH_REQUIRE_GPIOLIB
11 select ARM_ERRATA_754322 11 select ARM_ERRATA_754322
12 select ARM_ERRATA_764369 if SMP
13 select ARM_ERRATA_775420 12 select ARM_ERRATA_775420
14 select ARM_GIC 13 select ARM_GIC
15 select GPIO_BCM_KONA 14 select GPIO_BCM_KONA
@@ -26,16 +25,18 @@ menu "Broadcom Mobile SoC Selection"
26config ARCH_BCM_281XX 25config ARCH_BCM_281XX
27 bool "Broadcom BCM281XX SoC family" 26 bool "Broadcom BCM281XX SoC family"
28 default y 27 default y
28 select HAVE_SMP
29 help 29 help
30 Enable support for the the BCM281XX family, which includes 30 Enable support for the BCM281XX family, which includes
31 BCM11130, BCM11140, BCM11351, BCM28145 and BCM28155 31 BCM11130, BCM11140, BCM11351, BCM28145 and BCM28155
32 variants. 32 variants.
33 33
34config ARCH_BCM_21664 34config ARCH_BCM_21664
35 bool "Broadcom BCM21664 SoC family" 35 bool "Broadcom BCM21664 SoC family"
36 default y 36 default y
37 select HAVE_SMP
37 help 38 help
38 Enable support for the the BCM21664 family, which includes 39 Enable support for the BCM21664 family, which includes
39 BCM21663 and BCM21664 variants. 40 BCM21663 and BCM21664 variants.
40 41
41config ARCH_BCM_MOBILE_L2_CACHE 42config ARCH_BCM_MOBILE_L2_CACHE
@@ -49,6 +50,17 @@ config ARCH_BCM_MOBILE_SMC
49 bool 50 bool
50 depends on ARCH_BCM_281XX || ARCH_BCM_21664 51 depends on ARCH_BCM_281XX || ARCH_BCM_21664
51 52
53config ARCH_BCM_MOBILE_SMP
54 bool "Broadcom mobile SoC SMP support"
55 depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP
56 default y
57 select HAVE_ARM_SCU
58 select ARM_ERRATA_764369
59 help
60 SMP support for the BCM281XX and BCM21664 SoC families.
61 Provided as an option so SMP support for SoCs of this type
62 can be disabled for an SMP-enabled kernel.
63
52endmenu 64endmenu
53 65
54endif 66endif
@@ -87,4 +99,20 @@ config ARCH_BCM_5301X
87 different SoC or with the older BCM47XX and BCM53XX based 99 different SoC or with the older BCM47XX and BCM53XX based
88 network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx 100 network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx
89 101
102config ARCH_BRCMSTB
103 bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7
104 depends on MMU
105 select ARM_GIC
106 select MIGHT_HAVE_PCI
107 select HAVE_SMP
108 select HAVE_ARM_ARCH_TIMER
109 select BRCMSTB_GISB_ARB
110 select BRCMSTB_L2_IRQ
111 help
112 Say Y if you intend to run the kernel on a Broadcom ARM-based STB
113 chipset.
114
115 This enables support for Broadcom ARM-based set-top box chipsets,
116 including the 7445 family of chips.
117
90endif 118endif
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 731292114975..67c492aabf4d 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -16,6 +16,9 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
16# BCM21664 16# BCM21664
17obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o 17obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
18 18
19# BCM281XX and BCM21664 SMP support
20obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o
21
19# BCM281XX and BCM21664 L2 cache control 22# BCM281XX and BCM21664 L2 cache control
20obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o 23obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
21 24
@@ -30,3 +33,8 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2835.o
30 33
31# BCM5301X 34# BCM5301X
32obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o 35obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o
36
37ifeq ($(CONFIG_ARCH_BRCMSTB),y)
38obj-y += brcmstb.o
39obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o
40endif
diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c
new file mode 100644
index 000000000000..60a5afa06ed7
--- /dev/null
+++ b/arch/arm/mach-bcm/brcmstb.c
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2013-2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/init.h>
15#include <linux/of_platform.h>
16
17#include <asm/mach-types.h>
18#include <asm/mach/arch.h>
19
20static const char *brcmstb_match[] __initconst = {
21 "brcm,bcm7445",
22 "brcm,brcmstb",
23 NULL
24};
25
26DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)")
27 .dt_compat = brcmstb_match,
28MACHINE_END
diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h
new file mode 100644
index 000000000000..ec0c3d112b36
--- /dev/null
+++ b/arch/arm/mach-bcm/brcmstb.h
@@ -0,0 +1,19 @@
1/*
2 * Copyright (C) 2013-2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#ifndef __BRCMSTB_H__
15#define __BRCMSTB_H__
16
17void brcmstb_secondary_startup(void);
18
19#endif /* __BRCMSTB_H__ */
diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S
new file mode 100644
index 000000000000..199c1ea58248
--- /dev/null
+++ b/arch/arm/mach-bcm/headsmp-brcmstb.S
@@ -0,0 +1,33 @@
1/*
2 * SMP boot code for secondary CPUs
3 * Based on arch/arm/mach-tegra/headsmp.S
4 *
5 * Copyright (C) 2010 NVIDIA, Inc.
6 * Copyright (C) 2013-2014 Broadcom Corporation
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation version 2.
11 *
12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
13 * kind, whether express or implied; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <asm/assembler.h>
19#include <linux/linkage.h>
20#include <linux/init.h>
21
22 .section ".text.head", "ax"
23
24ENTRY(brcmstb_secondary_startup)
25 /*
26 * Ensure CPU is in a sane state by disabling all IRQs and switching
27 * into SVC mode.
28 */
29 setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r0
30
31 bl v7_invalidate_l1
32 b secondary_startup
33ENDPROC(brcmstb_secondary_startup)
diff --git a/arch/arm/mach-bcm/kona_smp.c b/arch/arm/mach-bcm/kona_smp.c
new file mode 100644
index 000000000000..66a0465528a5
--- /dev/null
+++ b/arch/arm/mach-bcm/kona_smp.c
@@ -0,0 +1,202 @@
1/*
2 * Copyright (C) 2014 Broadcom Corporation
3 * Copyright 2014 Linaro Limited
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation version 2.
8 *
9 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
10 * kind, whether express or implied; without even the implied warranty
11 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/init.h>
16#include <linux/errno.h>
17#include <linux/io.h>
18#include <linux/of.h>
19#include <linux/sched.h>
20
21#include <asm/smp.h>
22#include <asm/smp_plat.h>
23#include <asm/smp_scu.h>
24
25/* Size of mapped Cortex A9 SCU address space */
26#define CORTEX_A9_SCU_SIZE 0x58
27
28#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
29#define BOOT_ADDR_CPUID_MASK 0x3
30
31/* Name of device node property defining secondary boot register location */
32#define OF_SECONDARY_BOOT "secondary-boot-reg"
33
34/* I/O address of register used to coordinate secondary core startup */
35static u32 secondary_boot;
36
37/*
38 * Enable the Cortex A9 Snoop Control Unit
39 *
40 * By the time this is called we already know there are multiple
41 * cores present. We assume we're running on a Cortex A9 processor,
42 * so any trouble getting the base address register or getting the
43 * SCU base is a problem.
44 *
45 * Return 0 if successful or an error code otherwise.
46 */
47static int __init scu_a9_enable(void)
48{
49 unsigned long config_base;
50 void __iomem *scu_base;
51
52 if (!scu_a9_has_base()) {
53 pr_err("no configuration base address register!\n");
54 return -ENXIO;
55 }
56
57 /* Config base address register value is zero for uniprocessor */
58 config_base = scu_a9_get_base();
59 if (!config_base) {
60 pr_err("hardware reports only one core\n");
61 return -ENOENT;
62 }
63
64 scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
65 if (!scu_base) {
66 pr_err("failed to remap config base (%lu/%u) for SCU\n",
67 config_base, CORTEX_A9_SCU_SIZE);
68 return -ENOMEM;
69 }
70
71 scu_enable(scu_base);
72
73 iounmap(scu_base); /* That's the last we'll need of this */
74
75 return 0;
76}
77
78static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
79{
80 static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
81 struct device_node *node;
82 int ret;
83
84 BUG_ON(secondary_boot); /* We're called only once */
85
86 /*
87 * This function is only called via smp_ops->smp_prepare_cpu().
88 * That only happens if a "/cpus" device tree node exists
89 * and has an "enable-method" property that selects the SMP
90 * operations defined herein.
91 */
92 node = of_find_node_by_path("/cpus");
93 BUG_ON(!node);
94
95 /*
96 * Our secondary enable method requires a "secondary-boot-reg"
97 * property to specify a register address used to request the
98 * ROM code boot a secondary code. If we have any trouble
99 * getting this we fall back to uniprocessor mode.
100 */
101 if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
102 pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
103 node->name);
104 ret = -ENOENT; /* Arrange to disable SMP */
105 goto out;
106 }
107
108 /*
109 * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
110 * returned, the SoC reported a uniprocessor configuration.
111 * We bail on any other error.
112 */
113 ret = scu_a9_enable();
114out:
115 of_node_put(node);
116 if (ret) {
117 /* Update the CPU present map to reflect uniprocessor mode */
118 BUG_ON(ret != -ENOENT);
119 pr_warn("disabling SMP\n");
120 init_cpu_present(&only_cpu_0);
121 }
122}
123
124/*
125 * The ROM code has the secondary cores looping, waiting for an event.
126 * When an event occurs each core examines the bottom two bits of the
127 * secondary boot register. When a core finds those bits contain its
128 * own core id, it performs initialization, including computing its boot
129 * address by clearing the boot register value's bottom two bits. The
130 * core signals that it is beginning its execution by writing its boot
131 * address back to the secondary boot register, and finally jumps to
132 * that address.
133 *
134 * So to start a core executing we need to:
135 * - Encode the (hardware) CPU id with the bottom bits of the secondary
136 * start address.
137 * - Write that value into the secondary boot register.
138 * - Generate an event to wake up the secondary CPU(s).
139 * - Wait for the secondary boot register to be re-written, which
140 * indicates the secondary core has started.
141 */
142static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle)
143{
144 void __iomem *boot_reg;
145 phys_addr_t boot_func;
146 u64 start_clock;
147 u32 cpu_id;
148 u32 boot_val;
149 bool timeout = false;
150
151 cpu_id = cpu_logical_map(cpu);
152 if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
153 pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
154 return -EINVAL;
155 }
156
157 if (!secondary_boot) {
158 pr_err("required secondary boot register not specified\n");
159 return -EINVAL;
160 }
161
162 boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
163 if (!boot_reg) {
164 pr_err("unable to map boot register for cpu %u\n", cpu_id);
165 return -ENOSYS;
166 }
167
168 /*
169 * Secondary cores will start in secondary_startup(),
170 * defined in "arch/arm/kernel/head.S"
171 */
172 boot_func = virt_to_phys(secondary_startup);
173 BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
174 BUG_ON(boot_func > (phys_addr_t)U32_MAX);
175
176 /* The core to start is encoded in the low bits */
177 boot_val = (u32)boot_func | cpu_id;
178 writel_relaxed(boot_val, boot_reg);
179
180 sev();
181
182 /* The low bits will be cleared once the core has started */
183 start_clock = local_clock();
184 while (!timeout && readl_relaxed(boot_reg) == boot_val)
185 timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
186
187 iounmap(boot_reg);
188
189 if (!timeout)
190 return 0;
191
192 pr_err("timeout waiting for cpu %u to start\n", cpu_id);
193
194 return -ENOSYS;
195}
196
197static struct smp_operations bcm_smp_ops __initdata = {
198 .smp_prepare_cpus = bcm_smp_prepare_cpus,
199 .smp_boot_secondary = bcm_boot_secondary,
200};
201CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
202 &bcm_smp_ops);
diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c
new file mode 100644
index 000000000000..af780e9c23a6
--- /dev/null
+++ b/arch/arm/mach-bcm/platsmp-brcmstb.c
@@ -0,0 +1,363 @@
1/*
2 * Broadcom STB CPU SMP and hotplug support for ARM
3 *
4 * Copyright (C) 2013-2014 Broadcom Corporation
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation version 2.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/delay.h>
17#include <linux/errno.h>
18#include <linux/init.h>
19#include <linux/io.h>
20#include <linux/of_address.h>
21#include <linux/of_platform.h>
22#include <linux/printk.h>
23#include <linux/regmap.h>
24#include <linux/smp.h>
25#include <linux/mfd/syscon.h>
26#include <linux/spinlock.h>
27
28#include <asm/cacheflush.h>
29#include <asm/cp15.h>
30#include <asm/mach-types.h>
31#include <asm/smp_plat.h>
32
33#include "brcmstb.h"
34
35enum {
36 ZONE_MAN_CLKEN_MASK = BIT(0),
37 ZONE_MAN_RESET_CNTL_MASK = BIT(1),
38 ZONE_MAN_MEM_PWR_MASK = BIT(4),
39 ZONE_RESERVED_1_MASK = BIT(5),
40 ZONE_MAN_ISO_CNTL_MASK = BIT(6),
41 ZONE_MANUAL_CONTROL_MASK = BIT(7),
42 ZONE_PWR_DN_REQ_MASK = BIT(9),
43 ZONE_PWR_UP_REQ_MASK = BIT(10),
44 ZONE_BLK_RST_ASSERT_MASK = BIT(12),
45 ZONE_PWR_OFF_STATE_MASK = BIT(25),
46 ZONE_PWR_ON_STATE_MASK = BIT(26),
47 ZONE_DPG_PWR_STATE_MASK = BIT(28),
48 ZONE_MEM_PWR_STATE_MASK = BIT(29),
49 ZONE_RESET_STATE_MASK = BIT(31),
50 CPU0_PWR_ZONE_CTRL_REG = 1,
51 CPU_RESET_CONFIG_REG = 2,
52};
53
54static void __iomem *cpubiuctrl_block;
55static void __iomem *hif_cont_block;
56static u32 cpu0_pwr_zone_ctrl_reg;
57static u32 cpu_rst_cfg_reg;
58static u32 hif_cont_reg;
59
60#ifdef CONFIG_HOTPLUG_CPU
61static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state);
62
63static int per_cpu_sw_state_rd(u32 cpu)
64{
65 sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
66 return per_cpu(per_cpu_sw_state, cpu);
67}
68
69static void per_cpu_sw_state_wr(u32 cpu, int val)
70{
71 per_cpu(per_cpu_sw_state, cpu) = val;
72 dmb();
73 sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
74 dsb_sev();
75}
76#else
77static inline void per_cpu_sw_state_wr(u32 cpu, int val) { }
78#endif
79
80static void __iomem *pwr_ctrl_get_base(u32 cpu)
81{
82 void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg;
83 base += (cpu_logical_map(cpu) * 4);
84 return base;
85}
86
87static u32 pwr_ctrl_rd(u32 cpu)
88{
89 void __iomem *base = pwr_ctrl_get_base(cpu);
90 return readl_relaxed(base);
91}
92
93static void pwr_ctrl_wr(u32 cpu, u32 val)
94{
95 void __iomem *base = pwr_ctrl_get_base(cpu);
96 writel(val, base);
97}
98
99static void cpu_rst_cfg_set(u32 cpu, int set)
100{
101 u32 val;
102 val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
103 if (set)
104 val |= BIT(cpu_logical_map(cpu));
105 else
106 val &= ~BIT(cpu_logical_map(cpu));
107 writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
108}
109
110static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr)
111{
112 const int reg_ofs = cpu_logical_map(cpu) * 8;
113 writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
114 writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
115}
116
117static void brcmstb_cpu_boot(u32 cpu)
118{
119 pr_info("SMP: Booting CPU%d...\n", cpu);
120
121 /*
122 * set the reset vector to point to the secondary_startup
123 * routine
124 */
125 cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
126
127 /* unhalt the cpu */
128 cpu_rst_cfg_set(cpu, 0);
129}
130
131static void brcmstb_cpu_power_on(u32 cpu)
132{
133 /*
134 * The secondary cores power was cut, so we must go through
135 * power-on initialization.
136 */
137 u32 tmp;
138
139 pr_info("SMP: Powering up CPU%d...\n", cpu);
140
141 /* Request zone power up */
142 pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK);
143
144 /* Wait for the power up FSM to complete */
145 do {
146 tmp = pwr_ctrl_rd(cpu);
147 } while (!(tmp & ZONE_PWR_ON_STATE_MASK));
148
149 per_cpu_sw_state_wr(cpu, 1);
150}
151
152static int brcmstb_cpu_get_power_state(u32 cpu)
153{
154 int tmp = pwr_ctrl_rd(cpu);
155 return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1;
156}
157
158#ifdef CONFIG_HOTPLUG_CPU
159
160static void brcmstb_cpu_die(u32 cpu)
161{
162 v7_exit_coherency_flush(all);
163
164 /* Prevent all interrupts from reaching this CPU. */
165 arch_local_irq_disable();
166
167 /*
168 * Final full barrier to ensure everything before this instruction has
169 * quiesced.
170 */
171 isb();
172 dsb();
173
174 per_cpu_sw_state_wr(cpu, 0);
175
176 /* Sit and wait to die */
177 wfi();
178
179 /* We should never get here... */
180 panic("Spurious interrupt on CPU %d received!\n", cpu);
181}
182
183static int brcmstb_cpu_kill(u32 cpu)
184{
185 u32 tmp;
186
187 pr_info("SMP: Powering down CPU%d...\n", cpu);
188
189 while (per_cpu_sw_state_rd(cpu))
190 ;
191
192 /* Program zone reset */
193 pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK |
194 ZONE_PWR_DN_REQ_MASK);
195
196 /* Verify zone reset */
197 tmp = pwr_ctrl_rd(cpu);
198 if (!(tmp & ZONE_RESET_STATE_MASK))
199 pr_err("%s: Zone reset bit for CPU %d not asserted!\n",
200 __func__, cpu);
201
202 /* Wait for power down */
203 do {
204 tmp = pwr_ctrl_rd(cpu);
205 } while (!(tmp & ZONE_PWR_OFF_STATE_MASK));
206
207 /* Settle-time from Broadcom-internal DVT reference code */
208 udelay(7);
209
210 /* Assert reset on the CPU */
211 cpu_rst_cfg_set(cpu, 1);
212
213 return 1;
214}
215
216#endif /* CONFIG_HOTPLUG_CPU */
217
218static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
219{
220 int rc = 0;
221 char *name;
222 struct device_node *syscon_np = NULL;
223
224 name = "syscon-cpu";
225
226 syscon_np = of_parse_phandle(np, name, 0);
227 if (!syscon_np) {
228 pr_err("can't find phandle %s\n", name);
229 rc = -EINVAL;
230 goto cleanup;
231 }
232
233 cpubiuctrl_block = of_iomap(syscon_np, 0);
234 if (!cpubiuctrl_block) {
235 pr_err("iomap failed for cpubiuctrl_block\n");
236 rc = -EINVAL;
237 goto cleanup;
238 }
239
240 rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG,
241 &cpu0_pwr_zone_ctrl_reg);
242 if (rc) {
243 pr_err("failed to read 1st entry from %s property (%d)\n", name,
244 rc);
245 rc = -EINVAL;
246 goto cleanup;
247 }
248
249 rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG,
250 &cpu_rst_cfg_reg);
251 if (rc) {
252 pr_err("failed to read 2nd entry from %s property (%d)\n", name,
253 rc);
254 rc = -EINVAL;
255 goto cleanup;
256 }
257
258cleanup:
259 if (syscon_np)
260 of_node_put(syscon_np);
261
262 return rc;
263}
264
265static int __init setup_hifcont_regs(struct device_node *np)
266{
267 int rc = 0;
268 char *name;
269 struct device_node *syscon_np = NULL;
270
271 name = "syscon-cont";
272
273 syscon_np = of_parse_phandle(np, name, 0);
274 if (!syscon_np) {
275 pr_err("can't find phandle %s\n", name);
276 rc = -EINVAL;
277 goto cleanup;
278 }
279
280 hif_cont_block = of_iomap(syscon_np, 0);
281 if (!hif_cont_block) {
282 pr_err("iomap failed for hif_cont_block\n");
283 rc = -EINVAL;
284 goto cleanup;
285 }
286
287 /* offset is at top of hif_cont_block */
288 hif_cont_reg = 0;
289
290cleanup:
291 if (syscon_np)
292 of_node_put(syscon_np);
293
294 return rc;
295}
296
297static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
298{
299 int rc;
300 struct device_node *np;
301 char *name;
302
303 name = "brcm,brcmstb-smpboot";
304 np = of_find_compatible_node(NULL, NULL, name);
305 if (!np) {
306 pr_err("can't find compatible node %s\n", name);
307 return;
308 }
309
310 rc = setup_hifcpubiuctrl_regs(np);
311 if (rc)
312 return;
313
314 rc = setup_hifcont_regs(np);
315 if (rc)
316 return;
317}
318
319static DEFINE_SPINLOCK(boot_lock);
320
321static void brcmstb_secondary_init(unsigned int cpu)
322{
323 /*
324 * Synchronise with the boot thread.
325 */
326 spin_lock(&boot_lock);
327 spin_unlock(&boot_lock);
328}
329
330static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
331{
332 /*
333 * set synchronisation state between this boot processor
334 * and the secondary one
335 */
336 spin_lock(&boot_lock);
337
338 /* Bring up power to the core if necessary */
339 if (brcmstb_cpu_get_power_state(cpu) == 0)
340 brcmstb_cpu_power_on(cpu);
341
342 brcmstb_cpu_boot(cpu);
343
344 /*
345 * now the secondary core is starting up let it run its
346 * calibrations, then wait for it to finish
347 */
348 spin_unlock(&boot_lock);
349
350 return 0;
351}
352
353static struct smp_operations brcmstb_smp_ops __initdata = {
354 .smp_prepare_cpus = brcmstb_cpu_ctrl_setup,
355 .smp_secondary_init = brcmstb_secondary_init,
356 .smp_boot_secondary = brcmstb_boot_secondary,
357#ifdef CONFIG_HOTPLUG_CPU
358 .cpu_kill = brcmstb_cpu_kill,
359 .cpu_die = brcmstb_cpu_die,
360#endif
361};
362
363CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops);