18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2002 ARM Ltd. 48c2ecf20Sopenharmony_ci * Copyright (C) 2008 STMicroelctronics. 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 ST-Ericsson. 68c2ecf20Sopenharmony_ci * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is based on arm realview platform 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/smp.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/of_address.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 208c2ecf20Sopenharmony_ci#include <asm/smp_plat.h> 218c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "db8500-regs.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Magic triggers in backup RAM */ 268c2ecf20Sopenharmony_ci#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 278c2ecf20Sopenharmony_ci#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void __iomem *backupram; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void __init ux500_smp_prepare_cpus(unsigned int max_cpus) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct device_node *np; 348c2ecf20Sopenharmony_ci static void __iomem *scu_base; 358c2ecf20Sopenharmony_ci unsigned int ncores; 368c2ecf20Sopenharmony_ci int i; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "ste,dbx500-backupram"); 398c2ecf20Sopenharmony_ci if (!np) { 408c2ecf20Sopenharmony_ci pr_err("No backupram base address\n"); 418c2ecf20Sopenharmony_ci return; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci backupram = of_iomap(np, 0); 448c2ecf20Sopenharmony_ci of_node_put(np); 458c2ecf20Sopenharmony_ci if (!backupram) { 468c2ecf20Sopenharmony_ci pr_err("No backupram remap\n"); 478c2ecf20Sopenharmony_ci return; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 518c2ecf20Sopenharmony_ci if (!np) { 528c2ecf20Sopenharmony_ci pr_err("No SCU base address\n"); 538c2ecf20Sopenharmony_ci return; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci scu_base = of_iomap(np, 0); 568c2ecf20Sopenharmony_ci of_node_put(np); 578c2ecf20Sopenharmony_ci if (!scu_base) { 588c2ecf20Sopenharmony_ci pr_err("No SCU remap\n"); 598c2ecf20Sopenharmony_ci return; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci scu_enable(scu_base); 638c2ecf20Sopenharmony_ci ncores = scu_get_core_count(scu_base); 648c2ecf20Sopenharmony_ci for (i = 0; i < ncores; i++) 658c2ecf20Sopenharmony_ci set_cpu_possible(i, true); 668c2ecf20Sopenharmony_ci iounmap(scu_base); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * write the address of secondary startup into the backup ram register 738c2ecf20Sopenharmony_ci * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the 748c2ecf20Sopenharmony_ci * backup ram register at offset 0x1FF0, which is what boot rom code 758c2ecf20Sopenharmony_ci * is waiting for. This will wake up the secondary core from WFE. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci writel(__pa_symbol(secondary_startup), 788c2ecf20Sopenharmony_ci backupram + UX500_CPU1_JUMPADDR_OFFSET); 798c2ecf20Sopenharmony_ci writel(0xA1FEED01, 808c2ecf20Sopenharmony_ci backupram + UX500_CPU1_WAKEMAGIC_OFFSET); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* make sure write buffer is drained */ 838c2ecf20Sopenharmony_ci mb(); 848c2ecf20Sopenharmony_ci arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 898c2ecf20Sopenharmony_civoid ux500_cpu_die(unsigned int cpu) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci wfi(); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci#endif 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const struct smp_operations ux500_smp_ops __initconst = { 968c2ecf20Sopenharmony_ci .smp_prepare_cpus = ux500_smp_prepare_cpus, 978c2ecf20Sopenharmony_ci .smp_boot_secondary = ux500_boot_secondary, 988c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 998c2ecf20Sopenharmony_ci .cpu_die = ux500_cpu_die, 1008c2ecf20Sopenharmony_ci#endif 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(ux500_smp, "ste,dbx500-smp", &ux500_smp_ops); 103