162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Broadcom STB CPU SMP and hotplug support for ARM
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013-2014 Broadcom Corporation
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/jiffies.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci#include <linux/printk.h>
1662306a36Sopenharmony_ci#include <linux/regmap.h>
1762306a36Sopenharmony_ci#include <linux/smp.h>
1862306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <asm/cacheflush.h>
2162306a36Sopenharmony_ci#include <asm/cp15.h>
2262306a36Sopenharmony_ci#include <asm/mach-types.h>
2362306a36Sopenharmony_ci#include <asm/smp_plat.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cienum {
2662306a36Sopenharmony_ci	ZONE_MAN_CLKEN_MASK		= BIT(0),
2762306a36Sopenharmony_ci	ZONE_MAN_RESET_CNTL_MASK	= BIT(1),
2862306a36Sopenharmony_ci	ZONE_MAN_MEM_PWR_MASK		= BIT(4),
2962306a36Sopenharmony_ci	ZONE_RESERVED_1_MASK		= BIT(5),
3062306a36Sopenharmony_ci	ZONE_MAN_ISO_CNTL_MASK		= BIT(6),
3162306a36Sopenharmony_ci	ZONE_MANUAL_CONTROL_MASK	= BIT(7),
3262306a36Sopenharmony_ci	ZONE_PWR_DN_REQ_MASK		= BIT(9),
3362306a36Sopenharmony_ci	ZONE_PWR_UP_REQ_MASK		= BIT(10),
3462306a36Sopenharmony_ci	ZONE_BLK_RST_ASSERT_MASK	= BIT(12),
3562306a36Sopenharmony_ci	ZONE_PWR_OFF_STATE_MASK		= BIT(25),
3662306a36Sopenharmony_ci	ZONE_PWR_ON_STATE_MASK		= BIT(26),
3762306a36Sopenharmony_ci	ZONE_DPG_PWR_STATE_MASK		= BIT(28),
3862306a36Sopenharmony_ci	ZONE_MEM_PWR_STATE_MASK		= BIT(29),
3962306a36Sopenharmony_ci	ZONE_RESET_STATE_MASK		= BIT(31),
4062306a36Sopenharmony_ci	CPU0_PWR_ZONE_CTRL_REG		= 1,
4162306a36Sopenharmony_ci	CPU_RESET_CONFIG_REG		= 2,
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic void __iomem *cpubiuctrl_block;
4562306a36Sopenharmony_cistatic void __iomem *hif_cont_block;
4662306a36Sopenharmony_cistatic u32 cpu0_pwr_zone_ctrl_reg;
4762306a36Sopenharmony_cistatic u32 cpu_rst_cfg_reg;
4862306a36Sopenharmony_cistatic u32 hif_cont_reg;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * We must quiesce a dying CPU before it can be killed by the boot CPU. Because
5362306a36Sopenharmony_ci * one or more cache may be disabled, we must flush to ensure coherency. We
5462306a36Sopenharmony_ci * cannot use traditional completion structures or spinlocks as they rely on
5562306a36Sopenharmony_ci * coherency.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_cistatic DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int per_cpu_sw_state_rd(u32 cpu)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
6262306a36Sopenharmony_ci	return per_cpu(per_cpu_sw_state, cpu);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void per_cpu_sw_state_wr(u32 cpu, int val)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	dmb();
6862306a36Sopenharmony_ci	per_cpu(per_cpu_sw_state, cpu) = val;
6962306a36Sopenharmony_ci	sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci#else
7262306a36Sopenharmony_cistatic inline void per_cpu_sw_state_wr(u32 cpu, int val) { }
7362306a36Sopenharmony_ci#endif
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void __iomem *pwr_ctrl_get_base(u32 cpu)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg;
7862306a36Sopenharmony_ci	base += (cpu_logical_map(cpu) * 4);
7962306a36Sopenharmony_ci	return base;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic u32 pwr_ctrl_rd(u32 cpu)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	void __iomem *base = pwr_ctrl_get_base(cpu);
8562306a36Sopenharmony_ci	return readl_relaxed(base);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void pwr_ctrl_set(unsigned int cpu, u32 val, u32 mask)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	void __iomem *base = pwr_ctrl_get_base(cpu);
9162306a36Sopenharmony_ci	writel((readl(base) & mask) | val, base);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void pwr_ctrl_clr(unsigned int cpu, u32 val, u32 mask)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	void __iomem *base = pwr_ctrl_get_base(cpu);
9762306a36Sopenharmony_ci	writel((readl(base) & mask) & ~val, base);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define POLL_TMOUT_MS 500
10162306a36Sopenharmony_cistatic int pwr_ctrl_wait_tmout(unsigned int cpu, u32 set, u32 mask)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	const unsigned long timeo = jiffies + msecs_to_jiffies(POLL_TMOUT_MS);
10462306a36Sopenharmony_ci	u32 tmp;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	do {
10762306a36Sopenharmony_ci		tmp = pwr_ctrl_rd(cpu) & mask;
10862306a36Sopenharmony_ci		if (!set == !tmp)
10962306a36Sopenharmony_ci			return 0;
11062306a36Sopenharmony_ci	} while (time_before(jiffies, timeo));
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	tmp = pwr_ctrl_rd(cpu) & mask;
11362306a36Sopenharmony_ci	if (!set == !tmp)
11462306a36Sopenharmony_ci		return 0;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return -ETIMEDOUT;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void cpu_rst_cfg_set(u32 cpu, int set)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	u32 val;
12262306a36Sopenharmony_ci	val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
12362306a36Sopenharmony_ci	if (set)
12462306a36Sopenharmony_ci		val |= BIT(cpu_logical_map(cpu));
12562306a36Sopenharmony_ci	else
12662306a36Sopenharmony_ci		val &= ~BIT(cpu_logical_map(cpu));
12762306a36Sopenharmony_ci	writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	const int reg_ofs = cpu_logical_map(cpu) * 8;
13362306a36Sopenharmony_ci	writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
13462306a36Sopenharmony_ci	writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void brcmstb_cpu_boot(u32 cpu)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	/* Mark this CPU as "up" */
14062306a36Sopenharmony_ci	per_cpu_sw_state_wr(cpu, 1);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/*
14362306a36Sopenharmony_ci	 * Set the reset vector to point to the secondary_startup
14462306a36Sopenharmony_ci	 * routine
14562306a36Sopenharmony_ci	 */
14662306a36Sopenharmony_ci	cpu_set_boot_addr(cpu, __pa_symbol(secondary_startup));
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* Unhalt the cpu */
14962306a36Sopenharmony_ci	cpu_rst_cfg_set(cpu, 0);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic void brcmstb_cpu_power_on(u32 cpu)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	/*
15562306a36Sopenharmony_ci	 * The secondary cores power was cut, so we must go through
15662306a36Sopenharmony_ci	 * power-on initialization.
15762306a36Sopenharmony_ci	 */
15862306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, 0xffffff00);
15962306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
16062306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_RESERVED_1_MASK, -1);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_MEM_PWR_STATE_MASK))
16562306a36Sopenharmony_ci		panic("ZONE_MEM_PWR_STATE_MASK set timeout");
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_MAN_CLKEN_MASK, -1);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_DPG_PWR_STATE_MASK))
17062306a36Sopenharmony_ci		panic("ZONE_DPG_PWR_STATE_MASK set timeout");
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	pwr_ctrl_clr(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
17362306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_MAN_RESET_CNTL_MASK, -1);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int brcmstb_cpu_get_power_state(u32 cpu)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	int tmp = pwr_ctrl_rd(cpu);
17962306a36Sopenharmony_ci	return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic void brcmstb_cpu_die(u32 cpu)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	v7_exit_coherency_flush(all);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	per_cpu_sw_state_wr(cpu, 0);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* Sit and wait to die */
19162306a36Sopenharmony_ci	wfi();
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* We should never get here... */
19462306a36Sopenharmony_ci	while (1)
19562306a36Sopenharmony_ci		;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int brcmstb_cpu_kill(u32 cpu)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	/*
20162306a36Sopenharmony_ci	 * Ordinarily, the hardware forbids power-down of CPU0 (which is good
20262306a36Sopenharmony_ci	 * because it is the boot CPU), but this is not true when using BPCM
20362306a36Sopenharmony_ci	 * manual mode.  Consequently, we must avoid turning off CPU0 here to
20462306a36Sopenharmony_ci	 * ensure that TI2C master reset will work.
20562306a36Sopenharmony_ci	 */
20662306a36Sopenharmony_ci	if (cpu == 0) {
20762306a36Sopenharmony_ci		pr_warn("SMP: refusing to power off CPU0\n");
20862306a36Sopenharmony_ci		return 1;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	while (per_cpu_sw_state_rd(cpu))
21262306a36Sopenharmony_ci		;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
21562306a36Sopenharmony_ci	pwr_ctrl_clr(cpu, ZONE_MAN_RESET_CNTL_MASK, -1);
21662306a36Sopenharmony_ci	pwr_ctrl_clr(cpu, ZONE_MAN_CLKEN_MASK, -1);
21762306a36Sopenharmony_ci	pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
21862306a36Sopenharmony_ci	pwr_ctrl_clr(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_MEM_PWR_STATE_MASK))
22162306a36Sopenharmony_ci		panic("ZONE_MEM_PWR_STATE_MASK clear timeout");
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	pwr_ctrl_clr(cpu, ZONE_RESERVED_1_MASK, -1);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_DPG_PWR_STATE_MASK))
22662306a36Sopenharmony_ci		panic("ZONE_DPG_PWR_STATE_MASK clear timeout");
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* Flush pipeline before resetting CPU */
22962306a36Sopenharmony_ci	mb();
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Assert reset on the CPU */
23262306a36Sopenharmony_ci	cpu_rst_cfg_set(cpu, 1);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return 1;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#endif /* CONFIG_HOTPLUG_CPU */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int __init setup_hifcpubiuctrl_regs(struct device_node *np)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	int rc = 0;
24262306a36Sopenharmony_ci	char *name;
24362306a36Sopenharmony_ci	struct device_node *syscon_np = NULL;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	name = "syscon-cpu";
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	syscon_np = of_parse_phandle(np, name, 0);
24862306a36Sopenharmony_ci	if (!syscon_np) {
24962306a36Sopenharmony_ci		pr_err("can't find phandle %s\n", name);
25062306a36Sopenharmony_ci		rc = -EINVAL;
25162306a36Sopenharmony_ci		goto cleanup;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	cpubiuctrl_block = of_iomap(syscon_np, 0);
25562306a36Sopenharmony_ci	if (!cpubiuctrl_block) {
25662306a36Sopenharmony_ci		pr_err("iomap failed for cpubiuctrl_block\n");
25762306a36Sopenharmony_ci		rc = -EINVAL;
25862306a36Sopenharmony_ci		goto cleanup;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG,
26262306a36Sopenharmony_ci					&cpu0_pwr_zone_ctrl_reg);
26362306a36Sopenharmony_ci	if (rc) {
26462306a36Sopenharmony_ci		pr_err("failed to read 1st entry from %s property (%d)\n", name,
26562306a36Sopenharmony_ci			rc);
26662306a36Sopenharmony_ci		rc = -EINVAL;
26762306a36Sopenharmony_ci		goto cleanup;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG,
27162306a36Sopenharmony_ci					&cpu_rst_cfg_reg);
27262306a36Sopenharmony_ci	if (rc) {
27362306a36Sopenharmony_ci		pr_err("failed to read 2nd entry from %s property (%d)\n", name,
27462306a36Sopenharmony_ci			rc);
27562306a36Sopenharmony_ci		rc = -EINVAL;
27662306a36Sopenharmony_ci		goto cleanup;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cicleanup:
28062306a36Sopenharmony_ci	of_node_put(syscon_np);
28162306a36Sopenharmony_ci	return rc;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic int __init setup_hifcont_regs(struct device_node *np)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	int rc = 0;
28762306a36Sopenharmony_ci	char *name;
28862306a36Sopenharmony_ci	struct device_node *syscon_np = NULL;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	name = "syscon-cont";
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	syscon_np = of_parse_phandle(np, name, 0);
29362306a36Sopenharmony_ci	if (!syscon_np) {
29462306a36Sopenharmony_ci		pr_err("can't find phandle %s\n", name);
29562306a36Sopenharmony_ci		rc = -EINVAL;
29662306a36Sopenharmony_ci		goto cleanup;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	hif_cont_block = of_iomap(syscon_np, 0);
30062306a36Sopenharmony_ci	if (!hif_cont_block) {
30162306a36Sopenharmony_ci		pr_err("iomap failed for hif_cont_block\n");
30262306a36Sopenharmony_ci		rc = -EINVAL;
30362306a36Sopenharmony_ci		goto cleanup;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Offset is at top of hif_cont_block */
30762306a36Sopenharmony_ci	hif_cont_reg = 0;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cicleanup:
31062306a36Sopenharmony_ci	of_node_put(syscon_np);
31162306a36Sopenharmony_ci	return rc;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	int rc;
31762306a36Sopenharmony_ci	struct device_node *np;
31862306a36Sopenharmony_ci	char *name;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	name = "brcm,brcmstb-smpboot";
32162306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, name);
32262306a36Sopenharmony_ci	if (!np) {
32362306a36Sopenharmony_ci		pr_err("can't find compatible node %s\n", name);
32462306a36Sopenharmony_ci		return;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	rc = setup_hifcpubiuctrl_regs(np);
32862306a36Sopenharmony_ci	if (rc)
32962306a36Sopenharmony_ci		goto out_put_node;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	rc = setup_hifcont_regs(np);
33262306a36Sopenharmony_ci	if (rc)
33362306a36Sopenharmony_ci		goto out_put_node;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciout_put_node:
33662306a36Sopenharmony_ci	of_node_put(np);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	/* Missing the brcm,brcmstb-smpboot DT node? */
34262306a36Sopenharmony_ci	if (!cpubiuctrl_block || !hif_cont_block)
34362306a36Sopenharmony_ci		return -ENODEV;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Bring up power to the core if necessary */
34662306a36Sopenharmony_ci	if (brcmstb_cpu_get_power_state(cpu) == 0)
34762306a36Sopenharmony_ci		brcmstb_cpu_power_on(cpu);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	brcmstb_cpu_boot(cpu);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic const struct smp_operations brcmstb_smp_ops __initconst = {
35562306a36Sopenharmony_ci	.smp_prepare_cpus	= brcmstb_cpu_ctrl_setup,
35662306a36Sopenharmony_ci	.smp_boot_secondary	= brcmstb_boot_secondary,
35762306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
35862306a36Sopenharmony_ci	.cpu_kill		= brcmstb_cpu_kill,
35962306a36Sopenharmony_ci	.cpu_die		= brcmstb_cpu_die,
36062306a36Sopenharmony_ci#endif
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ciCPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops);
364