Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright (C) 2008 Ilya Yanok, Emcraft Systems
0004  */
0005 
0006 #include <linux/irq.h>
0007 #include <linux/of_address.h>
0008 #include <linux/of_irq.h>
0009 #include <linux/of_platform.h>
0010 #include <linux/io.h>
0011 
0012 /*
0013  * The FPGA supports 9 interrupt sources, which can be routed to 3
0014  * interrupt request lines of the MPIC. The line to be used can be
0015  * specified through the third cell of FDT property  "interrupts".
0016  */
0017 
0018 #define SOCRATES_FPGA_NUM_IRQS  9
0019 
0020 #define FPGA_PIC_IRQCFG     (0x0)
0021 #define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n))
0022 
0023 #define SOCRATES_FPGA_IRQ_MASK  ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
0024 
0025 struct socrates_fpga_irq_info {
0026     unsigned int irq_line;
0027     int type;
0028 };
0029 
0030 /*
0031  * Interrupt routing and type table
0032  *
0033  * IRQ_TYPE_NONE means the interrupt type is configurable,
0034  * otherwise it's fixed to the specified value.
0035  */
0036 static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
0037     [0] = {0, IRQ_TYPE_NONE},
0038     [1] = {0, IRQ_TYPE_LEVEL_HIGH},
0039     [2] = {0, IRQ_TYPE_LEVEL_LOW},
0040     [3] = {0, IRQ_TYPE_NONE},
0041     [4] = {0, IRQ_TYPE_NONE},
0042     [5] = {0, IRQ_TYPE_NONE},
0043     [6] = {0, IRQ_TYPE_NONE},
0044     [7] = {0, IRQ_TYPE_NONE},
0045     [8] = {0, IRQ_TYPE_LEVEL_HIGH},
0046 };
0047 
0048 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
0049 
0050 static void __iomem *socrates_fpga_pic_iobase;
0051 static struct irq_domain *socrates_fpga_pic_irq_host;
0052 static unsigned int socrates_fpga_irqs[3];
0053 
0054 static inline uint32_t socrates_fpga_pic_read(int reg)
0055 {
0056     return in_be32(socrates_fpga_pic_iobase + reg);
0057 }
0058 
0059 static inline void socrates_fpga_pic_write(int reg, uint32_t val)
0060 {
0061     out_be32(socrates_fpga_pic_iobase + reg, val);
0062 }
0063 
0064 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
0065 {
0066     uint32_t cause;
0067     unsigned long flags;
0068     int i;
0069 
0070     /* Check irq line routed to the MPIC */
0071     for (i = 0; i < 3; i++) {
0072         if (irq == socrates_fpga_irqs[i])
0073             break;
0074     }
0075     if (i == 3)
0076         return 0;
0077 
0078     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0079     cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
0080     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0081     for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
0082         if (cause >> (i + 16))
0083             break;
0084     }
0085     return irq_linear_revmap(socrates_fpga_pic_irq_host,
0086             (irq_hw_number_t)i);
0087 }
0088 
0089 static void socrates_fpga_pic_cascade(struct irq_desc *desc)
0090 {
0091     struct irq_chip *chip = irq_desc_get_chip(desc);
0092     unsigned int irq = irq_desc_get_irq(desc);
0093     unsigned int cascade_irq;
0094 
0095     /*
0096      * See if we actually have an interrupt, call generic handling code if
0097      * we do.
0098      */
0099     cascade_irq = socrates_fpga_pic_get_irq(irq);
0100 
0101     if (cascade_irq)
0102         generic_handle_irq(cascade_irq);
0103     chip->irq_eoi(&desc->irq_data);
0104 }
0105 
0106 static void socrates_fpga_pic_ack(struct irq_data *d)
0107 {
0108     unsigned long flags;
0109     unsigned int irq_line, hwirq = irqd_to_hwirq(d);
0110     uint32_t mask;
0111 
0112     irq_line = fpga_irqs[hwirq].irq_line;
0113     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0114     mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
0115         & SOCRATES_FPGA_IRQ_MASK;
0116     mask |= (1 << (hwirq + 16));
0117     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
0118     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0119 }
0120 
0121 static void socrates_fpga_pic_mask(struct irq_data *d)
0122 {
0123     unsigned long flags;
0124     unsigned int hwirq = irqd_to_hwirq(d);
0125     int irq_line;
0126     u32 mask;
0127 
0128     irq_line = fpga_irqs[hwirq].irq_line;
0129     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0130     mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
0131         & SOCRATES_FPGA_IRQ_MASK;
0132     mask &= ~(1 << hwirq);
0133     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
0134     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0135 }
0136 
0137 static void socrates_fpga_pic_mask_ack(struct irq_data *d)
0138 {
0139     unsigned long flags;
0140     unsigned int hwirq = irqd_to_hwirq(d);
0141     int irq_line;
0142     u32 mask;
0143 
0144     irq_line = fpga_irqs[hwirq].irq_line;
0145     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0146     mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
0147         & SOCRATES_FPGA_IRQ_MASK;
0148     mask &= ~(1 << hwirq);
0149     mask |= (1 << (hwirq + 16));
0150     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
0151     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0152 }
0153 
0154 static void socrates_fpga_pic_unmask(struct irq_data *d)
0155 {
0156     unsigned long flags;
0157     unsigned int hwirq = irqd_to_hwirq(d);
0158     int irq_line;
0159     u32 mask;
0160 
0161     irq_line = fpga_irqs[hwirq].irq_line;
0162     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0163     mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
0164         & SOCRATES_FPGA_IRQ_MASK;
0165     mask |= (1 << hwirq);
0166     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
0167     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0168 }
0169 
0170 static void socrates_fpga_pic_eoi(struct irq_data *d)
0171 {
0172     unsigned long flags;
0173     unsigned int hwirq = irqd_to_hwirq(d);
0174     int irq_line;
0175     u32 mask;
0176 
0177     irq_line = fpga_irqs[hwirq].irq_line;
0178     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0179     mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
0180         & SOCRATES_FPGA_IRQ_MASK;
0181     mask |= (1 << (hwirq + 16));
0182     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
0183     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0184 }
0185 
0186 static int socrates_fpga_pic_set_type(struct irq_data *d,
0187         unsigned int flow_type)
0188 {
0189     unsigned long flags;
0190     unsigned int hwirq = irqd_to_hwirq(d);
0191     int polarity;
0192     u32 mask;
0193 
0194     if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
0195         return -EINVAL;
0196 
0197     switch (flow_type & IRQ_TYPE_SENSE_MASK) {
0198     case IRQ_TYPE_LEVEL_HIGH:
0199         polarity = 1;
0200         break;
0201     case IRQ_TYPE_LEVEL_LOW:
0202         polarity = 0;
0203         break;
0204     default:
0205         return -EINVAL;
0206     }
0207     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0208     mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
0209     if (polarity)
0210         mask |= (1 << hwirq);
0211     else
0212         mask &= ~(1 << hwirq);
0213     socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
0214     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0215     return 0;
0216 }
0217 
0218 static struct irq_chip socrates_fpga_pic_chip = {
0219     .name       = "FPGA-PIC",
0220     .irq_ack    = socrates_fpga_pic_ack,
0221     .irq_mask   = socrates_fpga_pic_mask,
0222     .irq_mask_ack   = socrates_fpga_pic_mask_ack,
0223     .irq_unmask = socrates_fpga_pic_unmask,
0224     .irq_eoi    = socrates_fpga_pic_eoi,
0225     .irq_set_type   = socrates_fpga_pic_set_type,
0226 };
0227 
0228 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
0229         irq_hw_number_t hwirq)
0230 {
0231     /* All interrupts are LEVEL sensitive */
0232     irq_set_status_flags(virq, IRQ_LEVEL);
0233     irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
0234                  handle_fasteoi_irq);
0235 
0236     return 0;
0237 }
0238 
0239 static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
0240         struct device_node *ct, const u32 *intspec, unsigned int intsize,
0241         irq_hw_number_t *out_hwirq, unsigned int *out_flags)
0242 {
0243     struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
0244 
0245     *out_hwirq = intspec[0];
0246     if  (fpga_irq->type == IRQ_TYPE_NONE) {
0247         /* type is configurable */
0248         if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
0249             intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
0250             pr_warn("FPGA PIC: invalid irq type, setting default active low\n");
0251             *out_flags = IRQ_TYPE_LEVEL_LOW;
0252         } else {
0253             *out_flags = intspec[1];
0254         }
0255     } else {
0256         /* type is fixed */
0257         *out_flags = fpga_irq->type;
0258     }
0259 
0260     /* Use specified interrupt routing */
0261     if (intspec[2] <= 2)
0262         fpga_irq->irq_line = intspec[2];
0263     else
0264         pr_warn("FPGA PIC: invalid irq routing\n");
0265 
0266     return 0;
0267 }
0268 
0269 static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
0270     .map    = socrates_fpga_pic_host_map,
0271     .xlate  = socrates_fpga_pic_host_xlate,
0272 };
0273 
0274 void __init socrates_fpga_pic_init(struct device_node *pic)
0275 {
0276     unsigned long flags;
0277     int i;
0278 
0279     /* Setup an irq_domain structure */
0280     socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
0281             SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
0282     if (socrates_fpga_pic_irq_host == NULL) {
0283         pr_err("FPGA PIC: Unable to allocate host\n");
0284         return;
0285     }
0286 
0287     for (i = 0; i < 3; i++) {
0288         socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
0289         if (!socrates_fpga_irqs[i]) {
0290             pr_warn("FPGA PIC: can't get irq%d\n", i);
0291             continue;
0292         }
0293         irq_set_chained_handler(socrates_fpga_irqs[i],
0294                     socrates_fpga_pic_cascade);
0295     }
0296 
0297     socrates_fpga_pic_iobase = of_iomap(pic, 0);
0298 
0299     raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
0300     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
0301             SOCRATES_FPGA_IRQ_MASK << 16);
0302     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
0303             SOCRATES_FPGA_IRQ_MASK << 16);
0304     socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
0305             SOCRATES_FPGA_IRQ_MASK << 16);
0306     raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
0307 
0308     pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
0309 }