Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * | |
3 | * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> | |
4 | * | |
5 | * Module name: ppc403_pic.c | |
6 | * | |
7 | * Description: | |
8 | * Interrupt controller driver for PowerPC 403-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 | */ | |
19 | ||
20 | #include <linux/init.h> | |
21 | #include <linux/sched.h> | |
22 | #include <linux/signal.h> | |
23 | #include <linux/stddef.h> | |
24 | ||
25 | #include <asm/processor.h> | |
26 | #include <asm/system.h> | |
27 | #include <asm/irq.h> | |
28 | #include <asm/ppc4xx_pic.h> | |
fd582ec8 | 29 | #include <asm/machdep.h> |
1da177e4 LT |
30 | |
31 | /* Function Prototypes */ | |
32 | ||
33 | static void ppc403_aic_enable(unsigned int irq); | |
34 | static void ppc403_aic_disable(unsigned int irq); | |
35 | static void ppc403_aic_disable_and_ack(unsigned int irq); | |
36 | ||
37 | static struct hw_interrupt_type ppc403_aic = { | |
2830e21e TG |
38 | .typename = "403GC AIC", |
39 | .enable = ppc403_aic_enable, | |
40 | .disable = ppc403_aic_disable, | |
41 | .ack = ppc403_aic_disable_and_ack, | |
1da177e4 LT |
42 | }; |
43 | ||
44 | int | |
39e3eb72 | 45 | ppc403_pic_get_irq(void) |
1da177e4 LT |
46 | { |
47 | int irq; | |
48 | unsigned long bits; | |
49 | ||
50 | /* | |
51 | * Only report the status of those interrupts that are actually | |
52 | * enabled. | |
53 | */ | |
54 | ||
55 | bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER); | |
56 | ||
57 | /* | |
58 | * Walk through the interrupts from highest priority to lowest, and | |
59 | * report the first pending interrupt found. | |
60 | * We want PPC, not C bit numbering, so just subtract the ffs() | |
61 | * result from 32. | |
62 | */ | |
63 | irq = 32 - ffs(bits); | |
64 | ||
65 | if (irq == NR_AIC_IRQS) | |
66 | irq = -1; | |
67 | ||
68 | return (irq); | |
69 | } | |
70 | ||
71 | static void | |
72 | ppc403_aic_enable(unsigned int irq) | |
73 | { | |
74 | int bit, word; | |
75 | ||
76 | bit = irq & 0x1f; | |
77 | word = irq >> 5; | |
78 | ||
79 | ppc_cached_irq_mask[word] |= (1 << (31 - bit)); | |
80 | mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); | |
81 | } | |
82 | ||
83 | static void | |
84 | ppc403_aic_disable(unsigned int irq) | |
85 | { | |
86 | int bit, word; | |
87 | ||
88 | bit = irq & 0x1f; | |
89 | word = irq >> 5; | |
90 | ||
91 | ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); | |
92 | mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); | |
93 | } | |
94 | ||
95 | static void | |
96 | ppc403_aic_disable_and_ack(unsigned int irq) | |
97 | { | |
98 | int bit, word; | |
99 | ||
100 | bit = irq & 0x1f; | |
101 | word = irq >> 5; | |
102 | ||
103 | ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); | |
104 | mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); | |
105 | mtdcr(DCRN_EXISR, (1 << (31 - bit))); | |
106 | } | |
107 | ||
108 | void __init | |
109 | ppc4xx_pic_init(void) | |
110 | { | |
111 | int i; | |
112 | ||
113 | /* | |
114 | * Disable all external interrupts until they are | |
a8de5ce9 | 115 | * explicitly requested. |
1da177e4 LT |
116 | */ |
117 | ppc_cached_irq_mask[0] = 0; | |
118 | ||
119 | mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]); | |
120 | ||
121 | ppc_md.get_irq = ppc403_pic_get_irq; | |
122 | ||
123 | for (i = 0; i < NR_IRQS; i++) | |
d1bef4ed | 124 | irq_desc[i].chip = &ppc403_aic; |
1da177e4 | 125 | } |