Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * SPEAr platform shared irq layer source file
0003  *
0004  * Copyright (C) 2009-2012 ST Microelectronics
0005  * Viresh Kumar <vireshk@kernel.org>
0006  *
0007  * Copyright (C) 2012 ST Microelectronics
0008  * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
0009  *
0010  * This file is licensed under the terms of the GNU General Public
0011  * License version 2. This program is licensed "as is" without any
0012  * warranty of any kind, whether express or implied.
0013  */
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015 
0016 #include <linux/err.h>
0017 #include <linux/export.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/io.h>
0020 #include <linux/irq.h>
0021 #include <linux/irqchip.h>
0022 #include <linux/irqdomain.h>
0023 #include <linux/of.h>
0024 #include <linux/of_address.h>
0025 #include <linux/of_irq.h>
0026 #include <linux/spinlock.h>
0027 
0028 /*
0029  * struct spear_shirq: shared irq structure
0030  *
0031  * base:    Base register address
0032  * status_reg:  Status register offset for chained interrupt handler
0033  * mask_reg:    Mask register offset for irq chip
0034  * mask:    Mask to apply to the status register
0035  * virq_base:   Base virtual interrupt number
0036  * nr_irqs: Number of interrupts handled by this block
0037  * offset:  Bit offset of the first interrupt
0038  * irq_chip:    Interrupt controller chip used for this instance,
0039  *      if NULL group is disabled, but accounted
0040  */
0041 struct spear_shirq {
0042     void __iomem        *base;
0043     u32         status_reg;
0044     u32         mask_reg;
0045     u32         mask;
0046     u32         virq_base;
0047     u32         nr_irqs;
0048     u32         offset;
0049     struct irq_chip     *irq_chip;
0050 };
0051 
0052 /* spear300 shared irq registers offsets and masks */
0053 #define SPEAR300_INT_ENB_MASK_REG   0x54
0054 #define SPEAR300_INT_STS_MASK_REG   0x58
0055 
0056 static DEFINE_RAW_SPINLOCK(shirq_lock);
0057 
0058 static void shirq_irq_mask(struct irq_data *d)
0059 {
0060     struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
0061     u32 val, shift = d->irq - shirq->virq_base + shirq->offset;
0062     u32 __iomem *reg = shirq->base + shirq->mask_reg;
0063 
0064     raw_spin_lock(&shirq_lock);
0065     val = readl(reg) & ~(0x1 << shift);
0066     writel(val, reg);
0067     raw_spin_unlock(&shirq_lock);
0068 }
0069 
0070 static void shirq_irq_unmask(struct irq_data *d)
0071 {
0072     struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
0073     u32 val, shift = d->irq - shirq->virq_base + shirq->offset;
0074     u32 __iomem *reg = shirq->base + shirq->mask_reg;
0075 
0076     raw_spin_lock(&shirq_lock);
0077     val = readl(reg) | (0x1 << shift);
0078     writel(val, reg);
0079     raw_spin_unlock(&shirq_lock);
0080 }
0081 
0082 static struct irq_chip shirq_chip = {
0083     .name       = "spear-shirq",
0084     .irq_mask   = shirq_irq_mask,
0085     .irq_unmask = shirq_irq_unmask,
0086 };
0087 
0088 static struct spear_shirq spear300_shirq_ras1 = {
0089     .offset     = 0,
0090     .nr_irqs    = 9,
0091     .mask       = ((0x1 << 9) - 1) << 0,
0092     .irq_chip   = &shirq_chip,
0093     .status_reg = SPEAR300_INT_STS_MASK_REG,
0094     .mask_reg   = SPEAR300_INT_ENB_MASK_REG,
0095 };
0096 
0097 static struct spear_shirq *spear300_shirq_blocks[] = {
0098     &spear300_shirq_ras1,
0099 };
0100 
0101 /* spear310 shared irq registers offsets and masks */
0102 #define SPEAR310_INT_STS_MASK_REG   0x04
0103 
0104 static struct spear_shirq spear310_shirq_ras1 = {
0105     .offset     = 0,
0106     .nr_irqs    = 8,
0107     .mask       = ((0x1 << 8) - 1) << 0,
0108     .irq_chip   = &dummy_irq_chip,
0109     .status_reg = SPEAR310_INT_STS_MASK_REG,
0110 };
0111 
0112 static struct spear_shirq spear310_shirq_ras2 = {
0113     .offset     = 8,
0114     .nr_irqs    = 5,
0115     .mask       = ((0x1 << 5) - 1) << 8,
0116     .irq_chip   = &dummy_irq_chip,
0117     .status_reg = SPEAR310_INT_STS_MASK_REG,
0118 };
0119 
0120 static struct spear_shirq spear310_shirq_ras3 = {
0121     .offset     = 13,
0122     .nr_irqs    = 1,
0123     .mask       = ((0x1 << 1) - 1) << 13,
0124     .irq_chip   = &dummy_irq_chip,
0125     .status_reg = SPEAR310_INT_STS_MASK_REG,
0126 };
0127 
0128 static struct spear_shirq spear310_shirq_intrcomm_ras = {
0129     .offset     = 14,
0130     .nr_irqs    = 3,
0131     .mask       = ((0x1 << 3) - 1) << 14,
0132     .irq_chip   = &dummy_irq_chip,
0133     .status_reg = SPEAR310_INT_STS_MASK_REG,
0134 };
0135 
0136 static struct spear_shirq *spear310_shirq_blocks[] = {
0137     &spear310_shirq_ras1,
0138     &spear310_shirq_ras2,
0139     &spear310_shirq_ras3,
0140     &spear310_shirq_intrcomm_ras,
0141 };
0142 
0143 /* spear320 shared irq registers offsets and masks */
0144 #define SPEAR320_INT_STS_MASK_REG       0x04
0145 #define SPEAR320_INT_CLR_MASK_REG       0x04
0146 #define SPEAR320_INT_ENB_MASK_REG       0x08
0147 
0148 static struct spear_shirq spear320_shirq_ras3 = {
0149     .offset     = 0,
0150     .nr_irqs    = 7,
0151     .mask       = ((0x1 << 7) - 1) << 0,
0152     .irq_chip   = &dummy_irq_chip,
0153     .status_reg = SPEAR320_INT_STS_MASK_REG,
0154 };
0155 
0156 static struct spear_shirq spear320_shirq_ras1 = {
0157     .offset     = 7,
0158     .nr_irqs    = 3,
0159     .mask       = ((0x1 << 3) - 1) << 7,
0160     .irq_chip   = &dummy_irq_chip,
0161     .status_reg = SPEAR320_INT_STS_MASK_REG,
0162 };
0163 
0164 static struct spear_shirq spear320_shirq_ras2 = {
0165     .offset     = 10,
0166     .nr_irqs    = 1,
0167     .mask       = ((0x1 << 1) - 1) << 10,
0168     .irq_chip   = &dummy_irq_chip,
0169     .status_reg = SPEAR320_INT_STS_MASK_REG,
0170 };
0171 
0172 static struct spear_shirq spear320_shirq_intrcomm_ras = {
0173     .offset     = 11,
0174     .nr_irqs    = 11,
0175     .mask       = ((0x1 << 11) - 1) << 11,
0176     .irq_chip   = &dummy_irq_chip,
0177     .status_reg = SPEAR320_INT_STS_MASK_REG,
0178 };
0179 
0180 static struct spear_shirq *spear320_shirq_blocks[] = {
0181     &spear320_shirq_ras3,
0182     &spear320_shirq_ras1,
0183     &spear320_shirq_ras2,
0184     &spear320_shirq_intrcomm_ras,
0185 };
0186 
0187 static void shirq_handler(struct irq_desc *desc)
0188 {
0189     struct spear_shirq *shirq = irq_desc_get_handler_data(desc);
0190     u32 pend;
0191 
0192     pend = readl(shirq->base + shirq->status_reg) & shirq->mask;
0193     pend >>= shirq->offset;
0194 
0195     while (pend) {
0196         int irq = __ffs(pend);
0197 
0198         pend &= ~(0x1 << irq);
0199         generic_handle_irq(shirq->virq_base + irq);
0200     }
0201 }
0202 
0203 static void __init spear_shirq_register(struct spear_shirq *shirq,
0204                     int parent_irq)
0205 {
0206     int i;
0207 
0208     if (!shirq->irq_chip)
0209         return;
0210 
0211     irq_set_chained_handler_and_data(parent_irq, shirq_handler, shirq);
0212 
0213     for (i = 0; i < shirq->nr_irqs; i++) {
0214         irq_set_chip_and_handler(shirq->virq_base + i,
0215                      shirq->irq_chip, handle_simple_irq);
0216         irq_set_chip_data(shirq->virq_base + i, shirq);
0217     }
0218 }
0219 
0220 static int __init shirq_init(struct spear_shirq **shirq_blocks, int block_nr,
0221         struct device_node *np)
0222 {
0223     int i, parent_irq, virq_base, hwirq = 0, nr_irqs = 0;
0224     struct irq_domain *shirq_domain;
0225     void __iomem *base;
0226 
0227     base = of_iomap(np, 0);
0228     if (!base) {
0229         pr_err("%s: failed to map shirq registers\n", __func__);
0230         return -ENXIO;
0231     }
0232 
0233     for (i = 0; i < block_nr; i++)
0234         nr_irqs += shirq_blocks[i]->nr_irqs;
0235 
0236     virq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
0237     if (virq_base < 0) {
0238         pr_err("%s: irq desc alloc failed\n", __func__);
0239         goto err_unmap;
0240     }
0241 
0242     shirq_domain = irq_domain_add_legacy(np, nr_irqs, virq_base, 0,
0243             &irq_domain_simple_ops, NULL);
0244     if (WARN_ON(!shirq_domain)) {
0245         pr_warn("%s: irq domain init failed\n", __func__);
0246         goto err_free_desc;
0247     }
0248 
0249     for (i = 0; i < block_nr; i++) {
0250         shirq_blocks[i]->base = base;
0251         shirq_blocks[i]->virq_base = irq_find_mapping(shirq_domain,
0252                 hwirq);
0253 
0254         parent_irq = irq_of_parse_and_map(np, i);
0255         spear_shirq_register(shirq_blocks[i], parent_irq);
0256         hwirq += shirq_blocks[i]->nr_irqs;
0257     }
0258 
0259     return 0;
0260 
0261 err_free_desc:
0262     irq_free_descs(virq_base, nr_irqs);
0263 err_unmap:
0264     iounmap(base);
0265     return -ENXIO;
0266 }
0267 
0268 static int __init spear300_shirq_of_init(struct device_node *np,
0269                      struct device_node *parent)
0270 {
0271     return shirq_init(spear300_shirq_blocks,
0272             ARRAY_SIZE(spear300_shirq_blocks), np);
0273 }
0274 IRQCHIP_DECLARE(spear300_shirq, "st,spear300-shirq", spear300_shirq_of_init);
0275 
0276 static int __init spear310_shirq_of_init(struct device_node *np,
0277                      struct device_node *parent)
0278 {
0279     return shirq_init(spear310_shirq_blocks,
0280             ARRAY_SIZE(spear310_shirq_blocks), np);
0281 }
0282 IRQCHIP_DECLARE(spear310_shirq, "st,spear310-shirq", spear310_shirq_of_init);
0283 
0284 static int __init spear320_shirq_of_init(struct device_node *np,
0285                      struct device_node *parent)
0286 {
0287     return shirq_init(spear320_shirq_blocks,
0288             ARRAY_SIZE(spear320_shirq_blocks), np);
0289 }
0290 IRQCHIP_DECLARE(spear320_shirq, "st,spear320-shirq", spear320_shirq_of_init);