powerpc/powermac: move pmac_pci_probe_mode from setup.c to pci.c
[linux/fpc-iii.git] / arch / powerpc / platforms / 85xx / socrates_fpga_pic.c
blob55a9682b9529168a56e949779646ef8208693c89
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_address.h>
13 #include <linux/of_irq.h>
14 #include <linux/of_platform.h>
15 #include <linux/io.h>
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".
23 #define SOCRATES_FPGA_NUM_IRQS 9
25 #define FPGA_PIC_IRQCFG (0x0)
26 #define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n))
28 #define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
30 struct socrates_fpga_irq_info {
31 unsigned int irq_line;
32 int type;
36 * Interrupt routing and type table
38 * IRQ_TYPE_NONE means the interrupt type is configurable,
39 * otherwise it's fixed to the specified value.
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},
53 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
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];
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 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;
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 struct irq_chip *chip = irq_desc_get_chip(desc);
97 unsigned int cascade_irq;
100 * See if we actually have an interrupt, call generic handling code if
101 * we do.
103 cascade_irq = socrates_fpga_pic_get_irq(irq);
105 if (cascade_irq != NO_IRQ)
106 generic_handle_irq(cascade_irq);
107 chip->irq_eoi(&desc->irq_data);
110 static void socrates_fpga_pic_ack(struct irq_data *d)
112 unsigned long flags;
113 unsigned int irq_line, hwirq = irqd_to_hwirq(d);
114 uint32_t mask;
116 irq_line = fpga_irqs[hwirq].irq_line;
117 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
118 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
119 & SOCRATES_FPGA_IRQ_MASK;
120 mask |= (1 << (hwirq + 16));
121 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
122 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
125 static void socrates_fpga_pic_mask(struct irq_data *d)
127 unsigned long flags;
128 unsigned int hwirq = irqd_to_hwirq(d);
129 int irq_line;
130 u32 mask;
132 irq_line = fpga_irqs[hwirq].irq_line;
133 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
134 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
135 & SOCRATES_FPGA_IRQ_MASK;
136 mask &= ~(1 << hwirq);
137 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
138 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
141 static void socrates_fpga_pic_mask_ack(struct irq_data *d)
143 unsigned long flags;
144 unsigned int hwirq = irqd_to_hwirq(d);
145 int irq_line;
146 u32 mask;
148 irq_line = fpga_irqs[hwirq].irq_line;
149 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
150 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
151 & SOCRATES_FPGA_IRQ_MASK;
152 mask &= ~(1 << hwirq);
153 mask |= (1 << (hwirq + 16));
154 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
155 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
158 static void socrates_fpga_pic_unmask(struct irq_data *d)
160 unsigned long flags;
161 unsigned int hwirq = irqd_to_hwirq(d);
162 int irq_line;
163 u32 mask;
165 irq_line = fpga_irqs[hwirq].irq_line;
166 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
167 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
168 & SOCRATES_FPGA_IRQ_MASK;
169 mask |= (1 << hwirq);
170 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
171 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
174 static void socrates_fpga_pic_eoi(struct irq_data *d)
176 unsigned long flags;
177 unsigned int hwirq = irqd_to_hwirq(d);
178 int irq_line;
179 u32 mask;
181 irq_line = fpga_irqs[hwirq].irq_line;
182 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
183 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
184 & SOCRATES_FPGA_IRQ_MASK;
185 mask |= (1 << (hwirq + 16));
186 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
187 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
190 static int socrates_fpga_pic_set_type(struct irq_data *d,
191 unsigned int flow_type)
193 unsigned long flags;
194 unsigned int hwirq = irqd_to_hwirq(d);
195 int polarity;
196 u32 mask;
198 if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
199 return -EINVAL;
201 switch (flow_type & IRQ_TYPE_SENSE_MASK) {
202 case IRQ_TYPE_LEVEL_HIGH:
203 polarity = 1;
204 break;
205 case IRQ_TYPE_LEVEL_LOW:
206 polarity = 0;
207 break;
208 default:
209 return -EINVAL;
211 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
212 mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
213 if (polarity)
214 mask |= (1 << hwirq);
215 else
216 mask &= ~(1 << hwirq);
217 socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
218 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
219 return 0;
222 static struct irq_chip socrates_fpga_pic_chip = {
223 .name = "FPGA-PIC",
224 .irq_ack = socrates_fpga_pic_ack,
225 .irq_mask = socrates_fpga_pic_mask,
226 .irq_mask_ack = socrates_fpga_pic_mask_ack,
227 .irq_unmask = socrates_fpga_pic_unmask,
228 .irq_eoi = socrates_fpga_pic_eoi,
229 .irq_set_type = socrates_fpga_pic_set_type,
232 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
233 irq_hw_number_t hwirq)
235 /* All interrupts are LEVEL sensitive */
236 irq_set_status_flags(virq, IRQ_LEVEL);
237 irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
238 handle_fasteoi_irq);
240 return 0;
243 static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
244 struct device_node *ct, const u32 *intspec, unsigned int intsize,
245 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
247 struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
249 *out_hwirq = intspec[0];
250 if (fpga_irq->type == IRQ_TYPE_NONE) {
251 /* type is configurable */
252 if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
253 intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
254 pr_warning("FPGA PIC: invalid irq type, "
255 "setting default active low\n");
256 *out_flags = IRQ_TYPE_LEVEL_LOW;
257 } else {
258 *out_flags = intspec[1];
260 } else {
261 /* type is fixed */
262 *out_flags = fpga_irq->type;
265 /* Use specified interrupt routing */
266 if (intspec[2] <= 2)
267 fpga_irq->irq_line = intspec[2];
268 else
269 pr_warning("FPGA PIC: invalid irq routing\n");
271 return 0;
274 static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
275 .map = socrates_fpga_pic_host_map,
276 .xlate = socrates_fpga_pic_host_xlate,
279 void socrates_fpga_pic_init(struct device_node *pic)
281 unsigned long flags;
282 int i;
284 /* Setup an irq_domain structure */
285 socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
286 SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
287 if (socrates_fpga_pic_irq_host == NULL) {
288 pr_err("FPGA PIC: Unable to allocate host\n");
289 return;
292 for (i = 0; i < 3; i++) {
293 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
294 if (socrates_fpga_irqs[i] == NO_IRQ) {
295 pr_warning("FPGA PIC: can't get irq%d.\n", i);
296 continue;
298 irq_set_chained_handler(socrates_fpga_irqs[i],
299 socrates_fpga_pic_cascade);
302 socrates_fpga_pic_iobase = of_iomap(pic, 0);
304 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
305 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
306 SOCRATES_FPGA_IRQ_MASK << 16);
307 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
308 SOCRATES_FPGA_IRQ_MASK << 16);
309 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
310 SOCRATES_FPGA_IRQ_MASK << 16);
311 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
313 pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");