linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / ppc / syslib / xilinx_pic.c
1 /*
2  * arch/ppc/syslib/xilinx_pic.c
3  *
4  * Interrupt controller driver for Xilinx Virtex-II Pro.
5  *
6  * Author: MontaVista Software, Inc.
7  *         source@mvista.com
8  *
9  * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under
10  * the terms of the GNU General Public License version 2. This program
11  * is licensed "as is" without any warranty of any kind, whether express
12  * or implied.
13  */
14
15 #include <linux/init.h>
16 #include <linux/irq.h>
17 #include <asm/io.h>
18 #include <asm/xparameters.h>
19 #include <asm/ibm4xx.h>
20 #include <asm/machdep.h>
21
22 /* No one else should require these constants, so define them locally here. */
23 #define ISR 0                   /* Interrupt Status Register */
24 #define IPR 1                   /* Interrupt Pending Register */
25 #define IER 2                   /* Interrupt Enable Register */
26 #define IAR 3                   /* Interrupt Acknowledge Register */
27 #define SIE 4                   /* Set Interrupt Enable bits */
28 #define CIE 5                   /* Clear Interrupt Enable bits */
29 #define IVR 6                   /* Interrupt Vector Register */
30 #define MER 7                   /* Master Enable Register */
31
32 #if XPAR_XINTC_USE_DCR == 0
33 static volatile u32 *intc;
34 #define intc_out_be32(addr, mask)     out_be32((addr), (mask))
35 #define intc_in_be32(addr)            in_be32((addr))
36 #else
37 #define intc    XPAR_INTC_0_BASEADDR
38 #define intc_out_be32(addr, mask)     mtdcr((addr), (mask))
39 #define intc_in_be32(addr)            mfdcr((addr))
40 #endif
41
42 static void
43 xilinx_intc_enable(unsigned int irq)
44 {
45         unsigned long mask = (0x00000001 << (irq & 31));
46         pr_debug("enable: %d\n", irq);
47         intc_out_be32(intc + SIE, mask);
48 }
49
50 static void
51 xilinx_intc_disable(unsigned int irq)
52 {
53         unsigned long mask = (0x00000001 << (irq & 31));
54         pr_debug("disable: %d\n", irq);
55         intc_out_be32(intc + CIE, mask);
56 }
57
58 static void
59 xilinx_intc_disable_and_ack(unsigned int irq)
60 {
61         unsigned long mask = (0x00000001 << (irq & 31));
62         pr_debug("disable_and_ack: %d\n", irq);
63         intc_out_be32(intc + CIE, mask);
64         if (!(irq_desc[irq].status & IRQ_LEVEL))
65                 intc_out_be32(intc + IAR, mask);        /* ack edge triggered intr */
66 }
67
68 static void
69 xilinx_intc_end(unsigned int irq)
70 {
71         unsigned long mask = (0x00000001 << (irq & 31));
72
73         pr_debug("end: %d\n", irq);
74         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
75                 intc_out_be32(intc + SIE, mask);
76                 /* ack level sensitive intr */
77                 if (irq_desc[irq].status & IRQ_LEVEL)
78                         intc_out_be32(intc + IAR, mask);
79         }
80 }
81
82 static struct hw_interrupt_type xilinx_intc = {
83         .typename = "Xilinx Interrupt Controller",
84         .enable = xilinx_intc_enable,
85         .disable = xilinx_intc_disable,
86         .ack = xilinx_intc_disable_and_ack,
87         .end = xilinx_intc_end,
88 };
89
90 int
91 xilinx_pic_get_irq(struct pt_regs *regs)
92 {
93         int irq;
94
95         /*
96          * NOTE: This function is the one that needs to be improved in
97          * order to handle multiple interrupt controllers.  It currently
98          * is hardcoded to check for interrupts only on the first INTC.
99          */
100
101         irq = intc_in_be32(intc + IVR);
102         if (irq != -1)
103                 irq = irq;
104
105         pr_debug("get_irq: %d\n", irq);
106
107         return (irq);
108 }
109
110 void __init
111 ppc4xx_pic_init(void)
112 {
113         int i;
114
115         /*
116          * NOTE: The assumption here is that NR_IRQS is 32 or less
117          * (NR_IRQS is 32 for PowerPC 405 cores by default).
118          */
119 #if (NR_IRQS > 32)
120 #error NR_IRQS > 32 not supported
121 #endif
122
123 #if XPAR_XINTC_USE_DCR == 0
124         intc = ioremap(XPAR_INTC_0_BASEADDR, 32);
125
126         printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX mapped to 0x%08lX\n",
127                (unsigned long) XPAR_INTC_0_BASEADDR, (unsigned long) intc);
128 #else
129         printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX (DCR)\n",
130                (unsigned long) XPAR_INTC_0_BASEADDR);
131 #endif
132
133         /*
134          * Disable all external interrupts until they are
135          * explicity requested.
136          */
137         intc_out_be32(intc + IER, 0);
138
139         /* Acknowledge any pending interrupts just in case. */
140         intc_out_be32(intc + IAR, ~(u32) 0);
141
142         /* Turn on the Master Enable. */
143         intc_out_be32(intc + MER, 0x3UL);
144
145         ppc_md.get_irq = xilinx_pic_get_irq;
146
147         for (i = 0; i < NR_IRQS; ++i) {
148                 irq_desc[i].handler = &xilinx_intc;
149
150                 if (XPAR_INTC_0_KIND_OF_INTR & (0x00000001 << i))
151                         irq_desc[i].status &= ~IRQ_LEVEL;
152                 else
153                         irq_desc[i].status |= IRQ_LEVEL;
154         }
155 }