#include "media/cec.h"
 #include "vc4_drv.h"
 #include "vc4_hdmi.h"
+#include "vc4_hdmi_regs.h"
 #include "vc4_regs.h"
 
 #define HSM_CLOCK_FREQ 163682864
 #define CEC_CLOCK_FREQ 40000
 #define CEC_CLOCK_DIV  (HSM_CLOCK_FREQ / CEC_CLOCK_FREQ)
 
-static const struct debugfs_reg32 hdmi_regs[] = {
-       VC4_REG32(VC4_HDMI_CORE_REV),
-       VC4_REG32(VC4_HDMI_SW_RESET_CONTROL),
-       VC4_REG32(VC4_HDMI_HOTPLUG_INT),
-       VC4_REG32(VC4_HDMI_HOTPLUG),
-       VC4_REG32(VC4_HDMI_MAI_CHANNEL_MAP),
-       VC4_REG32(VC4_HDMI_MAI_CONFIG),
-       VC4_REG32(VC4_HDMI_MAI_FORMAT),
-       VC4_REG32(VC4_HDMI_AUDIO_PACKET_CONFIG),
-       VC4_REG32(VC4_HDMI_RAM_PACKET_CONFIG),
-       VC4_REG32(VC4_HDMI_HORZA),
-       VC4_REG32(VC4_HDMI_HORZB),
-       VC4_REG32(VC4_HDMI_FIFO_CTL),
-       VC4_REG32(VC4_HDMI_SCHEDULER_CONTROL),
-       VC4_REG32(VC4_HDMI_VERTA0),
-       VC4_REG32(VC4_HDMI_VERTA1),
-       VC4_REG32(VC4_HDMI_VERTB0),
-       VC4_REG32(VC4_HDMI_VERTB1),
-       VC4_REG32(VC4_HDMI_TX_PHY_RESET_CTL),
-       VC4_REG32(VC4_HDMI_TX_PHY_CTL0),
-
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_1),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_2),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_3),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_4),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_5),
-       VC4_REG32(VC4_HDMI_CPU_STATUS),
-       VC4_REG32(VC4_HDMI_CPU_MASK_STATUS),
-
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_1),
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_2),
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_3),
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_4),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_1),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_2),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_3),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_4),
-};
-
-static const struct debugfs_reg32 hd_regs[] = {
-       VC4_REG32(VC4_HD_M_CTL),
-       VC4_REG32(VC4_HD_MAI_CTL),
-       VC4_REG32(VC4_HD_MAI_THR),
-       VC4_REG32(VC4_HD_MAI_FMT),
-       VC4_REG32(VC4_HD_MAI_SMP),
-       VC4_REG32(VC4_HD_VID_CTL),
-       VC4_REG32(VC4_HD_CSC_CTL),
-       VC4_REG32(VC4_HD_FRAME_COUNT),
-};
-
 static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *)m->private;
        if (drm_probe_ddc(vc4_hdmi->ddc))
                return connector_status_connected;
 
-       if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
+       if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
                return connector_status_connected;
        cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
        return connector_status_disconnected;
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        u32 packet_id = type - 0x80;
 
-       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
-                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
 
-       return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+       return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) &
                          BIT(packet_id)), 100);
 }
 
 {
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        u32 packet_id = frame->any.type - 0x80;
-       u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id);
+       const struct vc4_hdmi_register *ram_packet_start =
+               &vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START];
+       u32 packet_reg = ram_packet_start->offset + VC4_HDMI_PACKET_STRIDE * packet_id;
+       void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
+                                                      ram_packet_start->reg);
        uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
        ssize_t len, i;
        int ret;
 
-       WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+       WARN_ONCE(!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
                    VC4_HDMI_RAM_PACKET_ENABLE),
                  "Packet RAM has to be on to store the packet.");
 
        }
 
        for (i = 0; i < len; i += 7) {
-               HDMI_WRITE(packet_reg,
-                          buffer[i + 0] << 0 |
-                          buffer[i + 1] << 8 |
-                          buffer[i + 2] << 16);
+               writel(buffer[i + 0] << 0 |
+                      buffer[i + 1] << 8 |
+                      buffer[i + 2] << 16,
+                      base + packet_reg);
                packet_reg += 4;
 
-               HDMI_WRITE(packet_reg,
-                          buffer[i + 3] << 0 |
-                          buffer[i + 4] << 8 |
-                          buffer[i + 5] << 16 |
-                          buffer[i + 6] << 24);
+               writel(buffer[i + 3] << 0 |
+                      buffer[i + 4] << 8 |
+                      buffer[i + 5] << 16 |
+                      buffer[i + 6] << 24,
+                      base + packet_reg);
                packet_reg += 4;
        }
 
-       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
-                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
-       ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
+       ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
                        BIT(packet_id)), 100);
        if (ret)
                DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        int ret;
 
-       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
 
-       HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
-       HD_WRITE(VC4_HD_VID_CTL,
-                HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
+       HDMI_WRITE(HDMI_VID_CTL,
+                  HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
 
        clk_disable_unprepare(vc4_hdmi->pixel_clock);
 
                return;
        }
 
-       HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL,
+       HDMI_WRITE(HDMI_SW_RESET_CONTROL,
                   VC4_HDMI_SW_RESET_HDMI |
                   VC4_HDMI_SW_RESET_FORMAT_DETECT);
 
-       HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0);
+       HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0);
 
        /* PHY should be in reset, like
         * vc4_hdmi_encoder_disable() does.
         */
-       HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
 
-       HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0);
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0);
 
        if (debug_dump_regs) {
                struct drm_printer p = drm_info_printer(&vc4_hdmi->pdev->dev);
                drm_print_regset32(&p, &vc4_hdmi->hd_regset);
        }
 
-       HD_WRITE(VC4_HD_VID_CTL, 0);
+       HDMI_WRITE(HDMI_VID_CTL, 0);
 
-       HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                  HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
+       HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                  HDMI_READ(HDMI_SCHEDULER_CONTROL) |
                   VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT |
                   VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
 
