aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/common/gic.c
diff options
context:
space:
mode:
authorRob Herring2011-09-28 21:27:52 -0500
committerArnd Bergmann2011-10-31 14:03:26 +0100
commitb3f7ed0324091e2cb23fe1b3c10570700f614014 (patch)
tree6f9a14a39fc4302276a1560cb48c1ede72fc5dff /arch/arm/common/gic.c
parent4294f8baaf174c9aa57886e7ed27caf4b02578f6 (diff)
ARM: gic: add OF based initialization
This adds ARM gic interrupt controller initialization using device tree data. The initialization function is intended to be called by of_irq_init function like this: const static struct of_device_id irq_match[] = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, {} }; static void __init init_irqs(void) { of_irq_init(irq_match); } Signed-off-by: Rob Herring <rob.herring@calxeda.com> Reviewed-by: Jamie Iles <jamie@jamieiles.com> Tested-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch/arm/common/gic.c')
-rw-r--r--arch/arm/common/gic.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index ccaa1ab18de7..1333e68b1f96 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -30,6 +30,9 @@
#include <linux/cpu_pm.h>
#include <linux/cpumask.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
@@ -530,7 +533,33 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
}
#endif
+#ifdef CONFIG_OF
+static int gic_irq_domain_dt_translate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ if (d->of_node != controller)
+ return -EINVAL;
+ if (intsize < 3)
+ return -EINVAL;
+
+ /* Get the interrupt number and add 16 to skip over SGIs */
+ *out_hwirq = intspec[1] + 16;
+
+ /* For SPIs, we need to add 16 more to get the GIC irq ID number */
+ if (!intspec[0])
+ *out_hwirq += 16;
+
+ *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+ return 0;
+}
+#endif
+
const struct irq_domain_ops gic_irq_domain_ops = {
+#ifdef CONFIG_OF
+ .dt_translate = gic_irq_domain_dt_translate,
+#endif
};
void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
@@ -608,3 +637,35 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
}
#endif
+
+#ifdef CONFIG_OF
+static int gic_cnt __initdata = 0;
+
+int __init gic_of_init(struct device_node *node, struct device_node *parent)
+{
+ void __iomem *cpu_base;
+ void __iomem *dist_base;
+ int irq;
+ struct irq_domain *domain = &gic_data[gic_cnt].domain;
+
+ if (WARN_ON(!node))
+ return -ENODEV;
+
+ dist_base = of_iomap(node, 0);
+ WARN(!dist_base, "unable to map gic dist registers\n");
+
+ cpu_base = of_iomap(node, 1);
+ WARN(!cpu_base, "unable to map gic cpu registers\n");
+
+ domain->of_node = of_node_get(node);
+
+ gic_init(gic_cnt, 16, dist_base, cpu_base);
+
+ if (parent) {
+ irq = irq_of_parse_and_map(node, 0);
+ gic_cascade_irq(gic_cnt, irq);
+ }
+ gic_cnt++;
+ return 0;
+}
+#endif