ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc / syslib / ppc4xx_pic.c
1 /*
2  *
3  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
4  *
5  *    Module name: ppc4xx_pic.c
6  *
7  *    Description:
8  *      Interrupt controller driver for PowerPC 4xx-based processors.
9  */
10
11 /*
12  * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
13  * 32 possible interrupts, a majority of which are not implemented on
14  * all cores. There are six configurable, external interrupt pins and
15  * there are eight internal interrupts for the on-chip serial port
16  * (SPU), DMA controller, and JTAG controller.
17  *
18  * The PowerPC 405/440 cores' Universal Interrupt Controller (UIC) has
19  * 32 possible interrupts as well.  Depending on the core and SoC
20  * implementation, a portion of the interrrupts are used for on-chip
21  * peripherals and a portion of the interrupts are available to be
22  * configured for external devices generating interrupts.
23  *
24  * The PowerNP and 440GP (and most likely future implementations) have
25  * cascaded UICs.
26  *
27  */
28
29 #include <linux/init.h>
30 #include <linux/sched.h>
31 #include <linux/signal.h>
32 #include <linux/stddef.h>
33
34 #include <asm/processor.h>
35 #include <asm/system.h>
36 #include <asm/irq.h>
37 #include <asm/ppc4xx_pic.h>
38
39 /* Global Variables */
40 struct hw_interrupt_type *ppc4xx_pic;
41 /*
42  * We define 4xxIRQ_InitSenses table thusly:
43  * bit 0x1: sense, 1 for edge and 0 for level.
44  * bit 0x2: polarity, 0 for negative, 1 for positive.
45  */
46 unsigned int ibm4xxPIC_NumInitSenses __initdata = 0;
47 unsigned char *ibm4xxPIC_InitSenses __initdata = NULL;
48
49 /* Six of one, half dozen of the other....#ifdefs, separate files,
50  * other tricks.....
51  *
52  * There are basically two types of interrupt controllers, the 403 AIC
53  * and the "others" with UIC.  I just kept them both here separated
54  * with #ifdefs, but it seems to change depending upon how supporting
55  * files (like ppc4xx.h) change.                -- Dan.
56  */
57
58 #ifdef CONFIG_403
59
60 /* Function Prototypes */
61
62 static void ppc403_aic_enable(unsigned int irq);
63 static void ppc403_aic_disable(unsigned int irq);
64 static void ppc403_aic_disable_and_ack(unsigned int irq);
65
66 static struct hw_interrupt_type ppc403_aic = {
67         "403GC AIC",
68         NULL,
69         NULL,
70         ppc403_aic_enable,
71         ppc403_aic_disable,
72         ppc403_aic_disable_and_ack,
73         0
74 };
75
76 int
77 ppc403_pic_get_irq(struct pt_regs *regs)
78 {
79         int irq;
80         unsigned long bits;
81
82         /*
83          * Only report the status of those interrupts that are actually
84          * enabled.
85          */
86
87         bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
88
89         /*
90          * Walk through the interrupts from highest priority to lowest, and
91          * report the first pending interrupt found.
92          * We want PPC, not C bit numbering, so just subtract the ffs()
93          * result from 32.
94          */
95         irq = 32 - ffs(bits);
96
97         if (irq == NR_AIC_IRQS)
98                 irq = -1;
99
100         return (irq);
101 }
102
103 static void
104 ppc403_aic_enable(unsigned int irq)
105 {
106         int bit, word;
107
108         bit = irq & 0x1f;
109         word = irq >> 5;
110
111         ppc_cached_irq_mask[word] |= (1 << (31 - bit));
112         mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
113 }
114
115 static void
116 ppc403_aic_disable(unsigned int irq)
117 {
118         int bit, word;
119
120         bit = irq & 0x1f;
121         word = irq >> 5;
122
123         ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
124         mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
125 }
126
127 static void
128 ppc403_aic_disable_and_ack(unsigned int irq)
129 {
130         int bit, word;
131
132         bit = irq & 0x1f;
133         word = irq >> 5;
134
135         ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
136         mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
137         mtdcr(DCRN_EXISR, (1 << (31 - bit)));
138 }
139
140 #else
141
142 #ifndef UIC1
143 #define UIC1 UIC0
144 #endif
145
146 static void
147 ppc405_uic_enable(unsigned int irq)
148 {
149         int bit, word;
150         irq_desc_t *desc = irq_desc + irq;
151
152         bit = irq & 0x1f;
153         word = irq >> 5;
154
155 #ifdef UIC_DEBUG
156         printk("ppc405_uic_enable - irq %d word %d bit 0x%x\n", irq, word, bit);
157 #endif
158         ppc_cached_irq_mask[word] |= 1 << (31 - bit);
159         switch (word) {
160         case 0:
161                 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
162                 if ((mfdcr(DCRN_UIC_TR(UIC0)) & (1 << (31 - bit))) == 0)
163                         desc->status |= IRQ_LEVEL;
164                 else
165                 /* lets hope this works since in linux/irq.h
166                  * there is no define for EDGE and it's assumed
167                  * once you set status to LEVEL you would not
168                  * want to change it - Armin
169                  */
170                 desc->status = desc->status & ~IRQ_LEVEL;
171                 break;
172         case 1:
173                 mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
174                 if ((mfdcr(DCRN_UIC_TR(UIC1)) & (1 << (31 - bit))) == 0)
175                         desc->status |= IRQ_LEVEL;
176                 else
177                 /* lets hope this works since in linux/irq.h
178                  * there is no define for EDGE and it's assumed
179                  * once you set status to LEVEL you would not
180                  * want to change it - Armin
181                  */
182                 desc->status = desc->status & ~IRQ_LEVEL;
183         break;
184         }
185
186 }
187
188 static void
189 ppc405_uic_disable(unsigned int irq)
190 {
191         int bit, word;
192
193         bit = irq & 0x1f;
194         word = irq >> 5;
195 #ifdef UIC_DEBUG
196         printk("ppc405_uic_disable - irq %d word %d bit 0x%x\n", irq, word,
197                bit);
198 #endif
199         ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
200         switch (word) {
201         case 0:
202                 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
203                 break;
204         case 1:
205                 mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
206                 break;
207         }
208 }
209
210 static void
211 ppc405_uic_disable_and_ack(unsigned int irq)
212 {
213         int bit, word;
214
215         bit = irq & 0x1f;
216         word = irq >> 5;
217
218 #ifdef UIC_DEBUG
219         printk("ppc405_uic_disable_and_ack - irq %d word %d bit 0x%x\n", irq,
220                word, bit);
221 #endif
222         ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
223         switch (word) {
224         case 0:
225                 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
226                 mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - bit)));
227                 break;
228         case 1:
229                 mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
230                 mtdcr(DCRN_UIC_SR(UIC1), (1 << (31 - bit)));
231                 break;
232         }
233 }
234
235 static void
236 ppc405_uic_end(unsigned int irq)
237 {
238         int bit, word;
239         unsigned int tr_bits;
240
241         bit = irq & 0x1f;
242         word = irq >> 5;
243
244 #ifdef UIC_DEBUG
245         printk("ppc405_uic_end - irq %d word %d bit 0x%x\n", irq, word, bit);
246 #endif
247
248         switch (word) {
249         case 0:
250                 tr_bits = mfdcr(DCRN_UIC_TR(UIC0));
251                 break;
252         case 1:
253                 tr_bits = mfdcr(DCRN_UIC_TR(UIC1));
254                 break;
255         }
256
257         if ((tr_bits & (1 << (31 - bit))) == 0) {
258                 /* level trigger */
259                 switch (word) {
260                 case 0:
261                         mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - bit));
262                         break;
263                 case 1:
264                         mtdcr(DCRN_UIC_SR(UIC1), 1 << (31 - bit));
265                         break;
266                 }
267         }
268
269         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
270                 ppc_cached_irq_mask[word] |= 1 << (31 - bit);
271                 switch (word) {
272                 case 0:
273                         mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
274                         break;
275                 case 1:
276                         mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
277                         break;
278                 }
279         }
280 }
281
282 static struct hw_interrupt_type ppc405_uic = {
283 #if (NR_UICS == 1)
284         "IBM UIC",
285 #else
286         "IBM UIC Cascade",
287 #endif
288         NULL,
289         NULL,
290         ppc405_uic_enable,
291         ppc405_uic_disable,
292         ppc405_uic_disable_and_ack,
293         ppc405_uic_end,
294         0
295 };
296
297 int
298 ppc405_pic_get_irq(struct pt_regs *regs)
299 {
300         int irq, cas_irq;
301         unsigned long bits;
302         cas_irq = 0;
303         /*
304          * Only report the status of those interrupts that are actually
305          * enabled.
306          */
307
308         bits = mfdcr(DCRN_UIC_MSR(UIC0));
309
310 #if (NR_UICS > 1)
311         if (bits & UIC_CASCADE_MASK) {
312                 bits = mfdcr(DCRN_UIC_MSR(UIC1));
313                 cas_irq = 32 - ffs(bits);
314                 irq = 32 + cas_irq;
315         } else {
316                 irq = 32 - ffs(bits);
317                 if (irq == 32)
318                         irq = -1;
319         }
320 #else
321         /*
322          * Walk through the interrupts from highest priority to lowest, and
323          * report the first pending interrupt found.
324          * We want PPC, not C bit numbering, so just subtract the ffs()
325          * result from 32.
326          */
327         irq = 32 - ffs(bits);
328 #endif
329         if (irq == (NR_UIC_IRQS * NR_UICS))
330                 irq = -1;
331
332 #ifdef UIC_DEBUG
333         printk("ppc405_pic_get_irq - irq %d bit 0x%x\n", irq, bits);
334 #endif
335
336         return (irq);
337 }
338 #endif
339
340 void __init
341 ppc4xx_extpic_init(void)
342 {
343         /* set polarity
344          * 1 = default/pos/rising  , 0= neg/falling internal
345          * 1 = neg/falling , 0= pos/rising external
346          * Sense
347          * 0 = default level internal
348          * 0 = level, 1 = edge external
349          */
350
351         unsigned int sense, irq;
352         int bit, word;
353         unsigned long ppc_cached_sense_mask[NR_MASK_WORDS];
354         unsigned long ppc_cached_pol_mask[NR_MASK_WORDS];
355         ppc_cached_sense_mask[0] = 0;
356         ppc_cached_sense_mask[1] = 0;
357         ppc_cached_pol_mask[0] = 0;
358         ppc_cached_pol_mask[1] = 0;
359
360         for (irq = 0; irq < NR_IRQS; irq++) {
361
362                 bit = irq & 0x1f;
363                 word = irq >> 5;
364
365                 sense =
366                     (irq <
367                      ibm4xxPIC_NumInitSenses) ? ibm4xxPIC_InitSenses[irq] : 3;
368 #ifdef PPC4xx_PIC_DEBUG
369                 printk("PPC4xx_picext %d word:%x bit:%x sense:%x", irq, word,
370                        bit, sense);
371 #endif
372                 ppc_cached_sense_mask[word] |=
373                     (sense & IRQ_SENSE_MASK) << (31 - bit);
374                 ppc_cached_pol_mask[word] |=
375                     ((sense & IRQ_POLARITY_MASK) >> 1) << (31 - bit);
376                 switch (word) {
377                 case 0:
378 #ifdef PPC4xx_PIC_DEBUG
379                         printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC0)));
380                         printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC0)));
381 #endif
382                         /* polarity  setting */
383                         mtdcr(DCRN_UIC_PR(UIC0), ppc_cached_pol_mask[word]);
384
385                         /* Level setting */
386                         mtdcr(DCRN_UIC_TR(UIC0), ppc_cached_sense_mask[word]);
387
388                         break;
389                 case 1:
390 #ifdef PPC4xx_PIC_DEBUG
391                         printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC1)));
392                         printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC1)));
393 #endif
394                         /* polarity  setting */
395                         mtdcr(DCRN_UIC_PR(UIC1), ppc_cached_pol_mask[word]);
396
397                         /* Level setting */
398                         mtdcr(DCRN_UIC_TR(UIC1), ppc_cached_sense_mask[word]);
399
400                         break;
401                 }
402         }
403
404 }
405 void __init
406 ppc4xx_pic_init(void)
407 {
408
409         /*
410          * Disable all external interrupts until they are
411          * explicity requested.
412          */
413         ppc_cached_irq_mask[0] = 0;
414         ppc_cached_irq_mask[1] = 0;
415
416 #if defined CONFIG_403
417         mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]);
418
419         ppc4xx_pic = &ppc403_aic;
420         ppc_md.get_irq = ppc403_pic_get_irq;
421 #else
422 #if  (NR_UICS > 1)
423         ppc_cached_irq_mask[0] |= 1 << (31 - UIC0_UIC1NC);      /* enable cascading interrupt */
424         mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[1]);
425         mtdcr(DCRN_UIC_CR(UIC1), 0);
426
427 #endif
428         mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
429         mtdcr(DCRN_UIC_CR(UIC0), 0);
430
431         if (ibm4xxPIC_InitSenses != NULL)
432                 ppc4xx_extpic_init();
433
434         /* Clear any pending interrupts */
435 #if (NR_UICS > 1)
436         mtdcr(DCRN_UIC_SR(UIC1), 0xffffffff);
437 #endif
438         mtdcr(DCRN_UIC_SR(UIC0), 0xffffffff);
439
440         ppc4xx_pic = &ppc405_uic;
441         ppc_md.get_irq = ppc405_pic_get_irq;
442 #endif
443
444 }