]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - drivers/irqchip/irq-mips-gic.c
Merge branch '4.14-features' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[thirdparty/kernel/stable.git] / drivers / irqchip / irq-mips-gic.c
index b3a60da088db4c7e7c17fc31f51445f091e3a2e9..6e52a88bbd9e9cc7a832d67b13c717efe5cb039a 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
-#include <linux/irqchip/mips-gic.h>
 #include <linux/of_address.h>
+#include <linux/percpu.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 
-#include <asm/mips-cm.h>
+#include <asm/mips-cps.h>
 #include <asm/setup.h>
 #include <asm/traps.h>
 
 #include <dt-bindings/interrupt-controller/mips-gic.h>
 
-unsigned int gic_present;
+#define GIC_MAX_INTRS          256
+#define GIC_MAX_LONGS          BITS_TO_LONGS(GIC_MAX_INTRS)
 
-struct gic_pcpu_mask {
-       DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
-};
+/* Add 2 to convert GIC CPU pin to core interrupt */
+#define GIC_CPU_PIN_OFFSET     2
+
+/* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */
+#define GIC_PIN_TO_VEC_OFFSET  1
+
+/* Convert between local/shared IRQ number and GIC HW IRQ number. */
+#define GIC_LOCAL_HWIRQ_BASE   0
+#define GIC_LOCAL_TO_HWIRQ(x)  (GIC_LOCAL_HWIRQ_BASE + (x))
+#define GIC_HWIRQ_TO_LOCAL(x)  ((x) - GIC_LOCAL_HWIRQ_BASE)
+#define GIC_SHARED_HWIRQ_BASE  GIC_NUM_LOCAL_INTRS
+#define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x))
+#define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE)
+
+void __iomem *mips_gic_base;
 
-static unsigned long __gic_base_addr;
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long[GIC_MAX_LONGS], pcpu_masks);
 
-static void __iomem *gic_base;
-static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
 static DEFINE_SPINLOCK(gic_lock);
 static struct irq_domain *gic_irq_domain;
 static struct irq_domain *gic_ipi_domain;
@@ -44,202 +55,13 @@ static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
 DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
 DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
 
-static void __gic_irq_dispatch(void);
-
-static inline u32 gic_read32(unsigned int reg)
-{
-       return __raw_readl(gic_base + reg);
-}
-
-static inline u64 gic_read64(unsigned int reg)
-{
-       return __raw_readq(gic_base + reg);
-}
-
-static inline unsigned long gic_read(unsigned int reg)
-{
-       if (!mips_cm_is64)
-               return gic_read32(reg);
-       else
-               return gic_read64(reg);
-}
-
-static inline void gic_write32(unsigned int reg, u32 val)
-{
-       return __raw_writel(val, gic_base + reg);
-}
-
-static inline void gic_write64(unsigned int reg, u64 val)
-{
-       return __raw_writeq(val, gic_base + reg);
-}
-
-static inline void gic_write(unsigned int reg, unsigned long val)
-{
-       if (!mips_cm_is64)
-               return gic_write32(reg, (u32)val);
-       else
-               return gic_write64(reg, (u64)val);
-}
-
-static inline void gic_update_bits(unsigned int reg, unsigned long mask,
-                                  unsigned long val)
-{
-       unsigned long regval;
-
-       regval = gic_read(reg);
-       regval &= ~mask;
-       regval |= val;
-       gic_write(reg, regval);
-}
-
-static inline void gic_reset_mask(unsigned int intr)
-{
-       gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr),
-                 1ul << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_mask(unsigned int intr)
-{
-       gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr),
-                 1ul << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_polarity(unsigned int intr, unsigned int pol)
-{
-       gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) +
-                       GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
-                       (unsigned long)pol << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_trigger(unsigned int intr, unsigned int trig)
-{
-       gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) +
-                       GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
-                       (unsigned long)trig << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual)
-{
-       gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr),
-                       1ul << GIC_INTR_BIT(intr),
-                       (unsigned long)dual << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_map_to_pin(unsigned int intr, unsigned int pin)
-{
-       gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) +
-                   GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin);
-}
-
-static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe)
-{
-       gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_VPE_BASE) +
-                 GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe),
-                 GIC_SH_MAP_TO_VPE_REG_BIT(vpe));
-}
-
-#ifdef CONFIG_CLKSRC_MIPS_GIC
-u64 notrace gic_read_count(void)
-{
-       unsigned int hi, hi2, lo;
-
-       if (mips_cm_is64)
-               return (u64)gic_read(GIC_REG(SHARED, GIC_SH_COUNTER));
-
-       do {
-               hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32));
-               lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00));
-               hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32));
-       } while (hi2 != hi);
-
-       return (((u64) hi) << 32) + lo;
-}
-
-unsigned int gic_get_count_width(void)
-{
-       unsigned int bits, config;
-
-       config = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
-       bits = 32 + 4 * ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >>
-                        GIC_SH_CONFIG_COUNTBITS_SHF);
-
-       return bits;
-}
-
-void notrace gic_write_compare(u64 cnt)
-{
-       if (mips_cm_is64) {
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt);
-       } else {
-               gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
-                                       (int)(cnt >> 32));
-               gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
-                                       (int)(cnt & 0xffffffff));
-       }
-}
-
-void notrace gic_write_cpu_compare(u64 cnt, int cpu)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), mips_cm_vp_id(cpu));
-
-       if (mips_cm_is64) {
-               gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt);
-       } else {
-               gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI),
-                                       (int)(cnt >> 32));
-               gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO),
-                                       (int)(cnt & 0xffffffff));
-       }
-
-       local_irq_restore(flags);
-}
-
-u64 gic_read_compare(void)
-{
-       unsigned int hi, lo;
-
-       if (mips_cm_is64)
-               return (u64)gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE));
-
-       hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI));
-       lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO));
-
-       return (((u64) hi) << 32) + lo;
-}
-
-void gic_start_count(void)
+static void gic_clear_pcpu_masks(unsigned int intr)
 {
-       u32 gicconfig;
-
-       /* Start the counter */
-       gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
-       gicconfig &= ~(1 << GIC_SH_CONFIG_COUNTSTOP_SHF);
-       gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
-}
-
-void gic_stop_count(void)
-{
-       u32 gicconfig;
-
-       /* Stop the counter */
-       gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
-       gicconfig |= 1 << GIC_SH_CONFIG_COUNTSTOP_SHF;
-       gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
-}
-
-#endif
-
-unsigned gic_read_local_vp_id(void)
-{
-       unsigned long ident;
+       unsigned int i;
 
-       ident = gic_read(GIC_REG(VPE_LOCAL, GIC_VP_IDENT));
-       return ident & GIC_VP_IDENT_VCNUM_MSK;
+       /* Clear the interrupt's bit in all pcpu_masks */
+       for_each_possible_cpu(i)
+               clear_bit(intr, per_cpu_ptr(pcpu_masks, i));
 }
 
 static bool gic_local_irq_is_routable(int intr)
@@ -250,17 +72,17 @@ static bool gic_local_irq_is_routable(int intr)
        if (cpu_has_veic)
                return true;
 
-       vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL));
+       vpe_ctl = read_gic_vl_ctl();
        switch (intr) {
        case GIC_LOCAL_INT_TIMER:
-               return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
+               return vpe_ctl & GIC_VX_CTL_TIMER_ROUTABLE;
        case GIC_LOCAL_INT_PERFCTR:
-               return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
+               return vpe_ctl & GIC_VX_CTL_PERFCNT_ROUTABLE;
        case GIC_LOCAL_INT_FDC:
-               return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
+               return vpe_ctl & GIC_VX_CTL_FDC_ROUTABLE;
        case GIC_LOCAL_INT_SWINT0:
        case GIC_LOCAL_INT_SWINT1:
-               return vpe_ctl & GIC_VPE_CTL_SWINT_RTBL_MSK;
+               return vpe_ctl & GIC_VX_CTL_SWINT_ROUTABLE;
        default:
                return true;
        }
@@ -272,15 +94,14 @@ static void gic_bind_eic_interrupt(int irq, int set)
        irq -= GIC_PIN_TO_VEC_OFFSET;
 
        /* Set irq to use shadow set */
-       gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_EIC_SHADOW_SET_BASE) +
-                 GIC_VPE_EIC_SS(irq), set);
+       write_gic_vl_eic_shadow_set(irq, set);
 }
 
 static void gic_send_ipi(struct irq_data *d, unsigned int cpu)
 {
        irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d));
 
-       gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(hwirq));
+       write_gic_wedge(GIC_WEDGE_RW | hwirq);
 }
 
 int gic_get_c0_compare_int(void)
@@ -316,47 +137,22 @@ int gic_get_c0_fdc_int(void)
                                  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
 }
 
-int gic_get_usm_range(struct resource *gic_usm_res)
-{
-       if (!gic_present)
-               return -1;
-
-       gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS;
-       gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1);
-
-       return 0;
-}
-
 static void gic_handle_shared_int(bool chained)
 {
-       unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4;
+       unsigned int intr, virq;
        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 */
-       pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
-
-       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);
-               intrmask[i] = gic_read(intrmask_reg);
-               pending_reg += gic_reg_step;
-               intrmask_reg += gic_reg_step;
-
-               if (!IS_ENABLED(CONFIG_64BIT) || mips_cm_is64)
-                       continue;
+       pcpu_mask = this_cpu_ptr(pcpu_masks);
 
-               pending[i] |= (u64)gic_read(pending_reg) << 32;
-               intrmask[i] |= (u64)gic_read(intrmask_reg) << 32;
-               pending_reg += gic_reg_step;
-               intrmask_reg += gic_reg_step;
-       }
+       if (mips_cm_is64)
+               __ioread64_copy(pending, addr_gic_pend(),
+                               DIV_ROUND_UP(gic_shared_intrs, 64));
+       else
+               __ioread32_copy(pending, addr_gic_pend(),
+                               DIV_ROUND_UP(gic_shared_intrs, 32));
 
-       bitmap_and(pending, pending, intrmask, gic_shared_intrs);
        bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
 
        for_each_set_bit(intr, pending, gic_shared_intrs) {
@@ -371,19 +167,30 @@ static void gic_handle_shared_int(bool chained)
 
 static void gic_mask_irq(struct irq_data *d)
 {
-       gic_reset_mask(GIC_HWIRQ_TO_SHARED(d->hwirq));
+       unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
+
+       write_gic_rmask(BIT(intr));
+       gic_clear_pcpu_masks(intr);
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
-       gic_set_mask(GIC_HWIRQ_TO_SHARED(d->hwirq));
+       struct cpumask *affinity = irq_data_get_affinity_mask(d);
+       unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
+       unsigned int cpu;
+
+       write_gic_smask(BIT(intr));
+
+       gic_clear_pcpu_masks(intr);
+       cpu = cpumask_first_and(affinity, cpu_online_mask);
+       set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
 }
 
 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), GIC_SH_WEDGE_CLR(irq));
+       write_gic_wedge(irq);
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -395,34 +202,34 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
        spin_lock_irqsave(&gic_lock, flags);
        switch (type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_FALLING:
-               gic_set_polarity(irq, GIC_POL_NEG);
-               gic_set_trigger(irq, GIC_TRIG_EDGE);
-               gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+               change_gic_pol(irq, GIC_POL_FALLING_EDGE);
+               change_gic_trig(irq, GIC_TRIG_EDGE);
+               change_gic_dual(irq, GIC_DUAL_SINGLE);
                is_edge = true;
                break;
        case IRQ_TYPE_EDGE_RISING:
-               gic_set_polarity(irq, GIC_POL_POS);
-               gic_set_trigger(irq, GIC_TRIG_EDGE);
-               gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+               change_gic_pol(irq, GIC_POL_RISING_EDGE);
+               change_gic_trig(irq, GIC_TRIG_EDGE);
+               change_gic_dual(irq, GIC_DUAL_SINGLE);
                is_edge = true;
                break;
        case IRQ_TYPE_EDGE_BOTH:
                /* polarity is irrelevant in this case */
-               gic_set_trigger(irq, GIC_TRIG_EDGE);
-               gic_set_dual_edge(irq, GIC_TRIG_DUAL_ENABLE);
+               change_gic_trig(irq, GIC_TRIG_EDGE);
+               change_gic_dual(irq, GIC_DUAL_DUAL);
                is_edge = true;
                break;
        case IRQ_TYPE_LEVEL_LOW:
-               gic_set_polarity(irq, GIC_POL_NEG);
-               gic_set_trigger(irq, GIC_TRIG_LEVEL);
-               gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+               change_gic_pol(irq, GIC_POL_ACTIVE_LOW);
+               change_gic_trig(irq, GIC_TRIG_LEVEL);
+               change_gic_dual(irq, GIC_DUAL_SINGLE);
                is_edge = false;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
        default:
-               gic_set_polarity(irq, GIC_POL_POS);
-               gic_set_trigger(irq, GIC_TRIG_LEVEL);
-               gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+               change_gic_pol(irq, GIC_POL_ACTIVE_HIGH);
+               change_gic_trig(irq, GIC_TRIG_LEVEL);
+               change_gic_dual(irq, GIC_DUAL_SINGLE);
                is_edge = false;
                break;
        }
@@ -443,32 +250,28 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
                            bool force)
 {
        unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
-       cpumask_t       tmp = CPU_MASK_NONE;
-       unsigned long   flags;
-       int             i, cpu;
+       unsigned long flags;
+       unsigned int cpu;
 
-       cpumask_and(&tmp, cpumask, cpu_online_mask);
-       if (cpumask_empty(&tmp))
+       cpu = cpumask_first_and(cpumask, cpu_online_mask);
+       if (cpu >= NR_CPUS)
                return -EINVAL;
 
-       cpu = cpumask_first(&tmp);
-
        /* Assumption : cpumask refers to a single CPU */
        spin_lock_irqsave(&gic_lock, flags);
 
        /* Re-route this IRQ */
-       gic_map_to_vpe(irq, mips_cm_vp_id(cpu));
+       write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu)));
 
        /* Update the pcpu_masks */
-       for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
-               clear_bit(irq, pcpu_masks[i].pcpu_mask);
-       set_bit(irq, pcpu_masks[cpu].pcpu_mask);
+       gic_clear_pcpu_masks(irq);
+       if (read_gic_mask(irq))
+               set_bit(irq, per_cpu_ptr(pcpu_masks, cpu));
 
-       cpumask_copy(irq_data_get_affinity_mask(d), cpumask);
        irq_data_update_effective_affinity(d, cpumask_of(cpu));
        spin_unlock_irqrestore(&gic_lock, flags);
 
-       return IRQ_SET_MASK_OK_NOCOPY;
+       return IRQ_SET_MASK_OK;
 }
 #endif
 
@@ -499,8 +302,8 @@ static void gic_handle_local_int(bool chained)
        unsigned long pending, masked;
        unsigned int intr, virq;
 
-       pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
-       masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK));
+       pending = read_gic_vl_pend();
+       masked = read_gic_vl_mask();
 
        bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
 
@@ -518,14 +321,14 @@ static void gic_mask_local_irq(struct irq_data *d)
 {
        int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
 
-       gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
+       write_gic_vl_rmask(BIT(intr));
 }
 
 static void gic_unmask_local_irq(struct irq_data *d)
 {
        int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
 
-       gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
+       write_gic_vl_smask(BIT(intr));
 }
 
 static struct irq_chip gic_local_irq_controller = {
@@ -542,9 +345,8 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d)
 
        spin_lock_irqsave(&gic_lock, flags);
        for (i = 0; i < gic_vpes; i++) {
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
-                         mips_cm_vp_id(i));
-               gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr);
+               write_gic_vl_other(mips_cm_vp_id(i));
+               write_gic_vo_rmask(BIT(intr));
        }
        spin_unlock_irqrestore(&gic_lock, flags);
 }
@@ -557,9 +359,8 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
 
        spin_lock_irqsave(&gic_lock, flags);
        for (i = 0; i < gic_vpes; i++) {
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
-                         mips_cm_vp_id(i));
-               gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr);
+               write_gic_vl_other(mips_cm_vp_id(i));
+               write_gic_vo_smask(BIT(intr));
        }
        spin_unlock_irqrestore(&gic_lock, flags);
 }
@@ -582,103 +383,50 @@ static void gic_irq_dispatch(struct irq_desc *desc)
        gic_handle_shared_int(true);
 }
 
