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