diff options
author | Andrew Bresticker <abrestic@chromium.org> | 2014-11-12 14:43:38 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-11-24 01:45:30 -0500 |
commit | a7057270c280a5904d747f40e53b5402e7dddc0e (patch) | |
tree | d14d79c5518c5070b210080131c0403f46b7f598 /drivers/irqchip/irq-mips-gic.c | |
parent | 2ff404005e9f94ee3d05b6b0dac8204c1fcc2346 (diff) |
irqchip: mips-gic: Add device-tree support
Add device-tree support for the MIPS GIC. Update the GIC irqdomain's
xlate() callback to handle the three-cell specifier described in the
MIPS GIC binding document.
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Jason Cooper <jason@lakedaemon.net>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: John Crispin <blogic@openwrt.org>
Cc: David Daney <ddaney.cavm@gmail.com>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/8422/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/irqchip/irq-mips-gic.c')
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 92 |
1 files changed, 87 insertions, 5 deletions
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 7ec3c18f1330..2b0468e3df6a 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c | |||
@@ -12,12 +12,18 @@ | |||
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | #include <linux/irqchip/mips-gic.h> | 14 | #include <linux/irqchip/mips-gic.h> |
15 | #include <linux/of_address.h> | ||
15 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
16 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
17 | 18 | ||
19 | #include <asm/mips-cm.h> | ||
18 | #include <asm/setup.h> | 20 | #include <asm/setup.h> |
19 | #include <asm/traps.h> | 21 | #include <asm/traps.h> |
20 | 22 | ||
23 | #include <dt-bindings/interrupt-controller/mips-gic.h> | ||
24 | |||
25 | #include "irqchip.h" | ||
26 | |||
21 | unsigned int gic_present; | 27 | unsigned int gic_present; |
22 | 28 | ||
23 | struct gic_pcpu_mask { | 29 | struct gic_pcpu_mask { |
@@ -662,14 +668,34 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, | |||
662 | return gic_shared_irq_domain_map(d, virq, hw); | 668 | return gic_shared_irq_domain_map(d, virq, hw); |
663 | } | 669 | } |
664 | 670 | ||
671 | static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, | ||
672 | const u32 *intspec, unsigned int intsize, | ||
673 | irq_hw_number_t *out_hwirq, | ||
674 | unsigned int *out_type) | ||
675 | { | ||
676 | if (intsize != 3) | ||
677 | return -EINVAL; | ||
678 | |||
679 | if (intspec[0] == GIC_SHARED) | ||
680 | *out_hwirq = GIC_SHARED_TO_HWIRQ(intspec[1]); | ||
681 | else if (intspec[0] == GIC_LOCAL) | ||
682 | *out_hwirq = GIC_LOCAL_TO_HWIRQ(intspec[1]); | ||
683 | else | ||
684 | return -EINVAL; | ||
685 | *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; | ||
686 | |||
687 | return 0; | ||
688 | } | ||
689 | |||
665 | static struct irq_domain_ops gic_irq_domain_ops = { | 690 | static struct irq_domain_ops gic_irq_domain_ops = { |
666 | .map = gic_irq_domain_map, | 691 | .map = gic_irq_domain_map, |
667 | .xlate = irq_domain_xlate_twocell, | 692 | .xlate = gic_irq_domain_xlate, |
668 | }; | 693 | }; |
669 | 694 | ||
670 | void __init gic_init(unsigned long gic_base_addr, | 695 | static void __init __gic_init(unsigned long gic_base_addr, |
671 | unsigned long gic_addrspace_size, unsigned int cpu_vec, | 696 | unsigned long gic_addrspace_size, |
672 | unsigned int irqbase) | 697 | unsigned int cpu_vec, unsigned int irqbase, |
698 | struct device_node *node) | ||
673 | { | 699 | { |
674 | unsigned int gicconfig; | 700 | unsigned int gicconfig; |
675 | 701 | ||
@@ -695,7 +721,7 @@ void __init gic_init(unsigned long gic_base_addr, | |||
695 | gic_irq_dispatch); | 721 | gic_irq_dispatch); |
696 | } | 722 | } |
697 | 723 | ||
698 | gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_LOCAL_INTRS + | 724 | gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + |
699 | gic_shared_intrs, irqbase, | 725 | gic_shared_intrs, irqbase, |
700 | &gic_irq_domain_ops, NULL); | 726 | &gic_irq_domain_ops, NULL); |
701 | if (!gic_irq_domain) | 727 | if (!gic_irq_domain) |
@@ -705,3 +731,59 @@ void __init gic_init(unsigned long gic_base_addr, | |||
705 | 731 | ||
706 | gic_ipi_init(); | 732 | gic_ipi_init(); |
707 | } | 733 | } |
734 | |||
735 | void __init gic_init(unsigned long gic_base_addr, | ||
736 | unsigned long gic_addrspace_size, | ||
737 | unsigned int cpu_vec, unsigned int irqbase) | ||
738 | { | ||
739 | __gic_init(gic_base_addr, gic_addrspace_size, cpu_vec, irqbase, NULL); | ||
740 | } | ||
741 | |||
742 | static int __init gic_of_init(struct device_node *node, | ||
743 | struct device_node *parent) | ||
744 | { | ||
745 | struct resource res; | ||
746 | unsigned int cpu_vec, i = 0, reserved = 0; | ||
747 | phys_addr_t gic_base; | ||
748 | size_t gic_len; | ||
749 | |||
750 | /* Find the first available CPU vector. */ | ||
751 | while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors", | ||
752 | i++, &cpu_vec)) | ||
753 | reserved |= BIT(cpu_vec); | ||
754 | for (cpu_vec = 2; cpu_vec < 8; cpu_vec++) { | ||
755 | if (!(reserved & BIT(cpu_vec))) | ||
756 | break; | ||
757 | } | ||
758 | if (cpu_vec == 8) { | ||
759 | pr_err("No CPU vectors available for GIC\n"); | ||
760 | return -ENODEV; | ||
761 | } | ||
762 | |||
763 | if (of_address_to_resource(node, 0, &res)) { | ||
764 | /* | ||
765 | * Probe the CM for the GIC base address if not specified | ||
766 | * in the device-tree. | ||
767 | */ | ||
768 | if (mips_cm_present()) { | ||
769 | gic_base = read_gcr_gic_base() & | ||
770 | ~CM_GCR_GIC_BASE_GICEN_MSK; | ||
771 | gic_len = 0x20000; | ||
772 | } else { | ||
773 | pr_err("Failed to get GIC memory range\n"); | ||
774 | return -ENODEV; | ||
775 | } | ||
776 | } else { | ||
777 | gic_base = res.start; | ||
778 | gic_len = resource_size(&res); | ||
779 | } | ||
780 | |||
781 | if (mips_cm_present()) | ||
782 | write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK); | ||
783 | gic_present = true; | ||
784 | |||
785 | __gic_init(gic_base, gic_len, cpu_vec, 0, node); | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init); | ||