linux/drivers/irqchip/spear-shirq.c
<<
>>
Prefs
   1/*
   2 * SPEAr platform shared irq layer source file
   3 *
   4 * Copyright (C) 2009-2012 ST Microelectronics
   5 * Viresh Kumar <vireshk@kernel.org>
   6 *
   7 * Copyright (C) 2012 ST Microelectronics
   8 * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
   9 *
  10 * This file is licensed under the terms of the GNU General Public
  11 * License version 2. This program is licensed "as is" without any
  12 * warranty of any kind, whether express or implied.
  13 */
  14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15
  16#include <linux/err.h>
  17#include <linux/export.h>
  18#include <linux/interrupt.h>
  19#include <linux/io.h>
  20#include <linux/irq.h>
  21#include <linux/irqchip.h>
  22#include <linux/irqdomain.h>
  23#include <linux/of.h>
  24#include <linux/of_address.h>
  25#include <linux/of_irq.h>
  26#include <linux/spinlock.h>
  27
  28/*
  29 * struct spear_shirq: shared irq structure
  30 *
  31 * base:        Base register address
  32 * status_reg:  Status register offset for chained interrupt handler
  33 * mask_reg:    Mask register offset for irq chip
  34 * mask:        Mask to apply to the status register
  35 * virq_base:   Base virtual interrupt number
  36 * nr_irqs:     Number of interrupts handled by this block
  37 * offset:      Bit offset of the first interrupt
  38 * irq_chip:    Interrupt controller chip used for this instance,
  39 *              if NULL group is disabled, but accounted
  40 */
  41struct spear_shirq {
  42        void __iomem            *base;
  43        u32                     status_reg;
  44        u32                     mask_reg;
  45        u32                     mask;
  46        u32                     virq_base;
  47        u32                     nr_irqs;
  48        u32                     offset;
  49        struct irq_chip         *irq_chip;
  50};
  51
  52/* spear300 shared irq registers offsets and masks */
  53#define SPEAR300_INT_ENB_MASK_REG       0x54
  54#define SPEAR300_INT_STS_MASK_REG       0x58
  55
  56static DEFINE_RAW_SPINLOCK(shirq_lock);
  57
  58static void shirq_irq_mask(struct irq_data *d)
  59{
  60        struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
  61        u32 val, shift = d->irq - shirq->virq_base + shirq->offset;
  62        u32 __iomem *reg = shirq->base + shirq->mask_reg;
  63
  64        raw_spin_lock(&shirq_lock);
  65        val = readl(reg) & ~(0x1 << shift);
  66        writel(val, reg);
  67        raw_spin_unlock(&shirq_lock);
  68}
  69
  70static void shirq_irq_unmask(struct irq_data *d)
  71{
  72        struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
  73        u32 val, shift = d->irq - shirq->virq_base + shirq->offset;
  74        u32 __iomem *reg = shirq->base + shirq->mask_reg;
  75
  76        raw_spin_lock(&shirq_lock);
  77        val = readl(reg) | (0x1 << shift);
  78        writel(val, reg);
  79        raw_spin_unlock(&shirq_lock);
  80}
  81
  82static struct irq_chip shirq_chip = {
  83        .name           = "spear-shirq",
  84        .irq_mask       = shirq_irq_mask,
  85        .irq_unmask     = shirq_irq_unmask,
  86};
  87
  88static struct spear_shirq spear300_shirq_ras1 = {
  89        .offset         = 0,
  90        .nr_irqs        = 9,
  91        .mask           = ((0x1 << 9) - 1) << 0,
  92        .irq_chip       = &shirq_chip,
  93        .status_reg     = SPEAR300_INT_STS_MASK_REG,
  94        .mask_reg       = SPEAR300_INT_ENB_MASK_REG,
  95};
  96
  97static struct spear_shirq *spear300_shirq_blocks[] = {
  98        &spear300_shirq_ras1,
  99};
 100
 101/* spear310 shared irq registers offsets and masks */
 102#define SPEAR310_INT_STS_MASK_REG       0x04
 103
 104static struct spear_shirq spear310_shirq_ras1 = {
 105        .offset         = 0,
 106        .nr_irqs        = 8,
 107        .mask           = ((0x1 << 8) - 1) << 0,
 108        .irq_chip       = &dummy_irq_chip,
 109        .status_reg     = SPEAR310_INT_STS_MASK_REG,
 110};
 111
 112static struct spear_shirq spear310_shirq_ras2 = {
 113        .offset         = 8,
 114        .nr_irqs        = 5,
 115        .mask           = ((0x1 << 5) - 1) << 8,
 116        .irq_chip       = &dummy_irq_chip,
 117        .status_reg     = SPEAR310_INT_STS_MASK_REG,
 118};
 119
 120static struct spear_shirq spear310_shirq_ras3 = {
 121        .offset         = 13,
 122        .nr_irqs        = 1,
 123        .mask           = ((0x1 << 1) - 1) << 13,
 124        .irq_chip       = &dummy_irq_chip,
 125        .status_reg     = SPEAR310_INT_STS_MASK_REG,
 126};
 127
 128static struct spear_shirq spear310_shirq_intrcomm_ras = {
 129        .offset         = 14,
 130        .nr_irqs        = 3,
 131        .mask           = ((0x1 << 3) - 1) << 14,
 132        .irq_chip       = &dummy_irq_chip,
 133        .status_reg     = SPEAR310_INT_STS_MASK_REG,
 134};
 135
 136static struct spear_shirq *spear310_shirq_blocks[] = {
 137        &spear310_shirq_ras1,
 138        &spear310_shirq_ras2,
 139        &spear310_shirq_ras3,
 140        &spear310_shirq_intrcomm_ras,
 141};
 142
 143/* spear320 shared irq registers offsets and masks */
 144#define SPEAR320_INT_STS_MASK_REG               0x04
 145#define SPEAR320_INT_CLR_MASK_REG               0x04
 146#define SPEAR320_INT_ENB_MASK_REG               0x08
 147
 148static struct spear_shirq spear320_shirq_ras3 = {
 149        .offset         = 0,
 150        .nr_irqs        = 7,
 151        .mask           = ((0x1 << 7) - 1) << 0,
 152};
 153
 154static struct spear_shirq spear320_shirq_ras1 = {
 155        .offset         = 7,
 156        .nr_irqs        = 3,
 157        .mask           = ((0x1 << 3) - 1) << 7,
 158        .irq_chip       = &dummy_irq_chip,
 159        .status_reg     = SPEAR320_INT_STS_MASK_REG,
 160};
 161
 162static struct spear_shirq spear320_shirq_ras2 = {
 163        .offset         = 10,
 164        .nr_irqs        = 1,
 165        .mask           = ((0x1 << 1) - 1) << 10,
 166        .irq_chip       = &dummy_irq_chip,
 167        .status_reg     = SPEAR320_INT_STS_MASK_REG,
 168};
 169
 170static struct spear_shirq spear320_shirq_intrcomm_ras = {
 171        .offset         = 11,
 172        .nr_irqs        = 11,
 173        .mask           = ((0x1 << 11) - 1) << 11,
 174        .irq_chip       = &dummy_irq_chip,
 175        .status_reg     = SPEAR320_INT_STS_MASK_REG,
 176};
 177
 178static struct spear_shirq *spear320_shirq_blocks[] = {
 179        &spear320_shirq_ras3,
 180        &spear320_shirq_ras1,
 181        &spear320_shirq_ras2,
 182        &spear320_shirq_intrcomm_ras,
 183};
 184
 185static void shirq_handler(struct irq_desc *desc)
 186{
 187        struct spear_shirq *shirq = irq_desc_get_handler_data(desc);
 188        u32 pend;
 189
 190        pend = readl(shirq->base + shirq->status_reg) & shirq->mask;
 191        pend >>= shirq->offset;
 192
 193        while (pend) {
 194                int irq = __ffs(pend);
 195
 196                pend &= ~(0x1 << irq);
 197                generic_handle_irq(shirq->virq_base + irq);
 198        }
 199}
 200
 201static void __init spear_shirq_register(struct spear_shirq *shirq,
 202                                        int parent_irq)
 203{
 204        int i;
 205
 206        if (!shirq->irq_chip)
 207                return;
 208
 209        irq_set_chained_handler_and_data(parent_irq, shirq_handler, shirq);
 210
 211        for (i = 0; i < shirq->nr_irqs; i++) {
 212                irq_set_chip_and_handler(shirq->virq_base + i,
 213                                         shirq->irq_chip, handle_simple_irq);
 214                irq_set_chip_data(shirq->virq_base + i, shirq);
 215        }
 216}
 217
 218static int __init shirq_init(struct spear_shirq **shirq_blocks, int block_nr,
 219                struct device_node *np)
 220{
 221        int i, parent_irq, virq_base, hwirq = 0, nr_irqs = 0;
 222        struct irq_domain *shirq_domain;
 223        void __iomem *base;
 224
 225        base = of_iomap(np, 0);
 226        if (!base) {
 227                pr_err("%s: failed to map shirq registers\n", __func__);
 228                return -ENXIO;
 229        }
 230
 231        for (i = 0; i < block_nr; i++)
 232                nr_irqs += shirq_blocks[i]->nr_irqs;
 233
 234        virq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
 235        if (virq_base < 0) {
 236                pr_err("%s: irq desc alloc failed\n", __func__);
 237                goto err_unmap;
 238        }
 239
 240        shirq_domain = irq_domain_add_legacy(np, nr_irqs, virq_base, 0,
 241                        &irq_domain_simple_ops, NULL);
 242        if (WARN_ON(!shirq_domain)) {
 243                pr_warn("%s: irq domain init failed\n", __func__);
 244                goto err_free_desc;
 245        }
 246
 247        for (i = 0; i < block_nr; i++) {
 248                shirq_blocks[i]->base = base;
 249                shirq_blocks[i]->virq_base = irq_find_mapping(shirq_domain,
 250                                hwirq);
 251
 252                parent_irq = irq_of_parse_and_map(np, i);
 253                spear_shirq_register(shirq_blocks[i], parent_irq);
 254                hwirq += shirq_blocks[i]->nr_irqs;
 255        }
 256
 257        return 0;
 258
 259err_free_desc:
 260        irq_free_descs(virq_base, nr_irqs);
 261err_unmap:
 262        iounmap(base);
 263        return -ENXIO;
 264}
 265
 266static int __init spear300_shirq_of_init(struct device_node *np,
 267                                         struct device_node *parent)
 268{
 269        return shirq_init(spear300_shirq_blocks,
 270                        ARRAY_SIZE(spear300_shirq_blocks), np);
 271}
 272IRQCHIP_DECLARE(spear300_shirq, "st,spear300-shirq", spear300_shirq_of_init);
 273
 274static int __init spear310_shirq_of_init(struct device_node *np,
 275                                         struct device_node *parent)
 276{
 277        return shirq_init(spear310_shirq_blocks,
 278                        ARRAY_SIZE(spear310_shirq_blocks), np);
 279}
 280IRQCHIP_DECLARE(spear310_shirq, "st,spear310-shirq", spear310_shirq_of_init);
 281
 282static int __init spear320_shirq_of_init(struct device_node *np,
 283                                         struct device_node *parent)
 284{
 285        return shirq_init(spear320_shirq_blocks,
 286                        ARRAY_SIZE(spear320_shirq_blocks), np);
 287}
 288IRQCHIP_DECLARE(spear320_shirq, "st,spear320-shirq", spear320_shirq_of_init);
 289