Pull sony into release branch
[pandora-kernel.git] / arch / mips / tx4927 / common / tx4927_irq.c
1 /*
2  * Common tx4927 irq handler
3  *
4  * Author: MontaVista Software, Inc.
5  *         source@mvista.com
6  *
7  *  under the terms of the GNU General Public License as published by the
8  *  Free Software Foundation; either version 2 of the License, or (at your
9  *  option) any later version.
10  *
11  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
12  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
13  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
15  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
16  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
17  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
18  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
19  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
20  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21  *
22  *  You should have received a copy of the GNU General Public License along
23  *  with this program; if not, write to the Free Software Foundation, Inc.,
24  *  675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26 #include <linux/errno.h>
27 #include <linux/init.h>
28 #include <linux/kernel_stat.h>
29 #include <linux/module.h>
30 #include <linux/signal.h>
31 #include <linux/sched.h>
32 #include <linux/types.h>
33 #include <linux/interrupt.h>
34 #include <linux/ioport.h>
35 #include <linux/timex.h>
36 #include <linux/slab.h>
37 #include <linux/random.h>
38 #include <linux/irq.h>
39 #include <linux/bitops.h>
40 #include <asm/bootinfo.h>
41 #include <asm/io.h>
42 #include <asm/irq.h>
43 #include <asm/mipsregs.h>
44 #include <asm/system.h>
45 #include <asm/tx4927/tx4927.h>
46
47 /*
48  * DEBUG
49  */
50
51 #undef TX4927_IRQ_DEBUG
52
53 #ifdef TX4927_IRQ_DEBUG
54 #define TX4927_IRQ_NONE        0x00000000
55
56 #define TX4927_IRQ_INFO        ( 1 <<  0 )
57 #define TX4927_IRQ_WARN        ( 1 <<  1 )
58 #define TX4927_IRQ_EROR        ( 1 <<  2 )
59
60 #define TX4927_IRQ_INIT        ( 1 <<  5 )
61 #define TX4927_IRQ_NEST1       ( 1 <<  6 )
62 #define TX4927_IRQ_NEST2       ( 1 <<  7 )
63 #define TX4927_IRQ_NEST3       ( 1 <<  8 )
64 #define TX4927_IRQ_NEST4       ( 1 <<  9 )
65
66 #define TX4927_IRQ_CP0_INIT     ( 1 << 10 )
67 #define TX4927_IRQ_CP0_ENABLE   ( 1 << 13 )
68 #define TX4927_IRQ_CP0_DISABLE  ( 1 << 14 )
69
70 #define TX4927_IRQ_PIC_INIT     ( 1 << 20 )
71 #define TX4927_IRQ_PIC_ENABLE   ( 1 << 23 )
72 #define TX4927_IRQ_PIC_DISABLE  ( 1 << 24 )
73
74 #define TX4927_IRQ_ALL         0xffffffff
75 #endif
76
77 #ifdef TX4927_IRQ_DEBUG
78 static const u32 tx4927_irq_debug_flag = (TX4927_IRQ_NONE
79                                           | TX4927_IRQ_INFO
80                                           | TX4927_IRQ_WARN | TX4927_IRQ_EROR
81 //                                       | TX4927_IRQ_CP0_INIT
82 //                                       | TX4927_IRQ_CP0_ENABLE
83 //                                       | TX4927_IRQ_CP0_ENDIRQ
84 //                                       | TX4927_IRQ_PIC_INIT
85 //                                       | TX4927_IRQ_PIC_ENABLE
86 //                                       | TX4927_IRQ_PIC_DISABLE
87 //                                       | TX4927_IRQ_INIT
88 //                                       | TX4927_IRQ_NEST1
89 //                                       | TX4927_IRQ_NEST2
90 //                                       | TX4927_IRQ_NEST3
91 //                                       | TX4927_IRQ_NEST4
92     );
93 #endif
94
95 #ifdef TX4927_IRQ_DEBUG
96 #define TX4927_IRQ_DPRINTK(flag,str...) \
97         if ( (tx4927_irq_debug_flag) & (flag) ) \
98         { \
99            char tmp[100]; \
100            sprintf( tmp, str ); \
101            printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \
102         }
103 #else
104 #define TX4927_IRQ_DPRINTK(flag,str...)
105 #endif
106
107 /*
108  * Forwad definitions for all pic's
109  */
110
111 static void tx4927_irq_cp0_enable(unsigned int irq);
112 static void tx4927_irq_cp0_disable(unsigned int irq);
113
114 static void tx4927_irq_pic_enable(unsigned int irq);
115 static void tx4927_irq_pic_disable(unsigned int irq);
116
117 /*
118  * Kernel structs for all pic's
119  */
120
121 #define TX4927_CP0_NAME "TX4927-CP0"
122 static struct irq_chip tx4927_irq_cp0_type = {
123         .name           = TX4927_CP0_NAME,
124         .ack            = tx4927_irq_cp0_disable,
125         .mask           = tx4927_irq_cp0_disable,
126         .mask_ack       = tx4927_irq_cp0_disable,
127         .unmask         = tx4927_irq_cp0_enable,
128 };
129
130 #define TX4927_PIC_NAME "TX4927-PIC"
131 static struct irq_chip tx4927_irq_pic_type = {
132         .name           = TX4927_PIC_NAME,
133         .ack            = tx4927_irq_pic_disable,
134         .mask           = tx4927_irq_pic_disable,
135         .mask_ack       = tx4927_irq_pic_disable,
136         .unmask         = tx4927_irq_pic_enable,
137 };
138
139 #define TX4927_PIC_ACTION(s) { no_action, 0, CPU_MASK_NONE, s, NULL, NULL }
140 static struct irqaction tx4927_irq_pic_action =
141 TX4927_PIC_ACTION(TX4927_PIC_NAME);
142
143 #define CCP0_STATUS 12
144 #define CCP0_CAUSE 13
145
146 /*
147  * Functions for cp0
148  */
149
150 #define tx4927_irq_cp0_mask(irq) ( 1 << ( irq-TX4927_IRQ_CP0_BEG+8 ) )
151
152 static void
153 tx4927_irq_cp0_modify(unsigned cp0_reg, unsigned clr_bits, unsigned set_bits)
154 {
155         unsigned long val = 0;
156
157         switch (cp0_reg) {
158         case CCP0_STATUS:
159                 val = read_c0_status();
160                 break;
161
162         case CCP0_CAUSE:
163                 val = read_c0_cause();
164                 break;
165
166         }
167
168         val &= (~clr_bits);
169         val |= (set_bits);
170
171         switch (cp0_reg) {
172         case CCP0_STATUS:{
173                         write_c0_status(val);
174                         break;
175                 }
176         case CCP0_CAUSE:{
177                         write_c0_cause(val);
178                         break;
179                 }
180         }
181 }
182
183 static void __init tx4927_irq_cp0_init(void)
184 {
185         int i;
186
187         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_INIT, "beg=%d end=%d\n",
188                            TX4927_IRQ_CP0_BEG, TX4927_IRQ_CP0_END);
189
190         for (i = TX4927_IRQ_CP0_BEG; i <= TX4927_IRQ_CP0_END; i++)
191                 set_irq_chip_and_handler(i, &tx4927_irq_cp0_type,
192                                          handle_level_irq);
193 }
194
195 static void tx4927_irq_cp0_enable(unsigned int irq)
196 {
197         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_ENABLE, "irq=%d \n", irq);
198
199         tx4927_irq_cp0_modify(CCP0_STATUS, 0, tx4927_irq_cp0_mask(irq));
200 }
201
202 static void tx4927_irq_cp0_disable(unsigned int irq)
203 {
204         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_DISABLE, "irq=%d \n", irq);
205
206         tx4927_irq_cp0_modify(CCP0_STATUS, tx4927_irq_cp0_mask(irq), 0);
207 }
208
209 /*
210  * Functions for pic
211  */
212 u32 tx4927_irq_pic_addr(int irq)
213 {
214         /* MVMCP -- need to formulize this */
215         irq -= TX4927_IRQ_PIC_BEG;
216         switch (irq) {
217         case 17:
218         case 16:
219         case 1:
220         case 0:
221                 return (0xff1ff610);
222
223         case 19:
224         case 18:
225         case 3:
226         case 2:
227                 return (0xff1ff614);
228
229         case 21:
230         case 20:
231         case 5:
232         case 4:
233                 return (0xff1ff618);
234
235         case 23:
236         case 22:
237         case 7:
238         case 6:
239                 return (0xff1ff61c);
240
241         case 25:
242         case 24:
243         case 9:
244         case 8:
245                 return (0xff1ff620);
246
247         case 27:
248         case 26:
249         case 11:
250         case 10:
251                 return (0xff1ff624);
252
253         case 29:
254         case 28:
255         case 13:
256         case 12:
257                 return (0xff1ff628);
258
259         case 31:
260         case 30:
261         case 15:
262         case 14:
263                 return (0xff1ff62c);
264
265         }
266         return (0);
267 }
268
269 u32 tx4927_irq_pic_mask(int irq)
270 {
271         /* MVMCP -- need to formulize this */
272         irq -= TX4927_IRQ_PIC_BEG;
273         switch (irq) {
274         case 31:
275         case 29:
276         case 27:
277         case 25:
278         case 23:
279         case 21:
280         case 19:
281         case 17:{
282                         return (0x07000000);
283                 }
284         case 30:
285         case 28:
286         case 26:
287         case 24:
288         case 22:
289         case 20:
290         case 18:
291         case 16:{
292                         return (0x00070000);
293                 }
294         case 15:
295         case 13:
296         case 11:
297         case 9:
298         case 7:
299         case 5:
300         case 3:
301         case 1:{
302                         return (0x00000700);
303                 }
304         case 14:
305         case 12:
306         case 10:
307         case 8:
308         case 6:
309         case 4:
310         case 2:
311         case 0:{
312                         return (0x00000007);
313                 }
314         }
315         return (0x00000000);
316 }
317
318 static void tx4927_irq_pic_modify(unsigned pic_reg, unsigned clr_bits,
319         unsigned set_bits)
320 {
321         unsigned long val = 0;
322
323         val = TX4927_RD(pic_reg);
324         val &= (~clr_bits);
325         val |= (set_bits);
326         TX4927_WR(pic_reg, val);
327 }
328
329 static void __init tx4927_irq_pic_init(void)
330 {
331         int i;
332
333         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_INIT, "beg=%d end=%d\n",
334                            TX4927_IRQ_PIC_BEG, TX4927_IRQ_PIC_END);
335
336         for (i = TX4927_IRQ_PIC_BEG; i <= TX4927_IRQ_PIC_END; i++)
337                 set_irq_chip_and_handler(i, &tx4927_irq_pic_type,
338                                          handle_level_irq);
339
340         setup_irq(TX4927_IRQ_NEST_PIC_ON_CP0, &tx4927_irq_pic_action);
341
342         TX4927_WR(0xff1ff640, 0x6);     /* irq level mask -- only accept hightest */
343         TX4927_WR(0xff1ff600, TX4927_RD(0xff1ff600) | 0x1);     /* irq enable */
344 }
345
346 static void tx4927_irq_pic_enable(unsigned int irq)
347 {
348         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_ENABLE, "irq=%d\n", irq);
349
350         tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq), 0,
351                               tx4927_irq_pic_mask(irq));
352 }
353
354 static void tx4927_irq_pic_disable(unsigned int irq)
355 {
356         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_DISABLE, "irq=%d\n", irq);
357
358         tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq),
359                               tx4927_irq_pic_mask(irq), 0);
360 }
361
362 /*
363  * Main init functions
364  */
365 void __init tx4927_irq_init(void)
366 {
367         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "-\n");
368
369         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_cp0_init()\n");
370         tx4927_irq_cp0_init();
371
372         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_pic_init()\n");
373         tx4927_irq_pic_init();
374
375         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "+\n");
376 }
377
378 static int tx4927_irq_nested(void)
379 {
380         int sw_irq = 0;
381         u32 level2;
382
383         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "-\n");
384
385         level2 = TX4927_RD(0xff1ff6a0);
386         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=level2a=0x%x\n", level2);
387
388         if ((level2 & 0x10000) == 0) {
389                 level2 &= 0x1f;
390                 TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=level2b=0x%x\n", level2);
391
392                 sw_irq = TX4927_IRQ_PIC_BEG + level2;
393                 TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=sw_irq=%d\n", sw_irq);
394
395                 if (sw_irq == 27) {
396                         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq-%d\n",
397                                            sw_irq);
398
399 #ifdef CONFIG_TOSHIBA_RBTX4927
400                         {
401                                 sw_irq = toshiba_rbtx4927_irq_nested(sw_irq);
402                         }
403 #endif
404
405                         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq+%d\n",
406                                            sw_irq);
407                 }
408         }
409
410         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=sw_irq=%d\n", sw_irq);
411
412         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "+\n");
413
414         return (sw_irq);
415 }
416
417 asmlinkage void plat_irq_dispatch(void)
418 {
419         unsigned int pending = read_c0_status() & read_c0_cause();
420
421         if (pending & STATUSF_IP7)                      /* cpu timer */
422                 do_IRQ(TX4927_IRQ_CPU_TIMER);
423         else if (pending & STATUSF_IP2) {               /* tx4927 pic */
424                 unsigned int irq = tx4927_irq_nested();
425
426                 if (unlikely(irq == 0)) {
427                         spurious_interrupt();
428                         return;
429                 }
430                 do_IRQ(irq);
431         } else if (pending & STATUSF_IP0)               /* user line 0 */
432                 do_IRQ(TX4927_IRQ_USER0);
433         else if (pending & STATUSF_IP1)                 /* user line 1 */
434                 do_IRQ(TX4927_IRQ_USER1);
435         else
436                 spurious_interrupt();
437 }