18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/mach-sti/platsmp.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 STMicroelectronics (R&D) Limited. 68c2ecf20Sopenharmony_ci * http://www.st.com 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Cloned from linux/arch/arm/mach-vexpress/platsmp.c 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright (C) 2002 ARM Ltd. 118c2ecf20Sopenharmony_ci * All Rights Reserved 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/smp.h> 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/of.h> 198c2ecf20Sopenharmony_ci#include <linux/of_address.h> 208c2ecf20Sopenharmony_ci#include <linux/memblock.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 238c2ecf20Sopenharmony_ci#include <asm/smp_plat.h> 248c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "smp.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic u32 __iomem *cpu_strt_ptr; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int sti_boot_secondary(unsigned int cpu, struct task_struct *idle) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci unsigned long entry_pa = __pa_symbol(secondary_startup); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* 358c2ecf20Sopenharmony_ci * Secondary CPU is initialised and started by a U-BOOTROM firmware. 368c2ecf20Sopenharmony_ci * Secondary CPU is spinning and waiting for a write at cpu_strt_ptr. 378c2ecf20Sopenharmony_ci * Writing secondary_startup address at cpu_strt_ptr makes it to 388c2ecf20Sopenharmony_ci * jump directly to secondary_startup(). 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci __raw_writel(entry_pa, cpu_strt_ptr); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* wmb so that data is actually written before cache flush is done */ 438c2ecf20Sopenharmony_ci smp_wmb(); 448c2ecf20Sopenharmony_ci sync_cache_w(cpu_strt_ptr); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void __init sti_smp_prepare_cpus(unsigned int max_cpus) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct device_node *np; 528c2ecf20Sopenharmony_ci void __iomem *scu_base; 538c2ecf20Sopenharmony_ci u32 release_phys; 548c2ecf20Sopenharmony_ci int cpu; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (np) { 598c2ecf20Sopenharmony_ci scu_base = of_iomap(np, 0); 608c2ecf20Sopenharmony_ci scu_enable(scu_base); 618c2ecf20Sopenharmony_ci of_node_put(np); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (max_cpus <= 1) 658c2ecf20Sopenharmony_ci return; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci np = of_get_cpu_node(cpu, NULL); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (!np) 728c2ecf20Sopenharmony_ci continue; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cpu-release-addr", 758c2ecf20Sopenharmony_ci &release_phys)) { 768c2ecf20Sopenharmony_ci pr_err("CPU %d: missing or invalid cpu-release-addr " 778c2ecf20Sopenharmony_ci "property\n", cpu); 788c2ecf20Sopenharmony_ci continue; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* 828c2ecf20Sopenharmony_ci * cpu-release-addr is usually configured in SBC DMEM but can 838c2ecf20Sopenharmony_ci * also be in RAM. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!memblock_is_memory(release_phys)) 878c2ecf20Sopenharmony_ci cpu_strt_ptr = 888c2ecf20Sopenharmony_ci ioremap(release_phys, sizeof(release_phys)); 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci cpu_strt_ptr = 918c2ecf20Sopenharmony_ci (u32 __iomem *)phys_to_virt(release_phys); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci set_cpu_possible(cpu, true); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciconst struct smp_operations sti_smp_ops __initconst = { 988c2ecf20Sopenharmony_ci .smp_prepare_cpus = sti_smp_prepare_cpus, 998c2ecf20Sopenharmony_ci .smp_boot_secondary = sti_boot_secondary, 1008c2ecf20Sopenharmony_ci}; 101