162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/mach-sti/platsmp.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 STMicroelectronics (R&D) Limited. 662306a36Sopenharmony_ci * http://www.st.com 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Cloned from linux/arch/arm/mach-vexpress/platsmp.c 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (C) 2002 ARM Ltd. 1162306a36Sopenharmony_ci * All Rights Reserved 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/smp.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/of_address.h> 2062306a36Sopenharmony_ci#include <linux/memblock.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <asm/cacheflush.h> 2362306a36Sopenharmony_ci#include <asm/smp_plat.h> 2462306a36Sopenharmony_ci#include <asm/smp_scu.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "smp.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic u32 __iomem *cpu_strt_ptr; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int sti_boot_secondary(unsigned int cpu, struct task_struct *idle) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci unsigned long entry_pa = __pa_symbol(secondary_startup); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci /* 3562306a36Sopenharmony_ci * Secondary CPU is initialised and started by a U-BOOTROM firmware. 3662306a36Sopenharmony_ci * Secondary CPU is spinning and waiting for a write at cpu_strt_ptr. 3762306a36Sopenharmony_ci * Writing secondary_startup address at cpu_strt_ptr makes it to 3862306a36Sopenharmony_ci * jump directly to secondary_startup(). 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci __raw_writel(entry_pa, cpu_strt_ptr); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* wmb so that data is actually written before cache flush is done */ 4362306a36Sopenharmony_ci smp_wmb(); 4462306a36Sopenharmony_ci sync_cache_w(cpu_strt_ptr); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return 0; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void __init sti_smp_prepare_cpus(unsigned int max_cpus) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct device_node *np; 5262306a36Sopenharmony_ci void __iomem *scu_base; 5362306a36Sopenharmony_ci u32 release_phys; 5462306a36Sopenharmony_ci int cpu; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (np) { 5962306a36Sopenharmony_ci scu_base = of_iomap(np, 0); 6062306a36Sopenharmony_ci scu_enable(scu_base); 6162306a36Sopenharmony_ci of_node_put(np); 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (max_cpus <= 1) 6562306a36Sopenharmony_ci return; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci np = of_get_cpu_node(cpu, NULL); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (!np) 7262306a36Sopenharmony_ci continue; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (of_property_read_u32(np, "cpu-release-addr", 7562306a36Sopenharmony_ci &release_phys)) { 7662306a36Sopenharmony_ci pr_err("CPU %d: missing or invalid cpu-release-addr " 7762306a36Sopenharmony_ci "property\n", cpu); 7862306a36Sopenharmony_ci continue; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* 8262306a36Sopenharmony_ci * cpu-release-addr is usually configured in SBC DMEM but can 8362306a36Sopenharmony_ci * also be in RAM. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!memblock_is_memory(release_phys)) 8762306a36Sopenharmony_ci cpu_strt_ptr = 8862306a36Sopenharmony_ci ioremap(release_phys, sizeof(release_phys)); 8962306a36Sopenharmony_ci else 9062306a36Sopenharmony_ci cpu_strt_ptr = 9162306a36Sopenharmony_ci (u32 __iomem *)phys_to_virt(release_phys); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci set_cpu_possible(cpu, true); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciconst struct smp_operations sti_smp_ops __initconst = { 9862306a36Sopenharmony_ci .smp_prepare_cpus = sti_smp_prepare_cpus, 9962306a36Sopenharmony_ci .smp_boot_secondary = sti_boot_secondary, 10062306a36Sopenharmony_ci}; 101