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