-       HDMI_WRITE(VC4_HDMI_HORZA,
+       HDMI_WRITE(HDMI_HORZA,
                   (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
                   (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) |
                   VC4_SET_FIELD(mode->hdisplay * pixel_rep,
                                 VC4_HDMI_HORZA_HAP));
 
-       HDMI_WRITE(VC4_HDMI_HORZB,
+       HDMI_WRITE(HDMI_HORZB,
                   VC4_SET_FIELD((mode->htotal -
                                  mode->hsync_end) * pixel_rep,
                                 VC4_HDMI_HORZB_HBP) |
                                  mode->hdisplay) * pixel_rep,
                                 VC4_HDMI_HORZB_HFP));
 
-       HDMI_WRITE(VC4_HDMI_VERTA0, verta);
-       HDMI_WRITE(VC4_HDMI_VERTA1, verta);
+       HDMI_WRITE(HDMI_VERTA0, verta);
+       HDMI_WRITE(HDMI_VERTA1, verta);
 
-       HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even);
-       HDMI_WRITE(VC4_HDMI_VERTB1, vertb);
+       HDMI_WRITE(HDMI_VERTB0, vertb_even);
+       HDMI_WRITE(HDMI_VERTB1, vertb);
 
-       HD_WRITE(VC4_HD_VID_CTL,
-                (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
-                (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
+       HDMI_WRITE(HDMI_VID_CTL,
+                  (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
+                  (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
 
        csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
                                VC4_HD_CSC_CTL_ORDER);
                csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
                                         VC4_HD_CSC_CTL_MODE);
 
-               HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000);
-               HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0);
-               HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000);
-               HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
-               HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
-               HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
+               HDMI_WRITE(HDMI_CSC_12_11, (0x000 << 16) | 0x000);
+               HDMI_WRITE(HDMI_CSC_14_13, (0x100 << 16) | 0x6e0);
+               HDMI_WRITE(HDMI_CSC_22_21, (0x6e0 << 16) | 0x000);
+               HDMI_WRITE(HDMI_CSC_24_23, (0x100 << 16) | 0x000);
+               HDMI_WRITE(HDMI_CSC_32_31, (0x000 << 16) | 0x6e0);
+               HDMI_WRITE(HDMI_CSC_34_33, (0x100 << 16) | 0x000);
                vc4_encoder->limited_rgb_range = true;
        } else {
                vc4_encoder->limited_rgb_range = false;
        }
 
        /* The RGB order applies even when CSC is disabled. */
-       HD_WRITE(VC4_HD_CSC_CTL, csc_ctl);
+       HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
 
-       HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
+       HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
 
        if (debug_dump_regs) {
                struct drm_printer p = drm_info_printer(&vc4_hdmi->pdev->dev);
                drm_print_regset32(&p, &vc4_hdmi->hd_regset);
        }
 
-       HD_WRITE(VC4_HD_VID_CTL,
-                HD_READ(VC4_HD_VID_CTL) |
-                VC4_HD_VID_CTL_ENABLE |
-                VC4_HD_VID_CTL_UNDERFLOW_ENABLE |
-                VC4_HD_VID_CTL_FRAME_COUNTER_RESET);
+       HDMI_WRITE(HDMI_VID_CTL,
+                  HDMI_READ(HDMI_VID_CTL) |
+                  VC4_HD_VID_CTL_ENABLE |
+                  VC4_HD_VID_CTL_UNDERFLOW_ENABLE |
+                  VC4_HD_VID_CTL_FRAME_COUNTER_RESET);
 
        if (vc4_encoder->hdmi_monitor) {
-               HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                          HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
+               HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                          HDMI_READ(HDMI_SCHEDULER_CONTROL) |
                           VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
-               ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                               VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        } else {
-               HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
-                          HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+               HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
+                          HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
                           ~(VC4_HDMI_RAM_PACKET_ENABLE));
-               HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                          HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                          HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                           ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
-               ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                                 VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        if (vc4_encoder->hdmi_monitor) {
                u32 drift;
 
-               WARN_ON(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                          VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE));
-               HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                          HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
+               HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                          HDMI_READ(HDMI_SCHEDULER_CONTROL) |
                           VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
 
-               HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+               HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
                           VC4_HDMI_RAM_PACKET_ENABLE);
 
                vc4_hdmi_set_infoframes(encoder);
 
-               drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
+               drift = HDMI_READ(HDMI_FIFO_CTL);
                drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
 
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
+               HDMI_WRITE(HDMI_FIFO_CTL,
                           drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
+               HDMI_WRITE(HDMI_FIFO_CTL,
                           drift | VC4_HDMI_FIFO_CTL_RECENTER);
                usleep_range(1000, 1100);
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
+               HDMI_WRITE(HDMI_FIFO_CTL,
                           drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
+               HDMI_WRITE(HDMI_FIFO_CTL,
                           drift | VC4_HDMI_FIFO_CTL_RECENTER);
 
-               ret = wait_for(HDMI_READ(VC4_HDMI_FIFO_CTL) &
+               ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) &
                               VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1);
                WARN_ONCE(ret, "Timeout waiting for "
                          "VC4_HDMI_FIFO_CTL_RECENTER_DONE");
                                     VC4_HD_MAI_SMP_M_SHIFT) + 1,
                                    &n, &m);
 
-       HD_WRITE(VC4_HD_MAI_SMP,
-                VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
-                VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
+       HDMI_WRITE(HDMI_MAI_SMP,
+                  VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
+                  VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
 }
 
 static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi)
        do_div(tmp, 128 * samplerate);
        cts = tmp;
 
-       HDMI_WRITE(VC4_HDMI_CRP_CFG,
+       HDMI_WRITE(HDMI_CRP_CFG,
                   VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN |
                   VC4_SET_FIELD(n, VC4_HDMI_CRP_CFG_N));
 
         * providing a CTS_1 value.  The two CTS values are alternated
         * between based on the period fields
         */
-       HDMI_WRITE(VC4_HDMI_CTS_0, cts);
-       HDMI_WRITE(VC4_HDMI_CTS_1, cts);
+       HDMI_WRITE(HDMI_CTS_0, cts);
+       HDMI_WRITE(HDMI_CTS_1, cts);
 }
 
 static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
         * If the HDMI encoder hasn't probed, or the encoder is
         * currently in DVI mode, treat the codec dai as missing.
         */
