ARM: OMAP2/3: intc: Add DT support for TI interrupt controller
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-omap2 / irq.c
index 1fef061f7927929be28987d7ca10b270f05f04d3..26eaf37ce4d931dae322411a589d8c36dae3af1c 100644 (file)
  * for more details.
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/exception.h>
 #include <asm/mach/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 
 
 /* selected INTC register offsets */
@@ -57,6 +61,8 @@ static struct omap_irq_bank {
        },
 };
 
+static struct irq_domain *domain;
+
 /* Structure to save interrupt controller context */
 struct omap3_intc_regs {
        u32 sysconfig;
@@ -147,17 +153,27 @@ omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
                                IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 }
 
-static void __init omap_init_irq(u32 base, int nr_irqs)
+static void __init omap_init_irq(u32 base, int nr_irqs,
+                                struct device_node *node)
 {
        void __iomem *omap_irq_base;
        unsigned long nr_of_irqs = 0;
        unsigned int nr_banks = 0;
-       int i, j;
+       int i, j, irq_base;
 
        omap_irq_base = ioremap(base, SZ_4K);
        if (WARN_ON(!omap_irq_base))
                return;
 
+       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+       if (irq_base < 0) {
+               pr_warn("Couldn't allocate IRQ numbers\n");
+               irq_base = 0;
+       }
+
+       domain = irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+                                      &irq_domain_simple_ops, NULL);
+
        for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
                struct omap_irq_bank *bank = irq_banks + i;
 
@@ -166,36 +182,36 @@ static void __init omap_init_irq(u32 base, int nr_irqs)
                /* Static mapping, never released */
                bank->base_reg = ioremap(base, SZ_4K);
                if (!bank->base_reg) {
-                       printk(KERN_ERR "Could not ioremap irq bank%i\n", i);
+                       pr_err("Could not ioremap irq bank%i\n", i);
                        continue;
                }
 
                omap_irq_bank_init_one(bank);
 
                for (j = 0; j < bank->nr_irqs; j += 32)
-                       omap_alloc_gc(bank->base_reg + j, j, 32);
+                       omap_alloc_gc(bank->base_reg + j, j + irq_base, 32);
 
                nr_of_irqs += bank->nr_irqs;
                nr_banks++;
        }
 
-       printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n",
-              nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
+       pr_info("Total of %ld interrupts on %d active controller%s\n",
+               nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
 }
 
 void __init omap2_init_irq(void)
 {
-       omap_init_irq(OMAP24XX_IC_BASE, 96);
+       omap_init_irq(OMAP24XX_IC_BASE, 96, NULL);
 }
 
 void __init omap3_init_irq(void)
 {
-       omap_init_irq(OMAP34XX_IC_BASE, 96);
+       omap_init_irq(OMAP34XX_IC_BASE, 96, NULL);
 }
 
 void __init ti81xx_init_irq(void)
 {
-       omap_init_irq(OMAP34XX_IC_BASE, 128);
+       omap_init_irq(OMAP34XX_IC_BASE, 128, NULL);
 }
 
 static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs *regs)
@@ -225,8 +241,10 @@ out:
                irqnr = readl_relaxed(base_addr + INTCPS_SIR_IRQ_OFFSET);
                irqnr &= ACTIVEIRQ_MASK;
 
-               if (irqnr)
+               if (irqnr) {
+                       irqnr = irq_find_mapping(domain, irqnr);
                        handle_IRQ(irqnr, regs);
+               }
        } while (irqnr);
 }
 
@@ -236,6 +254,28 @@ asmlinkage void __exception_irq_entry omap2_intc_handle_irq(struct pt_regs *regs
        omap_intc_handle_irq(base_addr, regs);
 }
 
+int __init omap_intc_of_init(struct device_node *node,
+                            struct device_node *parent)
+{
+       struct resource res;
+       u32 nr_irqs = 96;
+
+       if (WARN_ON(!node))
+               return -ENODEV;
+
+       if (of_address_to_resource(node, 0, &res)) {
+               WARN(1, "unable to get intc registers\n");
+               return -EINVAL;
+       }
+
+       if (of_property_read_u32(node, "ti,intc-size", &nr_irqs))
+               pr_warn("unable to get intc-size, default to %d\n", nr_irqs);
+
+       omap_init_irq(res.start, nr_irqs, of_node_get(node));
+
+       return 0;
+}
+
 #ifdef CONFIG_ARCH_OMAP3
 static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)];