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