-       if (!encoder->crtc || !(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+       if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
                                VC4_HDMI_RAM_PACKET_ENABLE))
                return -ENODEV;
 
        if (ret)
                dev_err(dev, "Failed to stop audio infoframe: %d\n", ret);
 
-       HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_RESET);
-       HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
-       HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
+       HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET);
+       HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
+       HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
 }
 
 static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream,
        vc4_hdmi->audio.channels = params_channels(params);
        vc4_hdmi->audio.samplerate = params_rate(params);
 
-       HD_WRITE(VC4_HD_MAI_CTL,
-                VC4_HD_MAI_CTL_RESET |
-                VC4_HD_MAI_CTL_FLUSH |
-                VC4_HD_MAI_CTL_DLATE |
-                VC4_HD_MAI_CTL_ERRORE |
-                VC4_HD_MAI_CTL_ERRORF);
+       HDMI_WRITE(HDMI_MAI_CTL,
+                  VC4_HD_MAI_CTL_RESET |
+                  VC4_HD_MAI_CTL_FLUSH |
+                  VC4_HD_MAI_CTL_DLATE |
+                  VC4_HD_MAI_CTL_ERRORE |
+                  VC4_HD_MAI_CTL_ERRORF);
 
        vc4_hdmi_audio_set_mai_clock(vc4_hdmi);
 
 
        /* Set the MAI threshold.  This logic mimics the firmware's. */
        if (vc4_hdmi->audio.samplerate > 96000) {
-               HD_WRITE(VC4_HD_MAI_THR,
-                        VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) |
-                        VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
+               HDMI_WRITE(HDMI_MAI_THR,
+                          VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) |
+                          VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
        } else if (vc4_hdmi->audio.samplerate > 48000) {
-               HD_WRITE(VC4_HD_MAI_THR,
-                        VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) |
-                        VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
+               HDMI_WRITE(HDMI_MAI_THR,
+                          VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) |
+                          VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
        } else {
-               HD_WRITE(VC4_HD_MAI_THR,
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
+               HDMI_WRITE(HDMI_MAI_THR,
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
        }
 
-       HDMI_WRITE(VC4_HDMI_MAI_CONFIG,
+       HDMI_WRITE(HDMI_MAI_CONFIG,
                   VC4_HDMI_MAI_CONFIG_BIT_REVERSE |
                   VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK));
 
                        channel_map |= i << (3 * i);
        }
 
-       HDMI_WRITE(VC4_HDMI_MAI_CHANNEL_MAP, channel_map);
-       HDMI_WRITE(VC4_HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
+       HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map);
+       HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
        vc4_hdmi_set_n_cts(vc4_hdmi);
 
        return 0;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                vc4_hdmi_set_audio_infoframe(encoder);
-               HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0,
-                          HDMI_READ(VC4_HDMI_TX_PHY_CTL0) &
+               HDMI_WRITE(HDMI_TX_PHY_CTL_0,
+                          HDMI_READ(HDMI_TX_PHY_CTL_0) &
                           ~VC4_HDMI_TX_PHY_RNG_PWRDN);
-               HD_WRITE(VC4_HD_MAI_CTL,
-                        VC4_SET_FIELD(vc4_hdmi->audio.channels,
-                                      VC4_HD_MAI_CTL_CHNUM) |
-                        VC4_HD_MAI_CTL_ENABLE);
+
+               HDMI_WRITE(HDMI_MAI_CTL,
+                          VC4_SET_FIELD(vc4_hdmi->audio.channels,
+                                        VC4_HD_MAI_CTL_CHNUM) |
+                          VC4_HD_MAI_CTL_ENABLE);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               HD_WRITE(VC4_HD_MAI_CTL,
-                        VC4_HD_MAI_CTL_DLATE |
-                        VC4_HD_MAI_CTL_ERRORE |
-                        VC4_HD_MAI_CTL_ERRORF);
-               HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0,
-                          HDMI_READ(VC4_HDMI_TX_PHY_CTL0) |
+               HDMI_WRITE(HDMI_MAI_CTL,
+                          VC4_HD_MAI_CTL_DLATE |
+                          VC4_HD_MAI_CTL_ERRORE |
+                          VC4_HD_MAI_CTL_ERRORF);
+               HDMI_WRITE(HDMI_TX_PHY_CTL_0,
+                          HDMI_READ(HDMI_TX_PHY_CTL_0) |
                           VC4_HDMI_TX_PHY_RNG_PWRDN);
                break;
        default:
 
 static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
 {
+       const struct vc4_hdmi_register *mai_data =
+               &vc4_hdmi->variant->registers[HDMI_MAI_DATA];
        struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link;
        struct snd_soc_card *card = &vc4_hdmi->audio.card;
        struct device *dev = &vc4_hdmi->pdev->dev;
                return 0;
        }
 
+       if (mai_data->reg != VC4_HD) {
+               WARN_ONCE(true, "MAI isn't in the HD block\n");
+               return -EINVAL;
+       }
+
        /*
         * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve
         * the bus address specified in the DT, because the physical address
         * This VC/MMU should probably be exposed to avoid this kind of hacks.
         */
        addr = of_get_address(dev->of_node, 1, NULL, NULL);
-       vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA;
+       vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset;
        vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        vc4_hdmi->audio.dma_data.maxburst = 2;
 
        msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
                                        VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
        for (i = 0; i < msg->len; i += 4) {
-               u32 val = HDMI_READ(VC4_HDMI_CEC_RX_DATA_1 + i);
+               u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + i);
 
                msg->msg[i] = val & 0xff;
                msg->msg[i + 1] = (val >> 8) & 0xff;
 static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
 {
        struct vc4_hdmi *vc4_hdmi = priv;
-       u32 stat = HDMI_READ(VC4_HDMI_CPU_STATUS);
+       u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS);
        u32 cntrl1, cntrl5;
 
        if (!(stat & VC4_HDMI_CPU_CEC))
                return IRQ_NONE;
        vc4_hdmi->cec_rx_msg.len = 0;
-       cntrl1 = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
-       cntrl5 = HDMI_READ(VC4_HDMI_CEC_CNTRL_5);
+       cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
+       cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
        vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
        if (vc4_hdmi->cec_irq_was_rx) {
                vc4_cec_read_msg(vc4_hdmi, cntrl1);
                cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1);
+               HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
                cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
        } else {
                vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
                cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
        }
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1);
-       HDMI_WRITE(VC4_HDMI_CPU_CLEAR, VC4_HDMI_CPU_CEC);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
+       HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
 
        return IRQ_WAKE_THREAD;
 }
        struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
        /* clock period in microseconds */
        const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
