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