2 * Programmable Interrupt Controller functions for the Freescale MPC52xx
6 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
8 * Based on (well, mostly copied from) the code from the 2.4 kernel by
9 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
11 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
12 * Copyright (C) 2003 Montavista Software, Inc
14 * This file is licensed under the terms of the GNU General Public License
15 * version 2. This program is licensed "as is" without any warranty of any
16 * kind, whether express or implied.
19 #include <linux/stddef.h>
20 #include <linux/init.h>
21 #include <linux/sched.h>
22 #include <linux/signal.h>
23 #include <linux/delay.h>
24 #include <linux/irq.h>
27 #include <asm/processor.h>
28 #include <asm/system.h>
30 #include <asm/mpc52xx.h>
33 static struct mpc52xx_intr __iomem
*intr
;
34 static struct mpc52xx_sdma __iomem
*sdma
;
37 mpc52xx_ic_disable(unsigned int irq
)
41 if (irq
== MPC52xx_IRQ0
) {
42 val
= in_be32(&intr
->ctrl
);
44 out_be32(&intr
->ctrl
, val
);
46 else if (irq
< MPC52xx_IRQ1
) {
49 else if (irq
<= MPC52xx_IRQ3
) {
50 val
= in_be32(&intr
->ctrl
);
51 val
&= ~(1 << (10 - (irq
- MPC52xx_IRQ1
)));
52 out_be32(&intr
->ctrl
, val
);
54 else if (irq
< MPC52xx_SDMA_IRQ_BASE
) {
55 val
= in_be32(&intr
->main_mask
);
56 val
|= 1 << (16 - (irq
- MPC52xx_MAIN_IRQ_BASE
));
57 out_be32(&intr
->main_mask
, val
);
59 else if (irq
< MPC52xx_PERP_IRQ_BASE
) {
60 val
= in_be32(&sdma
->IntMask
);
61 val
|= 1 << (irq
- MPC52xx_SDMA_IRQ_BASE
);
62 out_be32(&sdma
->IntMask
, val
);
65 val
= in_be32(&intr
->per_mask
);
66 val
|= 1 << (31 - (irq
- MPC52xx_PERP_IRQ_BASE
));
67 out_be32(&intr
->per_mask
, val
);
72 mpc52xx_ic_enable(unsigned int irq
)
76 if (irq
== MPC52xx_IRQ0
) {
77 val
= in_be32(&intr
->ctrl
);
79 out_be32(&intr
->ctrl
, val
);
81 else if (irq
< MPC52xx_IRQ1
) {
84 else if (irq
<= MPC52xx_IRQ3
) {
85 val
= in_be32(&intr
->ctrl
);
86 val
|= 1 << (10 - (irq
- MPC52xx_IRQ1
));
87 out_be32(&intr
->ctrl
, val
);
89 else if (irq
< MPC52xx_SDMA_IRQ_BASE
) {
90 val
= in_be32(&intr
->main_mask
);
91 val
&= ~(1 << (16 - (irq
- MPC52xx_MAIN_IRQ_BASE
)));
92 out_be32(&intr
->main_mask
, val
);
94 else if (irq
< MPC52xx_PERP_IRQ_BASE
) {
95 val
= in_be32(&sdma
->IntMask
);
96 val
&= ~(1 << (irq
- MPC52xx_SDMA_IRQ_BASE
));
97 out_be32(&sdma
->IntMask
, val
);
100 val
= in_be32(&intr
->per_mask
);
101 val
&= ~(1 << (31 - (irq
- MPC52xx_PERP_IRQ_BASE
)));
102 out_be32(&intr
->per_mask
, val
);
107 mpc52xx_ic_ack(unsigned int irq
)
112 * Only some irqs are reset here, others in interrupting hardware.
117 val
= in_be32(&intr
->ctrl
);
119 out_be32(&intr
->ctrl
, val
);
121 case MPC52xx_CCS_IRQ
:
122 val
= in_be32(&intr
->enc_status
);
124 out_be32(&intr
->enc_status
, val
);
127 val
= in_be32(&intr
->ctrl
);
129 out_be32(&intr
->ctrl
, val
);
132 val
= in_be32(&intr
->ctrl
);
134 out_be32(&intr
->ctrl
, val
);
137 val
= in_be32(&intr
->ctrl
);
139 out_be32(&intr
->ctrl
, val
);
142 if (irq
>= MPC52xx_SDMA_IRQ_BASE
143 && irq
< (MPC52xx_SDMA_IRQ_BASE
+ MPC52xx_SDMA_IRQ_NUM
)) {
144 out_be32(&sdma
->IntPend
,
145 1 << (irq
- MPC52xx_SDMA_IRQ_BASE
));
152 mpc52xx_ic_disable_and_ack(unsigned int irq
)
154 mpc52xx_ic_disable(irq
);
159 mpc52xx_ic_end(unsigned int irq
)
161 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
| IRQ_INPROGRESS
)))
162 mpc52xx_ic_enable(irq
);
165 static struct hw_interrupt_type mpc52xx_ic
= {
166 .typename
= " MPC52xx ",
167 .enable
= mpc52xx_ic_enable
,
168 .disable
= mpc52xx_ic_disable
,
169 .ack
= mpc52xx_ic_disable_and_ack
,
170 .end
= mpc52xx_ic_end
,
174 mpc52xx_init_irq(void)
179 /* Remap the necessary zones */
180 intr
= ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET
), MPC52xx_INTR_SIZE
);
181 sdma
= ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET
), MPC52xx_SDMA_SIZE
);
183 if ((intr
==NULL
) || (sdma
==NULL
))
184 panic("Can't ioremap PIC/SDMA register for init_irq !");
186 /* Disable all interrupt sources. */
187 out_be32(&sdma
->IntPend
, 0xffffffff); /* 1 means clear pending */
188 out_be32(&sdma
->IntMask
, 0xffffffff); /* 1 means disabled */
189 out_be32(&intr
->per_mask
, 0x7ffffc00); /* 1 means disabled */
190 out_be32(&intr
->main_mask
, 0x00010fff); /* 1 means disabled */
191 intr_ctrl
= in_be32(&intr
->ctrl
);
192 intr_ctrl
&= 0x00ff0000; /* Keeps IRQ[0-3] config */
193 intr_ctrl
|= 0x0f000000 | /* clear IRQ 0-3 */
194 0x00001000 | /* MEE master external enable */
195 0x00000000 | /* 0 means disable IRQ 0-3 */
196 0x00000001; /* CEb route critical normally */
197 out_be32(&intr
->ctrl
, intr_ctrl
);
199 /* Zero a bunch of the priority settings. */
200 out_be32(&intr
->per_pri1
, 0);
201 out_be32(&intr
->per_pri2
, 0);
202 out_be32(&intr
->per_pri3
, 0);
203 out_be32(&intr
->main_pri1
, 0);
204 out_be32(&intr
->main_pri2
, 0);
206 /* Initialize irq_desc[i].chip's with mpc52xx_ic. */
207 for (i
= 0; i
< NR_IRQS
; i
++) {
208 irq_desc
[i
].chip
= &mpc52xx_ic
;
209 irq_desc
[i
].status
= IRQ_LEVEL
;
212 #define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03)
213 for (i
=0 ; i
<4 ; i
++) {
215 mode
= IRQn_MODE(intr_ctrl
,i
);
216 if ((mode
== 0x1) || (mode
== 0x2))
217 irq_desc
[i
?MPC52xx_IRQ1
+i
-1:MPC52xx_IRQ0
].status
= 0;
222 mpc52xx_get_irq(void)
227 status
= in_be32(&intr
->enc_status
);
229 if (status
& 0x00000400) { /* critical */
230 irq
= (status
>> 8) & 0x3;
231 if (irq
== 2) /* high priority peripheral */
233 irq
+= MPC52xx_CRIT_IRQ_BASE
;
235 else if (status
& 0x00200000) { /* main */
236 irq
= (status
>> 16) & 0x1f;
237 if (irq
== 4) /* low priority peripheral */
239 irq
+= MPC52xx_MAIN_IRQ_BASE
;
241 else if (status
& 0x20000000) { /* peripheral */
243 irq
= (status
>> 24) & 0x1f;
244 if (irq
== 0) { /* bestcomm */
245 status
= in_be32(&sdma
->IntPend
);
246 irq
= ffs(status
) + MPC52xx_SDMA_IRQ_BASE
-1;
249 irq
+= MPC52xx_PERP_IRQ_BASE
;