-       u32 val = HDMI_READ(VC4_HDMI_CEC_CNTRL_5);
+       u32 val = HDMI_READ(HDMI_CEC_CNTRL_5);
 
        val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
                 VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
               ((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT);
 
        if (enable) {
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val |
+               HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
                           VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val);
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_2,
-                        ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
-                        ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
-                        ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
-                        ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
-                        ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_3,
-                        ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
-                        ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
-                        ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
-                        ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_4,
-                        ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
-                        ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
-                        ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
-                        ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
-
-               HDMI_WRITE(VC4_HDMI_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
+               HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
+               HDMI_WRITE(HDMI_CEC_CNTRL_2,
+                          ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
+                          ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
+                          ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
+                          ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
+                          ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
+               HDMI_WRITE(HDMI_CEC_CNTRL_3,
+                          ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
+                          ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
+                          ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
+                          ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
+               HDMI_WRITE(HDMI_CEC_CNTRL_4,
+                          ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
+                          ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
+                          ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
+                          ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
+
+               HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
        } else {
-               HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val |
+               HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
+               HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
                           VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
        }
        return 0;
 {
        struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
 
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1,
-                  (HDMI_READ(VC4_HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
+       HDMI_WRITE(HDMI_CEC_CNTRL_1,
+                  (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
                   (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
        return 0;
 }
        unsigned int i;
 
        for (i = 0; i < msg->len; i += 4)
-               HDMI_WRITE(VC4_HDMI_CEC_TX_DATA_1 + i,
+               HDMI_WRITE(HDMI_CEC_TX_DATA_1 + i,
                           (msg->msg[i]) |
                           (msg->msg[i + 1] << 8) |
                           (msg->msg[i + 2] << 16) |
                           (msg->msg[i + 3] << 24));
 
-       val = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
+       val = HDMI_READ(HDMI_CEC_CNTRL_1);
        val &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
        val &= ~VC4_HDMI_CEC_MESSAGE_LENGTH_MASK;
        val |= (msg->len - 1) << VC4_HDMI_CEC_MESSAGE_LENGTH_SHIFT;
        val |= VC4_HDMI_CEC_START_XMIT_BEGIN;
 
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
        return 0;
 }
 
 };
 #endif
 
+static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi,
+                                struct debugfs_regset32 *regset,
+                                enum vc4_hdmi_regs reg)
+{
+       const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
+       struct debugfs_reg32 *regs, *new_regs;
+       unsigned int count = 0;
+       unsigned int i;
+
+       regs = kcalloc(variant->num_registers, sizeof(*regs),
+                      GFP_KERNEL);
+       if (!regs)
+               return -ENOMEM;
+
+       for (i = 0; i < variant->num_registers; i++) {
+               const struct vc4_hdmi_register *field = &variant->registers[i];
+
+               if (field->reg != reg)
+                       continue;
+
+               regs[count].name = field->name;
+               regs[count].offset = field->offset;
+               count++;
+       }
+
+       new_regs = krealloc(regs, count * sizeof(*regs), GFP_KERNEL);
+       if (!new_regs)
+               return -ENOMEM;
+
+       regset->base = __vc4_hdmi_get_field_base(vc4_hdmi, reg);
+       regset->regs = new_regs;
+       regset->nregs = count;
+
+       return 0;
+}
+
 static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
 {
        struct platform_device *pdev = vc4_hdmi->pdev;
        if (IS_ERR(vc4_hdmi->hd_regs))
                return PTR_ERR(vc4_hdmi->hd_regs);
 
-       vc4_hdmi->hdmi_regset.base = vc4_hdmi->hdmicore_regs;
-       vc4_hdmi->hdmi_regset.regs = hdmi_regs;
-       vc4_hdmi->hdmi_regset.nregs = ARRAY_SIZE(hdmi_regs);
+       ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD);
+       if (ret)
+               return ret;
 
-       vc4_hdmi->hd_regset.base = vc4_hdmi->hd_regs;
-       vc4_hdmi->hd_regset.regs = hd_regs;
-       vc4_hdmi->hd_regset.nregs = ARRAY_SIZE(hd_regs);
+       ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI);
+       if (ret)
+               return ret;
 
        vc4_hdmi->pixel_clock = devm_clk_get(dev, "pixel");
        if (IS_ERR(vc4_hdmi->pixel_clock)) {
        }
 
        /* HDMI core must be enabled. */
-       if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) {
-               HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST);
+       if (!(HDMI_READ(HDMI_M_CTL) & VC4_HD_M_ENABLE)) {
+               HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST);
                udelay(1);
-               HD_WRITE(VC4_HD_M_CTL, 0);
+               HDMI_WRITE(HDMI_M_CTL, 0);
 
-               HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE);
+               HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_ENABLE);
        }
        pm_runtime_enable(dev);
 
        cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
        cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
 
-       HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff);
-       value = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
+       HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
+       value = HDMI_READ(HDMI_CEC_CNTRL_1);
        value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
        /*
         * Set the logical address to Unregistered and set the clock
         */
        value |= VC4_HDMI_CEC_ADDR_MASK |
                 (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT);
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, value);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
        ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
                                        vc4_cec_irq_handler,
                                        vc4_cec_irq_handler_thread, 0,
        BUILD_BUG_ON(offsetof(struct vc4_hdmi, audio) != 0);
        vc4_hdmi = dev_get_drvdata(dev);
 
