~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/85xx/socrates_fpga_pic.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php