xref: /OK3568_Linux_fs/kernel/arch/arm/mach-bcm/platsmp-brcmstb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Broadcom STB CPU SMP and hotplug support for ARM
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2013-2014 Broadcom Corporation
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
7*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License as
8*4882a593Smuzhiyun  * published by the Free Software Foundation version 2.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11*4882a593Smuzhiyun  * kind, whether express or implied; without even the implied warranty
12*4882a593Smuzhiyun  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*4882a593Smuzhiyun  * GNU General Public License for more details.
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/errno.h>
18*4882a593Smuzhiyun #include <linux/init.h>
19*4882a593Smuzhiyun #include <linux/io.h>
20*4882a593Smuzhiyun #include <linux/jiffies.h>
21*4882a593Smuzhiyun #include <linux/of_address.h>
22*4882a593Smuzhiyun #include <linux/of_platform.h>
23*4882a593Smuzhiyun #include <linux/printk.h>
24*4882a593Smuzhiyun #include <linux/regmap.h>
25*4882a593Smuzhiyun #include <linux/smp.h>
26*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <asm/cacheflush.h>
29*4882a593Smuzhiyun #include <asm/cp15.h>
30*4882a593Smuzhiyun #include <asm/mach-types.h>
31*4882a593Smuzhiyun #include <asm/smp_plat.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun enum {
34*4882a593Smuzhiyun 	ZONE_MAN_CLKEN_MASK		= BIT(0),
35*4882a593Smuzhiyun 	ZONE_MAN_RESET_CNTL_MASK	= BIT(1),
36*4882a593Smuzhiyun 	ZONE_MAN_MEM_PWR_MASK		= BIT(4),
37*4882a593Smuzhiyun 	ZONE_RESERVED_1_MASK		= BIT(5),
38*4882a593Smuzhiyun 	ZONE_MAN_ISO_CNTL_MASK		= BIT(6),
39*4882a593Smuzhiyun 	ZONE_MANUAL_CONTROL_MASK	= BIT(7),
40*4882a593Smuzhiyun 	ZONE_PWR_DN_REQ_MASK		= BIT(9),
41*4882a593Smuzhiyun 	ZONE_PWR_UP_REQ_MASK		= BIT(10),
42*4882a593Smuzhiyun 	ZONE_BLK_RST_ASSERT_MASK	= BIT(12),
43*4882a593Smuzhiyun 	ZONE_PWR_OFF_STATE_MASK		= BIT(25),
44*4882a593Smuzhiyun 	ZONE_PWR_ON_STATE_MASK		= BIT(26),
45*4882a593Smuzhiyun 	ZONE_DPG_PWR_STATE_MASK		= BIT(28),
46*4882a593Smuzhiyun 	ZONE_MEM_PWR_STATE_MASK		= BIT(29),
47*4882a593Smuzhiyun 	ZONE_RESET_STATE_MASK		= BIT(31),
48*4882a593Smuzhiyun 	CPU0_PWR_ZONE_CTRL_REG		= 1,
49*4882a593Smuzhiyun 	CPU_RESET_CONFIG_REG		= 2,
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun static void __iomem *cpubiuctrl_block;
53*4882a593Smuzhiyun static void __iomem *hif_cont_block;
54*4882a593Smuzhiyun static u32 cpu0_pwr_zone_ctrl_reg;
55*4882a593Smuzhiyun static u32 cpu_rst_cfg_reg;
56*4882a593Smuzhiyun static u32 hif_cont_reg;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun  * We must quiesce a dying CPU before it can be killed by the boot CPU. Because
61*4882a593Smuzhiyun  * one or more cache may be disabled, we must flush to ensure coherency. We
62*4882a593Smuzhiyun  * cannot use traditionl completion structures or spinlocks as they rely on
63*4882a593Smuzhiyun  * coherency.
64*4882a593Smuzhiyun  */
65*4882a593Smuzhiyun static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state);
66*4882a593Smuzhiyun 
per_cpu_sw_state_rd(u32 cpu)67*4882a593Smuzhiyun static int per_cpu_sw_state_rd(u32 cpu)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
70*4882a593Smuzhiyun 	return per_cpu(per_cpu_sw_state, cpu);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
per_cpu_sw_state_wr(u32 cpu,int val)73*4882a593Smuzhiyun static void per_cpu_sw_state_wr(u32 cpu, int val)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	dmb();
76*4882a593Smuzhiyun 	per_cpu(per_cpu_sw_state, cpu) = val;
77*4882a593Smuzhiyun 	sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun #else
per_cpu_sw_state_wr(u32 cpu,int val)80*4882a593Smuzhiyun static inline void per_cpu_sw_state_wr(u32 cpu, int val) { }
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun 
pwr_ctrl_get_base(u32 cpu)83*4882a593Smuzhiyun static void __iomem *pwr_ctrl_get_base(u32 cpu)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg;
86*4882a593Smuzhiyun 	base += (cpu_logical_map(cpu) * 4);
87*4882a593Smuzhiyun 	return base;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
pwr_ctrl_rd(u32 cpu)90*4882a593Smuzhiyun static u32 pwr_ctrl_rd(u32 cpu)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	void __iomem *base = pwr_ctrl_get_base(cpu);
93*4882a593Smuzhiyun 	return readl_relaxed(base);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
pwr_ctrl_set(unsigned int cpu,u32 val,u32 mask)96*4882a593Smuzhiyun static void pwr_ctrl_set(unsigned int cpu, u32 val, u32 mask)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	void __iomem *base = pwr_ctrl_get_base(cpu);
99*4882a593Smuzhiyun 	writel((readl(base) & mask) | val, base);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
pwr_ctrl_clr(unsigned int cpu,u32 val,u32 mask)102*4882a593Smuzhiyun static void pwr_ctrl_clr(unsigned int cpu, u32 val, u32 mask)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	void __iomem *base = pwr_ctrl_get_base(cpu);
105*4882a593Smuzhiyun 	writel((readl(base) & mask) & ~val, base);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun #define POLL_TMOUT_MS 500
pwr_ctrl_wait_tmout(unsigned int cpu,u32 set,u32 mask)109*4882a593Smuzhiyun static int pwr_ctrl_wait_tmout(unsigned int cpu, u32 set, u32 mask)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	const unsigned long timeo = jiffies + msecs_to_jiffies(POLL_TMOUT_MS);
112*4882a593Smuzhiyun 	u32 tmp;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	do {
115*4882a593Smuzhiyun 		tmp = pwr_ctrl_rd(cpu) & mask;
116*4882a593Smuzhiyun 		if (!set == !tmp)
117*4882a593Smuzhiyun 			return 0;
118*4882a593Smuzhiyun 	} while (time_before(jiffies, timeo));
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	tmp = pwr_ctrl_rd(cpu) & mask;
121*4882a593Smuzhiyun 	if (!set == !tmp)
122*4882a593Smuzhiyun 		return 0;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return -ETIMEDOUT;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
cpu_rst_cfg_set(u32 cpu,int set)127*4882a593Smuzhiyun static void cpu_rst_cfg_set(u32 cpu, int set)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	u32 val;
130*4882a593Smuzhiyun 	val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
131*4882a593Smuzhiyun 	if (set)
132*4882a593Smuzhiyun 		val |= BIT(cpu_logical_map(cpu));
133*4882a593Smuzhiyun 	else
134*4882a593Smuzhiyun 		val &= ~BIT(cpu_logical_map(cpu));
135*4882a593Smuzhiyun 	writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
cpu_set_boot_addr(u32 cpu,unsigned long boot_addr)138*4882a593Smuzhiyun static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	const int reg_ofs = cpu_logical_map(cpu) * 8;
141*4882a593Smuzhiyun 	writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
142*4882a593Smuzhiyun 	writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
brcmstb_cpu_boot(u32 cpu)145*4882a593Smuzhiyun static void brcmstb_cpu_boot(u32 cpu)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	/* Mark this CPU as "up" */
148*4882a593Smuzhiyun 	per_cpu_sw_state_wr(cpu, 1);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	/*
151*4882a593Smuzhiyun 	 * Set the reset vector to point to the secondary_startup
152*4882a593Smuzhiyun 	 * routine
153*4882a593Smuzhiyun 	 */
154*4882a593Smuzhiyun 	cpu_set_boot_addr(cpu, __pa_symbol(secondary_startup));
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* Unhalt the cpu */
157*4882a593Smuzhiyun 	cpu_rst_cfg_set(cpu, 0);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
brcmstb_cpu_power_on(u32 cpu)160*4882a593Smuzhiyun static void brcmstb_cpu_power_on(u32 cpu)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	/*
163*4882a593Smuzhiyun 	 * The secondary cores power was cut, so we must go through
164*4882a593Smuzhiyun 	 * power-on initialization.
165*4882a593Smuzhiyun 	 */
166*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, 0xffffff00);
167*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
168*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_RESERVED_1_MASK, -1);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_MEM_PWR_STATE_MASK))
173*4882a593Smuzhiyun 		panic("ZONE_MEM_PWR_STATE_MASK set timeout");
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_MAN_CLKEN_MASK, -1);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_DPG_PWR_STATE_MASK))
178*4882a593Smuzhiyun 		panic("ZONE_DPG_PWR_STATE_MASK set timeout");
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	pwr_ctrl_clr(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
181*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_MAN_RESET_CNTL_MASK, -1);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
brcmstb_cpu_get_power_state(u32 cpu)184*4882a593Smuzhiyun static int brcmstb_cpu_get_power_state(u32 cpu)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	int tmp = pwr_ctrl_rd(cpu);
187*4882a593Smuzhiyun 	return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
191*4882a593Smuzhiyun 
brcmstb_cpu_die(u32 cpu)192*4882a593Smuzhiyun static void brcmstb_cpu_die(u32 cpu)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	v7_exit_coherency_flush(all);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	per_cpu_sw_state_wr(cpu, 0);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	/* Sit and wait to die */
199*4882a593Smuzhiyun 	wfi();
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	/* We should never get here... */
202*4882a593Smuzhiyun 	while (1)
203*4882a593Smuzhiyun 		;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
brcmstb_cpu_kill(u32 cpu)206*4882a593Smuzhiyun static int brcmstb_cpu_kill(u32 cpu)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	/*
209*4882a593Smuzhiyun 	 * Ordinarily, the hardware forbids power-down of CPU0 (which is good
210*4882a593Smuzhiyun 	 * because it is the boot CPU), but this is not true when using BPCM
211*4882a593Smuzhiyun 	 * manual mode.  Consequently, we must avoid turning off CPU0 here to
212*4882a593Smuzhiyun 	 * ensure that TI2C master reset will work.
213*4882a593Smuzhiyun 	 */
214*4882a593Smuzhiyun 	if (cpu == 0) {
215*4882a593Smuzhiyun 		pr_warn("SMP: refusing to power off CPU0\n");
216*4882a593Smuzhiyun 		return 1;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	while (per_cpu_sw_state_rd(cpu))
220*4882a593Smuzhiyun 		;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
223*4882a593Smuzhiyun 	pwr_ctrl_clr(cpu, ZONE_MAN_RESET_CNTL_MASK, -1);
224*4882a593Smuzhiyun 	pwr_ctrl_clr(cpu, ZONE_MAN_CLKEN_MASK, -1);
225*4882a593Smuzhiyun 	pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
226*4882a593Smuzhiyun 	pwr_ctrl_clr(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_MEM_PWR_STATE_MASK))
229*4882a593Smuzhiyun 		panic("ZONE_MEM_PWR_STATE_MASK clear timeout");
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	pwr_ctrl_clr(cpu, ZONE_RESERVED_1_MASK, -1);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_DPG_PWR_STATE_MASK))
234*4882a593Smuzhiyun 		panic("ZONE_DPG_PWR_STATE_MASK clear timeout");
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	/* Flush pipeline before resetting CPU */
237*4882a593Smuzhiyun 	mb();
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	/* Assert reset on the CPU */
240*4882a593Smuzhiyun 	cpu_rst_cfg_set(cpu, 1);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	return 1;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun #endif /* CONFIG_HOTPLUG_CPU */
246*4882a593Smuzhiyun 
setup_hifcpubiuctrl_regs(struct device_node * np)247*4882a593Smuzhiyun static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	int rc = 0;
250*4882a593Smuzhiyun 	char *name;
251*4882a593Smuzhiyun 	struct device_node *syscon_np = NULL;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	name = "syscon-cpu";
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	syscon_np = of_parse_phandle(np, name, 0);
256*4882a593Smuzhiyun 	if (!syscon_np) {
257*4882a593Smuzhiyun 		pr_err("can't find phandle %s\n", name);
258*4882a593Smuzhiyun 		rc = -EINVAL;
259*4882a593Smuzhiyun 		goto cleanup;
260*4882a593Smuzhiyun 	}
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	cpubiuctrl_block = of_iomap(syscon_np, 0);
263*4882a593Smuzhiyun 	if (!cpubiuctrl_block) {
264*4882a593Smuzhiyun 		pr_err("iomap failed for cpubiuctrl_block\n");
265*4882a593Smuzhiyun 		rc = -EINVAL;
266*4882a593Smuzhiyun 		goto cleanup;
267*4882a593Smuzhiyun 	}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG,
270*4882a593Smuzhiyun 					&cpu0_pwr_zone_ctrl_reg);
271*4882a593Smuzhiyun 	if (rc) {
272*4882a593Smuzhiyun 		pr_err("failed to read 1st entry from %s property (%d)\n", name,
273*4882a593Smuzhiyun 			rc);
274*4882a593Smuzhiyun 		rc = -EINVAL;
275*4882a593Smuzhiyun 		goto cleanup;
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG,
279*4882a593Smuzhiyun 					&cpu_rst_cfg_reg);
280*4882a593Smuzhiyun 	if (rc) {
281*4882a593Smuzhiyun 		pr_err("failed to read 2nd entry from %s property (%d)\n", name,
282*4882a593Smuzhiyun 			rc);
283*4882a593Smuzhiyun 		rc = -EINVAL;
284*4882a593Smuzhiyun 		goto cleanup;
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun cleanup:
288*4882a593Smuzhiyun 	of_node_put(syscon_np);
289*4882a593Smuzhiyun 	return rc;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
setup_hifcont_regs(struct device_node * np)292*4882a593Smuzhiyun static int __init setup_hifcont_regs(struct device_node *np)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	int rc = 0;
295*4882a593Smuzhiyun 	char *name;
296*4882a593Smuzhiyun 	struct device_node *syscon_np = NULL;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	name = "syscon-cont";
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	syscon_np = of_parse_phandle(np, name, 0);
301*4882a593Smuzhiyun 	if (!syscon_np) {
302*4882a593Smuzhiyun 		pr_err("can't find phandle %s\n", name);
303*4882a593Smuzhiyun 		rc = -EINVAL;
304*4882a593Smuzhiyun 		goto cleanup;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	hif_cont_block = of_iomap(syscon_np, 0);
308*4882a593Smuzhiyun 	if (!hif_cont_block) {
309*4882a593Smuzhiyun 		pr_err("iomap failed for hif_cont_block\n");
310*4882a593Smuzhiyun 		rc = -EINVAL;
311*4882a593Smuzhiyun 		goto cleanup;
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* Offset is at top of hif_cont_block */
315*4882a593Smuzhiyun 	hif_cont_reg = 0;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun cleanup:
318*4882a593Smuzhiyun 	of_node_put(syscon_np);
319*4882a593Smuzhiyun 	return rc;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
brcmstb_cpu_ctrl_setup(unsigned int max_cpus)322*4882a593Smuzhiyun static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	int rc;
325*4882a593Smuzhiyun 	struct device_node *np;
326*4882a593Smuzhiyun 	char *name;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	name = "brcm,brcmstb-smpboot";
329*4882a593Smuzhiyun 	np = of_find_compatible_node(NULL, NULL, name);
330*4882a593Smuzhiyun 	if (!np) {
331*4882a593Smuzhiyun 		pr_err("can't find compatible node %s\n", name);
332*4882a593Smuzhiyun 		return;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	rc = setup_hifcpubiuctrl_regs(np);
336*4882a593Smuzhiyun 	if (rc)
337*4882a593Smuzhiyun 		goto out_put_node;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	rc = setup_hifcont_regs(np);
340*4882a593Smuzhiyun 	if (rc)
341*4882a593Smuzhiyun 		goto out_put_node;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun out_put_node:
344*4882a593Smuzhiyun 	of_node_put(np);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
brcmstb_boot_secondary(unsigned int cpu,struct task_struct * idle)347*4882a593Smuzhiyun static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	/* Missing the brcm,brcmstb-smpboot DT node? */
350*4882a593Smuzhiyun 	if (!cpubiuctrl_block || !hif_cont_block)
351*4882a593Smuzhiyun 		return -ENODEV;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	/* Bring up power to the core if necessary */
354*4882a593Smuzhiyun 	if (brcmstb_cpu_get_power_state(cpu) == 0)
355*4882a593Smuzhiyun 		brcmstb_cpu_power_on(cpu);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	brcmstb_cpu_boot(cpu);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	return 0;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun static const struct smp_operations brcmstb_smp_ops __initconst = {
363*4882a593Smuzhiyun 	.smp_prepare_cpus	= brcmstb_cpu_ctrl_setup,
364*4882a593Smuzhiyun 	.smp_boot_secondary	= brcmstb_boot_secondary,
365*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
366*4882a593Smuzhiyun 	.cpu_kill		= brcmstb_cpu_kill,
367*4882a593Smuzhiyun 	.cpu_die		= brcmstb_cpu_die,
368*4882a593Smuzhiyun #endif
369*4882a593Smuzhiyun };
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops);
372