Linux-2.6.12-rc2
[safe/jmp/linux-2.6] / arch / frv / kernel / irq-routing.c
1 /* irq-routing.c: IRQ routing
2  *
3  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/sched.h>
13 #include <linux/random.h>
14 #include <linux/init.h>
15 #include <linux/serial_reg.h>
16 #include <asm/io.h>
17 #include <asm/irq-routing.h>
18 #include <asm/irc-regs.h>
19 #include <asm/serial-regs.h>
20 #include <asm/dma.h>
21
22 struct irq_level frv_irq_levels[16] = {
23         [0 ... 15] = {
24                 .lock   = SPIN_LOCK_UNLOCKED,
25         }
26 };
27
28 struct irq_group *irq_groups[NR_IRQ_GROUPS];
29
30 extern struct irq_group frv_cpu_irqs;
31
32 void __init frv_irq_route(struct irq_source *source, int irqlevel)
33 {
34         source->level = &frv_irq_levels[irqlevel];
35         source->next = frv_irq_levels[irqlevel].sources;
36         frv_irq_levels[irqlevel].sources = source;
37 }
38
39 void __init frv_irq_route_external(struct irq_source *source, int irq)
40 {
41         int irqlevel = 0;
42
43         switch (irq) {
44         case IRQ_CPU_EXTERNAL0: irqlevel = IRQ_XIRQ0_LEVEL; break;
45         case IRQ_CPU_EXTERNAL1: irqlevel = IRQ_XIRQ1_LEVEL; break;
46         case IRQ_CPU_EXTERNAL2: irqlevel = IRQ_XIRQ2_LEVEL; break;
47         case IRQ_CPU_EXTERNAL3: irqlevel = IRQ_XIRQ3_LEVEL; break;
48         case IRQ_CPU_EXTERNAL4: irqlevel = IRQ_XIRQ4_LEVEL; break;
49         case IRQ_CPU_EXTERNAL5: irqlevel = IRQ_XIRQ5_LEVEL; break;
50         case IRQ_CPU_EXTERNAL6: irqlevel = IRQ_XIRQ6_LEVEL; break;
51         case IRQ_CPU_EXTERNAL7: irqlevel = IRQ_XIRQ7_LEVEL; break;
52         default: BUG();
53         }
54
55         source->level = &frv_irq_levels[irqlevel];
56         source->next = frv_irq_levels[irqlevel].sources;
57         frv_irq_levels[irqlevel].sources = source;
58 }
59
60 void __init frv_irq_set_group(struct irq_group *group)
61 {
62         irq_groups[group->first_irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP] = group;
63 }
64
65 void distribute_irqs(struct irq_group *group, unsigned long irqmask)
66 {
67         struct irqaction *action;
68         int irq;
69
70         while (irqmask) {
71                 asm("scan %1,gr0,%0" : "=r"(irq) : "r"(irqmask));
72                 if (irq < 0 || irq > 31)
73                         asm volatile("break");
74                 irq = 31 - irq;
75
76                 irqmask &= ~(1 << irq);
77                 action = group->actions[irq];
78
79                 irq += group->first_irq;
80
81                 if (action) {
82                         int status = 0;
83
84 //                      if (!(action->flags & SA_INTERRUPT))
85 //                              local_irq_enable();
86
87                         do {
88                                 status |= action->flags;
89                                 action->handler(irq, action->dev_id, __frame);
90                                 action = action->next;
91                         } while (action);
92
93                         if (status & SA_SAMPLE_RANDOM)
94                                 add_interrupt_randomness(irq);
95                         local_irq_disable();
96                 }
97         }
98 }
99
100 /*****************************************************************************/
101 /*
102  * CPU UART interrupts
103  */
104 static void frv_cpuuart_doirq(struct irq_source *source)
105 {
106 //      uint8_t iir = readb(source->muxdata + UART_IIR * 8);
107 //      if ((iir & 0x0f) != UART_IIR_NO_INT)
108                 distribute_irqs(&frv_cpu_irqs, source->irqmask);
109 }
110
111 struct irq_source frv_cpuuart[2] = {
112 #define __CPUUART(X, A)                                         \
113         [X] = {                                                 \
114                 .muxname        = "uart",                       \
115                 .muxdata        = (volatile void __iomem *) A,  \
116                 .irqmask        = 1 << IRQ_CPU_UART##X,         \
117                 .doirq          = frv_cpuuart_doirq,            \
118         }
119
120         __CPUUART(0, UART0_BASE),
121         __CPUUART(1, UART1_BASE),
122 };
123
124 /*****************************************************************************/
125 /*
126  * CPU DMA interrupts
127  */
128 static void frv_cpudma_doirq(struct irq_source *source)
129 {
130         uint32_t cstr = readl(source->muxdata + DMAC_CSTRx);
131         if (cstr & DMAC_CSTRx_INT)
132                 distribute_irqs(&frv_cpu_irqs, source->irqmask);
133 }
134
135 struct irq_source frv_cpudma[8] = {
136 #define __CPUDMA(X, A)                                          \
137         [X] = {                                                 \
138                 .muxname        = "dma",                        \
139                 .muxdata        = (volatile void __iomem *) A,  \
140                 .irqmask        = 1 << IRQ_CPU_DMA##X,          \
141                 .doirq          = frv_cpudma_doirq,             \
142         }
143
144         __CPUDMA(0, 0xfe000900),
145         __CPUDMA(1, 0xfe000980),
146         __CPUDMA(2, 0xfe000a00),
147         __CPUDMA(3, 0xfe000a80),
148         __CPUDMA(4, 0xfe001000),
149         __CPUDMA(5, 0xfe001080),
150         __CPUDMA(6, 0xfe001100),
151         __CPUDMA(7, 0xfe001180),
152 };
153
154 /*****************************************************************************/
155 /*
156  * CPU timer interrupts - can't tell whether they've generated an interrupt or not
157  */
158 static void frv_cputimer_doirq(struct irq_source *source)
159 {
160         distribute_irqs(&frv_cpu_irqs, source->irqmask);
161 }
162
163 struct irq_source frv_cputimer[3] = {
164 #define __CPUTIMER(X)                                           \
165         [X] = {                                                 \
166                 .muxname        = "timer",                      \
167                 .muxdata        = 0,                            \
168                 .irqmask        = 1 << IRQ_CPU_TIMER##X,        \
169                 .doirq          = frv_cputimer_doirq,           \
170         }
171
172         __CPUTIMER(0),
173         __CPUTIMER(1),
174         __CPUTIMER(2),
175 };
176
177 /*****************************************************************************/
178 /*
179  * external CPU interrupts - can't tell directly whether they've generated an interrupt or not
180  */
181 static void frv_cpuexternal_doirq(struct irq_source *source)
182 {
183         distribute_irqs(&frv_cpu_irqs, source->irqmask);
184 }
185
186 struct irq_source frv_cpuexternal[8] = {
187 #define __CPUEXTERNAL(X)                                        \
188         [X] = {                                                 \
189                 .muxname        = "ext",                        \
190                 .muxdata        = 0,                            \
191                 .irqmask        = 1 << IRQ_CPU_EXTERNAL##X,     \
192                 .doirq          = frv_cpuexternal_doirq,        \
193         }
194
195         __CPUEXTERNAL(0),
196         __CPUEXTERNAL(1),
197         __CPUEXTERNAL(2),
198         __CPUEXTERNAL(3),
199         __CPUEXTERNAL(4),
200         __CPUEXTERNAL(5),
201         __CPUEXTERNAL(6),
202         __CPUEXTERNAL(7),
203 };
204
205 #define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16))
206
207 struct irq_group frv_cpu_irqs = {
208         .sources = {
209                 [IRQ_CPU_UART0]         = &frv_cpuuart[0],
210                 [IRQ_CPU_UART1]         = &frv_cpuuart[1],
211                 [IRQ_CPU_TIMER0]        = &frv_cputimer[0],
212                 [IRQ_CPU_TIMER1]        = &frv_cputimer[1],
213                 [IRQ_CPU_TIMER2]        = &frv_cputimer[2],
214                 [IRQ_CPU_DMA0]          = &frv_cpudma[0],
215                 [IRQ_CPU_DMA1]          = &frv_cpudma[1],
216                 [IRQ_CPU_DMA2]          = &frv_cpudma[2],
217                 [IRQ_CPU_DMA3]          = &frv_cpudma[3],
218                 [IRQ_CPU_DMA4]          = &frv_cpudma[4],
219                 [IRQ_CPU_DMA5]          = &frv_cpudma[5],
220                 [IRQ_CPU_DMA6]          = &frv_cpudma[6],
221                 [IRQ_CPU_DMA7]          = &frv_cpudma[7],
222                 [IRQ_CPU_EXTERNAL0]     = &frv_cpuexternal[0],
223                 [IRQ_CPU_EXTERNAL1]     = &frv_cpuexternal[1],
224                 [IRQ_CPU_EXTERNAL2]     = &frv_cpuexternal[2],
225                 [IRQ_CPU_EXTERNAL3]     = &frv_cpuexternal[3],
226                 [IRQ_CPU_EXTERNAL4]     = &frv_cpuexternal[4],
227                 [IRQ_CPU_EXTERNAL5]     = &frv_cpuexternal[5],
228                 [IRQ_CPU_EXTERNAL6]     = &frv_cpuexternal[6],
229                 [IRQ_CPU_EXTERNAL7]     = &frv_cpuexternal[7],
230         },
231 };
232
233 /*****************************************************************************/
234 /*
235  * route the CPU's interrupt sources
236  */
237 void __init route_cpu_irqs(void)
238 {
239         frv_irq_set_group(&frv_cpu_irqs);
240
241         __set_IITMR(0, 0x003f0000);     /* DMA0-3, TIMER0-2 IRQ detect levels */
242         __set_IITMR(1, 0x20000000);     /* ERR0-1, UART0-1, DMA4-7 IRQ detect levels */
243
244         /* route UART and error interrupts */
245         frv_irq_route(&frv_cpuuart[0],  IRQ_UART0_LEVEL);
246         frv_irq_route(&frv_cpuuart[1],  IRQ_UART1_LEVEL);
247
248         set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL, IRQ_UART1_LEVEL, IRQ_UART0_LEVEL);
249
250         /* route DMA channel interrupts */
251         frv_irq_route(&frv_cpudma[0],   IRQ_DMA0_LEVEL);
252         frv_irq_route(&frv_cpudma[1],   IRQ_DMA1_LEVEL);
253         frv_irq_route(&frv_cpudma[2],   IRQ_DMA2_LEVEL);
254         frv_irq_route(&frv_cpudma[3],   IRQ_DMA3_LEVEL);
255         frv_irq_route(&frv_cpudma[4],   IRQ_DMA4_LEVEL);
256         frv_irq_route(&frv_cpudma[5],   IRQ_DMA5_LEVEL);
257         frv_irq_route(&frv_cpudma[6],   IRQ_DMA6_LEVEL);
258         frv_irq_route(&frv_cpudma[7],   IRQ_DMA7_LEVEL);
259
260         set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL, IRQ_DMA0_LEVEL);
261         set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL, IRQ_DMA4_LEVEL);
262
263         /* route timer interrupts */
264         frv_irq_route(&frv_cputimer[0], IRQ_TIMER0_LEVEL);
265         frv_irq_route(&frv_cputimer[1], IRQ_TIMER1_LEVEL);
266         frv_irq_route(&frv_cputimer[2], IRQ_TIMER2_LEVEL);
267
268         set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL);
269
270         /* route external interrupts */
271         frv_irq_route(&frv_cpuexternal[0], IRQ_XIRQ0_LEVEL);
272         frv_irq_route(&frv_cpuexternal[1], IRQ_XIRQ1_LEVEL);
273         frv_irq_route(&frv_cpuexternal[2], IRQ_XIRQ2_LEVEL);
274         frv_irq_route(&frv_cpuexternal[3], IRQ_XIRQ3_LEVEL);
275         frv_irq_route(&frv_cpuexternal[4], IRQ_XIRQ4_LEVEL);
276         frv_irq_route(&frv_cpuexternal[5], IRQ_XIRQ5_LEVEL);
277         frv_irq_route(&frv_cpuexternal[6], IRQ_XIRQ6_LEVEL);
278         frv_irq_route(&frv_cpuexternal[7], IRQ_XIRQ7_LEVEL);
279
280         set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL, IRQ_XIRQ4_LEVEL);
281         set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL, IRQ_XIRQ0_LEVEL);
282
283 #if defined(CONFIG_MB93091_VDK)
284         __set_TM1(0x55550000);          /* XIRQ7-0 all active low */
285 #elif defined(CONFIG_MB93093_PDK)
286         __set_TM1(0x15550000);          /* XIRQ7 active high, 6-0 all active low */
287 #else
288 #error dont know external IRQ trigger levels for this setup
289 #endif
290
291 } /* end route_cpu_irqs() */