Full support for Ginger Console
[linux-ginger.git] / arch / powerpc / platforms / 85xx / socrates_fpga_pic.c
blob60edf63d0157fbab56b6cdc473a15dfe01af3c9c
1 /*
2 * Copyright (C) 2008 Ilya Yanok, Emcraft Systems
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.
9 */
11 #include <linux/irq.h>
12 #include <linux/of_platform.h>
13 #include <linux/io.h>
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".
21 #define SOCRATES_FPGA_NUM_IRQS 9
23 #define FPGA_PIC_IRQCFG (0x0)
24 #define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n))
26 #define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
28 struct socrates_fpga_irq_info {
29 unsigned int irq_line;
30 int type;
34 * Interrupt routing and type table
36 * IRQ_TYPE_NONE means the interrupt type is configurable,
37 * otherwise it's fixed to the specified value.
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},
51 #define socrates_fpga_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
53 static DEFINE_SPINLOCK(socrates_fpga_pic_lock);
55 static void __iomem *socrates_fpga_pic_iobase;
56 static struct irq_host *socrates_fpga_pic_irq_host;
57 static unsigned int socrates_fpga_irqs[3];
59 static inline uint32_t socrates_fpga_pic_read(int reg)
61 return in_be32(socrates_fpga_pic_iobase + reg);
64 static inline void socrates_fpga_pic_write(int reg, uint32_t val)
66 out_be32(socrates_fpga_pic_iobase + reg, val);
69 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
71 uint32_t cause;
72 unsigned long flags;
73 int i;
75 /* Check irq line routed to the MPIC */
76 for (i = 0; i < 3; i++) {
77 if (irq == socrates_fpga_irqs[i])
78 break;
80 if (i == 3)
81 return NO_IRQ;
83 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
84 cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
85 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;
90 return irq_linear_revmap(socrates_fpga_pic_irq_host,
91 (irq_hw_number_t)i);
94 void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
96 unsigned int cascade_irq;
99 * See if we actually have an interrupt, call generic handling code if
100 * we do.
102 cascade_irq = socrates_fpga_pic_get_irq(irq);
104 if (cascade_irq != NO_IRQ)
105 generic_handle_irq(cascade_irq);
106 desc->chip->eoi(irq);
110 static void socrates_fpga_pic_ack(unsigned int virq)
112 unsigned long flags;
113 unsigned int hwirq, irq_line;
114 uint32_t mask;
116 hwirq = socrates_fpga_irq_to_hw(virq);
118 irq_line = fpga_irqs[hwirq].irq_line;
119 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
120 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
121 & SOCRATES_FPGA_IRQ_MASK;
122 mask |= (1 << (hwirq + 16));
123 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
124 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
127 static void socrates_fpga_pic_mask(unsigned int virq)
129 unsigned long flags;
130 unsigned int hwirq;
131 int irq_line;
132 u32 mask;
134 hwirq = socrates_fpga_irq_to_hw(virq);
136 irq_line = fpga_irqs[hwirq].irq_line;
137 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
138 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
139 & SOCRATES_FPGA_IRQ_MASK;
140 mask &= ~(1 << hwirq);
141 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
142 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
145 static void socrates_fpga_pic_mask_ack(unsigned int virq)
147 unsigned long flags;
148 unsigned int hwirq;
149 int irq_line;
150 u32 mask;
152 hwirq = socrates_fpga_irq_to_hw(virq);
154 irq_line = fpga_irqs[hwirq].irq_line;
155 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
156 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
157 & SOCRATES_FPGA_IRQ_MASK;
158 mask &= ~(1 << hwirq);
159 mask |= (1 << (hwirq + 16));
160 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
161 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
164 static void socrates_fpga_pic_unmask(unsigned int virq)
166 unsigned long flags;
167 unsigned int hwirq;
168 int irq_line;
169 u32 mask;
171 hwirq = socrates_fpga_irq_to_hw(virq);
173 irq_line = fpga_irqs[hwirq].irq_line;
174 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
175 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
176 & SOCRATES_FPGA_IRQ_MASK;
177 mask |= (1 << hwirq);
178 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
179 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
182 static void socrates_fpga_pic_eoi(unsigned int virq)
184 unsigned long flags;
185 unsigned int hwirq;
186 int irq_line;
187 u32 mask;
189 hwirq = socrates_fpga_irq_to_hw(virq);
191 irq_line = fpga_irqs[hwirq].irq_line;
192 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
193 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
194 & SOCRATES_FPGA_IRQ_MASK;
195 mask |= (1 << (hwirq + 16));
196 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
197 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
200 static int socrates_fpga_pic_set_type(unsigned int virq,
201 unsigned int flow_type)
203 unsigned long flags;
204 unsigned int hwirq;
205 int polarity;
206 u32 mask;
208 hwirq = socrates_fpga_irq_to_hw(virq);
210 if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
211 return -EINVAL;
213 switch (flow_type & IRQ_TYPE_SENSE_MASK) {
214 case IRQ_TYPE_LEVEL_HIGH:
215 polarity = 1;
216 break;
217 case IRQ_TYPE_LEVEL_LOW:
218 polarity = 0;
219 break;
220 default:
221 return -EINVAL;
223 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
224 mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
225 if (polarity)
226 mask |= (1 << hwirq);
227 else
228 mask &= ~(1 << hwirq);
229 socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
230 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
231 return 0;
234 static struct irq_chip socrates_fpga_pic_chip = {
235 .typename = " FPGA-PIC ",
236 .ack = socrates_fpga_pic_ack,
237 .mask = socrates_fpga_pic_mask,
238 .mask_ack = socrates_fpga_pic_mask_ack,
239 .unmask = socrates_fpga_pic_unmask,
240 .eoi = socrates_fpga_pic_eoi,
241 .set_type = socrates_fpga_pic_set_type,
244 static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
245 irq_hw_number_t hwirq)
247 /* All interrupts are LEVEL sensitive */
248 get_irq_desc(virq)->status |= IRQ_LEVEL;
249 set_irq_chip_and_handler(virq, &socrates_fpga_pic_chip,
250 handle_fasteoi_irq);
252 return 0;
255 static int socrates_fpga_pic_host_xlate(struct irq_host *h,
256 struct device_node *ct, u32 *intspec, unsigned int intsize,
257 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
259 struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
261 *out_hwirq = intspec[0];
262 if (fpga_irq->type == IRQ_TYPE_NONE) {
263 /* type is configurable */
264 if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
265 intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
266 pr_warning("FPGA PIC: invalid irq type, "
267 "setting default active low\n");
268 *out_flags = IRQ_TYPE_LEVEL_LOW;
269 } else {
270 *out_flags = intspec[1];
272 } else {
273 /* type is fixed */
274 *out_flags = fpga_irq->type;
277 /* Use specified interrupt routing */
278 if (intspec[2] <= 2)
279 fpga_irq->irq_line = intspec[2];
280 else
281 pr_warning("FPGA PIC: invalid irq routing\n");
283 return 0;
286 static struct irq_host_ops socrates_fpga_pic_host_ops = {
287 .map = socrates_fpga_pic_host_map,
288 .xlate = socrates_fpga_pic_host_xlate,
291 void socrates_fpga_pic_init(struct device_node *pic)
293 unsigned long flags;
294 int i;
296 /* Setup an irq_host structure */
297 socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
298 SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops,
299 SOCRATES_FPGA_NUM_IRQS);
300 if (socrates_fpga_pic_irq_host == NULL) {
301 pr_err("FPGA PIC: Unable to allocate host\n");
302 return;
305 for (i = 0; i < 3; i++) {
306 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
307 if (socrates_fpga_irqs[i] == NO_IRQ) {
308 pr_warning("FPGA PIC: can't get irq%d.\n", i);
309 continue;
311 set_irq_chained_handler(socrates_fpga_irqs[i],
312 socrates_fpga_pic_cascade);
315 socrates_fpga_pic_iobase = of_iomap(pic, 0);
317 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
318 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
319 SOCRATES_FPGA_IRQ_MASK << 16);
320 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
321 SOCRATES_FPGA_IRQ_MASK << 16);
322 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
323 SOCRATES_FPGA_IRQ_MASK << 16);
324 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
326 pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");