Commit a7057270 authored by Andrew Bresticker's avatar Andrew Bresticker Committed by Ralf Baechle

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: default avatarAndrew Bresticker <abrestic@chromium.org>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Acked-by: default avatarJason 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: default avatarRalf Baechle <ralf@linux-mips.org>
parent 2ff40400
...@@ -12,12 +12,18 @@ ...@@ -12,12 +12,18 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqchip/mips-gic.h> #include <linux/irqchip/mips-gic.h>
#include <linux/of_address.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <asm/mips-cm.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <dt-bindings/interrupt-controller/mips-gic.h>
#include "irqchip.h"
unsigned int gic_present; unsigned int gic_present;
struct gic_pcpu_mask { struct gic_pcpu_mask {
...@@ -662,14 +668,34 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, ...@@ -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); 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 = { static struct irq_domain_ops gic_irq_domain_ops = {
.map = gic_irq_domain_map, .map = gic_irq_domain_map,
.xlate = irq_domain_xlate_twocell, .xlate = gic_irq_domain_xlate,
}; };
void __init gic_init(unsigned long gic_base_addr, static void __init __gic_init(unsigned long gic_base_addr,
unsigned long gic_addrspace_size, unsigned int cpu_vec, unsigned long gic_addrspace_size,
unsigned int irqbase) unsigned int cpu_vec, unsigned int irqbase,
struct device_node *node)
{ {
unsigned int gicconfig; unsigned int gicconfig;
...@@ -695,7 +721,7 @@ void __init gic_init(unsigned long gic_base_addr, ...@@ -695,7 +721,7 @@ void __init gic_init(unsigned long gic_base_addr,
gic_irq_dispatch); 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_shared_intrs, irqbase,
&gic_irq_domain_ops, NULL); &gic_irq_domain_ops, NULL);
if (!gic_irq_domain) if (!gic_irq_domain)
...@@ -705,3 +731,59 @@ void __init gic_init(unsigned long gic_base_addr, ...@@ -705,3 +731,59 @@ void __init gic_init(unsigned long gic_base_addr,
gic_ipi_init(); 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment