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@xxxxxxxxxxxx> --- Changes from v2: - rebased on GIC irqchip cleanups - updated for change in bindings - only parse first CPU vector - allow platforms to use EIC mode Changes from v1: - updated for change in bindings - set base address and enable bit in GCR_GIC_BASE --- drivers/irqchip/irq-mips-gic.c | 71 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 61ac482..914d73d 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,38 @@ 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) +{ + int cpu_vec; + struct resource res; + + /* Use the first available CPU vector. */ + if (of_property_read_u32_index(node, "mti,available-cpu-vectors", 0, + &cpu_vec)) { + pr_err("No CPU vectors available for GIC\n"); + return -ENODEV; + } + + if (of_address_to_resource(node, 0, &res)) { + pr_err("Failed to get GIC memory range\n"); + return -ENODEV; + } + + if (mips_cm_present()) + write_gcr_gic_base(res.start | CM_GCR_GIC_BASE_GICEN_MSK); + gic_present = true; + + __gic_init(res.start, resource_size(&res), cpu_vec, 0, node); + + return 0; +} +IRQCHIP_DECLARE(mips_gic, "mti,interaptiv-gic", gic_of_init); -- 2.1.0.rc2.206.gedb03e5