--- /dev/null
+/*
+ * Copyright (C) 2017 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_MIPS_CPS_H__
+# error Please include asm/mips-cps.h rather than asm/mips-gic.h
+#endif
+
+#ifndef __MIPS_ASM_MIPS_GIC_H__
+#define __MIPS_ASM_MIPS_GIC_H__
+
+#include <linux/bitops.h>
+
+/* The base address of the GIC registers */
+extern void __iomem *mips_gic_base;
+
+/* Offsets from the GIC base address to various control blocks */
+#define MIPS_GIC_SHARED_OFS    0x00000
+#define MIPS_GIC_SHARED_SZ     0x08000
+#define MIPS_GIC_LOCAL_OFS     0x08000
+#define MIPS_GIC_LOCAL_SZ      0x04000
+#define MIPS_GIC_REDIR_OFS     0x0c000
+#define MIPS_GIC_REDIR_SZ      0x04000
+#define MIPS_GIC_USER_OFS      0x10000
+#define MIPS_GIC_USER_SZ       0x10000
+
+/* For read-only shared registers */
+#define GIC_ACCESSOR_RO(sz, off, name)                                 \
+       CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_SHARED_OFS + off, name)
+
+/* For read-write shared registers */
+#define GIC_ACCESSOR_RW(sz, off, name)                                 \
+       CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_SHARED_OFS + off, name)
+
+/* For read-only local registers */
+#define GIC_VX_ACCESSOR_RO(sz, off, name)                              \
+       CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_LOCAL_OFS + off, vl_##name)   \
+       CPS_ACCESSOR_RO(gic, sz, MIPS_GIC_REDIR_OFS + off, vo_##name)
+
+/* For read-write local registers */
+#define GIC_VX_ACCESSOR_RW(sz, off, name)                              \
+       CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_LOCAL_OFS + off, vl_##name)   \
+       CPS_ACCESSOR_RW(gic, sz, MIPS_GIC_REDIR_OFS + off, vo_##name)
+
+/* For read-only shared per-interrupt registers */
+#define GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name)                        \
+static inline void __iomem *addr_gic_##name(unsigned int intr)         \
+{                                                                      \
+       return mips_gic_base + (off) + (intr * (stride));               \
+}                                                                      \
+                                                                       \
+static inline unsigned int read_gic_##name(unsigned int intr)          \
+{                                                                      \
+       BUILD_BUG_ON(sz != 32);                                         \
+       return __raw_readl(addr_gic_##name(intr));                      \
+}
+
+/* For read-write shared per-interrupt registers */
+#define GIC_ACCESSOR_RW_INTR_REG(sz, off, stride, name)                        \
+       GIC_ACCESSOR_RO_INTR_REG(sz, off, stride, name)                 \
+                                                                       \
+static inline void write_gic_##name(unsigned int intr,                 \
+                                   unsigned int val)                   \
+{                                                                      \
+       BUILD_BUG_ON(sz != 32);                                         \
+       __raw_writel(val, addr_gic_##name(intr));                       \
+}
+
+/* For read-only local per-interrupt registers */
+#define GIC_VX_ACCESSOR_RO_INTR_REG(sz, off, stride, name)             \
+       GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off,          \
+                                stride, vl_##name)                     \
+       GIC_ACCESSOR_RO_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off,          \
+                                stride, vo_##name)
+
+/* For read-write local per-interrupt registers */
+#define GIC_VX_ACCESSOR_RW_INTR_REG(sz, off, stride, name)             \
+       GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_LOCAL_OFS + off,          \
+                                stride, vl_##name)                     \
+       GIC_ACCESSOR_RW_INTR_REG(sz, MIPS_GIC_REDIR_OFS + off,          \
+                                stride, vo_##name)
+
+/* For read-only shared bit-per-interrupt registers */
+#define GIC_ACCESSOR_RO_INTR_BIT(off, name)                            \
+static inline void __iomem *addr_gic_##name(void)                      \
+{                                                                      \
+       return mips_gic_base + (off);                                   \
+}                                                                      \
+                                                                       \
+static inline unsigned int read_gic_##name(unsigned int intr)          \
+{                                                                      \
+       void __iomem *addr = addr_gic_##name();                         \
+       unsigned int val;                                               \
+                                                                       \
+       if (mips_cm_is64) {                                             \
+               addr += (intr / 64) * sizeof(uint64_t);                 \
+               val = __raw_readq(addr) >> intr % 64;                   \
+       } else {                                                        \
+               addr += (intr / 32) * sizeof(uint32_t);                 \
+               val = __raw_readl(addr) >> intr % 32;                   \
+       }                                                               \
+                                                                       \
+       return val & 0x1;                                               \
+}
+
+/* For read-write shared bit-per-interrupt registers */
+#define GIC_ACCESSOR_RW_INTR_BIT(off, name)                            \
+       GIC_ACCESSOR_RO_INTR_BIT(off, name)                             \
+                                                                       \
+static inline void write_gic_##name(unsigned int intr)                 \
+{                                                                      \
+       void __iomem *addr = addr_gic_##name();                         \
+                                                                       \
+       if (mips_cm_is64) {                                             \
+               addr += (intr / 64) * sizeof(uint64_t);                 \
+               __raw_writeq(BIT(intr % 64), addr);                     \
+       } else {                                                        \
+               addr += (intr / 32) * sizeof(uint32_t);                 \
+               __raw_writel(BIT(intr % 32), addr);                     \
+       }                                                               \
+}                                                                      \
+                                                                       \
+static inline void change_gic_##name(unsigned int intr,                        \
+                                    unsigned int val)                  \
+{                                                                      \
+       void __iomem *addr = addr_gic_##name();                         \
+                                                                       \
+       if (mips_cm_is64) {                                             \
+               uint64_t _val;                                          \
+                                                                       \
+               addr += (intr / 64) * sizeof(uint64_t);                 \
+               _val = __raw_readq(addr);                               \
+               _val &= ~BIT_ULL(intr % 64);                            \
+               _val |= (uint64_t)val << (intr % 64);                   \
+               __raw_writeq(_val, addr);                               \
+       } else {                                                        \
+               uint32_t _val;                                          \
+                                                                       \
+               addr += (intr / 32) * sizeof(uint32_t);                 \
+               _val = __raw_readl(addr);                               \
+               _val &= ~BIT(intr % 32);                                \
+               _val |= val << (intr % 32);                             \
+               __raw_writel(_val, addr);                               \
+       }                                                               \
+}
+
+/* For read-only local bit-per-interrupt registers */
+#define GIC_VX_ACCESSOR_RO_INTR_BIT(sz, off, name)                     \
+       GIC_ACCESSOR_RO_INTR_BIT(sz, MIPS_GIC_LOCAL_OFS + off,          \
+                                vl_##name)                             \
+       GIC_ACCESSOR_RO_INTR_BIT(sz, MIPS_GIC_REDIR_OFS + off,          \
+                                vo_##name)
+
+/* For read-write local bit-per-interrupt registers */
+#define GIC_VX_ACCESSOR_RW_INTR_BIT(sz, off, name)                     \
+       GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_LOCAL_OFS + off,          \
+                                vl_##name)                             \
+       GIC_ACCESSOR_RW_INTR_BIT(sz, MIPS_GIC_REDIR_OFS + off,          \
+                                vo_##name)
+
+/* GIC_SH_CONFIG - Information about the GIC configuration */
+GIC_ACCESSOR_RW(32, 0x000, config)
+#define GIC_CONFIG_COUNTSTOP           BIT(28)
+#define GIC_CONFIG_COUNTBITS           GENMASK(27, 24)
+#define GIC_CONFIG_NUMINTERRUPTS       GENMASK(23, 16)
+#define GIC_CONFIG_PVPS                        GENMASK(6, 0)
+
+/* GIC_SH_COUNTER - Shared global counter value */
+GIC_ACCESSOR_RW(64, 0x010, counter)
+GIC_ACCESSOR_RW(32, 0x010, counter_32l)
+GIC_ACCESSOR_RW(32, 0x014, counter_32h)
+
+/* GIC_SH_POL_* - Configures interrupt polarity */
+GIC_ACCESSOR_RW_INTR_BIT(0x100, pol)
+#define GIC_POL_ACTIVE_LOW             0       /* when level triggered */
+#define GIC_POL_ACTIVE_HIGH            1       /* when level triggered */
+#define GIC_POL_FALLING_EDGE           0       /* when single-edge triggered */
+#define GIC_POL_RISING_EDGE            1       /* when single-edge triggered */
+
+/* GIC_SH_TRIG_* - Configures interrupts to be edge or level triggered */
+GIC_ACCESSOR_RW_INTR_BIT(0x180, trig)
+#define GIC_TRIG_LEVEL                 0
+#define GIC_TRIG_EDGE                  1
+
+/* GIC_SH_DUAL_* - Configures whether interrupts trigger on both edges */
+GIC_ACCESSOR_RW_INTR_BIT(0x200, dual)
+#define GIC_DUAL_SINGLE                        0       /* when edge-triggered */
+#define GIC_DUAL_DUAL                  1       /* when edge-triggered */
+
+/* GIC_SH_WEDGE - Write an 'edge', ie. trigger an interrupt */
+GIC_ACCESSOR_RW(32, 0x280, wedge)
+#define GIC_WEDGE_RW                   BIT(31)
+#define GIC_WEDGE_INTR                 GENMASK(7, 0)
+
+/* GIC_SH_RMASK_* - Reset/clear shared interrupt mask bits */
+GIC_ACCESSOR_RW_INTR_BIT(0x300, rmask)
+
+/* GIC_SH_SMASK_* - Set shared interrupt mask bits */
+GIC_ACCESSOR_RW_INTR_BIT(0x380, smask)
+
+/* GIC_SH_MASK_* - Read the current shared interrupt mask */
+GIC_ACCESSOR_RO_INTR_BIT(0x400, mask)
+
+/* GIC_SH_PEND_* - Read currently pending shared interrupts */
+GIC_ACCESSOR_RO_INTR_BIT(0x480, pend)
+
+/* GIC_SH_MAPx_PIN - Map shared interrupts to a particular CPU pin */
+GIC_ACCESSOR_RW_INTR_REG(32, 0x500, 0x4, map_pin)
+#define GIC_MAP_PIN_MAP_TO_PIN         BIT(31)
+#define GIC_MAP_PIN_MAP_TO_NMI         BIT(30)
+#define GIC_MAP_PIN_MAP                        GENMASK(5, 0)
+
+/* GIC_SH_MAPx_VP - Map shared interrupts to a particular Virtual Processor */
+GIC_ACCESSOR_RW_INTR_REG(32, 0x2000, 0x20, map_vp)
+
+/* GIC_Vx_CTL - VP-level interrupt control */
+GIC_VX_ACCESSOR_RW(32, 0x000, ctl)
+#define GIC_VX_CTL_FDC_ROUTABLE                BIT(4)
+#define GIC_VX_CTL_SWINT_ROUTABLE      BIT(3)
+#define GIC_VX_CTL_PERFCNT_ROUTABLE    BIT(2)
+#define GIC_VX_CTL_TIMER_ROUTABLE      BIT(1)
+#define GIC_VX_CTL_EIC                 BIT(0)
+
+/* GIC_Vx_PEND - Read currently pending local interrupts */
+GIC_VX_ACCESSOR_RO(32, 0x004, pend)
+
+/* GIC_Vx_MASK - Read the current local interrupt mask */
+GIC_VX_ACCESSOR_RO(32, 0x008, mask)
+
+/* GIC_Vx_RMASK - Reset/clear local interrupt mask bits */
+GIC_VX_ACCESSOR_RW(32, 0x00c, rmask)
+
+/* GIC_Vx_SMASK - Set local interrupt mask bits */
+GIC_VX_ACCESSOR_RW(32, 0x010, smask)
+
+/* GIC_Vx_*_MAP - Route local interrupts to the desired pins */
+GIC_VX_ACCESSOR_RW_INTR_REG(32, 0x040, 0x4, map)
+
+/* GIC_Vx_WD_MAP - Route the local watchdog timer interrupt */
+GIC_VX_ACCESSOR_RW(32, 0x040, wd_map)
+
+/* GIC_Vx_COMPARE_MAP - Route the local count/compare interrupt */
+GIC_VX_ACCESSOR_RW(32, 0x044, compare_map)
+
+/* GIC_Vx_TIMER_MAP - Route the local CPU timer (cp0 count/compare) interrupt */
+GIC_VX_ACCESSOR_RW(32, 0x048, timer_map)
+
+/* GIC_Vx_FDC_MAP - Route the local fast debug channel interrupt */
+GIC_VX_ACCESSOR_RW(32, 0x04c, fdc_map)
+
+/* GIC_Vx_PERFCTR_MAP - Route the local performance counter interrupt */
+GIC_VX_ACCESSOR_RW(32, 0x050, perfctr_map)
+
+/* GIC_Vx_SWINT0_MAP - Route the local software interrupt 0 */
+GIC_VX_ACCESSOR_RW(32, 0x054, swint0_map)
+
+/* GIC_Vx_SWINT1_MAP - Route the local software interrupt 1 */
+GIC_VX_ACCESSOR_RW(32, 0x058, swint1_map)
+
+/* GIC_Vx_OTHER - Configure access to other Virtual Processor registers */
+GIC_VX_ACCESSOR_RW(32, 0x080, other)
+#define GIC_VX_OTHER_VPNUM             GENMASK(5, 0)
+
+/* GIC_Vx_IDENT - Retrieve the local Virtual Processor's ID */
+GIC_VX_ACCESSOR_RO(32, 0x088, ident)
+#define GIC_VX_IDENT_VPNUM             GENMASK(5, 0)
+
+/* GIC_Vx_COMPARE - Value to compare with GIC_SH_COUNTER */
+GIC_VX_ACCESSOR_RW(64, 0x0a0, compare)
+
+/* GIC_Vx_EIC_SHADOW_SET_BASE - Set shadow register set for each interrupt */
+GIC_VX_ACCESSOR_RW_INTR_REG(32, 0x100, 0x4, eic_shadow_set)
+
+/**
+ * mips_gic_present() - Determine whether a GIC is present
+ *
+ * Determines whether a MIPS Global Interrupt Controller (GIC) is present in
+ * the system that the kernel is running on.
+ *
+ * Return true if a GIC is present, else false.
+ */
+static inline bool mips_gic_present(void)
+{
+       return IS_ENABLED(CONFIG_MIPS_GIC) && mips_gic_base;
+}
+
+#endif /* __MIPS_ASM_MIPS_CPS_H__ */