#include "../../i915/i915_reg_defs.h"
 
+/**
+ * struct xe_reg - Register definition
+ *
+ * Register defintion to be used by the individual register. Although the same
+ * definition is used for xe_reg and xe_reg_mcr, they use different internal
+ * APIs for accesses.
+ */
+struct xe_reg {
+       union {
+               struct {
+                       /** @reg: address */
+                       u32 reg:22;
+                       /**
+                        * @masked: register is "masked", with upper 16bits used
+                        * to identify the bits that are updated on the lower
+                        * bits
+                        */
+                       u32 masked:1;
+                       /**
+                        * @mcr: register is multicast/replicated in the
+                        * hardware and needs special handling. Any register
+                        * with this set should also use a type of xe_reg_mcr_t.
+                        * It's only here so the few places that deal with MCR
+                        * registers specially (xe_sr.c) and tests using the raw
+                        * value can inspect it.
+                        */
+                       u32 mcr:1;
+               };
+               /** @raw: Raw value with both address and options */
+               u32 raw;
+       };
+};
+
+/**
+ * struct xe_reg_mcr - MCR register definition
+ *
+ * MCR register is the same as a regular register, but uses another type since
+ * the internal API used for accessing them is different: it's never correct to
+ * use regular MMIO access.
+ */
+struct xe_reg_mcr {
+       /** @__reg: The register */
+       struct xe_reg __reg;
+};
+
+
+/**
+ * XE_REG_OPTION_MASKED - Register is "masked", with upper 16 bits marking the
+ * read/written bits on the lower 16 bits.
+ *
+ * To be used with XE_REG(). XE_REG_MCR() and XE_REG_INITIALIZER()
+ */
+#define XE_REG_OPTION_MASKED           .masked = 1
+
+/**
+ * XE_REG_INITIALIZER - Initializer for xe_reg_t.
+ * @r_: Register offset
+ * @...: Additional options like access mode. See struct xe_reg for available
+ *       options.
+ *
+ * Register field is mandatory, and additional options may be passed as
+ * arguments. Usually ``XE_REG()`` should be preferred since it creates an
+ * object of the right type. However when initializing static const storage,
+ * where a compound statement is not allowed, this can be used instead.
+ */
+#define XE_REG_INITIALIZER(r_, ...)    { .reg = r_, __VA_ARGS__ }
+
+
+/**
+ * XE_REG - Create a struct xe_reg from offset and additional flags
+ * @r_: Register offset
+ * @...: Additional options like access mode. See struct xe_reg for available
+ *       options.
+ */
+#define XE_REG(r_, ...)                ((const struct xe_reg)XE_REG_INITIALIZER(r_, ##__VA_ARGS__))
+
+/**
+ * XE_REG_MCR - Create a struct xe_reg_mcr from offset and additional flags
+ * @r_: Register offset
+ * @...: Additional options like access mode. See struct xe_reg for available
+ *       options.
+ */
+#define XE_REG_MCR(r_, ...)    ((const struct xe_reg_mcr){                                     \
+                                .__reg = XE_REG_INITIALIZER(r_,  ##__VA_ARGS__, .mcr = 1)      \
+                                })
+
+/*
+ * TODO: remove these once the register declarations are not using them anymore
+ */
+#undef _MMIO
+#undef MCR_REG
+#define _MMIO(r_)      ((const struct xe_reg){ .reg = r_ })
+#define MCR_REG(r_)    ((const struct xe_reg_mcr){ .__reg.reg = r_,            \
+                                                   .__reg.mcr = 1 })
+
 #endif
 
  * non-terminated instance.
  */
 