+       kfree(vc4_hdmi->hdmi_regset.regs);
+       kfree(vc4_hdmi->hd_regset.regs);
+
        cec_unregister_adapter(vc4_hdmi->cec_adap);
        vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
        drm_encoder_cleanup(&vc4_hdmi->encoder.base.base);
 }
 
 static const struct vc4_hdmi_variant bcm2835_variant = {
+       .registers              = vc4_hdmi_fields,
+       .num_registers          = ARRAY_SIZE(vc4_hdmi_fields),
+
        .init_resources         = vc4_hdmi_init_resources,
 };
 
 
--- /dev/null
+#ifndef _VC4_HDMI_REGS_H_
+#define _VC4_HDMI_REGS_H_
+
+#include "vc4_hdmi.h"
+
+#define VC4_HDMI_PACKET_STRIDE                 0x24
+
+enum vc4_hdmi_regs {
+       VC4_INVALID = 0,
+       VC4_HDMI,
+       VC4_HD,
+};
+
+enum vc4_hdmi_field {
+       HDMI_AUDIO_PACKET_CONFIG,
+       HDMI_CEC_CNTRL_1,
+       HDMI_CEC_CNTRL_2,
+       HDMI_CEC_CNTRL_3,
+       HDMI_CEC_CNTRL_4,
+       HDMI_CEC_CNTRL_5,
+       HDMI_CEC_CPU_CLEAR,
+       HDMI_CEC_CPU_MASK_CLEAR,
+       HDMI_CEC_CPU_MASK_SET,
+       HDMI_CEC_CPU_MASK_STATUS,
+       HDMI_CEC_CPU_STATUS,
+
+       /*
+        * Transmit data, first byte is low byte of the 32-bit reg.
+        * MSB of each byte transmitted first.
+        */
+       HDMI_CEC_RX_DATA_1,
+       HDMI_CEC_RX_DATA_2,
+       HDMI_CEC_RX_DATA_3,
+       HDMI_CEC_RX_DATA_4,
+       HDMI_CEC_TX_DATA_1,
+       HDMI_CEC_TX_DATA_2,
+       HDMI_CEC_TX_DATA_3,
+       HDMI_CEC_TX_DATA_4,
+       HDMI_CORE_REV,
+       HDMI_CRP_CFG,
+       HDMI_CSC_12_11,
+       HDMI_CSC_14_13,
+       HDMI_CSC_22_21,
+       HDMI_CSC_24_23,
+       HDMI_CSC_32_31,
+       HDMI_CSC_34_33,
+       HDMI_CSC_CTL,
+
+       /*
+        * 20-bit fields containing CTS values to be transmitted if
+        * !EXTERNAL_CTS_EN
+        */
+       HDMI_CTS_0,
+       HDMI_CTS_1,
+       HDMI_FIFO_CTL,
+       HDMI_FRAME_COUNT,
+       HDMI_HORZA,
+       HDMI_HORZB,
+       HDMI_HOTPLUG,
+       HDMI_HOTPLUG_INT,
+
+       /*
+        * 3 bits per field, where each field maps from that
+        * corresponding MAI bus channel to the given HDMI channel.
+        */
+       HDMI_MAI_CHANNEL_MAP,
+       HDMI_MAI_CONFIG,
+       HDMI_MAI_CTL,
+
+       /*
+        * Register for DMAing in audio data to be transported over
+        * the MAI bus to the Falcon core.
+        */
+       HDMI_MAI_DATA,
+
+       /* Format header to be placed on the MAI data. Unused. */
+       HDMI_MAI_FMT,
+
+       /* Last received format word on the MAI bus. */
+       HDMI_MAI_FORMAT,
+       HDMI_MAI_SMP,
+       HDMI_MAI_THR,
+       HDMI_M_CTL,
+       HDMI_RAM_PACKET_CONFIG,
+       HDMI_RAM_PACKET_START,
+       HDMI_RAM_PACKET_STATUS,
+       HDMI_SCHEDULER_CONTROL,
+       HDMI_SW_RESET_CONTROL,
+       HDMI_TX_PHY_CTL_0,
+       HDMI_TX_PHY_RESET_CTL,
+       HDMI_VERTA0,
+       HDMI_VERTA1,
+       HDMI_VERTB0,
+       HDMI_VERTB1,
+       HDMI_VID_CTL,
+};
+
+struct vc4_hdmi_register {
+       char *name;
+       enum vc4_hdmi_regs reg;
+       unsigned int offset;
+};
+
+#define _VC4_REG(_base, _reg, _offset) \
+       [_reg] = {                              \
+               .name = #_reg,                  \
+               .reg = _base,                   \
+               .offset = _offset,              \
+       }
+
+#define VC4_HD_REG(reg, offset)                _VC4_REG(VC4_HD, reg, offset)
+#define VC4_HDMI_REG(reg, offset)      _VC4_REG(VC4_HDMI, reg, offset)
+
+static const struct vc4_hdmi_register vc4_hdmi_fields[] = {
+       VC4_HD_REG(HDMI_M_CTL, 0x000c),
+       VC4_HD_REG(HDMI_MAI_CTL, 0x0014),
+       VC4_HD_REG(HDMI_MAI_THR, 0x0018),
+       VC4_HD_REG(HDMI_MAI_FMT, 0x001c),
+       VC4_HD_REG(HDMI_MAI_DATA, 0x0020),
+       VC4_HD_REG(HDMI_MAI_SMP, 0x002c),
+       VC4_HD_REG(HDMI_VID_CTL, 0x0038),
+       VC4_HD_REG(HDMI_CSC_CTL, 0x0040),
+       VC4_HD_REG(HDMI_CSC_12_11, 0x0044),
+       VC4_HD_REG(HDMI_CSC_14_13, 0x0048),
+       VC4_HD_REG(HDMI_CSC_22_21, 0x004c),
+       VC4_HD_REG(HDMI_CSC_24_23, 0x0050),
+       VC4_HD_REG(HDMI_CSC_32_31, 0x0054),
+       VC4_HD_REG(HDMI_CSC_34_33, 0x0058),
+       VC4_HD_REG(HDMI_FRAME_COUNT, 0x0068),
+
+       VC4_HDMI_REG(HDMI_CORE_REV, 0x0000),
+       VC4_HDMI_REG(HDMI_SW_RESET_CONTROL, 0x0004),
+       VC4_HDMI_REG(HDMI_HOTPLUG_INT, 0x0008),
+       VC4_HDMI_REG(HDMI_HOTPLUG, 0x000c),
+       VC4_HDMI_REG(HDMI_FIFO_CTL, 0x005c),
+       VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x0090),
+       VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0094),
+       VC4_HDMI_REG(HDMI_MAI_FORMAT, 0x0098),
+       VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x009c),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x00a0),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x00a4),
+       VC4_HDMI_REG(HDMI_CRP_CFG, 0x00a8),
+       VC4_HDMI_REG(HDMI_CTS_0, 0x00ac),
+       VC4_HDMI_REG(HDMI_CTS_1, 0x00b0),
+       VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x00c0),
+       VC4_HDMI_REG(HDMI_HORZA, 0x00c4),
+       VC4_HDMI_REG(HDMI_HORZB, 0x00c8),
+       VC4_HDMI_REG(HDMI_VERTA0, 0x00cc),
+       VC4_HDMI_REG(HDMI_VERTB0, 0x00d0),
+       VC4_HDMI_REG(HDMI_VERTA1, 0x00d4),
+       VC4_HDMI_REG(HDMI_VERTB1, 0x00d8),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_1, 0x00e8),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_2, 0x00ec),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_3, 0x00f0),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_4, 0x00f4),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_5, 0x00f8),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_1, 0x00fc),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_2, 0x0100),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_3, 0x0104),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_4, 0x0108),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_1, 0x010c),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_2, 0x0110),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_3, 0x0114),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_4, 0x0118),
+       VC4_HDMI_REG(HDMI_TX_PHY_RESET_CTL, 0x02c0),
+       VC4_HDMI_REG(HDMI_TX_PHY_CTL_0, 0x02c4),
+       VC4_HDMI_REG(HDMI_CEC_CPU_STATUS, 0x0340),
+       VC4_HDMI_REG(HDMI_CEC_CPU_CLEAR, 0x0348),
+       VC4_HDMI_REG(HDMI_CEC_CPU_MASK_STATUS, 0x034c),
+       VC4_HDMI_REG(HDMI_CEC_CPU_MASK_SET, 0x034c),
+       VC4_HDMI_REG(HDMI_CEC_CPU_MASK_CLEAR, 0x0354),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400),
+};
+
+static inline
+void __iomem *__vc4_hdmi_get_field_base(struct vc4_hdmi *hdmi,
+                                       enum vc4_hdmi_regs reg)
+{
+       switch (reg) {
+       case VC4_HD:
+               return hdmi->hd_regs;
+
+       case VC4_HDMI:
+               return hdmi->hdmicore_regs;
+
+       default:
+               return NULL;
+       }
+
+       return NULL;
+}
+
+static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
+                               enum vc4_hdmi_regs reg)
+{
+       const struct vc4_hdmi_register *field;
+       const struct vc4_hdmi_variant *variant = hdmi->variant;
+       void __iomem *base;
+
+       if (reg > variant->num_registers) {
+               dev_warn(&hdmi->pdev->dev,
+                        "Invalid register ID %u\n", reg);
+               return 0;
+       }
+
+       field = &variant->registers[reg];
+       base = __vc4_hdmi_get_field_base(hdmi, field->reg);
+       if (!base) {
+               dev_warn(&hdmi->pdev->dev,
+                        "Unknown register ID %u\n", reg);
+               return 0;
+       }
+
+       return readl(base + field->offset);
+}
+#define HDMI_READ(reg)         vc4_hdmi_read(vc4_hdmi, reg)
+
+static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
+                                 enum vc4_hdmi_regs reg,
+                                 u32 value)
+{
+       const struct vc4_hdmi_register *field;
+       const struct vc4_hdmi_variant *variant = hdmi->variant;
+       void __iomem *base;
+
+       if (reg > variant->num_registers) {
+               dev_warn(&hdmi->pdev->dev,
+                        "Invalid register ID %u\n", reg);
+               return;
+       }
+
+       field = &variant->registers[reg];
+       base = __vc4_hdmi_get_field_base(hdmi, field->reg);
+       if (!base)
+               return;
+
+       writel(value, base + field->offset);
+}
+#define HDMI_WRITE(reg, val)   vc4_hdmi_write(vc4_hdmi, reg, val)
+
+#endif /* _VC4_HDMI_REGS_H_ */
 
 
 #define SCALER5_DLIST_START                    0x00004000
 
