6702ecf3d9f814b0d0c38563788366acdca81885
[openwrt/staging/yousong.git] / target / linux / amazon-2.6 / files / arch / mips / amazon / interrupt.c
1 /*
2 * Gary Jennejohn (C) 2003 <gj@denx.de>
3 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Routines for generic manipulation of the interrupts found on the
19 * AMAZON boards.
20 */
21
22 #include <linux/init.h>
23 #include <linux/sched.h>
24 #include <linux/slab.h>
25 #include <linux/interrupt.h>
26 #include <linux/kernel_stat.h>
27 #include <linux/module.h>
28
29 #include <asm/amazon/amazon.h>
30 #include <asm/amazon/irq.h>
31 #include <asm/bootinfo.h>
32 #include <asm/irq_cpu.h>
33 #include <asm/irq.h>
34 #include <asm/time.h>
35
36 static void amazon_disable_irq(unsigned int irq_nr)
37 {
38 /* have to access the correct register here */
39 if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0)
40 /* access IM0 DMA channels */
41 *AMAZON_ICU_IM0_IER &= (~(AMAZON_DMA_H_MASK));
42 else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12)
43 /* access IM0 except DMA*/
44 *AMAZON_ICU_IM0_IER &= (~AMAZON_ICU_IM0_IER_IR(irq_nr));
45 else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0)
46 /* access IM1 */
47 *AMAZON_ICU_IM1_IER &= (~AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0));
48 else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0)
49 /* access IM2 */
50 *AMAZON_ICU_IM2_IER &= (~AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0));
51 else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0)
52 /* access IM3 */
53 *AMAZON_ICU_IM3_IER &= (~AMAZON_ICU_IM3_IER_IR((irq_nr - INT_NUM_IM3_IRL0)));
54 else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0)
55 /* access IM4 */
56 *AMAZON_ICU_IM4_IER &= (~AMAZON_ICU_IM4_IER_IR((irq_nr - INT_NUM_IM4_IRL0)));
57 }
58
59 static void amazon_mask_and_ack_irq(unsigned int irq_nr)
60 {
61 /* have to access the correct register here */
62 if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0) {
63 /* access IM0 DMA channels */
64 *AMAZON_ICU_IM0_IER &= (~(AMAZON_DMA_H_MASK)); /* mask */
65 *AMAZON_ICU_IM0_ISR = AMAZON_DMA_H_MASK; /* ack */
66 } else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12) {
67 /* access IM0 except DMA */
68 *AMAZON_ICU_IM0_IER &= ~AMAZON_ICU_IM0_IER_IR(irq_nr - INT_NUM_IM0_IRL0); /* mask */
69 *AMAZON_ICU_IM0_ISR = AMAZON_ICU_IM0_ISR_IR(irq_nr - INT_NUM_IM0_IRL0); /* ack */
70 } else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) {
71 /* access IM1 */
72 *AMAZON_ICU_IM1_IER &= ~AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0); /* mask */
73 *AMAZON_ICU_IM1_ISR = AMAZON_ICU_IM1_ISR_IR(irq_nr - INT_NUM_IM1_IRL0); /* ack */
74 } else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) {
75 /* access IM2 */
76 *AMAZON_ICU_IM2_IER &= ~AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0); /* mask */
77 *AMAZON_ICU_IM2_ISR = AMAZON_ICU_IM2_ISR_IR(irq_nr - INT_NUM_IM2_IRL0); /* ack */
78 } else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) {
79 /* access IM3 */
80 *AMAZON_ICU_IM3_IER &= ~AMAZON_ICU_IM3_IER_IR(irq_nr - INT_NUM_IM3_IRL0); /* mask */
81 *AMAZON_ICU_IM3_ISR = AMAZON_ICU_IM3_ISR_IR(irq_nr - INT_NUM_IM3_IRL0); /* ack */
82 } else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) {
83 *AMAZON_ICU_IM4_IER &= ~AMAZON_ICU_IM4_IER_IR(irq_nr - INT_NUM_IM4_IRL0); /* mask */
84 *AMAZON_ICU_IM4_ISR = AMAZON_ICU_IM4_ISR_IR(irq_nr - INT_NUM_IM4_IRL0); /* ack */
85 }
86 }
87
88 static void amazon_enable_irq(unsigned int irq_nr)
89 {
90 /* have to access the correct register here */
91 if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0)
92 /* access IM0 DMA*/
93 *AMAZON_ICU_IM0_IER |= AMAZON_DMA_H_MASK;
94 else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12)
95 /* access IM0 except DMA*/
96 *AMAZON_ICU_IM0_IER |= AMAZON_ICU_IM0_IER_IR(irq_nr - INT_NUM_IM0_IRL0);
97 else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0)
98 /* access IM1 */
99 *AMAZON_ICU_IM1_IER |= AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0);
100 else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0)
101 /* access IM2 */
102 *AMAZON_ICU_IM2_IER |= AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0);
103 else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0)
104 /* access IM3 */
105 *AMAZON_ICU_IM3_IER |= AMAZON_ICU_IM3_IER_IR((irq_nr - INT_NUM_IM3_IRL0));
106 else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0)
107 /* access IM4 */
108 *AMAZON_ICU_IM4_IER |= AMAZON_ICU_IM4_IER_IR((irq_nr - INT_NUM_IM4_IRL0));
109 }
110
111 static unsigned int amazon_startup_irq(unsigned int irq)
112 {
113 amazon_enable_irq(irq);
114 return 0;
115 }
116
117 static void amazon_end_irq(unsigned int irq)
118 {
119 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
120 amazon_enable_irq(irq);
121 }
122 }
123
124 static struct hw_interrupt_type amazon_irq_type = {
125 "AMAZON",
126 .startup = amazon_startup_irq,
127 .enable = amazon_enable_irq,
128 .disable = amazon_disable_irq,
129 .unmask = amazon_enable_irq,
130 .ack = amazon_mask_and_ack_irq,
131 .mask = amazon_disable_irq,
132 .mask_ack = amazon_mask_and_ack_irq,
133 .end = amazon_end_irq
134 };
135
136 /* Cascaded interrupts from IM0 */
137 static inline void amazon_hw0_irqdispatch(void)
138 {
139 u32 irq;
140
141 irq = (*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM0_VEC_MASK;
142 if (irq <= 11 && irq >= 0) {
143 //DMA fixed to IM0_IRL0
144 irq = 0;
145 }
146 do_IRQ(irq + INT_NUM_IM0_IRL0);
147 }
148
149 /* Cascaded interrupts from IM1 */
150 static inline void amazon_hw1_irqdispatch(void)
151 {
152 u32 irq;
153
154 irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM1_VEC_MASK) >> 5;
155 do_IRQ(irq + INT_NUM_IM1_IRL0);
156 }
157
158 /* Cascaded interrupts from IM2 */
159 static inline void amazon_hw2_irqdispatch(void)
160 {
161 u32 irq;
162
163 irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM2_VEC_MASK) >> 10;
164 do_IRQ(irq + INT_NUM_IM2_IRL0);
165 }
166
167 /* Cascaded interrupts from IM3 */
168 static inline void amazon_hw3_irqdispatch(void)
169 {
170 u32 irq;
171
172 irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM3_VEC_MASK) >> 15;
173 do_IRQ(irq + INT_NUM_IM3_IRL0);
174 }
175
176 /* Cascaded interrupts from IM4 */
177 static inline void amazon_hw4_irqdispatch(void)
178 {
179 u32 irq;
180
181 irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM4_VEC_MASK) >> 20;
182 do_IRQ(irq + INT_NUM_IM4_IRL0);
183 }
184
185 asmlinkage void plat_irq_dispatch(void)
186 {
187 unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
188 if (pending & CAUSEF_IP7){
189 do_IRQ(MIPS_CPU_TIMER_IRQ);
190 }
191 else if (pending & CAUSEF_IP2)
192 amazon_hw0_irqdispatch();
193 else if (pending & CAUSEF_IP3)
194 amazon_hw1_irqdispatch();
195 else if (pending & CAUSEF_IP4)
196 amazon_hw2_irqdispatch();
197 else if (pending & CAUSEF_IP5)
198 amazon_hw3_irqdispatch();
199 else if (pending & CAUSEF_IP6)
200 amazon_hw4_irqdispatch();
201 else
202 printk("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
203 }
204
205 static struct irqaction cascade = {
206 .handler = no_action,
207 .flags = SA_INTERRUPT,
208 .name = "cascade",
209 };
210
211
212 /* Function for careful CP0 interrupt mask access */
213
214 void __init arch_init_irq(void)
215 {
216 int i;
217
218 /* mask all interrupt sources */
219 *AMAZON_ICU_IM0_IER = 0;
220 *AMAZON_ICU_IM1_IER = 0;
221 *AMAZON_ICU_IM2_IER = 0;
222 *AMAZON_ICU_IM3_IER = 0;
223 *AMAZON_ICU_IM4_IER = 0;
224
225 mips_cpu_irq_init();
226
227 /* set up irq cascade */
228 for (i = 2; i <= 6; i++) {
229 setup_irq(i, &cascade);
230 }
231
232 for (i = INT_NUM_IRQ0; i <= INT_NUM_IM4_IRL31; i++) {
233 irq_desc[i].status = IRQ_DISABLED;
234 irq_desc[i].action = 0;
235 irq_desc[i].depth = 1;
236 set_irq_chip(i, &amazon_irq_type);
237 }
238 }