Merge remote-tracking branch 'scsi-queue/drivers-for-3.19' into for-linus
[cascardo/linux.git] / drivers / irqchip / irq-mips-gic.c
index bf0f7c9..2b0468e 100644 (file)
@@ -7,39 +7,31 @@
  * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
  */
 #include <linux/bitmap.h>
+#include <linux/clocksource.h>
 #include <linux/init.h>
 #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 <linux/irq.h>
-#include <linux/clocksource.h>
 
-#include <asm/io.h>
+#include <asm/mips-cm.h>
 #include <asm/setup.h>
 #include <asm/traps.h>
-#include <linux/hardirq.h>
-#include <asm-generic/bitops/find.h>
 
-unsigned int gic_frequency;
+#include <dt-bindings/interrupt-controller/mips-gic.h>
+
+#include "irqchip.h"
+
 unsigned int gic_present;
 
 struct gic_pcpu_mask {
        DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
 };
 
-struct gic_pending_regs {
-       DECLARE_BITMAP(pending, GIC_MAX_INTRS);
-};
-
-struct gic_intrmask_regs {
-       DECLARE_BITMAP(intrmask, GIC_MAX_INTRS);
-};
-
 static void __iomem *gic_base;
 static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
-static struct gic_pending_regs pending_regs[NR_CPUS];
-static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
 static DEFINE_SPINLOCK(gic_lock);
 static struct irq_domain *gic_irq_domain;
 static int gic_shared_intrs;
@@ -116,7 +108,7 @@ static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe)
                  GIC_SH_MAP_TO_VPE_REG_BIT(vpe));
 }
 
-#if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
+#ifdef CONFIG_CLKSRC_MIPS_GIC
 cycle_t gic_read_count(void)
 {
        unsigned int hi, hi2, lo;
@@ -219,7 +211,7 @@ static void gic_bind_eic_interrupt(int irq, int set)
 
 void gic_send_ipi(unsigned int intr)
 {
-       gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
+       gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(intr));
 }
 
 int gic_get_c0_compare_int(void)
@@ -245,16 +237,16 @@ int gic_get_c0_perfcount_int(void)
 static unsigned int gic_get_int(void)
 {
        unsigned int i;
-       unsigned long *pending, *intrmask, *pcpu_mask;
+       unsigned long *pcpu_mask;
        unsigned long pending_reg, intrmask_reg;
+       DECLARE_BITMAP(pending, GIC_MAX_INTRS);
+       DECLARE_BITMAP(intrmask, GIC_MAX_INTRS);
 
        /* Get per-cpu bitmaps */
-       pending = pending_regs[smp_processor_id()].pending;
-       intrmask = intrmask_regs[smp_processor_id()].intrmask;
        pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
 
-       pending_reg = GIC_REG(SHARED, GIC_SH_PEND_31_0);
-       intrmask_reg = GIC_REG(SHARED, GIC_SH_MASK_31_0);
+       pending_reg = GIC_REG(SHARED, GIC_SH_PEND);
+       intrmask_reg = GIC_REG(SHARED, GIC_SH_MASK);
 
        for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) {
                pending[i] = gic_read(pending_reg);
@@ -283,7 +275,7 @@ static void gic_ack_irq(struct irq_data *d)
 {
        unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
 
-       gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
+       gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_CLR(irq));
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -676,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;
 
@@ -709,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)
@@ -719,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);