3 * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
5 * Module name: ppc4xx_pic.c
8 * Interrupt controller driver for PowerPC 4xx-based processors.
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.
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.
24 * The PowerNP and 440GP (and most likely future implementations) have
29 #include <linux/init.h>
30 #include <linux/sched.h>
31 #include <linux/signal.h>
32 #include <linux/stddef.h>
34 #include <asm/processor.h>
35 #include <asm/system.h>
37 #include <asm/ppc4xx_pic.h>
39 /* Global Variables */
40 struct hw_interrupt_type *ppc4xx_pic;
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.
46 unsigned int ibm4xxPIC_NumInitSenses __initdata = 0;
47 unsigned char *ibm4xxPIC_InitSenses __initdata = NULL;
49 /* Six of one, half dozen of the other....#ifdefs, separate files,
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.
60 /* Function Prototypes */
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);
66 static struct hw_interrupt_type ppc403_aic = {
72 ppc403_aic_disable_and_ack,
77 ppc403_pic_get_irq(struct pt_regs *regs)
83 * Only report the status of those interrupts that are actually
87 bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
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()
97 if (irq == NR_AIC_IRQS)
104 ppc403_aic_enable(unsigned int irq)
111 ppc_cached_irq_mask[word] |= (1 << (31 - bit));
112 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
116 ppc403_aic_disable(unsigned int irq)
123 ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
124 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
128 ppc403_aic_disable_and_ack(unsigned int irq)
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)));
147 ppc405_uic_enable(unsigned int irq)
150 irq_desc_t *desc = irq_desc + irq;
156 printk("ppc405_uic_enable - irq %d word %d bit 0x%x\n", irq, word, bit);
158 ppc_cached_irq_mask[word] |= 1 << (31 - bit);
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;
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
170 desc->status = desc->status & ~IRQ_LEVEL;
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;
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
182 desc->status = desc->status & ~IRQ_LEVEL;
189 ppc405_uic_disable(unsigned int irq)
196 printk("ppc405_uic_disable - irq %d word %d bit 0x%x\n", irq, word,
199 ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
202 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
205 mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
211 ppc405_uic_disable_and_ack(unsigned int irq)
219 printk("ppc405_uic_disable_and_ack - irq %d word %d bit 0x%x\n", irq,
222 ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
225 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
226 mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - bit)));
229 mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
230 mtdcr(DCRN_UIC_SR(UIC1), (1 << (31 - bit)));
236 ppc405_uic_end(unsigned int irq)
239 unsigned int tr_bits;
245 printk("ppc405_uic_end - irq %d word %d bit 0x%x\n", irq, word, bit);
250 tr_bits = mfdcr(DCRN_UIC_TR(UIC0));
253 tr_bits = mfdcr(DCRN_UIC_TR(UIC1));
257 if ((tr_bits & (1 << (31 - bit))) == 0) {
261 mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - bit));
264 mtdcr(DCRN_UIC_SR(UIC1), 1 << (31 - bit));
269 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
270 ppc_cached_irq_mask[word] |= 1 << (31 - bit);
273 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
276 mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
282 static struct hw_interrupt_type ppc405_uic = {
292 ppc405_uic_disable_and_ack,
298 ppc405_pic_get_irq(struct pt_regs *regs)
304 * Only report the status of those interrupts that are actually
308 bits = mfdcr(DCRN_UIC_MSR(UIC0));
311 if (bits & UIC_CASCADE_MASK) {
312 bits = mfdcr(DCRN_UIC_MSR(UIC1));
313 cas_irq = 32 - ffs(bits);
316 irq = 32 - ffs(bits);
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()
327 irq = 32 - ffs(bits);
329 if (irq == (NR_UIC_IRQS * NR_UICS))
333 printk("ppc405_pic_get_irq - irq %d bit 0x%x\n", irq, bits);
341 ppc4xx_extpic_init(void)
344 * 1 = default/pos/rising , 0= neg/falling internal
345 * 1 = neg/falling , 0= pos/rising external
347 * 0 = default level internal
348 * 0 = level, 1 = edge external
351 unsigned int sense, irq;
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;
360 for (irq = 0; irq < NR_IRQS; 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,
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);
378 #ifdef PPC4xx_PIC_DEBUG
379 printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC0)));
380 printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC0)));
382 /* polarity setting */
383 mtdcr(DCRN_UIC_PR(UIC0), ppc_cached_pol_mask[word]);
386 mtdcr(DCRN_UIC_TR(UIC0), ppc_cached_sense_mask[word]);
390 #ifdef PPC4xx_PIC_DEBUG
391 printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC1)));
392 printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC1)));
394 /* polarity setting */
395 mtdcr(DCRN_UIC_PR(UIC1), ppc_cached_pol_mask[word]);
398 mtdcr(DCRN_UIC_TR(UIC1), ppc_cached_sense_mask[word]);
406 ppc4xx_pic_init(void)
410 * Disable all external interrupts until they are
411 * explicity requested.
413 ppc_cached_irq_mask[0] = 0;
414 ppc_cached_irq_mask[1] = 0;
416 #if defined CONFIG_403
417 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]);
419 ppc4xx_pic = &ppc403_aic;
420 ppc_md.get_irq = ppc403_pic_get_irq;
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);
428 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
429 mtdcr(DCRN_UIC_CR(UIC0), 0);
431 if (ibm4xxPIC_InitSenses != NULL)
432 ppc4xx_extpic_init();
434 /* Clear any pending interrupts */
436 mtdcr(DCRN_UIC_SR(UIC1), 0xffffffff);
438 mtdcr(DCRN_UIC_SR(UIC0), 0xffffffff);
440 ppc4xx_pic = &ppc405_uic;
441 ppc_md.get_irq = ppc405_pic_get_irq;