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 20 #include <asm/cacheflush.h> 21 #include <asm/hardware/gic.h> 22 #include <asm/smp_plat.h> 23 #include <asm/smp_scu.h> 24 #include <mach/hardware.h> 25 #include <mach/setup.h> 26 27 /* This is called from headsmp.S to wakeup the secondary core */ 28 extern void u8500_secondary_startup(void); 29 30 /* 31 * control for which core is the next to come out of the secondary 32 * boot "holding pen" 33 */ 34 volatile int pen_release = -1; 35 36 /* 37 * Write pen_release in a way that is guaranteed to be visible to all 38 * observers, irrespective of whether they're taking part in coherency 39 * or not. This is necessary for the hotplug code to work reliably. 40 */ 41 static void write_pen_release(int val) 42 { 43 pen_release = val; 44 smp_wmb(); 45 __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); 46 outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); 47 } 48 49 static void __iomem *scu_base_addr(void) 50 { 51 if (cpu_is_u8500_family()) 52 return __io_address(U8500_SCU_BASE); 53 else 54 ux500_unknown_soc(); 55 56 return NULL; 57 } 58 59 static DEFINE_SPINLOCK(boot_lock); 60 61 void __cpuinit platform_secondary_init(unsigned int cpu) 62 { 63 /* 64 * if any interrupts are already enabled for the primary 65 * core (e.g. timer irq), then they will not have been enabled 66 * for us: do so 67 */ 68 gic_secondary_init(0); 69 70 /* 71 * let the primary processor know we're out of the 72 * pen, then head off into the C entry point 73 */ 74 write_pen_release(-1); 75 76 /* 77 * Synchronise with the boot thread. 78 */ 79 spin_lock(&boot_lock); 80 spin_unlock(&boot_lock); 81 } 82 83 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 84 { 85 unsigned long timeout; 86 87 /* 88 * set synchronisation state between this boot processor 89 * and the secondary one 90 */ 91 spin_lock(&boot_lock); 92 93 /* 94 * The secondary processor is waiting to be released from 95 * the holding pen - release it, then wait for it to flag 96 * that it has been released by resetting pen_release. 97 */ 98 write_pen_release(cpu_logical_map(cpu)); 99 100 smp_send_reschedule(cpu); 101 102 timeout = jiffies + (1 * HZ); 103 while (time_before(jiffies, timeout)) { 104 if (pen_release == -1) 105 break; 106 } 107 108 /* 109 * now the secondary core is starting up let it run its 110 * calibrations, then wait for it to finish 111 */ 112 spin_unlock(&boot_lock); 113 114 return pen_release != -1 ? -ENOSYS : 0; 115 } 116 117 static void __init wakeup_secondary(void) 118 { 119 void __iomem *backupram; 120 121 if (cpu_is_u8500_family()) 122 backupram = __io_address(U8500_BACKUPRAM0_BASE); 123 else 124 ux500_unknown_soc(); 125 126 /* 127 * write the address of secondary startup into the backup ram register 128 * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the 129 * backup ram register at offset 0x1FF0, which is what boot rom code 130 * is waiting for. This would wake up the secondary core from WFE 131 */ 132 #define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 133 __raw_writel(virt_to_phys(u8500_secondary_startup), 134 backupram + UX500_CPU1_JUMPADDR_OFFSET); 135 136 #define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 137 __raw_writel(0xA1FEED01, 138 backupram + UX500_CPU1_WAKEMAGIC_OFFSET); 139 140 /* make sure write buffer is drained */ 141 mb(); 142 } 143 144 /* 145 * Initialise the CPU possible map early - this describes the CPUs 146 * which may be present or become present in the system. 147 */ 148 void __init smp_init_cpus(void) 149 { 150 void __iomem *scu_base = scu_base_addr(); 151 unsigned int i, ncores; 152 153 ncores = scu_base ? scu_get_core_count(scu_base) : 1; 154 155 /* sanity check */ 156 if (ncores > nr_cpu_ids) { 157 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", 158 ncores, nr_cpu_ids); 159 ncores = nr_cpu_ids; 160 } 161 162 for (i = 0; i < ncores; i++) 163 set_cpu_possible(i, true); 164 165 set_smp_cross_call(gic_raise_softirq); 166 } 167 168 void __init platform_smp_prepare_cpus(unsigned int max_cpus) 169 { 170 171 scu_enable(scu_base_addr()); 172 wakeup_secondary(); 173 } 174