genirq: Remove irq argument from irq flow handlers
[linux-drm-fsl-dcu.git] / arch / powerpc / platforms / 85xx / socrates_fpga_pic.c
1 /*
2  *  Copyright (C) 2008 Ilya Yanok, Emcraft Systems
3  *
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  */
10
11 #include <linux/irq.h>
12 #include <linux/of_address.h>
13 #include <linux/of_irq.h>
14 #include <linux/of_platform.h>
15 #include <linux/io.h>
16
17 /*
18  * The FPGA supports 9 interrupt sources, which can be routed to 3
19  * interrupt request lines of the MPIC. The line to be used can be
20  * specified through the third cell of FDT property  "interrupts".
21  */
22
23 #define SOCRATES_FPGA_NUM_IRQS  9
24
25 #define FPGA_PIC_IRQCFG         (0x0)
26 #define FPGA_PIC_IRQMASK(n)     (0x4 + 0x4 * (n))
27
28 #define SOCRATES_FPGA_IRQ_MASK  ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
29
30 struct socrates_fpga_irq_info {
31         unsigned int irq_line;
32         int type;
33 };
34
35 /*
36  * Interrupt routing and type table
37  *
38  * IRQ_TYPE_NONE means the interrupt type is configurable,
39  * otherwise it's fixed to the specified value.
40  */
41 static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
42         [0] = {0, IRQ_TYPE_NONE},
43         [1] = {0, IRQ_TYPE_LEVEL_HIGH},
44         [2] = {0, IRQ_TYPE_LEVEL_LOW},
45         [3] = {0, IRQ_TYPE_NONE},
46         [4] = {0, IRQ_TYPE_NONE},
47         [5] = {0, IRQ_TYPE_NONE},
48         [6] = {0, IRQ_TYPE_NONE},
49         [7] = {0, IRQ_TYPE_NONE},
50         [8] = {0, IRQ_TYPE_LEVEL_HIGH},
51 };
52
53 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
54
55 static void __iomem *socrates_fpga_pic_iobase;
56 static struct irq_domain *socrates_fpga_pic_irq_host;
57 static unsigned int socrates_fpga_irqs[3];
58
59 static inline uint32_t socrates_fpga_pic_read(int reg)
60 {
61         return in_be32(socrates_fpga_pic_iobase + reg);
62 }
63
64 static inline void socrates_fpga_pic_write(int reg, uint32_t val)
65 {
66         out_be32(socrates_fpga_pic_iobase + reg, val);
67 }
68
69 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
70 {
71         uint32_t cause;
72         unsigned long flags;
73         int i;
74
75         /* Check irq line routed to the MPIC */
76         for (i = 0; i < 3; i++) {
77                 if (irq == socrates_fpga_irqs[i])
78                         break;
79         }
80         if (i == 3)
81                 return NO_IRQ;
82
83         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
84         cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
85         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
86         for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
87                 if (cause >> (i + 16))
88                         break;
89         }
90         return irq_linear_revmap(socrates_fpga_pic_irq_host,
91                         (irq_hw_number_t)i);
92 }
93
94 static void socrates_fpga_pic_cascade(struct irq_desc *desc)
95 {
96         struct irq_chip *chip = irq_desc_get_chip(desc);
97         unsigned int irq = irq_desc_get_irq(desc);
98         unsigned int cascade_irq;
99
100         /*
101          * See if we actually have an interrupt, call generic handling code if
102          * we do.
103          */
104         cascade_irq = socrates_fpga_pic_get_irq(irq);
105
106         if (cascade_irq != NO_IRQ)
107                 generic_handle_irq(cascade_irq);
108         chip->irq_eoi(&desc->irq_data);
109 }
110
111 static void socrates_fpga_pic_ack(struct irq_data *d)
112 {
113         unsigned long flags;
114         unsigned int irq_line, hwirq = irqd_to_hwirq(d);
115         uint32_t mask;
116
117         irq_line = fpga_irqs[hwirq].irq_line;
118         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
119         mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
120                 & SOCRATES_FPGA_IRQ_MASK;
121         mask |= (1 << (hwirq + 16));
122         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
123         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
124 }
125
126 static void socrates_fpga_pic_mask(struct irq_data *d)
127 {
128         unsigned long flags;
129         unsigned int hwirq = irqd_to_hwirq(d);
130         int irq_line;
131         u32 mask;
132
133         irq_line = fpga_irqs[hwirq].irq_line;
134         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
135         mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
136                 & SOCRATES_FPGA_IRQ_MASK;
137         mask &= ~(1 << hwirq);
138         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
139         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
140 }
141
142 static void socrates_fpga_pic_mask_ack(struct irq_data *d)
143 {
144         unsigned long flags;
145         unsigned int hwirq = irqd_to_hwirq(d);
146         int irq_line;
147         u32 mask;
148
149         irq_line = fpga_irqs[hwirq].irq_line;
150         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
151         mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
152                 & SOCRATES_FPGA_IRQ_MASK;
153         mask &= ~(1 << hwirq);
154         mask |= (1 << (hwirq + 16));
155         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
156         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
157 }
158
159 static void socrates_fpga_pic_unmask(struct irq_data *d)
160 {
161         unsigned long flags;
162         unsigned int hwirq = irqd_to_hwirq(d);
163         int irq_line;
164         u32 mask;
165
166         irq_line = fpga_irqs[hwirq].irq_line;
167         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
168         mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
169                 & SOCRATES_FPGA_IRQ_MASK;
170         mask |= (1 << hwirq);
171         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
172         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
173 }
174
175 static void socrates_fpga_pic_eoi(struct irq_data *d)
176 {
177         unsigned long flags;
178         unsigned int hwirq = irqd_to_hwirq(d);
179         int irq_line;
180         u32 mask;
181
182         irq_line = fpga_irqs[hwirq].irq_line;
183         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
184         mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
185                 & SOCRATES_FPGA_IRQ_MASK;
186         mask |= (1 << (hwirq + 16));
187         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
188         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
189 }
190
191 static int socrates_fpga_pic_set_type(struct irq_data *d,
192                 unsigned int flow_type)
193 {
194         unsigned long flags;
195         unsigned int hwirq = irqd_to_hwirq(d);
196         int polarity;
197         u32 mask;
198
199         if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
200                 return -EINVAL;
201
202         switch (flow_type & IRQ_TYPE_SENSE_MASK) {
203         case IRQ_TYPE_LEVEL_HIGH:
204                 polarity = 1;
205                 break;
206         case IRQ_TYPE_LEVEL_LOW:
207                 polarity = 0;
208                 break;
209         default:
210                 return -EINVAL;
211         }
212         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
213         mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
214         if (polarity)
215                 mask |= (1 << hwirq);
216         else
217                 mask &= ~(1 << hwirq);
218         socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
219         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
220         return 0;
221 }
222
223 static struct irq_chip socrates_fpga_pic_chip = {
224         .name           = "FPGA-PIC",
225         .irq_ack        = socrates_fpga_pic_ack,
226         .irq_mask       = socrates_fpga_pic_mask,
227         .irq_mask_ack   = socrates_fpga_pic_mask_ack,
228         .irq_unmask     = socrates_fpga_pic_unmask,
229         .irq_eoi        = socrates_fpga_pic_eoi,
230         .irq_set_type   = socrates_fpga_pic_set_type,
231 };
232
233 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
234                 irq_hw_number_t hwirq)
235 {
236         /* All interrupts are LEVEL sensitive */
237         irq_set_status_flags(virq, IRQ_LEVEL);
238         irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
239                                  handle_fasteoi_irq);
240
241         return 0;
242 }
243
244 static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
245                 struct device_node *ct, const u32 *intspec, unsigned int intsize,
246                 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
247 {
248         struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
249
250         *out_hwirq = intspec[0];
251         if  (fpga_irq->type == IRQ_TYPE_NONE) {
252                 /* type is configurable */
253                 if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
254                     intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
255                         pr_warning("FPGA PIC: invalid irq type, "
256                                    "setting default active low\n");
257                         *out_flags = IRQ_TYPE_LEVEL_LOW;
258                 } else {
259                         *out_flags = intspec[1];
260                 }
261         } else {
262                 /* type is fixed */
263                 *out_flags = fpga_irq->type;
264         }
265
266         /* Use specified interrupt routing */
267         if (intspec[2] <= 2)
268                 fpga_irq->irq_line = intspec[2];
269         else
270                 pr_warning("FPGA PIC: invalid irq routing\n");
271
272         return 0;
273 }
274
275 static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
276         .map    = socrates_fpga_pic_host_map,
277         .xlate  = socrates_fpga_pic_host_xlate,
278 };
279
280 void socrates_fpga_pic_init(struct device_node *pic)
281 {
282         unsigned long flags;
283         int i;
284
285         /* Setup an irq_domain structure */
286         socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
287                     SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
288         if (socrates_fpga_pic_irq_host == NULL) {
289                 pr_err("FPGA PIC: Unable to allocate host\n");
290                 return;
291         }
292
293         for (i = 0; i < 3; i++) {
294                 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
295                 if (socrates_fpga_irqs[i] == NO_IRQ) {
296                         pr_warning("FPGA PIC: can't get irq%d.\n", i);
297                         continue;
298                 }
299                 irq_set_chained_handler(socrates_fpga_irqs[i],
300                                         socrates_fpga_pic_cascade);
301         }
302
303         socrates_fpga_pic_iobase = of_iomap(pic, 0);
304
305         raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
306         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
307                         SOCRATES_FPGA_IRQ_MASK << 16);
308         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
309                         SOCRATES_FPGA_IRQ_MASK << 16);
310         socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
311                         SOCRATES_FPGA_IRQ_MASK << 16);
312         raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
313
314         pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
315 }