+static inline struct xe_reg to_xe_reg(struct xe_reg_mcr reg_mcr)
+{
+       return reg_mcr.__reg;
+}
+
 enum {
        MCR_OP_READ,
        MCR_OP_WRITE
  * returned.  Returns false if the caller need not perform any steering
  */
 static bool xe_gt_mcr_get_nonterminated_steering(struct xe_gt *gt,
-                                                i915_mcr_reg_t reg,
+                                                struct xe_reg_mcr reg_mcr,
                                                 u8 *group, u8 *instance)
 {
+       const struct xe_reg reg = to_xe_reg(reg_mcr);
        const struct xe_mmio_range *implicit_ranges;
 
        for (int type = 0; type < IMPLICIT_STEERING; type++) {
  *
  * Caller needs to make sure the relevant forcewake wells are up.
  */
-static u32 rw_with_mcr_steering(struct xe_gt *gt, i915_mcr_reg_t reg, u8 rw_flag,
-                               int group, int instance, u32 value)
+static u32 rw_with_mcr_steering(struct xe_gt *gt, struct xe_reg_mcr reg_mcr,
+                               u8 rw_flag, int group, int instance, u32 value)
 {
+       const struct xe_reg reg = to_xe_reg(reg_mcr);
        u32 steer_reg, steer_val, val = 0;
 
        lockdep_assert_held(>->mcr_lock);
 /**
  * xe_gt_mcr_unicast_read_any - reads a non-terminated instance of an MCR register
  * @gt: GT structure
- * @reg: register to read
+ * @reg_mcr: register to read
  *
  * Reads a GT MCR register.  The read will be steered to a non-terminated
  * instance (i.e., one that isn't fused off or powered down by power gating).
  *
  * Returns the value from a non-terminated instance of @reg.
  */
-u32 xe_gt_mcr_unicast_read_any(struct xe_gt *gt, i915_mcr_reg_t reg)
+u32 xe_gt_mcr_unicast_read_any(struct xe_gt *gt, struct xe_reg_mcr reg_mcr)
 {
+       const struct xe_reg reg = to_xe_reg(reg_mcr);
        u8 group, instance;
        u32 val;
        bool steer;
 
-       steer = xe_gt_mcr_get_nonterminated_steering(gt, reg, &group, &instance);
+       steer = xe_gt_mcr_get_nonterminated_steering(gt, reg_mcr,
+                                                    &group, &instance);
 
        if (steer) {
                mcr_lock(gt);
-               val = rw_with_mcr_steering(gt, reg, MCR_OP_READ,
+               val = rw_with_mcr_steering(gt, reg_mcr, MCR_OP_READ,
                                           group, instance, 0);
                mcr_unlock(gt);
        } else {
 /**
  * xe_gt_mcr_unicast_read - read a specific instance of an MCR register
  * @gt: GT structure
- * @reg: the MCR register to read
+ * @reg_mcr: the MCR register to read
  * @group: the MCR group
  * @instance: the MCR instance
  *
  * group/instance.
  */
 u32 xe_gt_mcr_unicast_read(struct xe_gt *gt,
-                          i915_mcr_reg_t reg,
+                          struct xe_reg_mcr reg_mcr,
                           int group, int instance)
 {
        u32 val;
 
        mcr_lock(gt);
-       val = rw_with_mcr_steering(gt, reg, MCR_OP_READ, group, instance, 0);
+       val = rw_with_mcr_steering(gt, reg_mcr, MCR_OP_READ, group, instance, 0);
        mcr_unlock(gt);
 
        return val;
 /**
  * xe_gt_mcr_unicast_write - write a specific instance of an MCR register
  * @gt: GT structure
- * @reg: the MCR register to write
+ * @reg_mcr: the MCR register to write
  * @value: value to write
  * @group: the MCR group
  * @instance: the MCR instance
  * Write an MCR register in unicast mode after steering toward a specific
  * group/instance.
  */
-void xe_gt_mcr_unicast_write(struct xe_gt *gt, i915_mcr_reg_t reg, u32 value,
-                            int group, int instance)
+void xe_gt_mcr_unicast_write(struct xe_gt *gt, struct xe_reg_mcr reg_mcr,
+                            u32 value, int group, int instance)
 {
        mcr_lock(gt);
-       rw_with_mcr_steering(gt, reg, MCR_OP_WRITE, group, instance, value);
+       rw_with_mcr_steering(gt, reg_mcr, MCR_OP_WRITE, group, instance, value);
        mcr_unlock(gt);
 }
 
 /**
  * xe_gt_mcr_multicast_write - write a value to all instances of an MCR register
  * @gt: GT structure
- * @reg: the MCR register to write
+ * @reg_mcr: the MCR register to write
  * @value: value to write
  *
  * Write an MCR register in multicast mode to update all instances.
  */
-void xe_gt_mcr_multicast_write(struct xe_gt *gt, i915_mcr_reg_t reg, u32 value)
+void xe_gt_mcr_multicast_write(struct xe_gt *gt, struct xe_reg_mcr reg_mcr,
+                              u32 value)
 {
+       struct xe_reg reg = to_xe_reg(reg_mcr);
+
        /*
         * Synchronize with any unicast operations.  Once we have exclusive
         * access, the MULTICAST bit should already be set, so there's no need
 
 
 void xe_gt_mcr_set_implicit_defaults(struct xe_gt *gt);
 
-u32 xe_gt_mcr_unicast_read(struct xe_gt *gt, i915_mcr_reg_t reg,
+u32 xe_gt_mcr_unicast_read(struct xe_gt *gt, struct xe_reg_mcr mcr_reg,
                           int group, int instance);
-u32 xe_gt_mcr_unicast_read_any(struct xe_gt *gt, i915_mcr_reg_t reg);
+u32 xe_gt_mcr_unicast_read_any(struct xe_gt *gt, struct xe_reg_mcr mcr_reg);
 
-void xe_gt_mcr_unicast_write(struct xe_gt *gt, i915_mcr_reg_t reg, u32 value,
-                            int group, int instance);
-void xe_gt_mcr_multicast_write(struct xe_gt *gt, i915_mcr_reg_t reg, u32 value);
+void xe_gt_mcr_unicast_write(struct xe_gt *gt, struct xe_reg_mcr mcr_reg,
+                            u32 value, int group, int instance);
+void xe_gt_mcr_multicast_write(struct xe_gt *gt, struct xe_reg_mcr mcr_reg,
+                              u32 value);
 
 void xe_gt_mcr_steering_dump(struct xe_gt *gt, struct drm_printer *p);