]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/powerpc/platforms/52xx/mpc52xx_pic.c
[POWERPC] mpc5200: normalize compatible property bindings
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / 52xx / mpc52xx_pic.c
1 /*
2  *
3  * Programmable Interrupt Controller functions for the Freescale MPC52xx.
4  *
5  * Copyright (C) 2006 bplan GmbH
6  *
7  * Based on the code from the 2.4 kernel by
8  * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
9  *
10  * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
11  * Copyright (C) 2003 Montavista Software, Inc
12  *
13  * This file is licensed under the terms of the GNU General Public License
14  * version 2. This program is licensed "as is" without any warranty of any
15  * kind, whether express or implied.
16  *
17  */
18
19 #undef DEBUG
20
21 #include <linux/irq.h>
22 #include <linux/of.h>
23 #include <asm/io.h>
24 #include <asm/prom.h>
25 #include <asm/mpc52xx.h>
26 #include "mpc52xx_pic.h"
27
28 /*
29  *
30 */
31
32 /* MPC5200 device tree match tables */
33 static struct of_device_id mpc52xx_pic_ids[] __initdata = {
34         { .compatible = "fsl,mpc5200-pic", },
35         { .compatible = "mpc5200-pic", },
36         {}
37 };
38 static struct of_device_id mpc52xx_sdma_ids[] __initdata = {
39         { .compatible = "fsl,mpc5200-bestcomm", },
40         { .compatible = "mpc5200-bestcomm", },
41         {}
42 };
43
44 static struct mpc52xx_intr __iomem *intr;
45 static struct mpc52xx_sdma __iomem *sdma;
46 static struct irq_host *mpc52xx_irqhost = NULL;
47
48 static unsigned char mpc52xx_map_senses[4] = {
49         IRQ_TYPE_LEVEL_HIGH,
50         IRQ_TYPE_EDGE_RISING,
51         IRQ_TYPE_EDGE_FALLING,
52         IRQ_TYPE_LEVEL_LOW,
53 };
54
55 /*
56  *
57 */
58
59 static inline void io_be_setbit(u32 __iomem *addr, int bitno)
60 {
61         out_be32(addr, in_be32(addr) | (1 << bitno));
62 }
63
64 static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
65 {
66         out_be32(addr, in_be32(addr) & ~(1 << bitno));
67 }
68
69 /*
70  * IRQ[0-3] interrupt irq_chip
71 */
72
73 static void mpc52xx_extirq_mask(unsigned int virq)
74 {
75         int irq;
76         int l2irq;
77
78         irq = irq_map[virq].hwirq;
79         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
80
81         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
82
83         io_be_clrbit(&intr->ctrl, 11 - l2irq);
84 }
85
86 static void mpc52xx_extirq_unmask(unsigned int virq)
87 {
88         int irq;
89         int l2irq;
90
91         irq = irq_map[virq].hwirq;
92         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
93
94         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
95
96         io_be_setbit(&intr->ctrl, 11 - l2irq);
97 }
98
99 static void mpc52xx_extirq_ack(unsigned int virq)
100 {
101         int irq;
102         int l2irq;
103
104         irq = irq_map[virq].hwirq;
105         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
106
107         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
108
109         io_be_setbit(&intr->ctrl, 27-l2irq);
110 }
111
112 static struct irq_chip mpc52xx_extirq_irqchip = {
113         .typename = " MPC52xx IRQ[0-3] ",
114         .mask = mpc52xx_extirq_mask,
115         .unmask = mpc52xx_extirq_unmask,
116         .ack = mpc52xx_extirq_ack,
117 };
118
119 /*
120  * Main interrupt irq_chip
121 */
122
123 static void mpc52xx_main_mask(unsigned int virq)
124 {
125         int irq;
126         int l2irq;
127
128         irq = irq_map[virq].hwirq;
129         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
130
131         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
132
133         io_be_setbit(&intr->main_mask, 16 - l2irq);
134 }
135
136 static void mpc52xx_main_unmask(unsigned int virq)
137 {
138         int irq;
139         int l2irq;
140
141         irq = irq_map[virq].hwirq;
142         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
143
144         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
145
146         io_be_clrbit(&intr->main_mask, 16 - l2irq);
147 }
148
149 static struct irq_chip mpc52xx_main_irqchip = {
150         .typename = "MPC52xx Main",
151         .mask = mpc52xx_main_mask,
152         .mask_ack = mpc52xx_main_mask,
153         .unmask = mpc52xx_main_unmask,
154 };
155
156 /*
157  * Peripherals interrupt irq_chip
158 */
159
160 static void mpc52xx_periph_mask(unsigned int virq)
161 {
162         int irq;
163         int l2irq;
164
165         irq = irq_map[virq].hwirq;
166         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
167
168         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
169
170         io_be_setbit(&intr->per_mask, 31 - l2irq);
171 }
172
173 static void mpc52xx_periph_unmask(unsigned int virq)
174 {
175         int irq;
176         int l2irq;
177
178         irq = irq_map[virq].hwirq;
179         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
180
181         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
182
183         io_be_clrbit(&intr->per_mask, 31 - l2irq);
184 }
185
186 static struct irq_chip mpc52xx_periph_irqchip = {
187         .typename = "MPC52xx Peripherals",
188         .mask = mpc52xx_periph_mask,
189         .mask_ack = mpc52xx_periph_mask,
190         .unmask = mpc52xx_periph_unmask,
191 };
192
193 /*
194  * SDMA interrupt irq_chip
195 */
196
197 static void mpc52xx_sdma_mask(unsigned int virq)
198 {
199         int irq;
200         int l2irq;
201
202         irq = irq_map[virq].hwirq;
203         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
204
205         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
206
207         io_be_setbit(&sdma->IntMask, l2irq);
208 }
209
210 static void mpc52xx_sdma_unmask(unsigned int virq)
211 {
212         int irq;
213         int l2irq;
214
215         irq = irq_map[virq].hwirq;
216         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
217
218         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
219
220         io_be_clrbit(&sdma->IntMask, l2irq);
221 }
222
223 static void mpc52xx_sdma_ack(unsigned int virq)
224 {
225         int irq;
226         int l2irq;
227
228         irq = irq_map[virq].hwirq;
229         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
230
231         pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
232
233         out_be32(&sdma->IntPend, 1 << l2irq);
234 }
235
236 static struct irq_chip mpc52xx_sdma_irqchip = {
237         .typename = "MPC52xx SDMA",
238         .mask = mpc52xx_sdma_mask,
239         .unmask = mpc52xx_sdma_unmask,
240         .ack = mpc52xx_sdma_ack,
241 };
242
243 /*
244  * irq_host
245 */
246
247 static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
248                                  u32 * intspec, unsigned int intsize,
249                                  irq_hw_number_t * out_hwirq,
250                                  unsigned int *out_flags)
251 {
252         int intrvect_l1;
253         int intrvect_l2;
254         int intrvect_type;
255         int intrvect_linux;
256
257         if (intsize != 3)
258                 return -1;
259
260         intrvect_l1 = (int)intspec[0];
261         intrvect_l2 = (int)intspec[1];
262         intrvect_type = (int)intspec[2];
263
264         intrvect_linux =
265             (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;
266         intrvect_linux |=
267             (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;
268
269         pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
270                  intrvect_l2);
271
272         *out_hwirq = intrvect_linux;
273         *out_flags = mpc52xx_map_senses[intrvect_type];
274
275         return 0;
276 }
277
278 /*
279  * this function retrieves the correct IRQ type out
280  * of the MPC regs
281  * Only externals IRQs needs this
282 */
283 static int mpc52xx_irqx_gettype(int irq)
284 {
285         int type;
286         u32 ctrl_reg;
287
288         ctrl_reg = in_be32(&intr->ctrl);
289         type = (ctrl_reg >> (22 - irq * 2)) & 0x3;
290
291         return mpc52xx_map_senses[type];
292 }
293
294 static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
295                                irq_hw_number_t irq)
296 {
297         int l1irq;
298         int l2irq;
299         struct irq_chip *good_irqchip;
300         void *good_handle;
301         int type;
302
303         l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
304         l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
305
306         /*
307          * Most of ours IRQs will be level low
308          * Only external IRQs on some platform may be others
309          */
310         type = IRQ_TYPE_LEVEL_LOW;
311
312         switch (l1irq) {
313         case MPC52xx_IRQ_L1_CRIT:
314                 pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);
315
316                 BUG_ON(l2irq != 0);
317
318                 type = mpc52xx_irqx_gettype(l2irq);
319                 good_irqchip = &mpc52xx_extirq_irqchip;
320                 break;
321
322         case MPC52xx_IRQ_L1_MAIN:
323                 pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
324
325                 if ((l2irq >= 1) && (l2irq <= 3)) {
326                         type = mpc52xx_irqx_gettype(l2irq);
327                         good_irqchip = &mpc52xx_extirq_irqchip;
328                 } else {
329                         good_irqchip = &mpc52xx_main_irqchip;
330                 }
331                 break;
332
333         case MPC52xx_IRQ_L1_PERP:
334                 pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
335                 good_irqchip = &mpc52xx_periph_irqchip;
336                 break;
337
338         case MPC52xx_IRQ_L1_SDMA:
339                 pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
340                 good_irqchip = &mpc52xx_sdma_irqchip;
341                 break;
342
343         default:
344                 pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);
345                 printk(KERN_ERR "Unknow IRQ!\n");
346                 return -EINVAL;
347         }
348
349         switch (type) {
350         case IRQ_TYPE_EDGE_FALLING:
351         case IRQ_TYPE_EDGE_RISING:
352                 good_handle = handle_edge_irq;
353                 break;
354         default:
355                 good_handle = handle_level_irq;
356         }
357
358         set_irq_chip_and_handler(virq, good_irqchip, good_handle);
359
360         pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
361                  (int)irq, type);
362
363         return 0;
364 }
365
366 static struct irq_host_ops mpc52xx_irqhost_ops = {
367         .xlate = mpc52xx_irqhost_xlate,
368         .map = mpc52xx_irqhost_map,
369 };
370
371 /*
372  * init (public)
373 */
374
375 void __init mpc52xx_init_irq(void)
376 {
377         u32 intr_ctrl;
378         struct device_node *picnode;
379         struct device_node *np;
380
381         /* Remap the necessary zones */
382         picnode = of_find_matching_node(NULL, mpc52xx_pic_ids);
383         intr = of_iomap(picnode, 0);
384         if (!intr)
385                 panic(__FILE__  ": find_and_map failed on 'mpc5200-pic'. "
386                                 "Check node !");
387
388         np = of_find_matching_node(NULL, mpc52xx_sdma_ids);
389         sdma = of_iomap(np, 0);
390         of_node_put(np);
391         if (!sdma)
392                 panic(__FILE__  ": find_and_map failed on 'mpc5200-bestcomm'. "
393                                 "Check node !");
394
395         /* Disable all interrupt sources. */
396         out_be32(&sdma->IntPend, 0xffffffff);   /* 1 means clear pending */
397         out_be32(&sdma->IntMask, 0xffffffff);   /* 1 means disabled */
398         out_be32(&intr->per_mask, 0x7ffffc00);  /* 1 means disabled */
399         out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
400         intr_ctrl = in_be32(&intr->ctrl);
401         intr_ctrl &= 0x00ff0000;        /* Keeps IRQ[0-3] config */
402         intr_ctrl |=    0x0f000000 |    /* clear IRQ 0-3 */
403                         0x00001000 |    /* MEE master external enable */
404                         0x00000000 |    /* 0 means disable IRQ 0-3 */
405                         0x00000001;     /* CEb route critical normally */
406         out_be32(&intr->ctrl, intr_ctrl);
407
408         /* Zero a bunch of the priority settings. */
409         out_be32(&intr->per_pri1, 0);
410         out_be32(&intr->per_pri2, 0);
411         out_be32(&intr->per_pri3, 0);
412         out_be32(&intr->main_pri1, 0);
413         out_be32(&intr->main_pri2, 0);
414
415         /*
416          * As last step, add an irq host to translate the real
417          * hw irq information provided by the ofw to linux virq
418          */
419
420         mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR,
421                                          MPC52xx_IRQ_HIGHTESTHWIRQ,
422                                          &mpc52xx_irqhost_ops, -1);
423
424         if (!mpc52xx_irqhost)
425                 panic(__FILE__ ": Cannot allocate the IRQ host\n");
426
427         printk(KERN_INFO "MPC52xx PIC is up and running!\n");
428 }
429
430 /*
431  * get_irq (public)
432 */
433 unsigned int mpc52xx_get_irq(void)
434 {
435         u32 status;
436         int irq = NO_IRQ_IGNORE;
437
438         status = in_be32(&intr->enc_status);
439         if (status & 0x00000400) {      /* critical */
440                 irq = (status >> 8) & 0x3;
441                 if (irq == 2)   /* high priority peripheral */
442                         goto peripheral;
443                 irq |=  (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &
444                         MPC52xx_IRQ_L1_MASK;
445         } else if (status & 0x00200000) {       /* main */
446                 irq = (status >> 16) & 0x1f;
447                 if (irq == 4)   /* low priority peripheral */
448                         goto peripheral;
449                 irq |=  (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &
450                         MPC52xx_IRQ_L1_MASK;
451         } else if (status & 0x20000000) {       /* peripheral */
452               peripheral:
453                 irq = (status >> 24) & 0x1f;
454                 if (irq == 0) { /* bestcomm */
455                         status = in_be32(&sdma->IntPend);
456                         irq = ffs(status) - 1;
457                         irq |=  (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &
458                                 MPC52xx_IRQ_L1_MASK;
459                 } else {
460                         irq |=  (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &
461                                 MPC52xx_IRQ_L1_MASK;
462                 }
463         }
464
465         pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,
466                  irq_linear_revmap(mpc52xx_irqhost, irq));
467
468         return irq_linear_revmap(mpc52xx_irqhost, irq);
469 }