root/arch/powerpc/platforms/85xx/socrates_fpga_pic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. socrates_fpga_pic_read
  2. socrates_fpga_pic_write
  3. socrates_fpga_pic_get_irq
  4. socrates_fpga_pic_cascade
  5. socrates_fpga_pic_ack
  6. socrates_fpga_pic_mask
  7. socrates_fpga_pic_mask_ack
  8. socrates_fpga_pic_unmask
  9. socrates_fpga_pic_eoi
  10. socrates_fpga_pic_set_type
  11. socrates_fpga_pic_host_map
  12. socrates_fpga_pic_host_xlate
  13. socrates_fpga_pic_init

   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 }

/* [<][>][^][v][top][bottom][index][help] */