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