Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / powerpc / platforms / 85xx / socrates_fpga_pic.c
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/of_platform.h>
10 #include <linux/io.h>
11
12 /*
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".
16  */
17
18 #define SOCRATES_FPGA_NUM_IRQS  9
19
20 #define FPGA_PIC_IRQCFG         (0x0)
21 #define FPGA_PIC_IRQMASK(n)     (0x4 + 0x4 * (n))
22
23 #define SOCRATES_FPGA_IRQ_MASK  ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
24
25 struct socrates_fpga_irq_info {
26         unsigned int irq_line;
27         int type;
28 };
29
30 /*
31  * Interrupt routing and type table
32  *
33  * IRQ_TYPE_NONE means the interrupt type is configurable,
34  * otherwise it's fixed to the specified value.
35  */
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},
46 };
47
48 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
49
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];
53
54 static inline uint32_t socrates_fpga_pic_read(int reg)
55 {
56         return in_be32(socrates_fpga_pic_iobase + reg);
57 }
58
59 static inline void socrates_fpga_pic_write(int reg, uint32_t val)
60 {
61         out_be32(socrates_fpga_pic_iobase + reg, val);
62 }
63
64 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
65 {
66         uint32_t cause;
67         unsigned long flags;
68         int i;
69
70         /* Check irq line routed to the MPIC */
71         for (i = 0; i < 3; i++) {
72                 if (irq == socrates_fpga_irqs[i])
73                         break;
74         }
75         if (i == 3)
76                 return 0;
77
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;
84         }
85         return irq_linear_revmap(socrates_fpga_pic_irq_host,
86                         (irq_hw_number_t)i);
87 }
88
89 static void socrates_fpga_pic_cascade(struct irq_desc *desc)
90 {
91         struct irq_chip *chip = irq_desc_get_chip(desc);
92         unsigned int irq = irq_desc_get_irq(desc);
93         unsigned int cascade_irq;
94
95         /*
96          * See if we actually have an interrupt, call generic handling code if
97          * we do.
98          */
99         cascade_irq = socrates_fpga_pic_get_irq(irq);
100
101         if (cascade_irq)
102                 generic_handle_irq(cascade_irq);
103         chip->irq_eoi(&desc->irq_data);
104 }
105
106 static void socrates_fpga_pic_ack(struct irq_data *d)
107 {
108         unsigned long flags;
109         unsigned int irq_line, hwirq = irqd_to_hwirq(d);
110         uint32_t mask;
111
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);
119 }
120
121 static void socrates_fpga_pic_mask(struct irq_data *d)
122 {
123         unsigned long flags;
124         unsigned int hwirq = irqd_to_hwirq(d);
125         int irq_line;
126         u32 mask;
127
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);
135 }
136
137 static void socrates_fpga_pic_mask_ack(struct irq_data *d)
138 {
139         unsigned long flags;
140         unsigned int hwirq = irqd_to_hwirq(d);
141         int irq_line;
142         u32 mask;
143
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);
152 }
153
154 static void socrates_fpga_pic_unmask(struct irq_data *d)
155 {
156         unsigned long flags;
157         unsigned int hwirq = irqd_to_hwirq(d);
158         int irq_line;
159         u32 mask;
160
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);
168 }
169
170 static void socrates_fpga_pic_eoi(struct irq_data *d)
171 {
172         unsigned long flags;
173         unsigned int hwirq = irqd_to_hwirq(d);
174         int irq_line;
175         u32 mask;
176
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);
184 }
185
186 static int socrates_fpga_pic_set_type(struct irq_data *d,
187                 unsigned int flow_type)
188 {
189         unsigned long flags;
190         unsigned int hwirq = irqd_to_hwirq(d);
191         int polarity;
192         u32 mask;
193
194         if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
195                 return -EINVAL;
196
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;
206         }
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;
216 }
217
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,
226 };
227
228 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
229                 irq_hw_number_t hwirq)
230 {
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);
235
236         return 0;
237 }
238
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)
242 {
243         struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
244
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];
254                 }
255         } else {
256                 /* type is fixed */
257                 *out_flags = fpga_irq->type;
258         }
259
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");
265
266         return 0;
267 }
268
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,
272 };
273
274 void socrates_fpga_pic_init(struct device_node *pic)
275 {
276         unsigned long flags;
277         int i;
278
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;
285         }
286
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;
292                 }
293                 irq_set_chained_handler(socrates_fpga_irqs[i],
294                                         socrates_fpga_pic_cascade);
295         }
296
297         socrates_fpga_pic_iobase = of_iomap(pic, 0);
298
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);
307
308         pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
309 }