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