PageRenderTime 22ms CodeModel.GetById 7ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 1ms

/arch/frv/kernel/irq-routing.c

https://bitbucket.org/evzijst/gittest
C | 291 lines | 210 code | 43 blank | 38 comment | 9 complexity | 9efe9e3685012512eeae3ecbf27e743a MD5 | raw file
  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
 22struct irq_level frv_irq_levels[16] = {
 23	[0 ... 15] = {
 24		.lock	= SPIN_LOCK_UNLOCKED,
 25	}
 26};
 27
 28struct irq_group *irq_groups[NR_IRQ_GROUPS];
 29
 30extern struct irq_group frv_cpu_irqs;
 31
 32void __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
 39void __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
 60void __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
 65void 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 */
104static 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
111struct 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 */
128static 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
135struct 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 */
158static void frv_cputimer_doirq(struct irq_source *source)
159{
160	distribute_irqs(&frv_cpu_irqs, source->irqmask);
161}
162
163struct 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 */
181static void frv_cpuexternal_doirq(struct irq_source *source)
182{
183	distribute_irqs(&frv_cpu_irqs, source->irqmask);
184}
185
186struct 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
207struct 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 */
237void __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() */