-#define VC4_HDMI_CORE_REV                      0x000
-
-#define VC4_HDMI_SW_RESET_CONTROL              0x004
 # define VC4_HDMI_SW_RESET_FORMAT_DETECT       BIT(1)
 # define VC4_HDMI_SW_RESET_HDMI                        BIT(0)
 
-#define VC4_HDMI_HOTPLUG_INT                   0x008
-
-#define VC4_HDMI_HOTPLUG                       0x00c
 # define VC4_HDMI_HOTPLUG_CONNECTED            BIT(0)
 
-/* 3 bits per field, where each field maps from that corresponding MAI
- * bus channel to the given HDMI channel.
- */
-#define VC4_HDMI_MAI_CHANNEL_MAP               0x090
-
-#define VC4_HDMI_MAI_CONFIG                    0x094
 # define VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE            BIT(27)
 # define VC4_HDMI_MAI_CONFIG_BIT_REVERSE               BIT(26)
 # define VC4_HDMI_MAI_CHANNEL_MASK_MASK                        VC4_MASK(15, 0)
 # define VC4_HDMI_MAI_CHANNEL_MASK_SHIFT               0
 
-/* Last received format word on the MAI bus. */
-#define VC4_HDMI_MAI_FORMAT                    0x098
-
-#define VC4_HDMI_AUDIO_PACKET_CONFIG           0x09c
 # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT                BIT(29)
 # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS  BIT(24)
 # define VC4_HDMI_AUDIO_PACKET_FORCE_SAMPLE_PRESENT            BIT(19)
 # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_MASK                   VC4_MASK(7, 0)
 # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_SHIFT                  0
 
