linux/drivers/irqchip/irq-versatile-fpga.c
<<
>>
Prefs
   1/*
   2 *  Support for Versatile FPGA-based IRQ controllers
   3 */
   4#include <linux/bitops.h>
   5#include <linux/irq.h>
   6#include <linux/io.h>
   7#include <linux/irqchip/versatile-fpga.h>
   8#include <linux/irqdomain.h>
   9#include <linux/module.h>
  10#include <linux/of.h>
  11#include <linux/of_address.h>
  12
  13#include <asm/exception.h>
  14#include <asm/mach/irq.h>
  15
  16#define IRQ_STATUS              0x00
  17#define IRQ_RAW_STATUS          0x04
  18#define IRQ_ENABLE_SET          0x08
  19#define IRQ_ENABLE_CLEAR        0x0c
  20#define INT_SOFT_SET            0x10
  21#define INT_SOFT_CLEAR          0x14
  22#define FIQ_STATUS              0x20
  23#define FIQ_RAW_STATUS          0x24
  24#define FIQ_ENABLE              0x28
  25#define FIQ_ENABLE_SET          0x28
  26#define FIQ_ENABLE_CLEAR        0x2C
  27
  28/**
  29 * struct fpga_irq_data - irq data container for the FPGA IRQ controller
  30 * @base: memory offset in virtual memory
  31 * @chip: chip container for this instance
  32 * @domain: IRQ domain for this instance
  33 * @valid: mask for valid IRQs on this controller
  34 * @used_irqs: number of active IRQs on this controller
  35 */
  36struct fpga_irq_data {
  37        void __iomem *base;
  38        struct irq_chip chip;
  39        u32 valid;
  40        struct irq_domain *domain;
  41        u8 used_irqs;
  42};
  43
  44/* we cannot allocate memory when the controllers are initially registered */
  45static struct fpga_irq_data fpga_irq_devices[CONFIG_VERSATILE_FPGA_IRQ_NR];
  46static int fpga_irq_id;
  47
  48static void fpga_irq_mask(struct irq_data *d)
  49{
  50        struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
  51        u32 mask = 1 << d->hwirq;
  52
  53        writel(mask, f->base + IRQ_ENABLE_CLEAR);
  54}
  55
  56static void fpga_irq_unmask(struct irq_data *d)
  57{
  58        struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
  59        u32 mask = 1 << d->hwirq;
  60
  61        writel(mask, f->base + IRQ_ENABLE_SET);
  62}
  63
  64static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc)
  65{
  66        struct fpga_irq_data *f = irq_desc_get_handler_data(desc);
  67        u32 status = readl(f->base + IRQ_STATUS);
  68
  69        if (status == 0) {
  70                do_bad_IRQ(irq, desc);
  71                return;
  72        }
  73
  74        do {
  75                irq = ffs(status) - 1;
  76                status &= ~(1 << irq);
  77                generic_handle_irq(irq_find_mapping(f->domain, irq));
  78        } while (status);
  79}
  80
  81/*
  82 * Handle each interrupt in a single FPGA IRQ controller.  Returns non-zero
  83 * if we've handled at least one interrupt.  This does a single read of the
  84 * status register and handles all interrupts in order from LSB first.
  85 */
  86static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs)
  87{
  88        int handled = 0;
  89        int irq;
  90        u32 status;
  91
  92        while ((status  = readl(f->base + IRQ_STATUS))) {
  93                irq = ffs(status) - 1;
  94                handle_IRQ(irq_find_mapping(f->domain, irq), regs);
  95                handled = 1;
  96        }
  97
  98        return handled;
  99}
 100
 101/*
 102 * Keep iterating over all registered FPGA IRQ controllers until there are
 103 * no pending interrupts.
 104 */
 105asmlinkage void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs)
 106{
 107        int i, handled;
 108
 109        do {
 110                for (i = 0, handled = 0; i < fpga_irq_id; ++i)
 111                        handled |= handle_one_fpga(&fpga_irq_devices[i], regs);
 112        } while (handled);
 113}
 114
 115static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq,
 116                irq_hw_number_t hwirq)
 117{
 118        struct fpga_irq_data *f = d->host_data;
 119
 120        /* Skip invalid IRQs, only register handlers for the real ones */
 121        if (!(f->valid & BIT(hwirq)))
 122                return -EPERM;
 123        irq_set_chip_data(irq, f);
 124        irq_set_chip_and_handler(irq, &f->chip,
 125                                handle_level_irq);
 126        set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 127        return 0;
 128}
 129
 130static struct irq_domain_ops fpga_irqdomain_ops = {
 131        .map = fpga_irqdomain_map,
 132        .xlate = irq_domain_xlate_onetwocell,
 133};
 134
 135void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
 136                          int parent_irq, u32 valid, struct device_node *node)
 137{
 138        struct fpga_irq_data *f;
 139        int i;
 140
 141        if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) {
 142                pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_VERSATILE_FPGA_IRQ_NR\n", __func__);
 143                return;
 144        }
 145        f = &fpga_irq_devices[fpga_irq_id];
 146        f->base = base;
 147        f->chip.name = name;
 148        f->chip.irq_ack = fpga_irq_mask;
 149        f->chip.irq_mask = fpga_irq_mask;
 150        f->chip.irq_unmask = fpga_irq_unmask;
 151        f->valid = valid;
 152
 153        if (parent_irq != -1) {
 154                irq_set_handler_data(parent_irq, f);
 155                irq_set_chained_handler(parent_irq, fpga_irq_handle);
 156        }
 157
 158        /* This will also allocate irq descriptors */
 159        f->domain = irq_domain_add_simple(node, fls(valid), irq_start,
 160                                          &fpga_irqdomain_ops, f);
 161
 162        /* This will allocate all valid descriptors in the linear case */
 163        for (i = 0; i < fls(valid); i++)
 164                if (valid & BIT(i)) {
 165                        if (!irq_start)
 166                                irq_create_mapping(f->domain, i);
 167                        f->used_irqs++;
 168                }
 169
 170        pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n",
 171                fpga_irq_id, name, base, f->used_irqs);
 172
 173        fpga_irq_id++;
 174}
 175
 176#ifdef CONFIG_OF
 177int __init fpga_irq_of_init(struct device_node *node,
 178                            struct device_node *parent)
 179{
 180        void __iomem *base;
 181        u32 clear_mask;
 182        u32 valid_mask;
 183
 184        if (WARN_ON(!node))
 185                return -ENODEV;
 186
 187        base = of_iomap(node, 0);
 188        WARN(!base, "unable to map fpga irq registers\n");
 189
 190        if (of_property_read_u32(node, "clear-mask", &clear_mask))
 191                clear_mask = 0;
 192
 193        if (of_property_read_u32(node, "valid-mask", &valid_mask))
 194                valid_mask = 0;
 195
 196        fpga_irq_init(base, node->name, 0, -1, valid_mask, node);
 197
 198        writel(clear_mask, base + IRQ_ENABLE_CLEAR);
 199        writel(clear_mask, base + FIQ_ENABLE_CLEAR);
 200
 201        return 0;
 202}
 203#endif
 204
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.