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