2 * intc.c -- interrupt controller or ColdFire 5272 SoC
4 * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
11 #include <linux/types.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
17 #include <asm/coldfire.h>
18 #include <asm/mcfsim.h>
19 #include <asm/traps.h>
22 * The 5272 ColdFire interrupt controller is nothing like any other
23 * ColdFire interrupt controller - it truly is completely different.
24 * Given its age it is unlikely to be used on any other ColdFire CPU.
28 * The masking and priproty setting of interrupts on the 5272 is done
29 * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
30 * loose mapping of vector number to register and internal bits, but
31 * a table is the easiest and quickest way to map them.
39 static struct irqmap intc_irqmap
[MCFINT_VECMAX
- MCFINT_VECBASE
] = {
40 /*MCF_IRQ_SPURIOUS*/ { .icr
= 0, .index
= 0, .ack
= 0, },
41 /*MCF_IRQ_EINT1*/ { .icr
= MCFSIM_ICR1
, .index
= 28, .ack
= 1, },
42 /*MCF_IRQ_EINT2*/ { .icr
= MCFSIM_ICR1
, .index
= 24, .ack
= 1, },
43 /*MCF_IRQ_EINT3*/ { .icr
= MCFSIM_ICR1
, .index
= 20, .ack
= 1, },
44 /*MCF_IRQ_EINT4*/ { .icr
= MCFSIM_ICR1
, .index
= 16, .ack
= 1, },
45 /*MCF_IRQ_TIMER1*/ { .icr
= MCFSIM_ICR1
, .index
= 12, .ack
= 0, },
46 /*MCF_IRQ_TIMER2*/ { .icr
= MCFSIM_ICR1
, .index
= 8, .ack
= 0, },
47 /*MCF_IRQ_TIMER3*/ { .icr
= MCFSIM_ICR1
, .index
= 4, .ack
= 0, },
48 /*MCF_IRQ_TIMER4*/ { .icr
= MCFSIM_ICR1
, .index
= 0, .ack
= 0, },
49 /*MCF_IRQ_UART1*/ { .icr
= MCFSIM_ICR2
, .index
= 28, .ack
= 0, },
50 /*MCF_IRQ_UART2*/ { .icr
= MCFSIM_ICR2
, .index
= 24, .ack
= 0, },
51 /*MCF_IRQ_PLIP*/ { .icr
= MCFSIM_ICR2
, .index
= 20, .ack
= 0, },
52 /*MCF_IRQ_PLIA*/ { .icr
= MCFSIM_ICR2
, .index
= 16, .ack
= 0, },
53 /*MCF_IRQ_USB0*/ { .icr
= MCFSIM_ICR2
, .index
= 12, .ack
= 0, },
54 /*MCF_IRQ_USB1*/ { .icr
= MCFSIM_ICR2
, .index
= 8, .ack
= 0, },
55 /*MCF_IRQ_USB2*/ { .icr
= MCFSIM_ICR2
, .index
= 4, .ack
= 0, },
56 /*MCF_IRQ_USB3*/ { .icr
= MCFSIM_ICR2
, .index
= 0, .ack
= 0, },
57 /*MCF_IRQ_USB4*/ { .icr
= MCFSIM_ICR3
, .index
= 28, .ack
= 0, },
58 /*MCF_IRQ_USB5*/ { .icr
= MCFSIM_ICR3
, .index
= 24, .ack
= 0, },
59 /*MCF_IRQ_USB6*/ { .icr
= MCFSIM_ICR3
, .index
= 20, .ack
= 0, },
60 /*MCF_IRQ_USB7*/ { .icr
= MCFSIM_ICR3
, .index
= 16, .ack
= 0, },
61 /*MCF_IRQ_DMA*/ { .icr
= MCFSIM_ICR3
, .index
= 12, .ack
= 0, },
62 /*MCF_IRQ_ERX*/ { .icr
= MCFSIM_ICR3
, .index
= 8, .ack
= 0, },
63 /*MCF_IRQ_ETX*/ { .icr
= MCFSIM_ICR3
, .index
= 4, .ack
= 0, },
64 /*MCF_IRQ_ENTC*/ { .icr
= MCFSIM_ICR3
, .index
= 0, .ack
= 0, },
65 /*MCF_IRQ_QSPI*/ { .icr
= MCFSIM_ICR4
, .index
= 28, .ack
= 0, },
66 /*MCF_IRQ_EINT5*/ { .icr
= MCFSIM_ICR4
, .index
= 24, .ack
= 1, },
67 /*MCF_IRQ_EINT6*/ { .icr
= MCFSIM_ICR4
, .index
= 20, .ack
= 1, },
68 /*MCF_IRQ_SWTO*/ { .icr
= MCFSIM_ICR4
, .index
= 16, .ack
= 0, },
71 static void intc_irq_mask(unsigned int irq
)
73 if ((irq
>= MCFINT_VECBASE
) && (irq
<= MCFINT_VECMAX
)) {
75 irq
-= MCFINT_VECBASE
;
76 v
= 0x8 << intc_irqmap
[irq
].index
;
77 writel(v
, MCF_MBAR
+ intc_irqmap
[irq
].icr
);
81 static void intc_irq_unmask(unsigned int irq
)
83 if ((irq
>= MCFINT_VECBASE
) && (irq
<= MCFINT_VECMAX
)) {
85 irq
-= MCFINT_VECBASE
;
86 v
= 0xd << intc_irqmap
[irq
].index
;
87 writel(v
, MCF_MBAR
+ intc_irqmap
[irq
].icr
);
91 static void intc_irq_ack(unsigned int irq
)
93 /* Only external interrupts are acked */
94 if ((irq
>= MCFINT_VECBASE
) && (irq
<= MCFINT_VECMAX
)) {
95 irq
-= MCFINT_VECBASE
;
96 if (intc_irqmap
[irq
].ack
) {
98 v
= 0xd << intc_irqmap
[irq
].index
;
99 writel(v
, MCF_MBAR
+ intc_irqmap
[irq
].icr
);
104 static int intc_irq_set_type(unsigned int irq
, unsigned int type
)
106 /* We can set the edge type here for external interrupts */
110 static struct irq_chip intc_irq_chip
= {
112 .mask
= intc_irq_mask
,
113 .unmask
= intc_irq_unmask
,
115 .set_type
= intc_irq_set_type
,
118 void __init
init_IRQ(void)
124 /* Mask all interrupt sources */
125 writel(0x88888888, MCF_MBAR
+ MCFSIM_ICR1
);
126 writel(0x88888888, MCF_MBAR
+ MCFSIM_ICR2
);
127 writel(0x88888888, MCF_MBAR
+ MCFSIM_ICR3
);
128 writel(0x88888888, MCF_MBAR
+ MCFSIM_ICR4
);
130 for (irq
= 0; (irq
< NR_IRQS
); irq
++) {
131 irq_desc
[irq
].status
= IRQ_DISABLED
;
132 irq_desc
[irq
].action
= NULL
;
133 irq_desc
[irq
].depth
= 1;
134 irq_desc
[irq
].chip
= &intc_irq_chip
;
135 intc_irq_set_type(irq
, 0);