This commit was manufactured by cvs2svn to create branch 'vserver'.
[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
21 /* No one else should require these constants, so define them locally here. */
22 #define ISR 0                   /* Interrupt Status Register */
23 #define IPR 1                   /* Interrupt Pending Register */
24 #define IER 2                   /* Interrupt Enable Register */
25 #define IAR 3                   /* Interrupt Acknowledge Register */
26 #define SIE 4                   /* Set Interrupt Enable bits */
27 #define CIE 5                   /* Clear Interrupt Enable bits */
28 #define IVR 6                   /* Interrupt Vector Register */
29 #define MER 7                   /* Master Enable Register */
30
31 #if XPAR_XINTC_USE_DCR == 0
32 static volatile u32 *intc;
33 #define intc_out_be32(addr, mask)     out_be32((addr), (mask))
34 #define intc_in_be32(addr)            in_be32((addr))
35 #else
36 #define intc    XPAR_INTC_0_BASEADDR
37 #define intc_out_be32(addr, mask)     mtdcr((addr), (mask))
38 #define intc_in_be32(addr)            mfdcr((addr))
39 #endif
40
41 /* Global Variables */
42 struct hw_interrupt_type *ppc4xx_pic;
43
44 static void
45 xilinx_intc_enable(unsigned int irq)
46 {
47         unsigned long mask = (0x00000001 << (irq & 31));
48         pr_debug("enable: %d\n", irq);
49         intc_out_be32(intc + SIE, mask);
50 }
51
52 static void
53 xilinx_intc_disable(unsigned int irq)
54 {
55         unsigned long mask = (0x00000001 << (irq & 31));
56         pr_debug("disable: %d\n", irq);
57         intc_out_be32(intc + CIE, mask);
58 }
59
60 static void
61 xilinx_intc_disable_and_ack(unsigned int irq)
62 {
63         unsigned long mask = (0x00000001 << (irq & 31));
64         pr_debug("disable_and_ack: %d\n", irq);
65         intc_out_be32(intc + CIE, mask);
66         if (!(irq_desc[irq].status & IRQ_LEVEL))
67                 intc_out_be32(intc + IAR, mask);        /* ack edge triggered intr */
68 }
69
70 static void
71 xilinx_intc_end(unsigned int irq)
72 {
73         unsigned long mask = (0x00000001 << (irq & 31));
74
75         pr_debug("end: %d\n", irq);
76         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
77                 intc_out_be32(intc + SIE, mask);
78                 /* ack level sensitive intr */
79                 if (irq_desc[irq].status & IRQ_LEVEL)
80                         intc_out_be32(intc + IAR, mask);
81         }
82 }
83
84 static struct hw_interrupt_type xilinx_intc = {
85         "Xilinx Interrupt Controller",
86         NULL,
87         NULL,
88         xilinx_intc_enable,
89         xilinx_intc_disable,
90         xilinx_intc_disable_and_ack,
91         xilinx_intc_end,
92         0
93 };
94
95 int
96 xilinx_pic_get_irq(struct pt_regs *regs)
97 {
98         int irq;
99
100         /*
101          * NOTE: This function is the one that needs to be improved in
102          * order to handle multiple interrupt controllers.  It currently
103          * is hardcoded to check for interrupts only on the first INTC.
104          */
105
106         irq = intc_in_be32(intc + IVR);
107         if (irq != -1)
108                 irq = irq;
109
110         pr_debug("get_irq: %d\n", irq);
111
112         return (irq);
113 }
114
115 void __init
116 ppc4xx_pic_init(void)
117 {
118 #if XPAR_XINTC_USE_DCR == 0
119         intc = ioremap(XPAR_INTC_0_BASEADDR, 32);
120
121         printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX mapped to 0x%08lX\n",
122                (unsigned long) XPAR_INTC_0_BASEADDR, (unsigned long) intc);
123 #else
124         printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX (DCR)\n",
125                (unsigned long) XPAR_INTC_0_BASEADDR);
126 #endif
127
128         /*
129          * Disable all external interrupts until they are
130          * explicity requested.
131          */
132         intc_out_be32(intc + IER, 0);
133
134         /* Acknowledge any pending interrupts just in case. */
135         intc_out_be32(intc + IAR, ~(u32) 0);
136
137         /* Turn on the Master Enable. */
138         intc_out_be32(intc + MER, 0x3UL);
139
140         ppc4xx_pic = &xilinx_intc;
141         ppc_md.get_irq = xilinx_pic_get_irq;
142 }