Merge git://git.infradead.org/battery-2.6
[linux-2.6] / 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 #ifdef CONFIG_TOSHIBA_RBTX4927
47 #include <asm/tx4927/toshiba_rbtx4927.h>
48 #endif
49
50 /*
51  * DEBUG
52  */
53
54 #undef TX4927_IRQ_DEBUG
55
56 #ifdef TX4927_IRQ_DEBUG
57 #define TX4927_IRQ_NONE        0x00000000
58
59 #define TX4927_IRQ_INFO        ( 1 <<  0 )
60 #define TX4927_IRQ_WARN        ( 1 <<  1 )
61 #define TX4927_IRQ_EROR        ( 1 <<  2 )
62
63 #define TX4927_IRQ_INIT        ( 1 <<  5 )
64 #define TX4927_IRQ_NEST1       ( 1 <<  6 )
65 #define TX4927_IRQ_NEST2       ( 1 <<  7 )
66 #define TX4927_IRQ_NEST3       ( 1 <<  8 )
67 #define TX4927_IRQ_NEST4       ( 1 <<  9 )
68
69 #define TX4927_IRQ_CP0_INIT     ( 1 << 10 )
70 #define TX4927_IRQ_CP0_ENABLE   ( 1 << 13 )
71 #define TX4927_IRQ_CP0_DISABLE  ( 1 << 14 )
72
73 #define TX4927_IRQ_PIC_INIT     ( 1 << 20 )
74 #define TX4927_IRQ_PIC_ENABLE   ( 1 << 23 )
75 #define TX4927_IRQ_PIC_DISABLE  ( 1 << 24 )
76
77 #define TX4927_IRQ_ALL         0xffffffff
78 #endif
79
80 #ifdef TX4927_IRQ_DEBUG
81 static const u32 tx4927_irq_debug_flag = (TX4927_IRQ_NONE
82                                           | TX4927_IRQ_INFO
83                                           | TX4927_IRQ_WARN | TX4927_IRQ_EROR
84 //                                       | TX4927_IRQ_CP0_INIT
85 //                                       | TX4927_IRQ_CP0_ENABLE
86 //                                       | TX4927_IRQ_CP0_ENDIRQ
87 //                                       | TX4927_IRQ_PIC_INIT
88 //                                       | TX4927_IRQ_PIC_ENABLE
89 //                                       | TX4927_IRQ_PIC_DISABLE
90 //                                       | TX4927_IRQ_INIT
91 //                                       | TX4927_IRQ_NEST1
92 //                                       | TX4927_IRQ_NEST2
93 //                                       | TX4927_IRQ_NEST3
94 //                                       | TX4927_IRQ_NEST4
95     );
96 #endif
97
98 #ifdef TX4927_IRQ_DEBUG
99 #define TX4927_IRQ_DPRINTK(flag,str...) \
100         if ( (tx4927_irq_debug_flag) & (flag) ) \
101         { \
102            char tmp[100]; \
103            sprintf( tmp, str ); \
104            printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \
105         }
106 #else
107 #define TX4927_IRQ_DPRINTK(flag,str...)
108 #endif
109
110 /*
111  * Forwad definitions for all pic's
112  */
113
114 static void tx4927_irq_cp0_enable(unsigned int irq);
115 static void tx4927_irq_cp0_disable(unsigned int irq);
116
117 static void tx4927_irq_pic_enable(unsigned int irq);
118 static void tx4927_irq_pic_disable(unsigned int irq);
119
120 /*
121  * Kernel structs for all pic's
122  */
123
124 #define TX4927_CP0_NAME "TX4927-CP0"
125 static struct irq_chip tx4927_irq_cp0_type = {
126         .name           = TX4927_CP0_NAME,
127         .ack            = tx4927_irq_cp0_disable,
128         .mask           = tx4927_irq_cp0_disable,
129         .mask_ack       = tx4927_irq_cp0_disable,
130         .unmask         = tx4927_irq_cp0_enable,
131 };
132
133 #define TX4927_PIC_NAME "TX4927-PIC"
134 static struct irq_chip tx4927_irq_pic_type = {
135         .name           = TX4927_PIC_NAME,
136         .ack            = tx4927_irq_pic_disable,
137         .mask           = tx4927_irq_pic_disable,
138         .mask_ack       = tx4927_irq_pic_disable,
139         .unmask         = tx4927_irq_pic_enable,
140 };
141
142 #define TX4927_PIC_ACTION(s) { no_action, 0, CPU_MASK_NONE, s, NULL, NULL }
143 static struct irqaction tx4927_irq_pic_action =
144 TX4927_PIC_ACTION(TX4927_PIC_NAME);
145
146 #define CCP0_STATUS 12
147 #define CCP0_CAUSE 13
148
149 /*
150  * Functions for cp0
151  */
152
153 #define tx4927_irq_cp0_mask(irq) ( 1 << ( irq-TX4927_IRQ_CP0_BEG+8 ) )
154
155 static void
156 tx4927_irq_cp0_modify(unsigned cp0_reg, unsigned clr_bits, unsigned set_bits)
157 {
158         unsigned long val = 0;
159
160         switch (cp0_reg) {
161         case CCP0_STATUS:
162                 val = read_c0_status();
163                 break;
164
165         case CCP0_CAUSE:
166                 val = read_c0_cause();
167                 break;
168
169         }
170
171         val &= (~clr_bits);
172         val |= (set_bits);
173
174         switch (cp0_reg) {
175         case CCP0_STATUS:{
176                         write_c0_status(val);
177                         break;
178                 }
179         case CCP0_CAUSE:{
180                         write_c0_cause(val);
181                         break;
182                 }
183         }
184 }
185
186 static void __init tx4927_irq_cp0_init(void)
187 {
188         int i;
189
190         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_INIT, "beg=%d end=%d\n",
191                            TX4927_IRQ_CP0_BEG, TX4927_IRQ_CP0_END);
192
193         for (i = TX4927_IRQ_CP0_BEG; i <= TX4927_IRQ_CP0_END; i++)
194                 set_irq_chip_and_handler(i, &tx4927_irq_cp0_type,
195                                          handle_level_irq);
196 }
197
198 static void tx4927_irq_cp0_enable(unsigned int irq)
199 {
200         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_ENABLE, "irq=%d \n", irq);
201
202         tx4927_irq_cp0_modify(CCP0_STATUS, 0, tx4927_irq_cp0_mask(irq));
203 }
204
205 static void tx4927_irq_cp0_disable(unsigned int irq)
206 {
207         TX4927_IRQ_DPRINTK(TX4927_IRQ_CP0_DISABLE, "irq=%d \n", irq);
208
209         tx4927_irq_cp0_modify(CCP0_STATUS, tx4927_irq_cp0_mask(irq), 0);
210 }
211
212 /*
213  * Functions for pic
214  */
215 u32 tx4927_irq_pic_addr(int irq)
216 {
217         /* MVMCP -- need to formulize this */
218         irq -= TX4927_IRQ_PIC_BEG;
219         switch (irq) {
220         case 17:
221         case 16:
222         case 1:
223         case 0:
224                 return (0xff1ff610);
225
226         case 19:
227         case 18:
228         case 3:
229         case 2:
230                 return (0xff1ff614);
231
232         case 21:
233         case 20:
234         case 5:
235         case 4:
236                 return (0xff1ff618);
237
238         case 23:
239         case 22:
240         case 7:
241         case 6:
242                 return (0xff1ff61c);
243
244         case 25:
245         case 24:
246         case 9:
247         case 8:
248                 return (0xff1ff620);
249
250         case 27:
251         case 26:
252         case 11:
253         case 10:
254                 return (0xff1ff624);
255
256         case 29:
257         case 28:
258         case 13:
259         case 12:
260                 return (0xff1ff628);
261
262         case 31:
263         case 30:
264         case 15:
265         case 14:
266                 return (0xff1ff62c);
267
268         }
269         return (0);
270 }
271
272 u32 tx4927_irq_pic_mask(int irq)
273 {
274         /* MVMCP -- need to formulize this */
275         irq -= TX4927_IRQ_PIC_BEG;
276         switch (irq) {
277         case 31:
278         case 29:
279         case 27:
280         case 25:
281         case 23:
282         case 21:
283         case 19:
284         case 17:{
285                         return (0x07000000);
286                 }
287         case 30:
288         case 28:
289         case 26:
290         case 24:
291         case 22:
292         case 20:
293         case 18:
294         case 16:{
295                         return (0x00070000);
296                 }
297         case 15:
298         case 13:
299         case 11:
300         case 9:
301         case 7:
302         case 5:
303         case 3:
304         case 1:{
305                         return (0x00000700);
306                 }
307         case 14:
308         case 12:
309         case 10:
310         case 8:
311         case 6:
312         case 4:
313         case 2:
314         case 0:{
315                         return (0x00000007);
316                 }
317         }
318         return (0x00000000);
319 }
320
321 static void tx4927_irq_pic_modify(unsigned pic_reg, unsigned clr_bits,
322         unsigned set_bits)
323 {
324         unsigned long val = 0;
325
326         val = TX4927_RD(pic_reg);
327         val &= (~clr_bits);
328         val |= (set_bits);
329         TX4927_WR(pic_reg, val);
330 }
331
332 static void __init tx4927_irq_pic_init(void)
333 {
334         int i;
335
336         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_INIT, "beg=%d end=%d\n",
337                            TX4927_IRQ_PIC_BEG, TX4927_IRQ_PIC_END);
338
339         for (i = TX4927_IRQ_PIC_BEG; i <= TX4927_IRQ_PIC_END; i++)
340                 set_irq_chip_and_handler(i, &tx4927_irq_pic_type,
341                                          handle_level_irq);
342
343         setup_irq(TX4927_IRQ_NEST_PIC_ON_CP0, &tx4927_irq_pic_action);
344
345         TX4927_WR(0xff1ff640, 0x6);     /* irq level mask -- only accept hightest */
346         TX4927_WR(0xff1ff600, TX4927_RD(0xff1ff600) | 0x1);     /* irq enable */
347 }
348
349 static void tx4927_irq_pic_enable(unsigned int irq)
350 {
351         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_ENABLE, "irq=%d\n", irq);
352
353         tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq), 0,
354                               tx4927_irq_pic_mask(irq));
355 }
356
357 static void tx4927_irq_pic_disable(unsigned int irq)
358 {
359         TX4927_IRQ_DPRINTK(TX4927_IRQ_PIC_DISABLE, "irq=%d\n", irq);
360
361         tx4927_irq_pic_modify(tx4927_irq_pic_addr(irq),
362                               tx4927_irq_pic_mask(irq), 0);
363 }
364
365 /*
366  * Main init functions
367  */
368 void __init tx4927_irq_init(void)
369 {
370         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "-\n");
371
372         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_cp0_init()\n");
373         tx4927_irq_cp0_init();
374
375         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_pic_init()\n");
376         tx4927_irq_pic_init();
377
378         TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "+\n");
379 }
380
381 static int tx4927_irq_nested(void)
382 {
383         int sw_irq = 0;
384         u32 level2;
385
386         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "-\n");
387
388         level2 = TX4927_RD(0xff1ff6a0);
389         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=level2a=0x%x\n", level2);
390
391         if ((level2 & 0x10000) == 0) {
392                 level2 &= 0x1f;
393                 TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=level2b=0x%x\n", level2);
394
395                 sw_irq = TX4927_IRQ_PIC_BEG + level2;
396                 TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST3, "=sw_irq=%d\n", sw_irq);
397
398                 if (sw_irq == 27) {
399                         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq-%d\n",
400                                            sw_irq);
401
402 #ifdef CONFIG_TOSHIBA_RBTX4927
403                         {
404                                 sw_irq = toshiba_rbtx4927_irq_nested(sw_irq);
405                         }
406 #endif
407
408                         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST4, "=irq+%d\n",
409                                            sw_irq);
410                 }
411         }
412
413         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST2, "=sw_irq=%d\n", sw_irq);
414
415         TX4927_IRQ_DPRINTK(TX4927_IRQ_NEST1, "+\n");
416
417         return (sw_irq);
418 }
419
420 asmlinkage void plat_irq_dispatch(void)
421 {
422         unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
423
424         if (pending & STATUSF_IP7)                      /* cpu timer */
425                 do_IRQ(TX4927_IRQ_CPU_TIMER);
426         else if (pending & STATUSF_IP2) {               /* tx4927 pic */
427                 unsigned int irq = tx4927_irq_nested();
428
429                 if (unlikely(irq == 0)) {
430                         spurious_interrupt();
431                         return;
432                 }
433                 do_IRQ(irq);
434         } else if (pending & STATUSF_IP0)               /* user line 0 */
435                 do_IRQ(TX4927_IRQ_USER0);
436         else if (pending & STATUSF_IP1)                 /* user line 1 */
437                 do_IRQ(TX4927_IRQ_USER1);
438         else
439                 spurious_interrupt();
440 }