18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/mach-spear13xx/platsmp.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * based upon linux/arch/arm/mach-realview/platsmp.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics Ltd. 88c2ecf20Sopenharmony_ci * Shiraz Hashim <shiraz.linux.kernel@gmail.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/smp.h> 158c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 168c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 178c2ecf20Sopenharmony_ci#include <mach/spear.h> 188c2ecf20Sopenharmony_ci#include "generic.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* XXX spear_pen_release is cargo culted code - DO NOT COPY XXX */ 218c2ecf20Sopenharmony_civolatile int spear_pen_release = -1; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * XXX CARGO CULTED CODE - DO NOT COPY XXX 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Write spear_pen_release in a way that is guaranteed to be visible to 278c2ecf20Sopenharmony_ci * all observers, irrespective of whether they're taking part in coherency 288c2ecf20Sopenharmony_ci * or not. This is necessary for the hotplug code to work reliably. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistatic void spear_write_pen_release(int val) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci spear_pen_release = val; 338c2ecf20Sopenharmony_ci smp_wmb(); 348c2ecf20Sopenharmony_ci sync_cache_w(&spear_pen_release); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(boot_lock); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void __iomem *scu_base = IOMEM(VA_SCU_BASE); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void spear13xx_secondary_init(unsigned int cpu) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci /* 448c2ecf20Sopenharmony_ci * let the primary processor know we're out of the 458c2ecf20Sopenharmony_ci * pen, then head off into the C entry point 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci spear_write_pen_release(-1); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* 508c2ecf20Sopenharmony_ci * Synchronise with the boot thread. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci spin_lock(&boot_lock); 538c2ecf20Sopenharmony_ci spin_unlock(&boot_lock); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci unsigned long timeout; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * set synchronisation state between this boot processor 628c2ecf20Sopenharmony_ci * and the secondary one 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci spin_lock(&boot_lock); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * The secondary processor is waiting to be released from 688c2ecf20Sopenharmony_ci * the holding pen - release it, then wait for it to flag 698c2ecf20Sopenharmony_ci * that it has been released by resetting spear_pen_release. 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * Note that "spear_pen_release" is the hardware CPU ID, whereas 728c2ecf20Sopenharmony_ci * "cpu" is Linux's internal ID. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci spear_write_pen_release(cpu); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci timeout = jiffies + (1 * HZ); 778c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 788c2ecf20Sopenharmony_ci smp_rmb(); 798c2ecf20Sopenharmony_ci if (spear_pen_release == -1) 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci udelay(10); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* 868c2ecf20Sopenharmony_ci * now the secondary core is starting up let it run its 878c2ecf20Sopenharmony_ci * calibrations, then wait for it to finish 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci spin_unlock(&boot_lock); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return spear_pen_release != -1 ? -ENOSYS : 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * Initialise the CPU possible map early - this describes the CPUs 968c2ecf20Sopenharmony_ci * which may be present or become present in the system. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic void __init spear13xx_smp_init_cpus(void) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci unsigned int i, ncores = scu_get_core_count(scu_base); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (ncores > nr_cpu_ids) { 1038c2ecf20Sopenharmony_ci pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", 1048c2ecf20Sopenharmony_ci ncores, nr_cpu_ids); 1058c2ecf20Sopenharmony_ci ncores = nr_cpu_ids; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci for (i = 0; i < ncores; i++) 1098c2ecf20Sopenharmony_ci set_cpu_possible(i, true); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci scu_enable(scu_base); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * Write the address of secondary startup into the system-wide location 1198c2ecf20Sopenharmony_ci * (presently it is in SRAM). The BootMonitor waits until it receives a 1208c2ecf20Sopenharmony_ci * soft interrupt, and then the secondary CPU branches to this address. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci __raw_writel(__pa_symbol(spear13xx_secondary_startup), SYS_LOCATION); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciconst struct smp_operations spear13xx_smp_ops __initconst = { 1268c2ecf20Sopenharmony_ci .smp_init_cpus = spear13xx_smp_init_cpus, 1278c2ecf20Sopenharmony_ci .smp_prepare_cpus = spear13xx_smp_prepare_cpus, 1288c2ecf20Sopenharmony_ci .smp_secondary_init = spear13xx_secondary_init, 1298c2ecf20Sopenharmony_ci .smp_boot_secondary = spear13xx_boot_secondary, 1308c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 1318c2ecf20Sopenharmony_ci .cpu_die = spear13xx_cpu_die, 1328c2ecf20Sopenharmony_ci#endif 1338c2ecf20Sopenharmony_ci}; 134