]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/irqchip/irq-xilinx-intc.c
irqchip: xilinx: Add support for multiple instances
[zynq/linux.git] / drivers / irqchip / irq-xilinx-intc.c
1 /*
2  * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu>
3  * Copyright (C) 2012-2013 Xilinx, Inc.
4  * Copyright (C) 2007-2009 PetaLogix
5  * Copyright (C) 2006 Atmark Techno, Inc.
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License. See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11
12 #include <linux/irqdomain.h>
13 #include <linux/irq.h>
14 #include <linux/irqchip.h>
15 #include <linux/irqchip/chained_irq.h>
16 #include <linux/of_address.h>
17 #include <linux/io.h>
18 #include <linux/bug.h>
19 #include <linux/of_irq.h>
20
21 static struct xintc_irq_chip *primary_intc;
22
23 /* No one else should require these constants, so define them locally here. */
24 #define ISR 0x00                        /* Interrupt Status Register */
25 #define IPR 0x04                        /* Interrupt Pending Register */
26 #define IER 0x08                        /* Interrupt Enable Register */
27 #define IAR 0x0c                        /* Interrupt Acknowledge Register */
28 #define SIE 0x10                        /* Set Interrupt Enable bits */
29 #define CIE 0x14                        /* Clear Interrupt Enable bits */
30 #define IVR 0x18                        /* Interrupt Vector Register */
31 #define MER 0x1c                        /* Master Enable Register */
32
33 #define MER_ME (1<<0)
34 #define MER_HIE (1<<1)
35
36 struct xintc_irq_chip {
37         void            __iomem *base;
38         struct          irq_domain *root_domain;
39         u32             intr_mask;
40         struct                  irq_chip *intc_dev;
41         u32                             nr_irq;
42         unsigned int    (*read_fn)(void __iomem *addr);
43         void                    (*write_fn)(void __iomem *addr, u32);
44 };
45
46 static void xintc_write(void __iomem *addr, u32 data)
47 {
48                 iowrite32(data, addr);
49 }
50
51 static unsigned int xintc_read(void __iomem *addr)
52 {
53                 return ioread32(addr);
54 }
55
56 static void xintc_write_be(void __iomem *addr, u32 data)
57 {
58                 iowrite32be(data, addr);
59 }
60
61 static unsigned int xintc_read_be(void __iomem *addr)
62 {
63                 return ioread32be(addr);
64 }
65
66 static void intc_enable_or_unmask(struct irq_data *d)
67 {
68         unsigned long mask = 1 << d->hwirq;
69         struct xintc_irq_chip *local_intc = irq_data_get_irq_chip_data(d);
70
71         pr_debug("irq-xilinx: enable_or_unmask: %ld\n", d->hwirq);
72
73         /* ack level irqs because they can't be acked during
74          * ack function since the handle_level_irq function
75          * acks the irq before calling the interrupt handler
76          */
77         if (irqd_is_level_type(d))
78                 local_intc->write_fn(local_intc->base + IAR, mask);
79
80         local_intc->write_fn(local_intc->base + SIE, mask);
81 }
82
83 static void intc_disable_or_mask(struct irq_data *d)
84 {
85         struct xintc_irq_chip *local_intc = irq_data_get_irq_chip_data(d);
86
87         pr_debug("irq-xilinx: disable: %ld\n", d->hwirq);
88         local_intc->write_fn(local_intc->base + CIE, 1 << d->hwirq);
89 }
90
91 static void intc_ack(struct irq_data *d)
92 {
93         struct xintc_irq_chip *local_intc = irq_data_get_irq_chip_data(d);
94
95         pr_debug("irq-xilinx: ack: %ld\n", d->hwirq);
96         local_intc->write_fn(local_intc->base + IAR, 1 << d->hwirq);
97 }
98
99 static void intc_mask_ack(struct irq_data *d)
100 {
101         unsigned long mask = 1 << d->hwirq;
102         struct xintc_irq_chip *local_intc = irq_data_get_irq_chip_data(d);
103
104         pr_debug("irq-xilinx: disable_and_ack: %ld\n", d->hwirq);
105         local_intc->write_fn(local_intc->base + CIE, mask);
106         local_intc->write_fn(local_intc->base + IAR, mask);
107 }
108
109 static unsigned int xintc_get_irq_local(struct xintc_irq_chip *local_intc)
110 {
111         int hwirq, irq = -1;
112
113         hwirq = local_intc->read_fn(local_intc->base + IVR);
114         if (hwirq != -1U)
115                 irq = irq_find_mapping(local_intc->root_domain, hwirq);
116
117         pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
118
119         return irq;
120 }
121
122 unsigned int xintc_get_irq(void)
123 {
124         int hwirq, irq = -1;
125
126         hwirq = primary_intc->read_fn(primary_intc->base + IVR);
127         if (hwirq != -1U)
128                 irq = irq_find_mapping(primary_intc->root_domain, hwirq);
129
130         pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
131
132         return irq;
133 }
134
135 static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
136 {
137         struct xintc_irq_chip *local_intc = d->host_data;
138
139         if (local_intc->intr_mask & (1 << hw)) {
140                 irq_set_chip_and_handler_name(irq, local_intc->intc_dev,
141                                                 handle_edge_irq, "edge");
142                 irq_clear_status_flags(irq, IRQ_LEVEL);
143         } else {
144                 irq_set_chip_and_handler_name(irq, local_intc->intc_dev,
145                                                 handle_level_irq, "level");
146                 irq_set_status_flags(irq, IRQ_LEVEL);
147         }
148         irq_set_chip_data(irq, local_intc);
149         return 0;
150 }
151
152 static const struct irq_domain_ops xintc_irq_domain_ops = {
153         .xlate = irq_domain_xlate_onetwocell,
154         .map = xintc_map,
155 };
156
157 static void xil_intc_irq_handler(struct irq_desc *desc)
158 {
159         struct irq_chip *chip = irq_desc_get_chip(desc);
160         struct xintc_irq_chip *local_intc =
161                 irq_data_get_irq_handler_data(&desc->irq_data);
162         u32 pending;
163
164         chained_irq_enter(chip, desc);
165         do {
166                 pending = xintc_get_irq_local(local_intc);
167                 if (pending == -1U)
168                         break;
169                 generic_handle_irq(pending);
170         } while (true);
171         chained_irq_exit(chip, desc);
172 }
173
174 static int __init xilinx_intc_of_init(struct device_node *intc,
175                                              struct device_node *parent)
176 {
177         int ret, irq;
178         struct xintc_irq_chip *irqc;
179         struct irq_chip *intc_dev;
180
181         irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
182         if (!irqc)
183                 return -ENOMEM;
184         irqc->base = of_iomap(intc, 0);
185         BUG_ON(!irqc->base);
186
187         ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &irqc->nr_irq);
188         if (ret < 0) {
189                 pr_err("irq-xilinx: unable to read xlnx,num-intr-inputs\n");
190                 goto error;
191         }
192
193         ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &irqc->intr_mask);
194         if (ret < 0) {
195                 pr_warn("irq-xilinx: unable to read xlnx,kind-of-intr\n");
196                 irqc->intr_mask = 0;
197         }
198
199         if (irqc->intr_mask >> irqc->nr_irq)
200                 pr_warn("irq-xilinx: mismatch in kind-of-intr param\n");
201
202         pr_info("irq-xilinx: %pOF: num_irq=%d, edge=0x%x\n",
203                 intc, irqc->nr_irq, irqc->intr_mask);
204
205         intc_dev = kzalloc(sizeof(*intc_dev), GFP_KERNEL);
206         if (!intc_dev) {
207                 ret = -ENOMEM;
208                 goto error;
209         }
210
211         intc_dev->name = intc->full_name;
212         intc_dev->irq_unmask = intc_enable_or_unmask,
213         intc_dev->irq_mask = intc_disable_or_mask,
214         intc_dev->irq_ack = intc_ack,
215         intc_dev->irq_mask_ack = intc_mask_ack,
216         irqc->intc_dev = intc_dev;
217
218         irqc->write_fn = xintc_write;
219         irqc->read_fn = xintc_read;
220         /*
221          * Disable all external interrupts until they are
222          * explicity requested.
223          */
224         irqc->write_fn(irqc->base + IER, 0);
225
226         /* Acknowledge any pending interrupts just in case. */
227         irqc->write_fn(irqc->base + IAR, 0xffffffff);
228
229         /* Turn on the Master Enable. */
230         irqc->write_fn(irqc->base + MER, MER_HIE | MER_ME);
231         if (!(irqc->read_fn(irqc->base + MER) & (MER_HIE | MER_ME))) {
232                 irqc->write_fn = xintc_write_be;
233                 irqc->read_fn = xintc_read_be;
234                 irqc->write_fn(irqc->base + MER, MER_HIE | MER_ME);
235         }
236
237         irqc->root_domain = irq_domain_add_linear(intc, irqc->nr_irq,
238                                                   &xintc_irq_domain_ops, irqc);
239         if (!irqc->root_domain) {
240                 pr_err("irq-xilinx: Unable to create IRQ domain\n");
241                 goto err_alloc;
242         }
243
244         if (parent) {
245                 irq = irq_of_parse_and_map(intc, 0);
246                 if (irq) {
247                         irq_set_chained_handler_and_data(irq,
248                                                          xil_intc_irq_handler,
249                                                          irqc);
250                 } else {
251                         pr_err("irq-xilinx: interrupts property not in DT\n");
252                         ret = -EINVAL;
253                         goto err_alloc;
254                 }
255         } else {
256                 primary_intc = irqc;
257                 irq_set_default_host(primary_intc->root_domain);
258         }
259
260         return 0;
261
262 err_alloc:
263         kfree(intc_dev);
264 error:
265         iounmap(irqc->base);
266         kfree(irqc);
267         return ret;
268
269 }
270
271 IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
272 IRQCHIP_DECLARE(xilinx_intc_opb, "xlnx,opb-intc-1.00.c", xilinx_intc_of_init);