-#define VC4_HDMI_RAM_PACKET_CONFIG             0x0a0
 # define VC4_HDMI_RAM_PACKET_ENABLE            BIT(16)
 
-#define VC4_HDMI_RAM_PACKET_STATUS             0x0a4
-
-#define VC4_HDMI_CRP_CFG                       0x0a8
 /* When set, the CTS_PERIOD counts based on MAI bus sync pulse instead
  * of pixel clock.
  */
 # define VC4_HDMI_CRP_CFG_N_MASK               VC4_MASK(19, 0)
 # define VC4_HDMI_CRP_CFG_N_SHIFT              0
 
-/* 20-bit fields containing CTS values to be transmitted if !EXTERNAL_CTS_EN */
-#define VC4_HDMI_CTS_0                         0x0ac
-#define VC4_HDMI_CTS_1                         0x0b0
-/* 20-bit fields containing number of clocks to send CTS0/1 before
- * switching to the other one.
- */
-#define VC4_HDMI_CTS_PERIOD_0                  0x0b4
-#define VC4_HDMI_CTS_PERIOD_1                  0x0b8
-
-#define VC4_HDMI_HORZA                         0x0c4
 # define VC4_HDMI_HORZA_VPOS                   BIT(14)
 # define VC4_HDMI_HORZA_HPOS                   BIT(13)
 /* Horizontal active pixels (hdisplay). */
 # define VC4_HDMI_HORZA_HAP_MASK               VC4_MASK(12, 0)
 # define VC4_HDMI_HORZA_HAP_SHIFT              0
 
-#define VC4_HDMI_HORZB                         0x0c8
 /* Horizontal pack porch (htotal - hsync_end). */
 # define VC4_HDMI_HORZB_HBP_MASK               VC4_MASK(29, 20)
 # define VC4_HDMI_HORZB_HBP_SHIFT              20
 # define VC4_HDMI_HORZB_HFP_MASK               VC4_MASK(9, 0)
 # define VC4_HDMI_HORZB_HFP_SHIFT              0
 
-#define VC4_HDMI_FIFO_CTL                      0x05c
 # define VC4_HDMI_FIFO_CTL_RECENTER_DONE       BIT(14)
 # define VC4_HDMI_FIFO_CTL_USE_EMPTY           BIT(13)
 # define VC4_HDMI_FIFO_CTL_ON_VB               BIT(7)
 # define VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N      BIT(0)
 # define VC4_HDMI_FIFO_VALID_WRITE_MASK                0xefff
 
-#define VC4_HDMI_SCHEDULER_CONTROL             0x0c0
 # define VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT BIT(15)
 # define VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS BIT(5)
 # define VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT        BIT(3)
 # define VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE        BIT(1)
 # define VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI  BIT(0)
 
-#define VC4_HDMI_VERTA0                                0x0cc
-#define VC4_HDMI_VERTA1                                0x0d4
 /* Vertical sync pulse (vsync_end - vsync_start). */
 # define VC4_HDMI_VERTA_VSP_MASK               VC4_MASK(24, 20)
 # define VC4_HDMI_VERTA_VSP_SHIFT              20
 # define VC4_HDMI_VERTA_VAL_MASK               VC4_MASK(12, 0)
 # define VC4_HDMI_VERTA_VAL_SHIFT              0
 
-#define VC4_HDMI_VERTB0                                0x0d0
-#define VC4_HDMI_VERTB1                                0x0d8
 /* Vertical sync pulse offset (for interlaced) */
 # define VC4_HDMI_VERTB_VSPO_MASK              VC4_MASK(21, 9)
 # define VC4_HDMI_VERTB_VSPO_SHIFT             9
 # define VC4_HDMI_VERTB_VBP_MASK               VC4_MASK(8, 0)
 # define VC4_HDMI_VERTB_VBP_SHIFT              0
 
-#define VC4_HDMI_CEC_CNTRL_1                   0x0e8
 /* Set when the transmission has ended. */
 # define VC4_HDMI_CEC_TX_EOM                   BIT(31)
 /* If set, transmission was acked on the 1st or 2nd attempt (only one
 /* Set these fields to how many bit clock cycles get to that many
  * microseconds.
  */
-#define VC4_HDMI_CEC_CNTRL_2                   0x0ec
 # define VC4_HDMI_CEC_CNT_TO_1500_US_MASK      VC4_MASK(30, 24)
 # define VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT     24
 # define VC4_HDMI_CEC_CNT_TO_1300_US_MASK      VC4_MASK(23, 17)
 # define VC4_HDMI_CEC_CNT_TO_400_US_MASK       VC4_MASK(4, 0)
 # define VC4_HDMI_CEC_CNT_TO_400_US_SHIFT      0
 
-#define VC4_HDMI_CEC_CNTRL_3                   0x0f0
 # define VC4_HDMI_CEC_CNT_TO_2750_US_MASK      VC4_MASK(31, 24)
 # define VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT     24
 # define VC4_HDMI_CEC_CNT_TO_2400_US_MASK      VC4_MASK(23, 16)
 # define VC4_HDMI_CEC_CNT_TO_1700_US_MASK      VC4_MASK(7, 0)
 # define VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT     0
 
-#define VC4_HDMI_CEC_CNTRL_4                   0x0f4
 # define VC4_HDMI_CEC_CNT_TO_4300_US_MASK      VC4_MASK(31, 24)
 # define VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT     24
 # define VC4_HDMI_CEC_CNT_TO_3900_US_MASK      VC4_MASK(23, 16)
 # define VC4_HDMI_CEC_CNT_TO_3500_US_MASK      VC4_MASK(7, 0)
 # define VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT     0
 
