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