-static void __init gic_basic_init(void)
-{
-       unsigned int i;
-
-       board_bind_eic_interrupt = &gic_bind_eic_interrupt;
-
-       /* Setup defaults */
-       for (i = 0; i < gic_shared_intrs; i++) {
-               gic_set_polarity(i, GIC_POL_POS);
-               gic_set_trigger(i, GIC_TRIG_LEVEL);
-               gic_reset_mask(i);
-       }
-
-       for (i = 0; i < gic_vpes; i++) {
-               unsigned int j;
-
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
-                         mips_cm_vp_id(i));
-               for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
-                       if (!gic_local_irq_is_routable(j))
-                               continue;
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j);
-               }
-       }
-}
-
 static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
                                    irq_hw_number_t hw)
 {
        int intr = GIC_HWIRQ_TO_LOCAL(hw);
-       int ret = 0;
        int i;
        unsigned long flags;
+       u32 val;
 
        if (!gic_local_irq_is_routable(intr))
                return -EPERM;
 
+       if (intr > GIC_LOCAL_INT_FDC) {
+               pr_err("Invalid local IRQ %d\n", intr);
+               return -EINVAL;
+       }
+
+       if (intr == GIC_LOCAL_INT_TIMER) {
+               /* CONFIG_MIPS_CMP workaround (see __gic_init) */
+               val = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
+       } else {
+               val = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
+       }
+
        spin_lock_irqsave(&gic_lock, flags);
        for (i = 0; i < gic_vpes; i++) {
-               u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin;
-
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
-                         mips_cm_vp_id(i));
-
-               switch (intr) {
-               case GIC_LOCAL_INT_WD:
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val);
-                       break;
-               case GIC_LOCAL_INT_COMPARE:
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP),
-                                   val);
-                       break;
-               case GIC_LOCAL_INT_TIMER:
-                       /* CONFIG_MIPS_CMP workaround (see __gic_init) */
-                       val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin;
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
-                                   val);
-                       break;
-               case GIC_LOCAL_INT_PERFCTR:
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
-                                   val);
-                       break;
-               case GIC_LOCAL_INT_SWINT0:
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP),
-                                   val);
-                       break;
-               case GIC_LOCAL_INT_SWINT1:
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP),
-                                   val);
-                       break;
-               case GIC_LOCAL_INT_FDC:
-                       gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val);
-                       break;
-               default:
-                       pr_err("Invalid local IRQ %d\n", intr);
-                       ret = -EINVAL;
-                       break;
-               }
+               write_gic_vl_other(mips_cm_vp_id(i));
+               write_gic_vo_map(intr, val);
        }
        spin_unlock_irqrestore(&gic_lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
-                                    irq_hw_number_t hw, unsigned int vpe)
+                                    irq_hw_number_t hw, unsigned int cpu)
 {
        int intr = GIC_HWIRQ_TO_SHARED(hw);
        unsigned long flags;
-       int i;
 
        spin_lock_irqsave(&gic_lock, flags);
-       gic_map_to_pin(intr, gic_cpu_pin);
-       gic_map_to_vpe(intr, mips_cm_vp_id(vpe));
-       for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
-               clear_bit(intr, pcpu_masks[i].pcpu_mask);
-       set_bit(intr, pcpu_masks[vpe].pcpu_mask);
+       write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
+       write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
+       gic_clear_pcpu_masks(intr);
+       set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
        spin_unlock_irqrestore(&gic_lock, flags);
 
        return 0;
@@ -885,34 +633,69 @@ static const struct irq_domain_ops gic_ipi_domain_ops = {
        .match = gic_ipi_domain_match,
 };
 
-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)
+
+static int __init gic_of_init(struct device_node *node,
+                             struct device_node *parent)
 {
-       unsigned int gicconfig, cpu;
-       unsigned int v[2];
+       unsigned int cpu_vec, i, j, gicconfig, cpu, v[2];
+       unsigned long reserved;
+       phys_addr_t gic_base;
+       struct resource res;
+       size_t gic_len;
+
+       /* Find the first available CPU vector. */
+       i = 0;
+       reserved = (C_SW0 | C_SW1) >> __fls(C_SW0);
+       while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors",
+                                          i++, &cpu_vec))
+               reserved |= BIT(cpu_vec);
+
+       cpu_vec = find_first_zero_bit(&reserved, hweight_long(ST0_IM));
+       if (cpu_vec == hweight_long(ST0_IM)) {
+               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;
+                       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);
+       }
 
