aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-mips-gic.c
diff options
context:
space:
mode:
authorAndrew Bresticker <abrestic@chromium.org>2014-11-12 14:43:38 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-11-24 01:45:30 -0500
commita7057270c280a5904d747f40e53b5402e7dddc0e (patch)
treed14d79c5518c5070b210080131c0403f46b7f598 /drivers/irqchip/irq-mips-gic.c
parent2ff404005e9f94ee3d05b6b0dac8204c1fcc2346 (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.c92
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
21unsigned int gic_present; 27unsigned int gic_present;
22 28
23struct gic_pcpu_mask { 29struct 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
671static 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
665static struct irq_domain_ops gic_irq_domain_ops = { 690static 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
670void __init gic_init(unsigned long gic_base_addr, 695static 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
735void __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
742static 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}
789IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init);