diff options
Diffstat (limited to 'arch/arm/mach-bcm')
-rw-r--r-- | arch/arm/mach-bcm/Kconfig | 96 | ||||
-rw-r--r-- | arch/arm/mach-bcm/Makefile | 5 | ||||
-rw-r--r-- | arch/arm/mach-bcm/bcm_cygnus.c | 25 | ||||
-rw-r--r-- | arch/arm/mach-bcm/brcmstb.h | 19 | ||||
-rw-r--r-- | arch/arm/mach-bcm/headsmp-brcmstb.S | 33 | ||||
-rw-r--r-- | arch/arm/mach-bcm/platsmp-brcmstb.c | 329 |
6 files changed, 468 insertions, 39 deletions
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 2abad742516d..1bd39b45d08b 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig | |||
@@ -5,8 +5,56 @@ menuconfig ARCH_BCM | |||
5 | 5 | ||
6 | if ARCH_BCM | 6 | if ARCH_BCM |
7 | 7 | ||
8 | comment "IPROC architected SoCs" | ||
9 | |||
10 | config ARCH_BCM_IPROC | ||
11 | bool | ||
12 | select ARM_GIC | ||
13 | select CACHE_L2X0 | ||
14 | select HAVE_ARM_SCU if SMP | ||
15 | select HAVE_ARM_TWD if SMP | ||
16 | select ARM_GLOBAL_TIMER | ||
17 | |||
18 | select CLKSRC_MMIO | ||
19 | select ARCH_REQUIRE_GPIOLIB | ||
20 | select ARM_AMBA | ||
21 | select PINCTRL | ||
22 | help | ||
23 | This enables support for systems based on Broadcom IPROC architected SoCs. | ||
24 | The IPROC complex contains one or more ARM CPUs along with common | ||
25 | core periperals. Application specific SoCs are created by adding a | ||
26 | uArchitecture containing peripherals outside of the IPROC complex. | ||
27 | Currently supported SoCs are Cygnus. | ||
28 | |||
29 | config ARCH_BCM_CYGNUS | ||
30 | bool "Broadcom Cygnus Support" if ARCH_MULTI_V7 | ||
31 | select ARCH_BCM_IPROC | ||
32 | help | ||
33 | Enable support for the Cygnus family, | ||
34 | which includes the following variants: | ||
35 | BCM11300, BCM11320, BCM11350, BCM11360, | ||
36 | BCM58300, BCM58302, BCM58303, BCM58305. | ||
37 | |||
38 | config ARCH_BCM_5301X | ||
39 | bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 | ||
40 | select ARCH_BCM_IPROC | ||
41 | help | ||
42 | Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. | ||
43 | |||
44 | This is a network SoC line mostly used in home routers and | ||
45 | wifi access points, it's internal name is Northstar. | ||
46 | This inclused the following SoC: BCM53010, BCM53011, BCM53012, | ||
47 | BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, | ||
48 | BCM4708 and BCM4709. | ||
49 | |||
50 | Do not confuse this with the BCM4760 which is a totally | ||
51 | different SoC or with the older BCM47XX and BCM53XX based | ||
52 | network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx | ||
53 | |||
54 | comment "KONA architected SoCs" | ||
55 | |||
8 | config ARCH_BCM_MOBILE | 56 | config ARCH_BCM_MOBILE |
9 | bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 | 57 | bool |
10 | select ARCH_REQUIRE_GPIOLIB | 58 | select ARCH_REQUIRE_GPIOLIB |
11 | select ARM_ERRATA_754322 | 59 | select ARM_ERRATA_754322 |
12 | select ARM_ERRATA_775420 | 60 | select ARM_ERRATA_775420 |
@@ -15,16 +63,13 @@ config ARCH_BCM_MOBILE | |||
15 | select TICK_ONESHOT | 63 | select TICK_ONESHOT |
16 | select HAVE_ARM_ARCH_TIMER | 64 | select HAVE_ARM_ARCH_TIMER |
17 | select PINCTRL | 65 | select PINCTRL |
66 | select ARCH_BCM_MOBILE_SMP if SMP | ||
18 | help | 67 | help |
19 | This enables support for systems based on Broadcom mobile SoCs. | 68 | This enables support for systems based on Broadcom mobile SoCs. |
20 | 69 | ||
21 | if ARCH_BCM_MOBILE | ||
22 | |||
23 | menu "Broadcom Mobile SoC Selection" | ||
24 | |||
25 | config ARCH_BCM_281XX | 70 | config ARCH_BCM_281XX |
26 | bool "Broadcom BCM281XX SoC family" | 71 | bool "Broadcom BCM281XX SoC family" |
27 | default y | 72 | select ARCH_BCM_MOBILE |
28 | select HAVE_SMP | 73 | select HAVE_SMP |
29 | help | 74 | help |
30 | Enable support for the BCM281XX family, which includes | 75 | Enable support for the BCM281XX family, which includes |
@@ -33,7 +78,7 @@ config ARCH_BCM_281XX | |||
33 | 78 | ||
34 | config ARCH_BCM_21664 | 79 | config ARCH_BCM_21664 |
35 | bool "Broadcom BCM21664 SoC family" | 80 | bool "Broadcom BCM21664 SoC family" |
36 | default y | 81 | select ARCH_BCM_MOBILE |
37 | select HAVE_SMP | 82 | select HAVE_SMP |
38 | help | 83 | help |
39 | Enable support for the BCM21664 family, which includes | 84 | Enable support for the BCM21664 family, which includes |
@@ -41,19 +86,18 @@ config ARCH_BCM_21664 | |||
41 | 86 | ||
42 | config ARCH_BCM_MOBILE_L2_CACHE | 87 | config ARCH_BCM_MOBILE_L2_CACHE |
43 | bool "Broadcom mobile SoC level 2 cache support" | 88 | bool "Broadcom mobile SoC level 2 cache support" |
44 | depends on (ARCH_BCM_281XX || ARCH_BCM_21664) | 89 | depends on ARCH_BCM_MOBILE |
45 | default y | 90 | default y |
46 | select CACHE_L2X0 | 91 | select CACHE_L2X0 |
47 | select ARCH_BCM_MOBILE_SMC | 92 | select ARCH_BCM_MOBILE_SMC |
48 | 93 | ||
49 | config ARCH_BCM_MOBILE_SMC | 94 | config ARCH_BCM_MOBILE_SMC |
50 | bool | 95 | bool |
51 | depends on ARCH_BCM_281XX || ARCH_BCM_21664 | 96 | depends on ARCH_BCM_MOBILE |
52 | 97 | ||
53 | config ARCH_BCM_MOBILE_SMP | 98 | config ARCH_BCM_MOBILE_SMP |
54 | bool "Broadcom mobile SoC SMP support" | 99 | bool |
55 | depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP | 100 | depends on ARCH_BCM_MOBILE |
56 | default y | ||
57 | select HAVE_ARM_SCU | 101 | select HAVE_ARM_SCU |
58 | select ARM_ERRATA_764369 | 102 | select ARM_ERRATA_764369 |
59 | help | 103 | help |
@@ -61,9 +105,7 @@ config ARCH_BCM_MOBILE_SMP | |||
61 | Provided as an option so SMP support for SoCs of this type | 105 | Provided as an option so SMP support for SoCs of this type |
62 | can be disabled for an SMP-enabled kernel. | 106 | can be disabled for an SMP-enabled kernel. |
63 | 107 | ||
64 | endmenu | 108 | comment "Other Architectures" |
65 | |||
66 | endif | ||
67 | 109 | ||
68 | config ARCH_BCM2835 | 110 | config ARCH_BCM2835 |
69 | bool "Broadcom BCM2835 family" if ARCH_MULTI_V6 | 111 | bool "Broadcom BCM2835 family" if ARCH_MULTI_V6 |
@@ -78,27 +120,6 @@ config ARCH_BCM2835 | |||
78 | This enables support for the Broadcom BCM2835 SoC. This SoC is | 120 | This enables support for the Broadcom BCM2835 SoC. This SoC is |
79 | used in the Raspberry Pi and Roku 2 devices. | 121 | used in the Raspberry Pi and Roku 2 devices. |
80 | 122 | ||
81 | config ARCH_BCM_5301X | ||
82 | bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 | ||
83 | select ARM_GIC | ||
84 | select CACHE_L2X0 | ||
85 | select HAVE_ARM_SCU if SMP | ||
86 | select HAVE_ARM_TWD if SMP | ||
87 | select ARM_GLOBAL_TIMER | ||
88 | select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK | ||
89 | help | ||
90 | Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. | ||
91 | |||
92 | This is a network SoC line mostly used in home routers and | ||
93 | wifi access points, it's internal name is Northstar. | ||
94 | This inclused the following SoC: BCM53010, BCM53011, BCM53012, | ||
95 | BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, | ||
96 | BCM4708 and BCM4709. | ||
97 | |||
98 | Do not confuse this with the BCM4760 which is a totally | ||
99 | different SoC or with the older BCM47XX and BCM53XX based | ||
100 | network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx | ||
101 | |||
102 | config ARCH_BCM_63XX | 123 | config ARCH_BCM_63XX |
103 | bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7 | 124 | bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7 |
104 | depends on MMU | 125 | depends on MMU |
@@ -118,10 +139,7 @@ config ARCH_BCM_63XX | |||
118 | 139 | ||
119 | config ARCH_BRCMSTB | 140 | config ARCH_BRCMSTB |
120 | bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7 | 141 | bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7 |
121 | depends on MMU | ||
122 | select ARM_GIC | 142 | select ARM_GIC |
123 | select MIGHT_HAVE_PCI | ||
124 | select HAVE_SMP | ||
125 | select HAVE_ARM_ARCH_TIMER | 143 | select HAVE_ARM_ARCH_TIMER |
126 | select BRCMSTB_GISB_ARB | 144 | select BRCMSTB_GISB_ARB |
127 | select BRCMSTB_L2_IRQ | 145 | select BRCMSTB_L2_IRQ |
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 300ae4b79ae6..4c38674c73ec 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile | |||
@@ -10,6 +10,9 @@ | |||
10 | # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | # GNU General Public License for more details. | 11 | # GNU General Public License for more details. |
12 | 12 | ||
13 | # Cygnus | ||
14 | obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o | ||
15 | |||
13 | # BCM281XX | 16 | # BCM281XX |
14 | obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o | 17 | obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o |
15 | 18 | ||
@@ -38,5 +41,7 @@ obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o | |||
38 | obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o | 41 | obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o |
39 | 42 | ||
40 | ifeq ($(CONFIG_ARCH_BRCMSTB),y) | 43 | ifeq ($(CONFIG_ARCH_BRCMSTB),y) |
44 | CFLAGS_platsmp-brcmstb.o += -march=armv7-a | ||
41 | obj-y += brcmstb.o | 45 | obj-y += brcmstb.o |
46 | obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o | ||
42 | endif | 47 | endif |
diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c new file mode 100644 index 000000000000..30dc58be51b8 --- /dev/null +++ b/arch/arm/mach-bcm/bcm_cygnus.c | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Copyright (C) 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 <asm/mach/arch.h> | ||
15 | |||
16 | static const char const *bcm_cygnus_dt_compat[] = { | ||
17 | "brcm,cygnus", | ||
18 | NULL, | ||
19 | }; | ||
20 | |||
21 | DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC") | ||
22 | .l2c_aux_val = 0, | ||
23 | .l2c_aux_mask = ~0, | ||
24 | .dt_compat = bcm_cygnus_dt_compat, | ||
25 | MACHINE_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 | |||
17 | void 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 | |||
24 | ENTRY(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 | ||
33 | ENDPROC(brcmstb_secondary_startup) | ||
diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c new file mode 100644 index 000000000000..31c87a284a34 --- /dev/null +++ b/arch/arm/mach-bcm/platsmp-brcmstb.c | |||
@@ -0,0 +1,329 @@ | |||
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 | |||
27 | #include <asm/cacheflush.h> | ||
28 | #include <asm/cp15.h> | ||
29 | #include <asm/mach-types.h> | ||
30 | #include <asm/smp_plat.h> | ||
31 | |||
32 | #include "brcmstb.h" | ||
33 | |||
34 | enum { | ||
35 | ZONE_MAN_CLKEN_MASK = BIT(0), | ||
36 | ZONE_MAN_RESET_CNTL_MASK = BIT(1), | ||
37 | ZONE_MAN_MEM_PWR_MASK = BIT(4), | ||
38 | ZONE_RESERVED_1_MASK = BIT(5), | ||
39 | ZONE_MAN_ISO_CNTL_MASK = BIT(6), | ||
40 | ZONE_MANUAL_CONTROL_MASK = BIT(7), | ||
41 | ZONE_PWR_DN_REQ_MASK = BIT(9), | ||
42 | ZONE_PWR_UP_REQ_MASK = BIT(10), | ||
43 | ZONE_BLK_RST_ASSERT_MASK = BIT(12), | ||
44 | ZONE_PWR_OFF_STATE_MASK = BIT(25), | ||
45 | ZONE_PWR_ON_STATE_MASK = BIT(26), | ||
46 | ZONE_DPG_PWR_STATE_MASK = BIT(28), | ||
47 | ZONE_MEM_PWR_STATE_MASK = BIT(29), | ||
48 | ZONE_RESET_STATE_MASK = BIT(31), | ||
49 | CPU0_PWR_ZONE_CTRL_REG = 1, | ||
50 | CPU_RESET_CONFIG_REG = 2, | ||
51 | }; | ||
52 | |||
53 | static void __iomem *cpubiuctrl_block; | ||
54 | static void __iomem *hif_cont_block; | ||
55 | static u32 cpu0_pwr_zone_ctrl_reg; | ||
56 | static u32 cpu_rst_cfg_reg; | ||
57 | static u32 hif_cont_reg; | ||
58 | |||
59 | #ifdef CONFIG_HOTPLUG_CPU | ||
60 | /* | ||
61 | * We must quiesce a dying CPU before it can be killed by the boot CPU. Because | ||
62 | * one or more cache may be disabled, we must flush to ensure coherency. We | ||
63 | * cannot use traditionl completion structures or spinlocks as they rely on | ||
64 | * coherency. | ||
65 | */ | ||
66 | static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state); | ||
67 | |||
68 | static int per_cpu_sw_state_rd(u32 cpu) | ||
69 | { | ||
70 | sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); | ||
71 | return per_cpu(per_cpu_sw_state, cpu); | ||
72 | } | ||
73 | |||
74 | static void per_cpu_sw_state_wr(u32 cpu, int val) | ||
75 | { | ||
76 | dmb(); | ||
77 | per_cpu(per_cpu_sw_state, cpu) = val; | ||
78 | sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); | ||
79 | } | ||
80 | #else | ||
81 | static inline void per_cpu_sw_state_wr(u32 cpu, int val) { } | ||
82 | #endif | ||
83 | |||
84 | static void __iomem *pwr_ctrl_get_base(u32 cpu) | ||
85 | { | ||
86 | void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg; | ||
87 | base += (cpu_logical_map(cpu) * 4); | ||
88 | return base; | ||
89 | } | ||
90 | |||
91 | static u32 pwr_ctrl_rd(u32 cpu) | ||
92 | { | ||
93 | void __iomem *base = pwr_ctrl_get_base(cpu); | ||
94 | return readl_relaxed(base); | ||
95 | } | ||
96 | |||
97 | static void pwr_ctrl_wr(u32 cpu, u32 val) | ||
98 | { | ||
99 | void __iomem *base = pwr_ctrl_get_base(cpu); | ||
100 | writel(val, base); | ||
101 | } | ||
102 | |||
103 | static void cpu_rst_cfg_set(u32 cpu, int set) | ||
104 | { | ||
105 | u32 val; | ||
106 | val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg); | ||
107 | if (set) | ||
108 | val |= BIT(cpu_logical_map(cpu)); | ||
109 | else | ||
110 | val &= ~BIT(cpu_logical_map(cpu)); | ||
111 | writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg); | ||
112 | } | ||
113 | |||
114 | static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr) | ||
115 | { | ||
116 | const int reg_ofs = cpu_logical_map(cpu) * 8; | ||
117 | writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs); | ||
118 | writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs); | ||
119 | } | ||
120 | |||
121 | static void brcmstb_cpu_boot(u32 cpu) | ||
122 | { | ||
123 | /* Mark this CPU as "up" */ | ||
124 | per_cpu_sw_state_wr(cpu, 1); | ||
125 | |||
126 | /* | ||
127 | * Set the reset vector to point to the secondary_startup | ||
128 | * routine | ||
129 | */ | ||
130 | cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup)); | ||
131 | |||
132 | /* Unhalt the cpu */ | ||
133 | cpu_rst_cfg_set(cpu, 0); | ||
134 | } | ||
135 | |||
136 | static void brcmstb_cpu_power_on(u32 cpu) | ||
137 | { | ||
138 | /* | ||
139 | * The secondary cores power was cut, so we must go through | ||
140 | * power-on initialization. | ||
141 | */ | ||
142 | u32 tmp; | ||
143 | |||
144 | /* Request zone power up */ | ||
145 | pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK); | ||
146 | |||
147 | /* Wait for the power up FSM to complete */ | ||
148 | do { | ||
149 | tmp = pwr_ctrl_rd(cpu); | ||
150 | } while (!(tmp & ZONE_PWR_ON_STATE_MASK)); | ||
151 | } | ||
152 | |||
153 | static int brcmstb_cpu_get_power_state(u32 cpu) | ||
154 | { | ||
155 | int tmp = pwr_ctrl_rd(cpu); | ||
156 | return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1; | ||
157 | } | ||
158 | |||
159 | #ifdef CONFIG_HOTPLUG_CPU | ||
160 | |||
161 | static void brcmstb_cpu_die(u32 cpu) | ||
162 | { | ||
163 | v7_exit_coherency_flush(all); | ||
164 | |||
165 | per_cpu_sw_state_wr(cpu, 0); | ||
166 | |||
167 | /* Sit and wait to die */ | ||
168 | wfi(); | ||
169 | |||
170 | /* We should never get here... */ | ||
171 | while (1) | ||
172 | ; | ||
173 | } | ||
174 | |||
175 | static int brcmstb_cpu_kill(u32 cpu) | ||
176 | { | ||
177 | u32 tmp; | ||
178 | |||
179 | while (per_cpu_sw_state_rd(cpu)) | ||
180 | ; | ||
181 | |||
182 | /* Program zone reset */ | ||
183 | pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK | | ||
184 | ZONE_PWR_DN_REQ_MASK); | ||
185 | |||
186 | /* Verify zone reset */ | ||
187 | tmp = pwr_ctrl_rd(cpu); | ||
188 | if (!(tmp & ZONE_RESET_STATE_MASK)) | ||
189 | pr_err("%s: Zone reset bit for CPU %d not asserted!\n", | ||
190 | __func__, cpu); | ||
191 | |||
192 | /* Wait for power down */ | ||
193 | do { | ||
194 | tmp = pwr_ctrl_rd(cpu); | ||
195 | } while (!(tmp & ZONE_PWR_OFF_STATE_MASK)); | ||
196 | |||
197 | /* Flush pipeline before resetting CPU */ | ||
198 | mb(); | ||
199 | |||
200 | /* Assert reset on the CPU */ | ||
201 | cpu_rst_cfg_set(cpu, 1); | ||
202 | |||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
207 | |||
208 | static int __init setup_hifcpubiuctrl_regs(struct device_node *np) | ||
209 | { | ||
210 | int rc = 0; | ||
211 | char *name; | ||
212 | struct device_node *syscon_np = NULL; | ||
213 | |||
214 | name = "syscon-cpu"; | ||
215 | |||
216 | syscon_np = of_parse_phandle(np, name, 0); | ||
217 | if (!syscon_np) { | ||
218 | pr_err("can't find phandle %s\n", name); | ||
219 | rc = -EINVAL; | ||
220 | goto cleanup; | ||
221 | } | ||
222 | |||
223 | cpubiuctrl_block = of_iomap(syscon_np, 0); | ||
224 | if (!cpubiuctrl_block) { | ||
225 | pr_err("iomap failed for cpubiuctrl_block\n"); | ||
226 | rc = -EINVAL; | ||
227 | goto cleanup; | ||
228 | } | ||
229 | |||
230 | rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG, | ||
231 | &cpu0_pwr_zone_ctrl_reg); | ||
232 | if (rc) { | ||
233 | pr_err("failed to read 1st entry from %s property (%d)\n", name, | ||
234 | rc); | ||
235 | rc = -EINVAL; | ||
236 | goto cleanup; | ||
237 | } | ||
238 | |||
239 | rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG, | ||
240 | &cpu_rst_cfg_reg); | ||
241 | if (rc) { | ||
242 | pr_err("failed to read 2nd entry from %s property (%d)\n", name, | ||
243 | rc); | ||
244 | rc = -EINVAL; | ||
245 | goto cleanup; | ||
246 | } | ||
247 | |||
248 | cleanup: | ||
249 | of_node_put(syscon_np); | ||
250 | return rc; | ||
251 | } | ||
252 | |||
253 | static int __init setup_hifcont_regs(struct device_node *np) | ||
254 | { | ||
255 | int rc = 0; | ||
256 | char *name; | ||
257 | struct device_node *syscon_np = NULL; | ||
258 | |||
259 | name = "syscon-cont"; | ||
260 | |||
261 | syscon_np = of_parse_phandle(np, name, 0); | ||
262 | if (!syscon_np) { | ||
263 | pr_err("can't find phandle %s\n", name); | ||
264 | rc = -EINVAL; | ||
265 | goto cleanup; | ||
266 | } | ||
267 | |||
268 | hif_cont_block = of_iomap(syscon_np, 0); | ||
269 | if (!hif_cont_block) { | ||
270 | pr_err("iomap failed for hif_cont_block\n"); | ||
271 | rc = -EINVAL; | ||
272 | goto cleanup; | ||
273 | } | ||
274 | |||
275 | /* Offset is at top of hif_cont_block */ | ||
276 | hif_cont_reg = 0; | ||
277 | |||
278 | cleanup: | ||
279 | of_node_put(syscon_np); | ||
280 | return rc; | ||
281 | } | ||
282 | |||
283 | static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus) | ||
284 | { | ||
285 | int rc; | ||
286 | struct device_node *np; | ||
287 | char *name; | ||
288 | |||
289 | name = "brcm,brcmstb-smpboot"; | ||
290 | np = of_find_compatible_node(NULL, NULL, name); | ||
291 | if (!np) { | ||
292 | pr_err("can't find compatible node %s\n", name); | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | rc = setup_hifcpubiuctrl_regs(np); | ||
297 | if (rc) | ||
298 | return; | ||
299 | |||
300 | rc = setup_hifcont_regs(np); | ||
301 | if (rc) | ||
302 | return; | ||
303 | } | ||
304 | |||
305 | static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
306 | { | ||
307 | /* Missing the brcm,brcmstb-smpboot DT node? */ | ||
308 | if (!cpubiuctrl_block || !hif_cont_block) | ||
309 | return -ENODEV; | ||
310 | |||
311 | /* Bring up power to the core if necessary */ | ||
312 | if (brcmstb_cpu_get_power_state(cpu) == 0) | ||
313 | brcmstb_cpu_power_on(cpu); | ||
314 | |||
315 | brcmstb_cpu_boot(cpu); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static struct smp_operations brcmstb_smp_ops __initdata = { | ||
321 | .smp_prepare_cpus = brcmstb_cpu_ctrl_setup, | ||
322 | .smp_boot_secondary = brcmstb_boot_secondary, | ||
323 | #ifdef CONFIG_HOTPLUG_CPU | ||
324 | .cpu_kill = brcmstb_cpu_kill, | ||
325 | .cpu_die = brcmstb_cpu_die, | ||
326 | #endif | ||
327 | }; | ||
328 | |||
329 | CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops); | ||