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