]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - arch/powerpc/sysdev/xilinx_intc.c
3ee1fd37bbfc3b819107a8dd4d9b2496f59ecc84
[~shefty/rdma-dev.git] / arch / powerpc / sysdev / xilinx_intc.c
1 /*
2  * Interrupt controller driver for Xilinx Virtex FPGAs
3  *
4  * Copyright (C) 2007 Secret Lab Technologies Ltd.
5  *
6  * This file is licensed under the terms of the GNU General Public License
7  * version 2. This program is licensed "as is" without any warranty of any
8  * kind, whether express or implied.
9  *
10  */
11
12 /*
13  * This is a driver for the interrupt controller typically found in
14  * Xilinx Virtex FPGA designs.
15  *
16  * The interrupt sense levels are hard coded into the FPGA design with
17  * typically a 1:1 relationship between irq lines and devices (no shared
18  * irq lines).  Therefore, this driver does not attempt to handle edge
19  * and level interrupts differently.
20  */
21 #undef DEBUG
22
23 #include <linux/kernel.h>
24 #include <linux/irq.h>
25 #include <linux/of.h>
26 #include <asm/io.h>
27 #include <asm/processor.h>
28 #include <asm/i8259.h>
29 #include <asm/irq.h>
30
31 /*
32  * INTC Registers
33  */
34 #define XINTC_ISR       0       /* Interrupt Status */
35 #define XINTC_IPR       4       /* Interrupt Pending */
36 #define XINTC_IER       8       /* Interrupt Enable */
37 #define XINTC_IAR       12      /* Interrupt Acknowledge */
38 #define XINTC_SIE       16      /* Set Interrupt Enable bits */
39 #define XINTC_CIE       20      /* Clear Interrupt Enable bits */
40 #define XINTC_IVR       24      /* Interrupt Vector */
41 #define XINTC_MER       28      /* Master Enable */
42
43 static struct irq_host *master_irqhost;
44
45 #define XILINX_INTC_MAXIRQS     (32)
46
47 /* The following table allows the interrupt type, edge or level,
48  * to be cached after being read from the device tree until the interrupt
49  * is mapped
50  */
51 static int xilinx_intc_typetable[XILINX_INTC_MAXIRQS];
52
53 /* Map the interrupt type from the device tree to the interrupt types
54  * used by the interrupt subsystem
55  */
56 static unsigned char xilinx_intc_map_senses[] = {
57         IRQ_TYPE_EDGE_RISING,
58         IRQ_TYPE_EDGE_FALLING,
59         IRQ_TYPE_LEVEL_HIGH,
60         IRQ_TYPE_LEVEL_LOW,
61 };
62
63 /*
64  * The interrupt controller is setup such that it doesn't work well with
65  * the level interrupt handler in the kernel because the handler acks the
66  * interrupt before calling the application interrupt handler. To deal with
67  * that, we use 2 different irq chips so that different functions can be
68  * used for level and edge type interrupts.
69  *
70  * IRQ Chip common (across level and edge) operations
71  */
72 static void xilinx_intc_mask(unsigned int virq)
73 {
74         int irq = virq_to_hw(virq);
75         void * regs = get_irq_chip_data(virq);
76         pr_debug("mask: %d\n", irq);
77         out_be32(regs + XINTC_CIE, 1 << irq);
78 }
79
80 static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type)
81 {
82         struct irq_desc *desc = get_irq_desc(virq);
83
84         desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
85         desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
86         if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
87                 desc->status |= IRQ_LEVEL;
88         return 0;
89 }
90
91 /*
92  * IRQ Chip level operations
93  */
94 static void xilinx_intc_level_unmask(unsigned int virq)
95 {
96         int irq = virq_to_hw(virq);
97         void * regs = get_irq_chip_data(virq);
98         pr_debug("unmask: %d\n", irq);
99         out_be32(regs + XINTC_SIE, 1 << irq);
100
101         /* ack level irqs because they can't be acked during
102          * ack function since the handle_level_irq function
103          * acks the irq before calling the inerrupt handler
104          */
105         out_be32(regs + XINTC_IAR, 1 << irq);
106 }
107
108 static struct irq_chip xilinx_intc_level_irqchip = {
109         .typename = "Xilinx Level INTC",
110         .mask = xilinx_intc_mask,
111         .mask_ack = xilinx_intc_mask,
112         .unmask = xilinx_intc_level_unmask,
113         .set_type = xilinx_intc_set_type,
114 };
115
116 /*
117  * IRQ Chip edge operations
118  */
119 static void xilinx_intc_edge_unmask(unsigned int virq)
120 {
121         int irq = virq_to_hw(virq);
122         void *regs = get_irq_chip_data(virq);
123         pr_debug("unmask: %d\n", irq);
124         out_be32(regs + XINTC_SIE, 1 << irq);
125 }
126
127 static void xilinx_intc_edge_ack(unsigned int virq)
128 {
129         int irq = virq_to_hw(virq);
130         void * regs = get_irq_chip_data(virq);
131         pr_debug("ack: %d\n", irq);
132         out_be32(regs + XINTC_IAR, 1 << irq);
133 }
134
135 static struct irq_chip xilinx_intc_edge_irqchip = {
136         .typename = "Xilinx Edge  INTC",
137         .mask = xilinx_intc_mask,
138         .unmask = xilinx_intc_edge_unmask,
139         .ack = xilinx_intc_edge_ack,
140         .set_type = xilinx_intc_set_type,
141 };
142
143 /*
144  * IRQ Host operations
145  */
146
147 /**
148  * xilinx_intc_xlate - translate virq# from device tree interrupts property
149  */
150 static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,
151                                 u32 *intspec, unsigned int intsize,
152                                 irq_hw_number_t *out_hwirq,
153                                 unsigned int *out_flags)
154 {
155         if ((intsize < 2) || (intspec[0] >= XILINX_INTC_MAXIRQS))
156                 return -EINVAL;
157
158         /* keep a copy of the interrupt type til the interrupt is mapped
159          */
160         xilinx_intc_typetable[intspec[0]] = xilinx_intc_map_senses[intspec[1]];
161
162         /* Xilinx uses 2 interrupt entries, the 1st being the h/w
163          * interrupt number, the 2nd being the interrupt type, edge or level
164          */
165         *out_hwirq = intspec[0];
166         *out_flags = xilinx_intc_map_senses[intspec[1]];
167
168         return 0;
169 }
170 static int xilinx_intc_map(struct irq_host *h, unsigned int virq,
171                                   irq_hw_number_t irq)
172 {
173         set_irq_chip_data(virq, h->host_data);
174
175         if (xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_HIGH ||
176             xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_LOW) {
177                 set_irq_chip_and_handler(virq, &xilinx_intc_level_irqchip,
178                         handle_level_irq);
179         } else {
180                 set_irq_chip_and_handler(virq, &xilinx_intc_edge_irqchip,
181                         handle_edge_irq);
182         }
183         return 0;
184 }
185
186 static struct irq_host_ops xilinx_intc_ops = {
187         .map = xilinx_intc_map,
188         .xlate = xilinx_intc_xlate,
189 };
190
191 struct irq_host * __init
192 xilinx_intc_init(struct device_node *np)
193 {
194         struct irq_host * irq;
195         void * regs;
196
197         /* Find and map the intc registers */
198         regs = of_iomap(np, 0);
199         if (!regs) {
200                 pr_err("xilinx_intc: could not map registers\n");
201                 return NULL;
202         }
203
204         /* Setup interrupt controller */
205         out_be32(regs + XINTC_IER, 0); /* disable all irqs */
206         out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */
207         out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */
208
209         /* Allocate and initialize an irq_host structure. */
210         irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, XILINX_INTC_MAXIRQS,
211                              &xilinx_intc_ops, -1);
212         if (!irq)
213                 panic(__FILE__ ": Cannot allocate IRQ host\n");
214         irq->host_data = regs;
215
216         return irq;
217 }
218
219 int xilinx_intc_get_irq(void)
220 {
221         void * regs = master_irqhost->host_data;
222         pr_debug("get_irq:\n");
223         return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR));
224 }
225
226 #if defined(CONFIG_PPC_I8259)
227 /*
228  * Support code for cascading to 8259 interrupt controllers
229  */
230 static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc)
231 {
232         unsigned int cascade_irq = i8259_irq();
233         if (cascade_irq)
234                 generic_handle_irq(cascade_irq);
235
236         /* Let xilinx_intc end the interrupt */
237         desc->chip->ack(irq);
238         desc->chip->unmask(irq);
239 }
240
241 static void __init xilinx_i8259_setup_cascade(void)
242 {
243         struct device_node *cascade_node;
244         int cascade_irq;
245
246         /* Initialize i8259 controller */
247         cascade_node = of_find_compatible_node(NULL, NULL, "chrp,iic");
248         if (!cascade_node)
249                 return;
250
251         cascade_irq = irq_of_parse_and_map(cascade_node, 0);
252         if (!cascade_irq) {
253                 pr_err("virtex_ml510: Failed to map cascade interrupt\n");
254                 goto out;
255         }
256
257         i8259_init(cascade_node, 0);
258         set_irq_chained_handler(cascade_irq, xilinx_i8259_cascade);
259
260         /* Program irq 7 (usb/audio), 14/15 (ide) to level sensitive */
261         /* This looks like a dirty hack to me --gcl */
262         outb(0xc0, 0x4d0);
263         outb(0xc0, 0x4d1);
264
265  out:
266         of_node_put(cascade_node);
267 }
268 #else
269 static inline void xilinx_i8259_setup_cascade(void) { return; }
270 #endif /* defined(CONFIG_PPC_I8259) */
271
272 static struct of_device_id xilinx_intc_match[] __initconst = {
273         { .compatible = "xlnx,opb-intc-1.00.c", },
274         { .compatible = "xlnx,xps-intc-1.00.a", },
275         {}
276 };
277
278 /*
279  * Initialize master Xilinx interrupt controller
280  */
281 void __init xilinx_intc_init_tree(void)
282 {
283         struct device_node *np;
284
285         /* find top level interrupt controller */
286         for_each_matching_node(np, xilinx_intc_match) {
287                 if (!of_get_property(np, "interrupts", NULL))
288                         break;
289         }
290         BUG_ON(!np);
291
292         master_irqhost = xilinx_intc_init(np);
293         BUG_ON(!master_irqhost);
294
295         irq_set_default_host(master_irqhost);
296         of_node_put(np);
297
298         xilinx_i8259_setup_cascade();
299 }