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 #include "db8500-regs.h" 24 25 /* Magic triggers in backup RAM */ 26 #define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 27 #define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 28 29 static void __iomem *backupram; 30 31 static void __init ux500_smp_prepare_cpus(unsigned int max_cpus) 32 { 33 struct device_node *np; 34 static void __iomem *scu_base; 35 unsigned int ncores; 36 int i; 37 38 np = of_find_compatible_node(NULL, NULL, "ste,dbx500-backupram"); 39 if (!np) { 40 pr_err("No backupram base address\n"); 41 return; 42 } 43 backupram = of_iomap(np, 0); 44 of_node_put(np); 45 if (!backupram) { 46 pr_err("No backupram remap\n"); 47 return; 48 } 49 50 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 51 if (!np) { 52 pr_err("No SCU base address\n"); 53 return; 54 } 55 scu_base = of_iomap(np, 0); 56 of_node_put(np); 57 if (!scu_base) { 58 pr_err("No SCU remap\n"); 59 return; 60 } 61 62 scu_enable(scu_base); 63 ncores = scu_get_core_count(scu_base); 64 for (i = 0; i < ncores; i++) 65 set_cpu_possible(i, true); 66 iounmap(scu_base); 67 } 68 69 static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle) 70 { 71 /* 72 * write the address of secondary startup into the backup ram register 73 * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the 74 * backup ram register at offset 0x1FF0, which is what boot rom code 75 * is waiting for. This will wake up the secondary core from WFE. 76 */ 77 writel(__pa_symbol(secondary_startup), 78 backupram + UX500_CPU1_JUMPADDR_OFFSET); 79 writel(0xA1FEED01, 80 backupram + UX500_CPU1_WAKEMAGIC_OFFSET); 81 82 /* make sure write buffer is drained */ 83 mb(); 84 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 85 return 0; 86 } 87 88 #ifdef CONFIG_HOTPLUG_CPU 89 static void ux500_cpu_die(unsigned int cpu) 90 { 91 wfi(); 92 } 93 #endif 94 95 static const struct smp_operations ux500_smp_ops __initconst = { 96 .smp_prepare_cpus = ux500_smp_prepare_cpus, 97 .smp_boot_secondary = ux500_boot_secondary, 98 #ifdef CONFIG_HOTPLUG_CPU 99 .cpu_die = ux500_cpu_die, 100 #endif 101 }; 102 CPU_METHOD_OF_DECLARE(ux500_smp, "ste,dbx500-smp", &ux500_smp_ops); 103