-#define VC4_HDMI_CEC_CNTRL_5                   0x0f8
 # define VC4_HDMI_CEC_TX_SW_RESET              BIT(27)
 # define VC4_HDMI_CEC_RX_SW_RESET              BIT(26)
 # define VC4_HDMI_CEC_PAD_SW_RESET             BIT(25)
 # define VC4_HDMI_CEC_CNT_TO_4500_US_MASK      VC4_MASK(7, 0)
 # define VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT     0
 
-/* Transmit data, first byte is low byte of the 32-bit reg.  MSB of
- * each byte transmitted first.
- */
-#define VC4_HDMI_CEC_TX_DATA_1                 0x0fc
-#define VC4_HDMI_CEC_TX_DATA_2                 0x100
-#define VC4_HDMI_CEC_TX_DATA_3                 0x104
-#define VC4_HDMI_CEC_TX_DATA_4                 0x108
-#define VC4_HDMI_CEC_RX_DATA_1                 0x10c
-#define VC4_HDMI_CEC_RX_DATA_2                 0x110
-#define VC4_HDMI_CEC_RX_DATA_3                 0x114
-#define VC4_HDMI_CEC_RX_DATA_4                 0x118
-
-#define VC4_HDMI_TX_PHY_RESET_CTL              0x2c0
-
-#define VC4_HDMI_TX_PHY_CTL0                   0x2c4
 # define VC4_HDMI_TX_PHY_RNG_PWRDN             BIT(25)
 
-/* Interrupt status bits */
-#define VC4_HDMI_CPU_STATUS                    0x340
-#define VC4_HDMI_CPU_SET                       0x344
-#define VC4_HDMI_CPU_CLEAR                     0x348
 # define VC4_HDMI_CPU_CEC                      BIT(6)
 # define VC4_HDMI_CPU_HOTPLUG                  BIT(0)
 
-#define VC4_HDMI_CPU_MASK_STATUS               0x34c
-#define VC4_HDMI_CPU_MASK_SET                  0x350
-#define VC4_HDMI_CPU_MASK_CLEAR                        0x354
-
-#define VC4_HDMI_GCP(x)                                (0x400 + ((x) * 0x4))
-#define VC4_HDMI_RAM_PACKET(x)                 (0x400 + ((x) * 0x24))
-#define VC4_HDMI_PACKET_STRIDE                 0x24
-
-#define VC4_HD_M_CTL                           0x00c
 /* Debug: Current receive value on the CEC pad. */
 # define VC4_HD_CECRXD                         BIT(9)
 /* Debug: Override CEC output to 0. */
 # define VC4_HD_M_SW_RST                       BIT(2)
 # define VC4_HD_M_ENABLE                       BIT(0)
 
-#define VC4_HD_MAI_CTL                         0x014
 /* Set when audio stream is received at a slower rate than the
  * sampling period, so MAI fifo goes empty.  Write 1 to clear.
  */
 /* Single-shot reset bit.  Read value is undefined. */
 # define VC4_HD_MAI_CTL_RESET                  BIT(0)
 
-#define VC4_HD_MAI_THR                         0x018
 # define VC4_HD_MAI_THR_PANICHIGH_MASK         VC4_MASK(29, 24)
 # define VC4_HD_MAI_THR_PANICHIGH_SHIFT                24
 # define VC4_HD_MAI_THR_PANICLOW_MASK          VC4_MASK(21, 16)
 # define VC4_HD_MAI_THR_DREQLOW_MASK           VC4_MASK(5, 0)
 # define VC4_HD_MAI_THR_DREQLOW_SHIFT          0
 
-/* Format header to be placed on the MAI data. Unused. */
-#define VC4_HD_MAI_FMT                         0x01c
-
-/* Register for DMAing in audio data to be transported over the MAI
- * bus to the Falcon core.
- */
-#define VC4_HD_MAI_DATA                                0x020
-
 /* Divider from HDMI HSM clock to MAI serial clock.  Sampling period
  * converges to N / (M + 1) cycles.
  */
-#define VC4_HD_MAI_SMP                         0x02c
 # define VC4_HD_MAI_SMP_N_MASK                 VC4_MASK(31, 8)
 # define VC4_HD_MAI_SMP_N_SHIFT                        8
 # define VC4_HD_MAI_SMP_M_MASK                 VC4_MASK(7, 0)
 # define VC4_HD_MAI_SMP_M_SHIFT                        0
 
-#define VC4_HD_VID_CTL                         0x038
 # define VC4_HD_VID_CTL_ENABLE                 BIT(31)
 # define VC4_HD_VID_CTL_UNDERFLOW_ENABLE       BIT(30)
 # define VC4_HD_VID_CTL_FRAME_COUNTER_RESET    BIT(29)
 # define VC4_HD_VID_CTL_VSYNC_LOW              BIT(28)
 # define VC4_HD_VID_CTL_HSYNC_LOW              BIT(27)
 
-#define VC4_HD_CSC_CTL                         0x040
 # define VC4_HD_CSC_CTL_ORDER_MASK             VC4_MASK(7, 5)
 # define VC4_HD_CSC_CTL_ORDER_SHIFT            5
 # define VC4_HD_CSC_CTL_ORDER_RGB              0
 # define VC4_HD_CSC_CTL_RGB2YCC                        BIT(1)
 # define VC4_HD_CSC_CTL_ENABLE                 BIT(0)
 
-#define VC4_HD_CSC_12_11                       0x044
-#define VC4_HD_CSC_14_13                       0x048
-#define VC4_HD_CSC_22_21                       0x04c
-#define VC4_HD_CSC_24_23                       0x050
-#define VC4_HD_CSC_32_31                       0x054
-#define VC4_HD_CSC_34_33                       0x058
-
-#define VC4_HD_FRAME_COUNT                     0x068
-
 /* HVS display list information. */
 #define HVS_BOOTLOADER_DLIST_END                32