diff options
author | Rob Herring <rob.herring@calxeda.com> | 2011-09-28 22:27:52 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2011-10-31 09:03:26 -0400 |
commit | b3f7ed0324091e2cb23fe1b3c10570700f614014 (patch) | |
tree | 6f9a14a39fc4302276a1560cb48c1ede72fc5dff /arch/arm/common | |
parent | 4294f8baaf174c9aa57886e7ed27caf4b02578f6 (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')
-rw-r--r-- | arch/arm/common/gic.c | 61 |
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 @@ | |||
30 | #include <linux/cpu_pm.h> | 30 | #include <linux/cpu_pm.h> |
31 | #include <linux/cpumask.h> | 31 | #include <linux/cpumask.h> |
32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/of.h> | ||
34 | #include <linux/of_address.h> | ||
35 | #include <linux/of_irq.h> | ||
33 | #include <linux/irqdomain.h> | 36 | #include <linux/irqdomain.h> |
34 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
35 | #include <linux/percpu.h> | 38 | #include <linux/percpu.h> |
@@ -530,7 +533,33 @@ static void __init gic_pm_init(struct gic_chip_data *gic) | |||
530 | } | 533 | } |
531 | #endif | 534 | #endif |
532 | 535 | ||
536 | #ifdef CONFIG_OF | ||
537 | static int gic_irq_domain_dt_translate(struct irq_domain *d, | ||
538 | struct device_node *controller, | ||
539 | const u32 *intspec, unsigned int intsize, | ||
540 | unsigned long *out_hwirq, unsigned int *out_type) | ||
541 | { | ||
542 | if (d->of_node != controller) | ||
543 | return -EINVAL; | ||
544 | if (intsize < 3) | ||
545 | return -EINVAL; | ||
546 | |||
547 | /* Get the interrupt number and add 16 to skip over SGIs */ | ||
548 | *out_hwirq = intspec[1] + 16; | ||
549 | |||
550 | /* For SPIs, we need to add 16 more to get the GIC irq ID number */ | ||
551 | if (!intspec[0]) | ||
552 | *out_hwirq += 16; | ||
553 | |||
554 | *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; | ||
555 | return 0; | ||
556 | } | ||
557 | #endif | ||
558 | |||
533 | const struct irq_domain_ops gic_irq_domain_ops = { | 559 | const struct irq_domain_ops gic_irq_domain_ops = { |
560 | #ifdef CONFIG_OF | ||
561 | .dt_translate = gic_irq_domain_dt_translate, | ||
562 | #endif | ||
534 | }; | 563 | }; |
535 | 564 | ||
536 | void __init gic_init(unsigned int gic_nr, unsigned int irq_start, | 565 | 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) | |||
608 | writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); | 637 | writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); |
609 | } | 638 | } |
610 | #endif | 639 | #endif |
640 | |||
641 | #ifdef CONFIG_OF | ||
642 | static int gic_cnt __initdata = 0; | ||
643 | |||
644 | int __init gic_of_init(struct device_node *node, struct device_node *parent) | ||
645 | { | ||
646 | void __iomem *cpu_base; | ||
647 | void __iomem *dist_base; | ||
648 | int irq; | ||
649 | struct irq_domain *domain = &gic_data[gic_cnt].domain; | ||
650 | |||
651 | if (WARN_ON(!node)) | ||
652 | return -ENODEV; | ||
653 | |||
654 | dist_base = of_iomap(node, 0); | ||
655 | WARN(!dist_base, "unable to map gic dist registers\n"); | ||
656 | |||
657 | cpu_base = of_iomap(node, 1); | ||
658 | WARN(!cpu_base, "unable to map gic cpu registers\n"); | ||
659 | |||
660 | domain->of_node = of_node_get(node); | ||
661 | |||
662 | gic_init(gic_cnt, 16, dist_base, cpu_base); | ||
663 | |||
664 | if (parent) { | ||
665 | irq = irq_of_parse_and_map(node, 0); | ||
666 | gic_cascade_irq(gic_cnt, irq); | ||
667 | } | ||
668 | gic_cnt++; | ||
669 | return 0; | ||
670 | } | ||
671 | #endif | ||