-       __gic_base_addr = gic_base_addr;
+       if (mips_cm_present()) {
+               write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN);
+               /* Ensure GIC region is enabled before trying to access it */
+               __sync();
+       }
 
-       gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size);
+       mips_gic_base = ioremap_nocache(gic_base, gic_len);
 
-       gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
-       gic_shared_intrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
-                  GIC_SH_CONFIG_NUMINTRS_SHF;
-       gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
+       gicconfig = read_gic_config();
+       gic_shared_intrs = gicconfig & GIC_CONFIG_NUMINTERRUPTS;
+       gic_shared_intrs >>= __fls(GIC_CONFIG_NUMINTERRUPTS);
+       gic_shared_intrs = (gic_shared_intrs + 1) * 8;
 
-       gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
-                 GIC_SH_CONFIG_NUMVPES_SHF;
+       gic_vpes = gicconfig & GIC_CONFIG_PVPS;
+       gic_vpes >>= __fls(GIC_CONFIG_PVPS);
        gic_vpes = gic_vpes + 1;
 
        if (cpu_has_veic) {
                /* Set EIC mode for all VPEs */
                for_each_present_cpu(cpu) {
-                       gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
-                                 mips_cm_vp_id(cpu));
-                       gic_write(GIC_REG(VPE_OTHER, GIC_VPE_CTL),
-                                 GIC_VPE_CTL_EIC_MODE_MSK);
+                       write_gic_vl_other(mips_cm_vp_id(cpu));
+                       write_gic_vo_ctl(GIC_VX_CTL_EIC);
                }
 
                /* Always use vector 1 in EIC mode */
@@ -937,9 +720,7 @@ static void __init __gic_init(unsigned long gic_base_addr,
                 */
                if (IS_ENABLED(CONFIG_MIPS_CMP) &&
                    gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) {
-                       timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL,
-                                                        GIC_VPE_TIMER_MAP)) &
-                                       GIC_MAP_MSK;
+                       timer_cpu_pin = read_gic_vl_timer_map() & GIC_MAP_PIN_MAP;
                        irq_set_chained_handler(MIPS_CPU_IRQ_BASE +
                                                GIC_CPU_PIN_OFFSET +
                                                timer_cpu_pin,
@@ -950,17 +731,21 @@ static void __init __gic_init(unsigned long gic_base_addr,
        }
 
        gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +
-                                              gic_shared_intrs, irqbase,
+                                              gic_shared_intrs, 0,
                                               &gic_irq_domain_ops, NULL);
-       if (!gic_irq_domain)
-               panic("Failed to add GIC IRQ domain");
+       if (!gic_irq_domain) {
+               pr_err("Failed to add GIC IRQ domain");
+               return -ENXIO;
+       }
 
        gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
                                                  IRQ_DOMAIN_FLAG_IPI_PER_CPU,
                                                  GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
                                                  node, &gic_ipi_domain_ops, NULL);
-       if (!gic_ipi_domain)
-               panic("Failed to add GIC IPI domain");
+       if (!gic_ipi_domain) {
+               pr_err("Failed to add GIC IPI domain");
+               return -ENXIO;
+       }
 
        irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI);
 
@@ -975,64 +760,25 @@ static void __init __gic_init(unsigned long gic_base_addr,
        }
 
        bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
-       gic_basic_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;
+       board_bind_eic_interrupt = &gic_bind_eic_interrupt;
 
-       /* 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;
+       /* Setup defaults */
+       for (i = 0; i < gic_shared_intrs; i++) {
+               change_gic_pol(i, GIC_POL_ACTIVE_HIGH);
+               change_gic_trig(i, GIC_TRIG_LEVEL);
+               write_gic_rmask(BIT(i));
        }
 
-       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;
+       for (i = 0; i < gic_vpes; i++) {
+               write_gic_vl_other(mips_cm_vp_id(i));
+               for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
+                       if (!gic_local_irq_is_routable(j))
+                               continue;
+                       write_gic_vo_rmask(BIT(j));
                }
-       } 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);
-               /* Ensure GIC region is enabled before trying to access it */
-               __sync();
-       }
-       gic_present = true;
-
-       __gic_init(gic_base, gic_len, cpu_vec, 0, node);
-
        return 0;
 }
 IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init);