WIP FPC-III support
[linux/fpc-iii.git] / arch / powerpc / platforms / 85xx / socrates_fpga_pic.c
blob199a137c0ddb08ecf23a2b4cd578864198433abd
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2008 Ilya Yanok, Emcraft Systems
4 */
6 #include <linux/irq.h>
7 #include <linux/of_address.h>
8 #include <linux/of_irq.h>
9 #include <linux/of_platform.h>
10 #include <linux/io.h>
13 * The FPGA supports 9 interrupt sources, which can be routed to 3
14 * interrupt request lines of the MPIC. The line to be used can be
15 * specified through the third cell of FDT property "interrupts".
18 #define SOCRATES_FPGA_NUM_IRQS 9
20 #define FPGA_PIC_IRQCFG (0x0)
21 #define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n))
23 #define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
25 struct socrates_fpga_irq_info {
26 unsigned int irq_line;
27 int type;
31 * Interrupt routing and type table
33 * IRQ_TYPE_NONE means the interrupt type is configurable,
34 * otherwise it's fixed to the specified value.
36 static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
37 [0] = {0, IRQ_TYPE_NONE},
38 [1] = {0, IRQ_TYPE_LEVEL_HIGH},
39 [2] = {0, IRQ_TYPE_LEVEL_LOW},
40 [3] = {0, IRQ_TYPE_NONE},
41 [4] = {0, IRQ_TYPE_NONE},
42 [5] = {0, IRQ_TYPE_NONE},
43 [6] = {0, IRQ_TYPE_NONE},
44 [7] = {0, IRQ_TYPE_NONE},
45 [8] = {0, IRQ_TYPE_LEVEL_HIGH},
48 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
50 static void __iomem *socrates_fpga_pic_iobase;
51 static struct irq_domain *socrates_fpga_pic_irq_host;
52 static unsigned int socrates_fpga_irqs[3];
54 static inline uint32_t socrates_fpga_pic_read(int reg)
56 return in_be32(socrates_fpga_pic_iobase + reg);
59 static inline void socrates_fpga_pic_write(int reg, uint32_t val)
61 out_be32(socrates_fpga_pic_iobase + reg, val);
64 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
66 uint32_t cause;
67 unsigned long flags;
68 int i;
70 /* Check irq line routed to the MPIC */
71 for (i = 0; i < 3; i++) {
72 if (irq == socrates_fpga_irqs[i])
73 break;
75 if (i == 3)
76 return 0;
78 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
79 cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
80 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
81 for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
82 if (cause >> (i + 16))
83 break;
85 return irq_linear_revmap(socrates_fpga_pic_irq_host,
86 (irq_hw_number_t)i);
89 static void socrates_fpga_pic_cascade(struct irq_desc *desc)
91 struct irq_chip *chip = irq_desc_get_chip(desc);
92 unsigned int irq = irq_desc_get_irq(desc);
93 unsigned int cascade_irq;
96 * See if we actually have an interrupt, call generic handling code if
97 * we do.
99 cascade_irq = socrates_fpga_pic_get_irq(irq);
101 if (cascade_irq)
102 generic_handle_irq(cascade_irq);
103 chip->irq_eoi(&desc->irq_data);
106 static void socrates_fpga_pic_ack(struct irq_data *d)
108 unsigned long flags;
109 unsigned int irq_line, hwirq = irqd_to_hwirq(d);
110 uint32_t mask;
112 irq_line = fpga_irqs[hwirq].irq_line;
113 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
114 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
115 & SOCRATES_FPGA_IRQ_MASK;
116 mask |= (1 << (hwirq + 16));
117 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
118 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
121 static void socrates_fpga_pic_mask(struct irq_data *d)
123 unsigned long flags;
124 unsigned int hwirq = irqd_to_hwirq(d);
125 int irq_line;
126 u32 mask;
128 irq_line = fpga_irqs[hwirq].irq_line;
129 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
130 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
131 & SOCRATES_FPGA_IRQ_MASK;
132 mask &= ~(1 << hwirq);
133 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
134 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
137 static void socrates_fpga_pic_mask_ack(struct irq_data *d)
139 unsigned long flags;
140 unsigned int hwirq = irqd_to_hwirq(d);
141 int irq_line;
142 u32 mask;
144 irq_line = fpga_irqs[hwirq].irq_line;
145 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
146 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
147 & SOCRATES_FPGA_IRQ_MASK;
148 mask &= ~(1 << hwirq);
149 mask |= (1 << (hwirq + 16));
150 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
151 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
154 static void socrates_fpga_pic_unmask(struct irq_data *d)
156 unsigned long flags;
157 unsigned int hwirq = irqd_to_hwirq(d);
158 int irq_line;
159 u32 mask;
161 irq_line = fpga_irqs[hwirq].irq_line;
162 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
163 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
164 & SOCRATES_FPGA_IRQ_MASK;
165 mask |= (1 << hwirq);
166 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
167 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
170 static void socrates_fpga_pic_eoi(struct irq_data *d)
172 unsigned long flags;
173 unsigned int hwirq = irqd_to_hwirq(d);
174 int irq_line;
175 u32 mask;
177 irq_line = fpga_irqs[hwirq].irq_line;
178 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
179 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
180 & SOCRATES_FPGA_IRQ_MASK;
181 mask |= (1 << (hwirq + 16));
182 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
183 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
186 static int socrates_fpga_pic_set_type(struct irq_data *d,
187 unsigned int flow_type)
189 unsigned long flags;
190 unsigned int hwirq = irqd_to_hwirq(d);
191 int polarity;
192 u32 mask;
194 if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
195 return -EINVAL;
197 switch (flow_type & IRQ_TYPE_SENSE_MASK) {
198 case IRQ_TYPE_LEVEL_HIGH:
199 polarity = 1;
200 break;
201 case IRQ_TYPE_LEVEL_LOW:
202 polarity = 0;
203 break;
204 default:
205 return -EINVAL;
207 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
208 mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
209 if (polarity)
210 mask |= (1 << hwirq);
211 else
212 mask &= ~(1 << hwirq);
213 socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
214 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
215 return 0;
218 static struct irq_chip socrates_fpga_pic_chip = {
219 .name = "FPGA-PIC",
220 .irq_ack = socrates_fpga_pic_ack,
221 .irq_mask = socrates_fpga_pic_mask,
222 .irq_mask_ack = socrates_fpga_pic_mask_ack,
223 .irq_unmask = socrates_fpga_pic_unmask,
224 .irq_eoi = socrates_fpga_pic_eoi,
225 .irq_set_type = socrates_fpga_pic_set_type,
228 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
229 irq_hw_number_t hwirq)
231 /* All interrupts are LEVEL sensitive */
232 irq_set_status_flags(virq, IRQ_LEVEL);
233 irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
234 handle_fasteoi_irq);
236 return 0;
239 static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
240 struct device_node *ct, const u32 *intspec, unsigned int intsize,
241 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
243 struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
245 *out_hwirq = intspec[0];
246 if (fpga_irq->type == IRQ_TYPE_NONE) {
247 /* type is configurable */
248 if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
249 intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
250 pr_warn("FPGA PIC: invalid irq type, setting default active low\n");
251 *out_flags = IRQ_TYPE_LEVEL_LOW;
252 } else {
253 *out_flags = intspec[1];
255 } else {
256 /* type is fixed */
257 *out_flags = fpga_irq->type;
260 /* Use specified interrupt routing */
261 if (intspec[2] <= 2)
262 fpga_irq->irq_line = intspec[2];
263 else
264 pr_warn("FPGA PIC: invalid irq routing\n");
266 return 0;
269 static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
270 .map = socrates_fpga_pic_host_map,
271 .xlate = socrates_fpga_pic_host_xlate,
274 void socrates_fpga_pic_init(struct device_node *pic)
276 unsigned long flags;
277 int i;
279 /* Setup an irq_domain structure */
280 socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
281 SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
282 if (socrates_fpga_pic_irq_host == NULL) {
283 pr_err("FPGA PIC: Unable to allocate host\n");
284 return;
287 for (i = 0; i < 3; i++) {
288 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
289 if (!socrates_fpga_irqs[i]) {
290 pr_warn("FPGA PIC: can't get irq%d\n", i);
291 continue;
293 irq_set_chained_handler(socrates_fpga_irqs[i],
294 socrates_fpga_pic_cascade);
297 socrates_fpga_pic_iobase = of_iomap(pic, 0);
299 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
300 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
301 SOCRATES_FPGA_IRQ_MASK << 16);
302 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
303 SOCRATES_FPGA_IRQ_MASK << 16);
304 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
305 SOCRATES_FPGA_IRQ_MASK << 16);
306 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
308 pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");