6702ecf3d9f814b0d0c38563788366acdca81885
[librecmc/librecmc.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 }