oxnas: remove obsolete __cpuinit
[openwrt.git] / target / linux / oxnas / files / arch / arm / mach-oxnas / platsmp.c
1 /*
2  *  arch/arm/mach-ox820/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/device.h>
13 #include <linux/jiffies.h>
14 #include <linux/smp.h>
15 #include <linux/io.h>
16 #include <linux/dma-mapping.h>
17 #include <linux/cache.h>
18 #include <asm/cacheflush.h>
19 #include <asm/smp_scu.h>
20 #include <asm/tlbflush.h>
21 #include <asm/cputype.h>
22 #include <linux/delay.h>
23 #include <asm/fiq.h>
24
25 #include <linux/irqchip/arm-gic.h>
26 #include <mach/iomap.h>
27 #include <mach/smp.h>
28 #include <mach/hardware.h>
29 #include <mach/irqs.h>
30
31 #ifdef CONFIG_DMA_CACHE_FIQ_BROADCAST
32
33 #define FIQ_GENERATE            0x00000002
34 #define OXNAS_MAP_AREA          0x01000000
35 #define OXNAS_UNMAP_AREA        0x02000000
36 #define OXNAS_FLUSH_RANGE       0x03000000
37
38 struct fiq_req {
39         union {
40                 struct {
41                         const void *addr;
42                         size_t size;
43                 } map;
44                 struct {
45                         const void *addr;
46                         size_t size;
47                 } unmap;
48                 struct {
49                         const void *start;
50                         const void *end;
51                 } flush;
52         };
53         volatile uint flags;
54         void __iomem *reg;
55 } ____cacheline_aligned;
56
57 static struct fiq_handler fh = {
58         .name = "oxnas-fiq"
59 };
60
61 DEFINE_PER_CPU(struct fiq_req, fiq_data);
62
63 static inline void ox820_set_fiq_regs(unsigned int cpu)
64 {
65         struct pt_regs FIQ_regs;
66         struct fiq_req *fiq_req = &per_cpu(fiq_data, !cpu);
67
68         FIQ_regs.ARM_r8 = 0;
69         FIQ_regs.ARM_ip = (unsigned int)fiq_req;
70         FIQ_regs.ARM_sp = (int)(cpu ? RPSC_IRQ_SOFT : RPSA_IRQ_SOFT);
71         fiq_req->reg = cpu ? RPSC_IRQ_SOFT : RPSA_IRQ_SOFT;
72
73         set_fiq_regs(&FIQ_regs);
74 }
75
76 static void __init ox820_init_fiq(void)
77 {
78         void *fiqhandler_start;
79         unsigned int fiqhandler_length;
80         int ret;
81
82         fiqhandler_start = &ox820_fiq_start;
83         fiqhandler_length = &ox820_fiq_end - &ox820_fiq_start;
84
85         ret = claim_fiq(&fh);
86
87         if (ret)
88                 return;
89
90         set_fiq_handler(fiqhandler_start, fiqhandler_length);
91
92         writel(IRQ_SOFT, RPSA_FIQ_IRQ_TO_FIQ);
93         writel(1, RPSA_FIQ_ENABLE);
94         writel(IRQ_SOFT, RPSC_FIQ_IRQ_TO_FIQ);
95         writel(1, RPSC_FIQ_ENABLE);
96 }
97
98 void fiq_dma_map_area(const void *addr, size_t size, int dir)
99 {
100         unsigned long flags;
101         struct fiq_req *req;
102
103         raw_local_irq_save(flags);
104         /* currently, not possible to take cpu0 down, so only check cpu1 */
105         if (!cpu_online(1)) {
106                 raw_local_irq_restore(flags);
107                 v6_dma_map_area(addr, size, dir);
108                 return;
109         }
110
111         req = this_cpu_ptr(&fiq_data);
112         req->map.addr = addr;
113         req->map.size = size;
114         req->flags = dir | OXNAS_MAP_AREA;
115         smp_mb();
116
117         writel_relaxed(FIQ_GENERATE, req->reg);
118
119         v6_dma_map_area(addr, size, dir);
120         while (req->flags)
121                 barrier();
122
123         raw_local_irq_restore(flags);
124 }
125
126 void fiq_dma_unmap_area(const void *addr, size_t size, int dir)
127 {
128         unsigned long flags;
129         struct fiq_req *req;
130
131         raw_local_irq_save(flags);
132         /* currently, not possible to take cpu0 down, so only check cpu1 */
133         if (!cpu_online(1)) {
134                 raw_local_irq_restore(flags);
135                 v6_dma_unmap_area(addr, size, dir);
136                 return;
137         }
138
139         req = this_cpu_ptr(&fiq_data);
140         req->unmap.addr = addr;
141         req->unmap.size = size;
142         req->flags = dir | OXNAS_UNMAP_AREA;
143         smp_mb();
144
145         writel_relaxed(FIQ_GENERATE, req->reg);
146
147         v6_dma_unmap_area(addr, size, dir);
148         while (req->flags)
149                 barrier();
150
151         raw_local_irq_restore(flags);
152 }
153
154 void fiq_dma_flush_range(const void *start, const void *end)
155 {
156         unsigned long flags;
157         struct fiq_req *req;
158
159         raw_local_irq_save(flags);
160         /* currently, not possible to take cpu0 down, so only check cpu1 */
161         if (!cpu_online(1)) {
162                 raw_local_irq_restore(flags);
163                 v6_dma_flush_range(start, end);
164                 return;
165         }
166
167         req = this_cpu_ptr(&fiq_data);
168
169         req->flush.start = start;
170         req->flush.end = end;
171         req->flags = OXNAS_FLUSH_RANGE;
172         smp_mb();
173
174         writel_relaxed(FIQ_GENERATE, req->reg);
175
176         v6_dma_flush_range(start, end);
177
178         while (req->flags)
179                 barrier();
180
181         raw_local_irq_restore(flags);
182 }
183
184 void fiq_flush_kern_dcache_area(void *addr, size_t size)
185 {
186         fiq_dma_flush_range(addr, addr + size);
187 }
188 #else
189
190 #define ox820_set_fiq_regs(cpu) do {} while (0) /* nothing */
191 #define ox820_init_fiq()        do {} while (0) /* nothing */
192
193 #endif /* DMA_CACHE_FIQ_BROADCAST */
194
195 static DEFINE_SPINLOCK(boot_lock);
196
197 void ox820_secondary_init(unsigned int cpu)
198 {
199         /*
200          * Setup Secondary Core FIQ regs
201          */
202         ox820_set_fiq_regs(1);
203
204         /*
205          * let the primary processor know we're out of the
206          * pen, then head off into the C entry point
207          */
208         write_pen_release(-1);
209
210         /*
211          * Synchronise with the boot thread.
212          */
213         spin_lock(&boot_lock);
214         spin_unlock(&boot_lock);
215 }
216
217 int ox820_boot_secondary(unsigned int cpu, struct task_struct *idle)
218 {
219         unsigned long timeout;
220
221         /*
222          * Set synchronisation state between this boot processor
223          * and the secondary one
224          */
225         spin_lock(&boot_lock);
226
227         /*
228          * This is really belt and braces; we hold unintended secondary
229          * CPUs in the holding pen until we're ready for them.  However,
230          * since we haven't sent them a soft interrupt, they shouldn't
231          * be there.
232          */
233         write_pen_release(cpu);
234
235         writel(1, IOMEM(OXNAS_GICN_BASE_VA(cpu) + GIC_CPU_CTRL));
236
237         /*
238          * Send the secondary CPU a soft interrupt, thereby causing
239          * the boot monitor to read the system wide flags register,
240          * and branch to the address found there.
241          */
242
243         arch_send_wakeup_ipi_mask(cpumask_of(cpu));
244         timeout = jiffies + (1 * HZ);
245         while (time_before(jiffies, timeout)) {
246                 smp_rmb();
247                 if (read_pen_release() == -1)
248                         break;
249
250                 udelay(10);
251         }
252
253         /*
254          * now the secondary core is starting up let it run its
255          * calibrations, then wait for it to finish
256          */
257         spin_unlock(&boot_lock);
258
259         return read_pen_release() != -1 ? -ENOSYS : 0;
260 }
261
262 void *scu_base_addr(void)
263 {
264         return IOMEM(OXNAS_SCU_BASE_VA);
265 }
266
267 /*
268  * Initialise the CPU possible map early - this describes the CPUs
269  * which may be present or become present in the system.
270  */
271 static void __init ox820_smp_init_cpus(void)
272 {
273         void __iomem *scu_base = scu_base_addr();
274         unsigned int i, ncores;
275
276         ncores = scu_base ? scu_get_core_count(scu_base) : 1;
277
278         /* sanity check */
279         if (ncores > nr_cpu_ids) {
280                 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
281                         ncores, nr_cpu_ids);
282                 ncores = nr_cpu_ids;
283         }
284
285         for (i = 0; i < ncores; i++)
286                 set_cpu_possible(i, true);
287 }
288
289 static void __init ox820_smp_prepare_cpus(unsigned int max_cpus)
290 {
291
292         scu_enable(scu_base_addr());
293
294         /*
295          * Write the address of secondary startup into the
296          * system-wide flags register. The BootMonitor waits
297          * until it receives a soft interrupt, and then the
298          * secondary CPU branches to this address.
299          */
300         writel(virt_to_phys(ox820_secondary_startup),
301                                         HOLDINGPEN_LOCATION);
302         ox820_init_fiq();
303
304         ox820_set_fiq_regs(0);
305 }
306
307 struct smp_operations ox820_smp_ops __initdata = {
308         .smp_init_cpus          = ox820_smp_init_cpus,
309         .smp_prepare_cpus       = ox820_smp_prepare_cpus,
310         .smp_secondary_init     = ox820_secondary_init,
311         .smp_boot_secondary     = ox820_boot_secondary,
312 #ifdef CONFIG_HOTPLUG_CPU
313         .cpu_die                = ox820_cpu_die,
314 #endif
315 };