diff options
author | Andrew Bresticker <abrestic@chromium.org> | 2014-11-12 11:43:38 -0800 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-11-24 07:45:30 +0100 |
commit | a7057270c280a5904d747f40e53b5402e7dddc0e (patch) | |
tree | d14d79c5518c5070b210080131c0403f46b7f598 | |
parent | 2ff404005e9f94ee3d05b6b0dac8204c1fcc2346 (diff) | |
download | linux-a7057270c280a5904d747f40e53b5402e7dddc0e.tar.bz2 |
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>
-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 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqchip/mips-gic.h> +#include <linux/of_address.h> #include <linux/sched.h> #include <linux/smp.h> +#include <asm/mips-cm.h> #include <asm/setup.h> #include <asm/traps.h> +#include <dt-bindings/interrupt-controller/mips-gic.h> + +#include "irqchip.h" + unsigned int gic_present; struct gic_pcpu_mask { @@ -662,14 +668,34 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, return gic_shared_irq_domain_map(d, virq, hw); } +static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_type) +{ + if (intsize != 3) + return -EINVAL; + + if (intspec[0] == GIC_SHARED) + *out_hwirq = GIC_SHARED_TO_HWIRQ(intspec[1]); + else if (intspec[0] == GIC_LOCAL) + *out_hwirq = GIC_LOCAL_TO_HWIRQ(intspec[1]); + else + return -EINVAL; + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return 0; +} + static struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, - .xlate = irq_domain_xlate_twocell, + .xlate = gic_irq_domain_xlate, }; -void __init gic_init(unsigned long gic_base_addr, - unsigned long gic_addrspace_size, unsigned int cpu_vec, - unsigned int irqbase) +static void __init __gic_init(unsigned long gic_base_addr, + unsigned long gic_addrspace_size, + unsigned int cpu_vec, unsigned int irqbase, + struct device_node *node) { unsigned int gicconfig; @@ -695,7 +721,7 @@ void __init gic_init(unsigned long gic_base_addr, gic_irq_dispatch); } - gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_LOCAL_INTRS + + gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + gic_shared_intrs, irqbase, &gic_irq_domain_ops, NULL); if (!gic_irq_domain) @@ -705,3 +731,59 @@ void __init gic_init(unsigned long gic_base_addr, gic_ipi_init(); } + +void __init gic_init(unsigned long gic_base_addr, + unsigned long gic_addrspace_size, + unsigned int cpu_vec, unsigned int irqbase) +{ + __gic_init(gic_base_addr, gic_addrspace_size, cpu_vec, irqbase, NULL); +} + +static int __init gic_of_init(struct device_node *node, + struct device_node *parent) +{ + struct resource res; + unsigned int cpu_vec, i = 0, reserved = 0; + phys_addr_t gic_base; + size_t gic_len; + + /* Find the first available CPU vector. */ + while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors", + i++, &cpu_vec)) + reserved |= BIT(cpu_vec); + for (cpu_vec = 2; cpu_vec < 8; cpu_vec++) { + if (!(reserved & BIT(cpu_vec))) + break; + } + if (cpu_vec == 8) { + pr_err("No CPU vectors available for GIC\n"); + return -ENODEV; + } + + if (of_address_to_resource(node, 0, &res)) { + /* + * Probe the CM for the GIC base address if not specified + * in the device-tree. + */ + if (mips_cm_present()) { + gic_base = read_gcr_gic_base() & + ~CM_GCR_GIC_BASE_GICEN_MSK; + gic_len = 0x20000; + } else { + pr_err("Failed to get GIC memory range\n"); + return -ENODEV; + } + } else { + gic_base = res.start; + gic_len = resource_size(&res); + } + + if (mips_cm_present()) + write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK); + gic_present = true; + + __gic_init(gic_base, gic_len, cpu_vec, 0, node); + + return 0; +} +IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init); |