1 /* irq-routing.c: IRQ routing
3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/sched.h>
13 #include <linux/random.h>
14 #include <linux/init.h>
15 #include <linux/serial_reg.h>
17 #include <asm/irq-routing.h>
18 #include <asm/irc-regs.h>
19 #include <asm/serial-regs.h>
22 struct irq_level frv_irq_levels
[16] = {
24 .lock
= SPIN_LOCK_UNLOCKED
,
28 struct irq_group
*irq_groups
[NR_IRQ_GROUPS
];
30 extern struct irq_group frv_cpu_irqs
;
32 void __init
frv_irq_route(struct irq_source
*source
, int irqlevel
)
34 source
->level
= &frv_irq_levels
[irqlevel
];
35 source
->next
= frv_irq_levels
[irqlevel
].sources
;
36 frv_irq_levels
[irqlevel
].sources
= source
;
39 void __init
frv_irq_route_external(struct irq_source
*source
, int 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;
55 source
->level
= &frv_irq_levels
[irqlevel
];
56 source
->next
= frv_irq_levels
[irqlevel
].sources
;
57 frv_irq_levels
[irqlevel
].sources
= source
;
60 void __init
frv_irq_set_group(struct irq_group
*group
)
62 irq_groups
[group
->first_irq
>> NR_IRQ_LOG2_ACTIONS_PER_GROUP
] = group
;
65 void distribute_irqs(struct irq_group
*group
, unsigned long irqmask
)
67 struct irqaction
*action
;
71 asm("scan %1,gr0,%0" : "=r"(irq
) : "r"(irqmask
));
72 if (irq
< 0 || irq
> 31)
73 asm volatile("break");
76 irqmask
&= ~(1 << irq
);
77 action
= group
->actions
[irq
];
79 irq
+= group
->first_irq
;
84 // if (!(action->flags & SA_INTERRUPT))
85 // local_irq_enable();
88 status
|= action
->flags
;
89 action
->handler(irq
, action
->dev_id
, __frame
);
90 action
= action
->next
;
93 if (status
& SA_SAMPLE_RANDOM
)
94 add_interrupt_randomness(irq
);
100 /*****************************************************************************/
102 * CPU UART interrupts
104 static void frv_cpuuart_doirq(struct irq_source
*source
)
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
);
111 struct irq_source frv_cpuuart
[2] = {
112 #define __CPUUART(X, A) \
115 .muxdata = (volatile void __iomem *) A, \
116 .irqmask = 1 << IRQ_CPU_UART##X, \
117 .doirq = frv_cpuuart_doirq, \
120 __CPUUART(0, UART0_BASE
),
121 __CPUUART(1, UART1_BASE
),
124 /*****************************************************************************/
128 static void frv_cpudma_doirq(struct irq_source
*source
)
130 uint32_t cstr
= readl(source
->muxdata
+ DMAC_CSTRx
);
131 if (cstr
& DMAC_CSTRx_INT
)
132 distribute_irqs(&frv_cpu_irqs
, source
->irqmask
);
135 struct irq_source frv_cpudma
[8] = {
136 #define __CPUDMA(X, A) \
139 .muxdata = (volatile void __iomem *) A, \
140 .irqmask = 1 << IRQ_CPU_DMA##X, \
141 .doirq = frv_cpudma_doirq, \
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),
154 /*****************************************************************************/
156 * CPU timer interrupts - can't tell whether they've generated an interrupt or not
158 static void frv_cputimer_doirq(struct irq_source
*source
)
160 distribute_irqs(&frv_cpu_irqs
, source
->irqmask
);
163 struct irq_source frv_cputimer
[3] = {
164 #define __CPUTIMER(X) \
166 .muxname = "timer", \
168 .irqmask = 1 << IRQ_CPU_TIMER##X, \
169 .doirq = frv_cputimer_doirq, \
177 /*****************************************************************************/
179 * external CPU interrupts - can't tell directly whether they've generated an interrupt or not
181 static void frv_cpuexternal_doirq(struct irq_source
*source
)
183 distribute_irqs(&frv_cpu_irqs
, source
->irqmask
);
186 struct irq_source frv_cpuexternal
[8] = {
187 #define __CPUEXTERNAL(X) \
191 .irqmask = 1 << IRQ_CPU_EXTERNAL##X, \
192 .doirq = frv_cpuexternal_doirq, \
205 #define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16))
207 struct irq_group frv_cpu_irqs
= {
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],
233 /*****************************************************************************/
235 * route the CPU's interrupt sources
237 void __init
route_cpu_irqs(void)
239 frv_irq_set_group(&frv_cpu_irqs
);
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 */
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
);
248 set_IRR(6, IRQ_GDBSTUB_LEVEL
, IRQ_GDBSTUB_LEVEL
, IRQ_UART1_LEVEL
, IRQ_UART0_LEVEL
);
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
);
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
);
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
);
268 set_IRR(5, 0, IRQ_TIMER2_LEVEL
, IRQ_TIMER1_LEVEL
, IRQ_TIMER0_LEVEL
);
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
);
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
);
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 */
288 #error dont know external IRQ trigger levels for this setup
291 } /* end route_cpu_irqs() */