Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / arch / mips / mips-boards / sead / sead_int.c
1 /*
2  * Carsten Langgaard, carstenl@mips.com
3  * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
4  * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org)
5  * Copyright (C) 2004  Maciej W. Rozycki
6  *
7  *  This program is free software; you can distribute it and/or modify it
8  *  under the terms of the GNU General Public License (Version 2) as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope it will be useful, but WITHOUT
12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  *  for more details.
15  *
16  *  You should have received a copy of the GNU General Public License along
17  *  with this program; if not, write to the Free Software Foundation, Inc.,
18  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19  *
20  * Routines for generic manipulation of the interrupts found on the MIPS
21  * Sead board.
22  */
23 #include <linux/init.h>
24 #include <linux/irq.h>
25
26 #include <asm/irq_cpu.h>
27 #include <asm/mipsregs.h>
28 #include <asm/system.h>
29
30 #include <asm/mips-boards/seadint.h>
31
32 static inline int clz(unsigned long x)
33 {
34         __asm__ (
35         "       .set    push                                    \n"
36         "       .set    mips32                                  \n"
37         "       clz     %0, %1                                  \n"
38         "       .set    pop                                     \n"
39         : "=r" (x)
40         : "r" (x));
41
42         return x;
43 }
44
45 /*
46  * Version of ffs that only looks at bits 12..15.
47  */
48 static inline unsigned int irq_ffs(unsigned int pending)
49 {
50 #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
51         return -clz(pending) + 31 - CAUSEB_IP;
52 #else
53         unsigned int a0 = 7;
54         unsigned int t0;
55
56         t0 = s0 & 0xf000;
57         t0 = t0 < 1;
58         t0 = t0 << 2;
59         a0 = a0 - t0;
60         s0 = s0 << t0;
61
62         t0 = s0 & 0xc000;
63         t0 = t0 < 1;
64         t0 = t0 << 1;
65         a0 = a0 - t0;
66         s0 = s0 << t0;
67
68         t0 = s0 & 0x8000;
69         t0 = t0 < 1;
70         //t0 = t0 << 2;
71         a0 = a0 - t0;
72         //s0 = s0 << t0;
73
74         return a0;
75 #endif
76 }
77
78 /*
79  * IRQs on the SEAD board look basically are combined together on hardware
80  * interrupt 0 (MIPS IRQ 2)) like:
81  *
82  *      MIPS IRQ        Source
83  *      --------        ------
84  *             0        Software (ignored)
85  *             1        Software (ignored)
86  *             2        UART0 (hw0)
87  *             3        UART1 (hw1)
88  *             4        Hardware (ignored)
89  *             5        Hardware (ignored)
90  *             6        Hardware (ignored)
91  *             7        R4k timer (what we use)
92  *
93  * We handle the IRQ according to _our_ priority which is:
94  *
95  * Highest ----     R4k Timer
96  * Lowest  ----     Combined hardware interrupt
97  *
98  * then we just return, if multiple IRQs are pending then we will just take
99  * another exception, big deal.
100  */
101 asmlinkage void plat_irq_dispatch(void)
102 {
103         unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
104         int irq;
105
106         irq = irq_ffs(pending);
107
108         if (irq >= 0)
109                 do_IRQ(MIPSCPU_INT_BASE + irq);
110         else
111                 spurious_interrupt(regs);
112 }
113
114 void __init arch_init_irq(void)
115 {
116         mips_cpu_irq_init(MIPSCPU_INT_BASE);
117 }