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/localtimer.h> 22 #include <asm/smp_scu.h> 23 #include <mach/hardware.h> 24 25 /* 26 * control for which core is the next to come out of the secondary 27 * boot "holding pen" 28 */ 29 volatile int __cpuinitdata pen_release = -1; 30 31 static unsigned int __init get_core_count(void) 32 { 33 return scu_get_core_count(__io_address(U8500_SCU_BASE)); 34 } 35 36 static DEFINE_SPINLOCK(boot_lock); 37 38 void __cpuinit platform_secondary_init(unsigned int cpu) 39 { 40 trace_hardirqs_off(); 41 42 /* 43 * if any interrupts are already enabled for the primary 44 * core (e.g. timer irq), then they will not have been enabled 45 * for us: do so 46 */ 47 gic_cpu_init(0, __io_address(U8500_GIC_CPU_BASE)); 48 49 /* 50 * let the primary processor know we're out of the 51 * pen, then head off into the C entry point 52 */ 53 pen_release = -1; 54 55 /* 56 * Synchronise with the boot thread. 57 */ 58 spin_lock(&boot_lock); 59 spin_unlock(&boot_lock); 60 } 61 62 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 63 { 64 unsigned long timeout; 65 66 /* 67 * set synchronisation state between this boot processor 68 * and the secondary one 69 */ 70 spin_lock(&boot_lock); 71 72 /* 73 * The secondary processor is waiting to be released from 74 * the holding pen - release it, then wait for it to flag 75 * that it has been released by resetting pen_release. 76 */ 77 pen_release = cpu; 78 flush_cache_all(); 79 80 timeout = jiffies + (1 * HZ); 81 while (time_before(jiffies, timeout)) { 82 if (pen_release == -1) 83 break; 84 } 85 86 /* 87 * now the secondary core is starting up let it run its 88 * calibrations, then wait for it to finish 89 */ 90 spin_unlock(&boot_lock); 91 92 return pen_release != -1 ? -ENOSYS : 0; 93 } 94 95 static void __init wakeup_secondary(void) 96 { 97 /* nobody is to be released from the pen yet */ 98 pen_release = -1; 99 100 /* 101 * write the address of secondary startup into the backup ram register 102 * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the 103 * backup ram register at offset 0x1FF0, which is what boot rom code 104 * is waiting for. This would wake up the secondary core from WFE 105 */ 106 #define U8500_CPU1_JUMPADDR_OFFSET 0x1FF4 107 __raw_writel(virt_to_phys(u8500_secondary_startup), 108 (void __iomem *)IO_ADDRESS(U8500_BACKUPRAM0_BASE) + 109 U8500_CPU1_JUMPADDR_OFFSET); 110 111 #define U8500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 112 __raw_writel(0xA1FEED01, 113 (void __iomem *)IO_ADDRESS(U8500_BACKUPRAM0_BASE) + 114 U8500_CPU1_WAKEMAGIC_OFFSET); 115 116 /* make sure write buffer is drained */ 117 mb(); 118 } 119 120 /* 121 * Initialise the CPU possible map early - this describes the CPUs 122 * which may be present or become present in the system. 123 */ 124 void __init smp_init_cpus(void) 125 { 126 unsigned int i, ncores = get_core_count(); 127 128 for (i = 0; i < ncores; i++) 129 set_cpu_possible(i, true); 130 } 131 132 void __init smp_prepare_cpus(unsigned int max_cpus) 133 { 134 unsigned int ncores = get_core_count(); 135 unsigned int cpu = smp_processor_id(); 136 int i; 137 138 /* sanity check */ 139 if (ncores == 0) { 140 printk(KERN_ERR 141 "U8500: strange CM count of 0? Default to 1\n"); 142 ncores = 1; 143 } 144 145 if (ncores > num_possible_cpus()) { 146 printk(KERN_WARNING 147 "U8500: no. of cores (%d) greater than configured " 148 "maximum of %d - clipping\n", 149 ncores, num_possible_cpus()); 150 ncores = num_possible_cpus(); 151 } 152 153 smp_store_cpu_info(cpu); 154 155 /* 156 * are we trying to boot more cores than exist? 157 */ 158 if (max_cpus > ncores) 159 max_cpus = ncores; 160 161 /* 162 * Initialise the present map, which describes the set of CPUs 163 * actually populated at the present time. 164 */ 165 for (i = 0; i < max_cpus; i++) 166 set_cpu_present(i, true); 167 168 if (max_cpus > 1) { 169 /* 170 * Enable the local timer or broadcast device for the 171 * boot CPU, but only if we have more than one CPU. 172 */ 173 percpu_timer_setup(); 174 scu_enable(__io_address(U8500_SCU_BASE)); 175 wakeup_secondary(); 176 } 177 } 178