18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2014-2015 Broadcom Corporation 48c2ecf20Sopenharmony_ci * Copyright 2014 Linaro Limited 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/irqchip/irq-bcm2836.h> 138c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/of_address.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/sched/clock.h> 188c2ecf20Sopenharmony_ci#include <linux/smp.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 218c2ecf20Sopenharmony_ci#include <asm/smp.h> 228c2ecf20Sopenharmony_ci#include <asm/smp_plat.h> 238c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "platsmp.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Size of mapped Cortex A9 SCU address space */ 288c2ecf20Sopenharmony_ci#define CORTEX_A9_SCU_SIZE 0x58 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ 318c2ecf20Sopenharmony_ci#define BOOT_ADDR_CPUID_MASK 0x3 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Name of device node property defining secondary boot register location */ 348c2ecf20Sopenharmony_ci#define OF_SECONDARY_BOOT "secondary-boot-reg" 358c2ecf20Sopenharmony_ci#define MPIDR_CPUID_BITMASK 0x3 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * Enable the Cortex A9 Snoop Control Unit 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * By the time this is called we already know there are multiple 418c2ecf20Sopenharmony_ci * cores present. We assume we're running on a Cortex A9 processor, 428c2ecf20Sopenharmony_ci * so any trouble getting the base address register or getting the 438c2ecf20Sopenharmony_ci * SCU base is a problem. 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Return 0 if successful or an error code otherwise. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistatic int __init scu_a9_enable(void) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci unsigned long config_base; 508c2ecf20Sopenharmony_ci void __iomem *scu_base; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (!scu_a9_has_base()) { 538c2ecf20Sopenharmony_ci pr_err("no configuration base address register!\n"); 548c2ecf20Sopenharmony_ci return -ENXIO; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* Config base address register value is zero for uniprocessor */ 588c2ecf20Sopenharmony_ci config_base = scu_a9_get_base(); 598c2ecf20Sopenharmony_ci if (!config_base) { 608c2ecf20Sopenharmony_ci pr_err("hardware reports only one core\n"); 618c2ecf20Sopenharmony_ci return -ENOENT; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE); 658c2ecf20Sopenharmony_ci if (!scu_base) { 668c2ecf20Sopenharmony_ci pr_err("failed to remap config base (%lu/%u) for SCU\n", 678c2ecf20Sopenharmony_ci config_base, CORTEX_A9_SCU_SIZE); 688c2ecf20Sopenharmony_ci return -ENOMEM; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci scu_enable(scu_base); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci iounmap(scu_base); /* That's the last we'll need of this */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic u32 secondary_boot_addr_for(unsigned int cpu) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci u32 secondary_boot_addr = 0; 818c2ecf20Sopenharmony_ci struct device_node *cpu_node = of_get_cpu_node(cpu, NULL); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (!cpu_node) { 848c2ecf20Sopenharmony_ci pr_err("Failed to find device tree node for CPU%u\n", cpu); 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (of_property_read_u32(cpu_node, 898c2ecf20Sopenharmony_ci OF_SECONDARY_BOOT, 908c2ecf20Sopenharmony_ci &secondary_boot_addr)) 918c2ecf20Sopenharmony_ci pr_err("required secondary boot register not specified for CPU%u\n", 928c2ecf20Sopenharmony_ci cpu); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci of_node_put(cpu_node); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return secondary_boot_addr; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int nsp_write_lut(unsigned int cpu) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci void __iomem *sku_rom_lut; 1028c2ecf20Sopenharmony_ci phys_addr_t secondary_startup_phy; 1038c2ecf20Sopenharmony_ci const u32 secondary_boot_addr = secondary_boot_addr_for(cpu); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (!secondary_boot_addr) 1068c2ecf20Sopenharmony_ci return -EINVAL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci sku_rom_lut = ioremap((phys_addr_t)secondary_boot_addr, 1098c2ecf20Sopenharmony_ci sizeof(phys_addr_t)); 1108c2ecf20Sopenharmony_ci if (!sku_rom_lut) { 1118c2ecf20Sopenharmony_ci pr_warn("unable to ioremap SKU-ROM LUT register for cpu %u\n", cpu); 1128c2ecf20Sopenharmony_ci return -ENOMEM; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci secondary_startup_phy = __pa_symbol(secondary_startup); 1168c2ecf20Sopenharmony_ci BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci writel_relaxed(secondary_startup_phy, sku_rom_lut); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Ensure the write is visible to the secondary core */ 1218c2ecf20Sopenharmony_ci smp_wmb(); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci iounmap(sku_rom_lut); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void __init bcm_smp_prepare_cpus(unsigned int max_cpus) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci const cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Enable the SCU on Cortex A9 based SoCs */ 1338c2ecf20Sopenharmony_ci if (scu_a9_enable()) { 1348c2ecf20Sopenharmony_ci /* Update the CPU present map to reflect uniprocessor mode */ 1358c2ecf20Sopenharmony_ci pr_warn("failed to enable A9 SCU - disabling SMP\n"); 1368c2ecf20Sopenharmony_ci init_cpu_present(&only_cpu_0); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * The ROM code has the secondary cores looping, waiting for an event. 1428c2ecf20Sopenharmony_ci * When an event occurs each core examines the bottom two bits of the 1438c2ecf20Sopenharmony_ci * secondary boot register. When a core finds those bits contain its 1448c2ecf20Sopenharmony_ci * own core id, it performs initialization, including computing its boot 1458c2ecf20Sopenharmony_ci * address by clearing the boot register value's bottom two bits. The 1468c2ecf20Sopenharmony_ci * core signals that it is beginning its execution by writing its boot 1478c2ecf20Sopenharmony_ci * address back to the secondary boot register, and finally jumps to 1488c2ecf20Sopenharmony_ci * that address. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * So to start a core executing we need to: 1518c2ecf20Sopenharmony_ci * - Encode the (hardware) CPU id with the bottom bits of the secondary 1528c2ecf20Sopenharmony_ci * start address. 1538c2ecf20Sopenharmony_ci * - Write that value into the secondary boot register. 1548c2ecf20Sopenharmony_ci * - Generate an event to wake up the secondary CPU(s). 1558c2ecf20Sopenharmony_ci * - Wait for the secondary boot register to be re-written, which 1568c2ecf20Sopenharmony_ci * indicates the secondary core has started. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic int kona_boot_secondary(unsigned int cpu, struct task_struct *idle) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci void __iomem *boot_reg; 1618c2ecf20Sopenharmony_ci phys_addr_t boot_func; 1628c2ecf20Sopenharmony_ci u64 start_clock; 1638c2ecf20Sopenharmony_ci u32 cpu_id; 1648c2ecf20Sopenharmony_ci u32 boot_val; 1658c2ecf20Sopenharmony_ci bool timeout = false; 1668c2ecf20Sopenharmony_ci const u32 secondary_boot_addr = secondary_boot_addr_for(cpu); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci cpu_id = cpu_logical_map(cpu); 1698c2ecf20Sopenharmony_ci if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { 1708c2ecf20Sopenharmony_ci pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); 1718c2ecf20Sopenharmony_ci return -EINVAL; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!secondary_boot_addr) 1758c2ecf20Sopenharmony_ci return -EINVAL; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci boot_reg = ioremap((phys_addr_t)secondary_boot_addr, 1788c2ecf20Sopenharmony_ci sizeof(phys_addr_t)); 1798c2ecf20Sopenharmony_ci if (!boot_reg) { 1808c2ecf20Sopenharmony_ci pr_err("unable to map boot register for cpu %u\n", cpu_id); 1818c2ecf20Sopenharmony_ci return -ENOMEM; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* 1858c2ecf20Sopenharmony_ci * Secondary cores will start in secondary_startup(), 1868c2ecf20Sopenharmony_ci * defined in "arch/arm/kernel/head.S" 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci boot_func = __pa_symbol(secondary_startup); 1898c2ecf20Sopenharmony_ci BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); 1908c2ecf20Sopenharmony_ci BUG_ON(boot_func > (phys_addr_t)U32_MAX); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* The core to start is encoded in the low bits */ 1938c2ecf20Sopenharmony_ci boot_val = (u32)boot_func | cpu_id; 1948c2ecf20Sopenharmony_ci writel_relaxed(boot_val, boot_reg); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci sev(); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* The low bits will be cleared once the core has started */ 1998c2ecf20Sopenharmony_ci start_clock = local_clock(); 2008c2ecf20Sopenharmony_ci while (!timeout && readl_relaxed(boot_reg) == boot_val) 2018c2ecf20Sopenharmony_ci timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci iounmap(boot_reg); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (!timeout) 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci pr_err("timeout waiting for cpu %u to start\n", cpu_id); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return -ENXIO; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* Cluster Dormant Control command to bring CPU into a running state */ 2148c2ecf20Sopenharmony_ci#define CDC_CMD 6 2158c2ecf20Sopenharmony_ci#define CDC_CMD_OFFSET 0 2168c2ecf20Sopenharmony_ci#define CDC_CMD_REG(cpu) (CDC_CMD_OFFSET + 4*(cpu)) 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* 2198c2ecf20Sopenharmony_ci * BCM23550 has a Cluster Dormant Control block that keeps the core in 2208c2ecf20Sopenharmony_ci * idle state. A command needs to be sent to the block to bring the CPU 2218c2ecf20Sopenharmony_ci * into running state. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_cistatic int bcm23550_boot_secondary(unsigned int cpu, struct task_struct *idle) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci void __iomem *cdc_base; 2268c2ecf20Sopenharmony_ci struct device_node *dn; 2278c2ecf20Sopenharmony_ci char *name; 2288c2ecf20Sopenharmony_ci int ret; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Make sure a CDC node exists before booting the 2318c2ecf20Sopenharmony_ci * secondary core. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci name = "brcm,bcm23550-cdc"; 2348c2ecf20Sopenharmony_ci dn = of_find_compatible_node(NULL, NULL, name); 2358c2ecf20Sopenharmony_ci if (!dn) { 2368c2ecf20Sopenharmony_ci pr_err("unable to find cdc node\n"); 2378c2ecf20Sopenharmony_ci return -ENODEV; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci cdc_base = of_iomap(dn, 0); 2418c2ecf20Sopenharmony_ci of_node_put(dn); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!cdc_base) { 2448c2ecf20Sopenharmony_ci pr_err("unable to remap cdc base register\n"); 2458c2ecf20Sopenharmony_ci return -ENOMEM; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Boot the secondary core */ 2498c2ecf20Sopenharmony_ci ret = kona_boot_secondary(cpu, idle); 2508c2ecf20Sopenharmony_ci if (ret) 2518c2ecf20Sopenharmony_ci goto out; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Bring this CPU to RUN state so that nIRQ nFIQ 2548c2ecf20Sopenharmony_ci * signals are unblocked. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ci writel_relaxed(CDC_CMD, cdc_base + CDC_CMD_REG(cpu)); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ciout: 2598c2ecf20Sopenharmony_ci iounmap(cdc_base); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return ret; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int ret; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * After wake up, secondary core branches to the startup 2708c2ecf20Sopenharmony_ci * address programmed at SKU ROM LUT location. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci ret = nsp_write_lut(cpu); 2738c2ecf20Sopenharmony_ci if (ret) { 2748c2ecf20Sopenharmony_ci pr_err("unable to write startup addr to SKU ROM LUT\n"); 2758c2ecf20Sopenharmony_ci goto out; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Send a CPU wakeup interrupt to the secondary core */ 2798c2ecf20Sopenharmony_ci arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ciout: 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int bcm2836_boot_secondary(unsigned int cpu, struct task_struct *idle) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci void __iomem *intc_base; 2888c2ecf20Sopenharmony_ci struct device_node *dn; 2898c2ecf20Sopenharmony_ci char *name; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci name = "brcm,bcm2836-l1-intc"; 2928c2ecf20Sopenharmony_ci dn = of_find_compatible_node(NULL, NULL, name); 2938c2ecf20Sopenharmony_ci if (!dn) { 2948c2ecf20Sopenharmony_ci pr_err("unable to find intc node\n"); 2958c2ecf20Sopenharmony_ci return -ENODEV; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci intc_base = of_iomap(dn, 0); 2998c2ecf20Sopenharmony_ci of_node_put(dn); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (!intc_base) { 3028c2ecf20Sopenharmony_ci pr_err("unable to remap intc base register\n"); 3038c2ecf20Sopenharmony_ci return -ENOMEM; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci writel(virt_to_phys(secondary_startup), 3078c2ecf20Sopenharmony_ci intc_base + LOCAL_MAILBOX3_SET0 + 16 * cpu); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci dsb(sy); 3108c2ecf20Sopenharmony_ci sev(); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci iounmap(intc_base); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic const struct smp_operations kona_smp_ops __initconst = { 3188c2ecf20Sopenharmony_ci .smp_prepare_cpus = bcm_smp_prepare_cpus, 3198c2ecf20Sopenharmony_ci .smp_boot_secondary = kona_boot_secondary, 3208c2ecf20Sopenharmony_ci}; 3218c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", 3228c2ecf20Sopenharmony_ci &kona_smp_ops); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic const struct smp_operations bcm23550_smp_ops __initconst = { 3258c2ecf20Sopenharmony_ci .smp_boot_secondary = bcm23550_boot_secondary, 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(bcm_smp_bcm23550, "brcm,bcm23550", 3288c2ecf20Sopenharmony_ci &bcm23550_smp_ops); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic const struct smp_operations nsp_smp_ops __initconst = { 3318c2ecf20Sopenharmony_ci .smp_prepare_cpus = bcm_smp_prepare_cpus, 3328c2ecf20Sopenharmony_ci .smp_boot_secondary = nsp_boot_secondary, 3338c2ecf20Sopenharmony_ci}; 3348c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ciconst struct smp_operations bcm2836_smp_ops __initconst = { 3378c2ecf20Sopenharmony_ci .smp_boot_secondary = bcm2836_boot_secondary, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(bcm_smp_bcm2836, "brcm,bcm2836-smp", &bcm2836_smp_ops); 340