Pull ec into release branch
[sfrench/cifs-2.6.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/config.h>
27 #include <linux/errno.h>
28 #include <linux/init.h>
29 #include <linux/kernel_stat.h>
30 #include <linux/module.h>
31 #include <linux/signal.h>
32 #include <linux/sched.h>
33 #include <linux/types.h>
34 #include <linux/interrupt.h>
35 #include <linux/ioport.h>
36 #include <linux/timex.h>
37 #include <linux/slab.h>
38 #include <linux/random.h>
39 #include <linux/irq.h>
40 #include <linux/bitops.h>
41 #include <asm/bootinfo.h>
42 #include <asm/io.h>
43 #include <asm/irq.h>
44 #include <asm/mipsregs.h>
45 #include <asm/system.h>
46 #include <asm/tx4927/tx4927.h>
47
48 /*
49  * DEBUG
50  */
51
52 #undef TX4927_IRQ_DEBUG
53
54 #ifdef TX4927_IRQ_DEBUG
55 #define TX4927_IRQ_NONE        0x00000000
56
57 #define TX4927_IRQ_INFO        ( 1 <<  0 )
58 #define TX4927_IRQ_WARN        ( 1 <<  1 )
59 #define TX4927_IRQ_EROR        ( 1 <<  2 )
60
61 #define TX4927_IRQ_INIT        ( 1 <<  5 )
62 #define TX4927_IRQ_NEST1       ( 1 <<  6 )
63 #define TX4927_IRQ_NEST2       ( 1 <<  7 )
64 #define TX4927_IRQ_NEST3       ( 1 <<  8 )
65 #define TX4927_IRQ_NEST4       ( 1 <<  9 )
66
67 #define TX4927_IRQ_CP0_INIT     ( 1 << 10 )
68 #define TX4927_IRQ_CP0_STARTUP  ( 1 << 11 )
69 #define TX4927_IRQ_CP0_SHUTDOWN ( 1 << 12 )
70 #define TX4927_IRQ_CP0_ENABLE   ( 1 << 13 )
71 #define TX4927_IRQ_CP0_DISABLE  ( 1 << 14 )
72 #define TX4927_IRQ_CP0_MASK     ( 1 << 15 )
73 #define TX4927_IRQ_CP0_ENDIRQ   ( 1 << 16 )
74
75 #define TX4927_IRQ_PIC_INIT     ( 1 << 20 )
76 #define TX4927_IRQ_PIC_STARTUP  ( 1 << 21 )
77 #define TX4927_IRQ_PIC_SHUTDOWN ( 1 << 22 )
78 #define TX4927_IRQ_PIC_ENABLE   ( 1 << 23 )
79 #define TX4927_IRQ_PIC_DISABLE  ( 1 << 24 )
80 #define TX4927_IRQ_PIC_MASK     ( 1 << 25 )
81 #define TX4927_IRQ_PIC_ENDIRQ   ( 1 << 26 )
82
83 #define TX4927_IRQ_ALL         0xffffffff
84 #endif
85
86 #ifdef TX4927_IRQ_DEBUG
87 static const u32 tx4927_irq_debug_flag = (TX4927_IRQ_NONE
88                                           | TX4927_IRQ_INFO
89                                           | TX4927_IRQ_WARN | TX4927_IRQ_EROR
90 //                                       | TX4927_IRQ_CP0_INIT
91 //                                       | TX4927_IRQ_CP0_STARTUP
92 //                                       | TX4927_IRQ_CP0_SHUTDOWN
93 //                                       | TX4927_IRQ_CP0_ENABLE
94 //                                       | TX4927_IRQ_CP0_DISABLE
95 //                                       | TX4927_IRQ_CP0_MASK
96 //                                       | TX4927_IRQ_CP0_ENDIRQ
97 //                                       | TX4927_IRQ_PIC_INIT
98 //                                       | TX4927_IRQ_PIC_STARTUP
99 //                                       | TX4927_IRQ_PIC_SHUTDOWN
100 //                                       | TX4927_IRQ_PIC_ENABLE
101 //                                       | TX4927_IRQ_PIC_DISABLE
102 //                                       | TX4927_IRQ_PIC_MASK
103 //                                       | TX4927_IRQ_PIC_ENDIRQ
104 //                                       | TX4927_IRQ_INIT
105 //                                       | TX4927_IRQ_NEST1
106 //                                       | TX4927_IRQ_NEST2
107 //                                       | TX4927_IRQ_NEST3
108 //                                       | TX4927_IRQ_NEST4
109     );
110 #endif
111
112 #ifdef TX4927_IRQ_DEBUG
113 #define TX4927_IRQ_DPRINTK(flag,str...) \
114         if ( (tx4927_irq_debug_flag) & (flag) ) \
115         { \
116            char tmp[100]; \
117            sprintf( tmp, str ); \
118            printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \
119         }
120 #else
121 #define TX4927_IRQ_DPRINTK(flag,str...)
122 #endif
123
124 /*
125  * Forwad definitions for all pic's
126  */
127
128 static unsigned int tx4927_irq_cp0_startup(unsigned int irq);
129 static void tx4927_irq_cp0_shutdown(unsigned int irq);
130 static void tx4927_irq_cp0_enable(unsigned int irq);
131 static void tx4927_irq_cp0_disable(unsigned int irq);
132 static void tx4927_irq_cp0_mask_and_ack(unsigned int irq);
133 static void tx4927_irq_cp0_end(unsigned int irq);
134
135 static unsigned int tx4927_irq_pic_startup(unsigned int irq);
136 static void tx4927_irq_pic_shutdown(unsigned int irq);
137 static void tx4927_irq_pic_enable(unsigned int irq);
138 static void tx4927_irq_pic_disable(unsigned int irq);
139 static void tx4927_irq_pic_mask_and_ack(unsigned int irq);
140 static void tx4927_irq_pic_end(unsigned int irq);
141
142 /*
143  * Kernel structs for all pic's
144  */
145
146 static DEFINE_SPINLOCK(tx4927_cp0_lock);
147 static DEFINE_SPINLOCK(tx4927_pic_lock);
148
149 #define TX4927_CP0_NAME "TX4927-CP0"
150 static struct hw_interrupt_type tx4927_irq_cp0_type = {
151         .typename       = TX4927_CP0_NAME,
152         .startup        = tx4927_irq_cp0_startup,
153         .shutdown       = tx4927_irq_cp0_shutdown,
154         .enable         = tx4927_irq_cp0_enable,
155         .disable        = tx4927_irq_cp0_disable,
156         .ack            = tx4927_irq_cp0_mask_and_ack,
157         .end            = tx4927_irq_cp0_end,
158         .set_affinity   = NULL
159 };
160
161 #define TX4927_PIC_NAME "TX4927-PIC"
162 static struct hw_interrupt_type tx4927_irq_pic_type = {
163         .typename       = TX4927_PIC_NAME,
164         .startup        = tx4927_irq_pic_startup,
165         .shutdown       = tx4927_irq_pic_shutdown,
166         .enable         = tx4927_irq_pic_enable,
167         .disable        = tx4927_irq_pic_disable,
168         .ack            = tx4927_irq_pic_mask_and_ack,
169         .end            = tx4927_irq_pic_end,
170         .set_affinity   = NULL
171 };
172
173 #define TX4927_PIC_ACTION(s) { no_action, 0, CPU_MASK_NONE, s, NULL, NULL }
174 static struct irqaction tx4927_irq_pic_action =
175 TX4927_PIC_ACTION(TX4927_PIC_NAME);
176
177 #define CCP0_STATUS 12
178 #define CCP0_CAUSE 13
179
180 /*
181  * Functions for cp0
182  */
183
184 #define tx4927_irq_cp0_mask(irq) ( 1 << ( irq-TX4927_IRQ_CP0_BEG+8 ) )
185
186 static void
187 tx4927_irq_cp0_modify(unsigned cp0_reg, unsigned clr_bits, unsigned set_bits)
188 {
189         unsigned long val = 0;
190
191         switch (cp0_reg) {
192         case CCP0_STATUS:
193                 val = read_c0_status();
194                 break;
195
196         case CCP0_CAUSE:
197                 val = read_c0_cause();
198                 break;
199
200         }
201
202         val &= (~clr_bits);
203         val |= (set_bits);
204
205         switch (cp0_reg) {
206         case CCP0_STATUS:{
207                         write_c0_status(val);
208                         break;
209                 }
210         case CCP0_CAUSE:{
211                         write_c0_cause(val);
212                         break;
213                 }
214         }
215
216         return;
217 }
218
219 static void __init tx4927_irq_cp0_init(void)
220 {
221         int i;
222
223         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_INIT, "beg=%d end=%d\n",
224                            TX4927_IRQ_CP0_BEG, TX4927_IRQ_CP0_END);
225
226         for (i = TX4927_IRQ_CP0_BEG; i <= TX4927_IRQ_CP0_END; i++) {
227                 irq_desc[i].status = IRQ_DISABLED;
228                 irq_desc[i].action = 0;
229                 irq_desc[i].depth = 1;
230                 irq_desc[i].handler = &tx4927_irq_cp0_type;
231         }
232
233         return;
234 }
235
236 static unsigned int tx4927_irq_cp0_startup(unsigned int irq)
237 {
238         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_STARTUP, "irq=%d \n", irq);
239
240         tx4927_irq_cp0_enable(irq);
241
242         return (0);
243 }
244
245 static void tx4927_irq_cp0_shutdown(unsigned int irq)
246 {
247         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_SHUTDOWN, "irq=%d \n", irq);
248
249         tx4927_irq_cp0_disable(irq);
250
251         return;
252 }
253
254 static void tx4927_irq_cp0_enable(unsigned int irq)
255 {
256         unsigned long flags;
257
258         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_ENABLE, "irq=%d \n", irq);
259
260         spin_lock_irqsave(&tx4927_cp0_lock, flags);
261
262         tx4927_irq_cp0_modify(CCP0_STATUS, 0, tx4927_irq_cp0_mask(irq));
263
264         spin_unlock_irqrestore(&tx4927_cp0_lock, flags);
265
266         return;
267 }
268
269 static void tx4927_irq_cp0_disable(unsigned int irq)
270 {
271         unsigned long flags;
272
273         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_DISABLE, "irq=%d \n", irq);
274
275         spin_lock_irqsave(&tx4927_cp0_lock, flags);
276
277         tx4927_irq_cp0_modify(CCP0_STATUS, tx4927_irq_cp0_mask(irq), 0);
278
279         spin_unlock_irqrestore(&tx4927_cp0_lock, flags);
280
281         return;
282 }
283
284 static void tx4927_irq_cp0_mask_and_ack(unsigned int irq)
285 {
286         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_MASK, "irq=%d \n", irq);
287
288         tx4927_irq_cp0_disable(irq);
289
290         return;
291 }
292
293 static void tx4927_irq_cp0_end(unsigned int irq)
294 {
295         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_ENDIRQ, "irq=%d \n", irq);
296
297         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
298                 tx4927_irq_cp0_enable(irq);
299         }
300
301         return;
302 }
303
304 /*
305  * Functions for pic
306  */
307 u32 tx4927_irq_pic_addr(int irq)
308 {
309         /* MVMCP -- need to formulize this */
310         irq -= TX4927_IRQ_PIC_BEG;
311         switch (irq) {
312         case 17:
313         case 16:
314         case 1:
315         case 0:
316                 return (0xff1ff610);
317
318         case 19:
319         case 18:
320         case 3:
321         case 2:
322                 return (0xff1ff614);
323
324         case 21:
325         case 20:
326         case 5:
327         case 4:
328                 return (0xff1ff618);
329
330         case 23:
331         case 22:
332         case 7:
333         case 6:
334                 return (0xff1ff61c);
335
336         case 25:
337         case 24:
338         case 9:
339         case 8:
340                 return (0xff1ff620);
341
342         case 27:
343         case 26:
344         case 11:
345         case 10:
346                 return (0xff1ff624);
347
348         case 29:
349         case 28:
350         case 13:
351         case 12:
352                 return (0xff1ff628);
353
354         case 31:
355         case 30:
356         case 15:
357         case 14:
358                 return (0xff1ff62c);
359
360         }
361         return (0);
362 }
363
364 u32 tx4927_irq_pic_mask(int irq)
365 {
366         /* MVMCP -- need to formulize this */
367         irq -= TX4927_IRQ_PIC_BEG;
368         switch (irq) {
369         case 31:
370         case 29:
371         case 27:
372         case 25:
373         case 23:
374         case 21:
375         case 19:
376         case 17:{
377                         return (0x07000000);
378                 }
379         case 30:
380         case 28:
381         case 26:
382         case 24:
383         case 22:
384         case 20:
385         case 18:
386         case 16:{
387                         return (0x00070000);
388                 }
389         case 15:
390         case 13:
391         case 11:
392         case 9:
393         case 7:
394         case 5:
395         case 3:
396         case 1:{
397                         return (0x00000700);
398                 }
399         case 14:
400         case 12:
401         case 10:
402         case 8:
403         case 6:
404         case 4:
405         case 2:
406         case 0:{
407                         return (0x00000007);
408                 }
409         }
410         return (0x00000000);
411 }
412
413 static void tx4927_irq_pic_modify(unsigned pic_reg, unsigned clr_bits,
414         unsigned set_bits)
415 {
416         unsigned long val = 0;
417
418         val = TX4927_RD(pic_reg);
419         val &= (~clr_bits);
420         val |= (set_bits);
421         TX4927_WR(pic_reg, val);
422
423         return;
424 }
425
426 static void __init tx4927_irq_pic_init(void)
427 {
428         unsigned long flags;
429         int i;
430
431         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_INIT, "beg=%d end=%d\n",
432                            TX4927_IRQ_PIC_BEG, TX4927_IRQ_PIC_END);
433
434         for (i = TX4927_IRQ_PIC_BEG; i <= TX4927_IRQ_PIC_END; i++) {
435                 irq_desc[i].status = IRQ_DISABLED;
436                 irq_desc[i].action = 0;
437                 irq_desc[i].depth = 2;
438                 irq_desc[i].handler = &tx4927_irq_pic_type;
439         }
440
441         setup_irq(TX4927_IRQ_NEST_PIC_ON_CP0, &tx4927_irq_pic_action);
442
443         spin_lock_irqsave(&tx4927_pic_lock, flags);
444
445         TX4927_WR(0xff1ff640, 0x6);     /* irq level mask -- only accept hightest */
446         TX4927_WR(0xff1ff600, TX4927_RD(0xff1ff600) | 0x1);     /* irq enable */
447
448         spin_unlock_irqrestore(&tx4927_pic_lock, flags);
449
450         return;
451 }
452
453 static unsigned int tx4927_irq_pic_startup(unsigned int irq)
454 {
455         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_STARTUP, "irq=%d\n", irq);
456
457         tx4927_irq_pic_enable(irq);
458
459         return (0);
460 }
461
462 static void tx4927_irq_pic_shutdown(unsigned int irq)
463 {
464         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_SHUTDOWN, "irq=%d\n", irq);
465
466         tx4927_irq_pic_disable(irq);
467
468         return;
469 }
470
471 static void tx4927_irq_pic_enable(unsigned int irq)
472 {
473         unsigned long flags;
474
475         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_ENABLE, "irq=%d\n", irq);
476
477         spin_lock_irqsave(&tx4927_pic_lock, flags);
478
479         tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq), 0,
480                               tx4927_irq_pic_mask(irq));
481
482         spin_unlock_irqrestore(&tx4927_pic_lock, flags);
483
484         return;
485 }
486
487 static void tx4927_irq_pic_disable(unsigned int irq)
488 {
489         unsigned long flags;
490
491         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_DISABLE, "irq=%d\n", irq);
492
493         spin_lock_irqsave(&tx4927_pic_lock, flags);
494
495         tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq),
496                               tx4927_irq_pic_mask(irq), 0);
497
498         spin_unlock_irqrestore(&tx4927_pic_lock, flags);
499
500         return;
501 }
502
503 static void tx4927_irq_pic_mask_and_ack(unsigned int irq)
504 {
505         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_MASK, "irq=%d\n", irq);
506
507         tx4927_irq_pic_disable(irq);
508
509         return;
510 }
511
512 static void tx4927_irq_pic_end(unsigned int irq)
513 {
514         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_ENDIRQ, "irq=%d\n", irq);
515
516         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
517                 tx4927_irq_pic_enable(irq);
518         }
519
520         return;
521 }
522
523 /*
524  * Main init functions
525  */
526 void __init tx4927_irq_init(void)
527 {
528         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "-\n");
529
530         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_cp0_init()\n");
531         tx4927_irq_cp0_init();
532
533         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_pic_init()\n");
534         tx4927_irq_pic_init();
535
536         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "+\n");
537
538         return;
539 }
540
541 static int tx4927_irq_nested(void)
542 {
543         int sw_irq = 0;
544         u32 level2;
545
546         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "-\n");
547
548         level2 = TX4927_RD(0xff1ff6a0);
549         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=level2a=0x%x\n", level2);
550
551         if ((level2 & 0x10000) == 0) {
552                 level2 &= 0x1f;
553                 TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=level2b=0x%x\n", level2);
554
555                 sw_irq = TX4927_IRQ_PIC_BEG + level2;
556                 TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=sw_irq=%d\n", sw_irq);
557
558                 if (sw_irq == 27) {
559                         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq-%d\n",
560                                            sw_irq);
561
562 #ifdef CONFIG_TOSHIBA_RBTX4927
563                         {
564                                 sw_irq = toshiba_rbtx4927_irq_nested(sw_irq);
565                         }
566 #endif
567
568                         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq+%d\n",
569                                            sw_irq);
570                 }
571         }
572
573         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=sw_irq=%d\n", sw_irq);
574
575         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "+\n");
576
577         return (sw_irq);
578 }
579
580 asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
581 {
582         unsigned int pending = read_c0_status() & read_c0_cause();
583
584         if (pending & STATUSF_IP7)                      /* cpu timer */
585                 do_IRQ(TX4927_IRQ_CPU_TIMER, regs);
586         else if (pending & STATUSF_IP2) {               /* tx4927 pic */
587                 unsigned int irq = tx4927_irq_nested();
588
589                 if (unlikely(irq == 0)) {
590                         spurious_interrupt(regs);
591                         return;
592                 }
593                 do_IRQ(irq, regs);
594         } else if (pending & STATUSF_IP0)               /* user line 0 */
595                 do_IRQ(TX4927_IRQ_USER0, regs);
596         else if (pending & STATUSF_IP1)                 /* user line 1 */
597                 do_IRQ(TX4927_IRQ_USER1, regs);
598         else
599                 spurious_interrupt(regs);
600 }