diff options
author | Greg Ungerer <gerg@uclinux.org> | 2009-07-06 19:39:11 -0400 |
---|---|---|
committer | Greg Ungerer <gerg@uclinux.org> | 2009-09-15 19:43:54 -0400 |
commit | 9075216d2c8761c91dc268125f6580af3ffc58b5 (patch) | |
tree | 95df9112cacda86d5fc7603b0e83bd88abdfde45 /arch/m68knommu/platform/5272 | |
parent | da3601a5fa664c8d51383fe916d96bd4fbce84b8 (diff) |
m68knommu: create a speciailized ColdFire 5272 interrupt controller
The ColdFire 5272 CPU has a very different interrupt controller than
any of the other ColdFire parts. It needs its own controller code to
correctly setup and ack interrupts.
Signed-off-by: Greg Ungerer <gerg@uclinux.org>
Diffstat (limited to 'arch/m68knommu/platform/5272')
-rw-r--r-- | arch/m68knommu/platform/5272/Makefile | 2 | ||||
-rw-r--r-- | arch/m68knommu/platform/5272/intc.c | 138 |
2 files changed, 139 insertions, 1 deletions
diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile index 3d90e6d92459..93673ef8e2c1 100644 --- a/arch/m68knommu/platform/5272/Makefile +++ b/arch/m68knommu/platform/5272/Makefile | |||
@@ -14,5 +14,5 @@ | |||
14 | 14 | ||
15 | asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 | 15 | asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 |
16 | 16 | ||
17 | obj-y := config.o gpio.o | 17 | obj-y := config.o gpio.o intc.o |
18 | 18 | ||
diff --git a/arch/m68knommu/platform/5272/intc.c b/arch/m68knommu/platform/5272/intc.c new file mode 100644 index 000000000000..7081e0a9720e --- /dev/null +++ b/arch/m68knommu/platform/5272/intc.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * intc.c -- interrupt controller or ColdFire 5272 SoC | ||
3 | * | ||
4 | * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> | ||
5 | * | ||
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 | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
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> | ||
16 | #include <linux/io.h> | ||
17 | #include <asm/coldfire.h> | ||
18 | #include <asm/mcfsim.h> | ||
19 | #include <asm/traps.h> | ||
20 | |||
21 | /* | ||
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. | ||
25 | */ | ||
26 | |||
27 | /* | ||
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. | ||
32 | */ | ||
33 | struct irqmap { | ||
34 | unsigned char icr; | ||
35 | unsigned char index; | ||
36 | unsigned char ack; | ||
37 | }; | ||
38 | |||
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, }, | ||
69 | }; | ||
70 | |||
71 | static void intc_irq_mask(unsigned int irq) | ||
72 | { | ||
73 | if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { | ||
74 | u32 v; | ||
75 | irq -= MCFINT_VECBASE; | ||
76 | v = 0x8 << intc_irqmap[irq].index; | ||
77 | writel(v, MCF_MBAR + intc_irqmap[irq].icr); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | static void intc_irq_unmask(unsigned int irq) | ||
82 | { | ||
83 | if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { | ||
84 | u32 v; | ||
85 | irq -= MCFINT_VECBASE; | ||
86 | v = 0xd << intc_irqmap[irq].index; | ||
87 | writel(v, MCF_MBAR + intc_irqmap[irq].icr); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void intc_irq_ack(unsigned int irq) | ||
92 | { | ||
93 | /* Only external interrupts are acked */ | ||
94 | if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { | ||
95 | irq -= MCFINT_VECBASE; | ||
96 | if (intc_irqmap[irq].ack) { | ||
97 | u32 v; | ||
98 | v = 0xd << intc_irqmap[irq].index; | ||
99 | writel(v, MCF_MBAR + intc_irqmap[irq].icr); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | static int intc_irq_set_type(unsigned int irq, unsigned int type) | ||
105 | { | ||
106 | /* We can set the edge type here for external interrupts */ | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static struct irq_chip intc_irq_chip = { | ||
111 | .name = "CF-INTC", | ||
112 | .mask = intc_irq_mask, | ||
113 | .unmask = intc_irq_unmask, | ||
114 | .ack = intc_irq_ack, | ||
115 | .set_type = intc_irq_set_type, | ||
116 | }; | ||
117 | |||
118 | void __init init_IRQ(void) | ||
119 | { | ||
120 | int irq; | ||
121 | |||
122 | init_vectors(); | ||
123 | |||
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); | ||
129 | |||
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); | ||
136 | } | ||
137 | } | ||
138 | |||