1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2002 ARM Ltd. 4 * Copyright (C) 2008 STMicroelctronics. 5 * Copyright (C) 2009 ST-Ericsson. 6 * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 7 * 8 * This file is based on arm realview platform 9 */ 10#include <linux/init.h> 11#include <linux/errno.h> 12#include <linux/delay.h> 13#include <linux/device.h> 14#include <linux/smp.h> 15#include <linux/io.h> 16#include <linux/of.h> 17#include <linux/of_address.h> 18 19#include <asm/cacheflush.h> 20#include <asm/smp_plat.h> 21#include <asm/smp_scu.h> 22 23/* Magic triggers in backup RAM */ 24#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 25#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 26 27static void __iomem *backupram; 28 29static void __init ux500_smp_prepare_cpus(unsigned int max_cpus) 30{ 31 struct device_node *np; 32 static void __iomem *scu_base; 33 unsigned int ncores; 34 int i; 35 36 np = of_find_compatible_node(NULL, NULL, "ste,dbx500-backupram"); 37 if (!np) { 38 pr_err("No backupram base address\n"); 39 return; 40 } 41 backupram = of_iomap(np, 0); 42 of_node_put(np); 43 if (!backupram) { 44 pr_err("No backupram remap\n"); 45 return; 46 } 47 48 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 49 if (!np) { 50 pr_err("No SCU base address\n"); 51 return; 52 } 53 scu_base = of_iomap(np, 0); 54 of_node_put(np); 55 if (!scu_base) { 56 pr_err("No SCU remap\n"); 57 return; 58 } 59 60 scu_enable(scu_base); 61 ncores = scu_get_core_count(scu_base); 62 for (i = 0; i < ncores; i++) 63 set_cpu_possible(i, true); 64 iounmap(scu_base); 65} 66 67static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle) 68{ 69 /* 70 * write the address of secondary startup into the backup ram register 71 * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the 72 * backup ram register at offset 0x1FF0, which is what boot rom code 73 * is waiting for. This will wake up the secondary core from WFE. 74 */ 75 writel(__pa_symbol(secondary_startup), 76 backupram + UX500_CPU1_JUMPADDR_OFFSET); 77 writel(0xA1FEED01, 78 backupram + UX500_CPU1_WAKEMAGIC_OFFSET); 79 80 /* make sure write buffer is drained */ 81 mb(); 82 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 83 return 0; 84} 85 86#ifdef CONFIG_HOTPLUG_CPU 87static void ux500_cpu_die(unsigned int cpu) 88{ 89 wfi(); 90} 91#endif 92 93static const struct smp_operations ux500_smp_ops __initconst = { 94 .smp_prepare_cpus = ux500_smp_prepare_cpus, 95 .smp_boot_secondary = ux500_boot_secondary, 96#ifdef CONFIG_HOTPLUG_CPU 97 .cpu_die = ux500_cpu_die, 98#endif 99}; 100CPU_METHOD_OF_DECLARE(ux500_smp, "ste,dbx500-smp", &ux500_smp_ops); 101