fb7643a25618ee7c57968277ab10e26bd2ae7a40
[kernel.git] / arch / mips / lemote / lm2e / irq.c
1 /*
2  * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
3  * Author: Fuxin Zhang, zhangfx@lemote.com
4  *
5  *  This program is free software; you can redistribute  it and/or modify it
6  *  under  the terms of  the GNU General  Public License as published by the
7  *  Free Software Foundation;  either version 2 of the  License, or (at your
8  *  option) any later version.
9  */
10 #include <linux/delay.h>
11 #include <linux/interrupt.h>
12
13 #include <asm/irq_cpu.h>
14 #include <asm/i8259.h>
15
16 #include <loongson.h>
17 /*
18  * the first level int-handler will jump here if it is a bonito irq
19  */
20 static void bonito_irqdispatch(void)
21 {
22         u32 int_status;
23         int i;
24
25         /* workaround the IO dma problem: let cpu looping to allow DMA finish */
26         int_status = BONITO_INTISR;
27         if (int_status & (1 << 10)) {
28                 while (int_status & (1 << 10)) {
29                         udelay(1);
30                         int_status = BONITO_INTISR;
31                 }
32         }
33
34         /* Get pending sources, masked by current enables */
35         int_status = BONITO_INTISR & BONITO_INTEN;
36
37         if (int_status != 0) {
38                 i = __ffs(int_status);
39                 int_status &= ~(1 << i);
40                 do_IRQ(BONITO_IRQ_BASE + i);
41         }
42 }
43
44 static void i8259_irqdispatch(void)
45 {
46         int irq;
47
48         irq = i8259_irq();
49         if (irq >= 0)
50                 do_IRQ(irq);
51         else
52                 spurious_interrupt();
53 }
54
55 asmlinkage void plat_irq_dispatch(void)
56 {
57         unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
58
59         if (pending & CAUSEF_IP7)
60                 do_IRQ(MIPS_CPU_IRQ_BASE + 7);
61         else if (pending & CAUSEF_IP5)
62                 i8259_irqdispatch();
63         else if (pending & CAUSEF_IP2)
64                 bonito_irqdispatch();
65         else
66                 spurious_interrupt();
67 }
68
69 static struct irqaction cascade_irqaction = {
70         .handler = no_action,
71         .name = "cascade",
72 };
73
74 void __init arch_init_irq(void)
75 {
76         /*
77          * Clear all of the interrupts while we change the able around a bit.
78          * int-handler is not on bootstrap
79          */
80         clear_c0_status(ST0_IM | ST0_BEV);
81         local_irq_disable();
82
83         /* most bonito irq should be level triggered */
84         BONITO_INTEDGE = BONITO_ICU_SYSTEMERR | BONITO_ICU_MASTERERR |
85                 BONITO_ICU_RETRYERR | BONITO_ICU_MBOXES;
86         BONITO_INTSTEER = 0;
87
88         /*
89          * Mask out all interrupt by writing "1" to all bit position in
90          * the interrupt reset reg.
91          */
92         BONITO_INTENCLR = ~0;
93
94         /* init all controller
95          *   0-15         ------> i8259 interrupt
96          *   16-23        ------> mips cpu interrupt
97          *   32-63        ------> bonito irq
98          */
99
100         /* Sets the first-level interrupt dispatcher. */
101         mips_cpu_irq_init();
102         init_i8259_irqs();
103         bonito_irq_init();
104
105         /* bonito irq at IP2 */
106         setup_irq(MIPS_CPU_IRQ_BASE + 2, &cascade_irqaction);
107         /* 8259 irq at IP5 */
108         setup_irq(MIPS_CPU_IRQ_BASE + 5, &cascade_irqaction);
109 }