blob: 47f04c71fe9c023bdcf17f119b380b096eeecc69 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Paul Mackerrasfd582ec2005-10-11 22:08:12 +100020#include <asm/machdep.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
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
33static 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
42static void
43xilinx_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
50static void
51xilinx_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
58static void
59xilinx_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
68static void
69xilinx_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
82static struct hw_interrupt_type xilinx_intc = {
Thomas Gleixner2830e212005-09-10 00:26:40 -070083 .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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
90int
91xilinx_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
110void __init
111ppc4xx_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}