Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / arch / arm / mach-realview / platsmp.c
1 /*
2  *  linux/arch/arm/mach-realview/platsmp.c
3  *
4  *  Copyright (C) 2002 ARM Ltd.
5  *  All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/init.h>
12 #include <linux/errno.h>
13 #include <linux/delay.h>
14 #include <linux/device.h>
15 #include <linux/smp.h>
16 #include <linux/io.h>
17
18 #include <asm/cacheflush.h>
19 #include <mach/hardware.h>
20 #include <asm/mach-types.h>
21
22 #include <mach/board-eb.h>
23 #include <mach/board-pb11mp.h>
24 #include <mach/scu.h>
25
26 extern void realview_secondary_startup(void);
27
28 /*
29  * control for which core is the next to come out of the secondary
30  * boot "holding pen"
31  */
32 volatile int __cpuinitdata pen_release = -1;
33
34 static unsigned int __init get_core_count(void)
35 {
36         unsigned int ncores;
37         void __iomem *scu_base = 0;
38
39         if (machine_is_realview_eb() && core_tile_eb11mp())
40                 scu_base = __io_address(REALVIEW_EB11MP_SCU_BASE);
41         else if (machine_is_realview_pb11mp())
42                 scu_base = __io_address(REALVIEW_TC11MP_SCU_BASE);
43
44         if (scu_base) {
45                 ncores = __raw_readl(scu_base + SCU_CONFIG);
46                 ncores = (ncores & 0x03) + 1;
47         } else
48                 ncores = 1;
49
50         return ncores;
51 }
52
53 /*
54  * Setup the SCU
55  */
56 static void scu_enable(void)
57 {
58         u32 scu_ctrl;
59         void __iomem *scu_base;
60
61         if (machine_is_realview_eb() && core_tile_eb11mp())
62                 scu_base = __io_address(REALVIEW_EB11MP_SCU_BASE);
63         else if (machine_is_realview_pb11mp())
64                 scu_base = __io_address(REALVIEW_TC11MP_SCU_BASE);
65         else
66                 BUG();
67
68         scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
69         scu_ctrl |= 1;
70         __raw_writel(scu_ctrl, scu_base + SCU_CTRL);
71 }
72
73 static DEFINE_SPINLOCK(boot_lock);
74
75 void __cpuinit platform_secondary_init(unsigned int cpu)
76 {
77         trace_hardirqs_off();
78
79         /*
80          * the primary core may have used a "cross call" soft interrupt
81          * to get this processor out of WFI in the BootMonitor - make
82          * sure that we are no longer being sent this soft interrupt
83          */
84         smp_cross_call_done(cpumask_of_cpu(cpu));
85
86         /*
87          * if any interrupts are already enabled for the primary
88          * core (e.g. timer irq), then they will not have been enabled
89          * for us: do so
90          */
91         if (machine_is_realview_eb() && core_tile_eb11mp())
92                 gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
93         else if (machine_is_realview_pb11mp())
94                 gic_cpu_init(0, __io_address(REALVIEW_TC11MP_GIC_CPU_BASE));
95
96         /*
97          * let the primary processor know we're out of the
98          * pen, then head off into the C entry point
99          */
100         pen_release = -1;
101         smp_wmb();
102
103         /*
104          * Synchronise with the boot thread.
105          */
106         spin_lock(&boot_lock);
107         spin_unlock(&boot_lock);
108 }
109
110 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
111 {
112         unsigned long timeout;
113
114         /*
115          * set synchronisation state between this boot processor
116          * and the secondary one
117          */
118         spin_lock(&boot_lock);
119
120         /*
121          * The secondary processor is waiting to be released from
122          * the holding pen - release it, then wait for it to flag
123          * that it has been released by resetting pen_release.
124          *
125          * Note that "pen_release" is the hardware CPU ID, whereas
126          * "cpu" is Linux's internal ID.
127          */
128         pen_release = cpu;
129         flush_cache_all();
130
131         /*
132          * XXX
133          *
134          * This is a later addition to the booting protocol: the
135          * bootMonitor now puts secondary cores into WFI, so
136          * poke_milo() no longer gets the cores moving; we need
137          * to send a soft interrupt to wake the secondary core.
138          * Use smp_cross_call() for this, since there's little
139          * point duplicating the code here
140          */
141         smp_cross_call(cpumask_of_cpu(cpu));
142
143         timeout = jiffies + (1 * HZ);
144         while (time_before(jiffies, timeout)) {
145                 smp_rmb();
146                 if (pen_release == -1)
147                         break;
148
149                 udelay(10);
150         }
151
152         /*
153          * now the secondary core is starting up let it run its
154          * calibrations, then wait for it to finish
155          */
156         spin_unlock(&boot_lock);
157
158         return pen_release != -1 ? -ENOSYS : 0;
159 }
160
161 static void __init poke_milo(void)
162 {
163         extern void secondary_startup(void);
164
165         /* nobody is to be released from the pen yet */
166         pen_release = -1;
167
168         /*
169          * write the address of secondary startup into the system-wide
170          * flags register, then clear the bottom two bits, which is what
171          * BootMonitor is waiting for
172          */
173 #if 1
174 #define REALVIEW_SYS_FLAGSS_OFFSET 0x30
175         __raw_writel(virt_to_phys(realview_secondary_startup),
176                      __io_address(REALVIEW_SYS_BASE) +
177                      REALVIEW_SYS_FLAGSS_OFFSET);
178 #define REALVIEW_SYS_FLAGSC_OFFSET 0x34
179         __raw_writel(3,
180                      __io_address(REALVIEW_SYS_BASE) +
181                      REALVIEW_SYS_FLAGSC_OFFSET);
182 #endif
183
184         mb();
185 }
186
187 /*
188  * Initialise the CPU possible map early - this describes the CPUs
189  * which may be present or become present in the system.
190  */
191 void __init smp_init_cpus(void)
192 {
193         unsigned int i, ncores = get_core_count();
194
195         for (i = 0; i < ncores; i++)
196                 cpu_set(i, cpu_possible_map);
197 }
198
199 void __init smp_prepare_cpus(unsigned int max_cpus)
200 {
201         unsigned int ncores = get_core_count();
202         unsigned int cpu = smp_processor_id();
203         int i;
204
205         /* sanity check */
206         if (ncores == 0) {
207                 printk(KERN_ERR
208                        "Realview: strange CM count of 0? Default to 1\n");
209
210                 ncores = 1;
211         }
212
213         if (ncores > NR_CPUS) {
214                 printk(KERN_WARNING
215                        "Realview: no. of cores (%d) greater than configured "
216                        "maximum of %d - clipping\n",
217                        ncores, NR_CPUS);
218                 ncores = NR_CPUS;
219         }
220
221         smp_store_cpu_info(cpu);
222
223         /*
224          * are we trying to boot more cores than exist?
225          */
226         if (max_cpus > ncores)
227                 max_cpus = ncores;
228
229 #ifdef CONFIG_LOCAL_TIMERS
230         /*
231          * Enable the local timer for primary CPU. If the device is
232          * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
233          * realview_timer_init
234          */
235         if ((machine_is_realview_eb() && core_tile_eb11mp()) ||
236             machine_is_realview_pb11mp())
237                 local_timer_setup(cpu);
238 #endif
239
240         /*
241          * Initialise the present map, which describes the set of CPUs
242          * actually populated at the present time.
243          */
244         for (i = 0; i < max_cpus; i++)
245                 cpu_set(i, cpu_present_map);
246
247         /*
248          * Initialise the SCU if there are more than one CPU and let
249          * them know where to start. Note that, on modern versions of
250          * MILO, the "poke" doesn't actually do anything until each
251          * individual core is sent a soft interrupt to get it out of
252          * WFI
253          */
254         if (max_cpus > 1) {
255                 scu_enable();
256                 poke_milo();
257         }
258 }