From cc92a80bf5fcdd4cceef6e395f383975422965b3 Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Tue, 14 Feb 2023 14:58:33 +0000
Subject: [PATCH] drm: Add RP1 DSI driver

Add support for the RP1 DSI hardware.

Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>

drm/rp1: depends on, instead of select, MFD_RP1

According to kconfig-language.txt [1], select should be used only for
"non-visible symbols ... and for symbols with no dependencies". Since
MFD_RP1 both is visible and has a dependency, "select" should not be
used and "depends on" should be used instead.

In particular, this fixes the build of this kernel tree on NixOS, where
its kernel config system will try to answer 'M' to as many config as
possible.

[1] https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html

Signed-off-by: Ratchanan Srirattanamet <peathot@hotmail.com>

DRM: rp1: rp1-dsi: Fix escape clock divider and timeouts.

Escape clock divider was fixed at 5, which is correct at 800Mbps/lane
but increasingly out of spec for higher rates. Compute it correctly.

High speed timeout was fixed at 5*512 == 2560 byte-clocks per lane.
Compute it conservatively to be 8/7 times the line period (assuming
there will be a transition to LP some time during each scanline?)
keeping the old value as a lower bound. Increase LPRX TO to 1024,
and BTA TO to 0xb00 (same value as in bridge/synopsys/dw-mipi-dsi).

(No change to LP_CMD_TIM. To do: compute this correctly.)

Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>

drm: rp1: rp1-dsi: Switch to PLL_SYS source for DPI when 8 * lanes > bpp

To support 4 lanes, re-parent DPI clock source between DSI byteclock
(using the new "variable sources" defined in clk-rp1) and PLL_SYS.
This is to cover cases in which byteclock < pixclock <= 200MHz.

Tidying: All frequencies now in Hz (not kHz), where DSI speed is now
represented by byteclock to simplify arithmetic. Clamp DPI and byte
clocks to their legal ranges; fix up HSTX timeout to avoid an unsafe
assumption that it would return to LP state for every scanline.

Because of RP1's clock topology, the ratio between DSI and DPI clocks
may not be exact with 3 or 4 lanes, leading to slightly irregular
timings each time DSI switches between HS and LP states. Tweak to
inhibit LP during Horizontal BP when sync pulses were requested.

Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>

drm: rp1: rp1-dsi: Add DRM_FORMAT_ARGB8888 and DRM_FORMAT_ABGR8888

Android requires this.
As the underlying hardware doesn't support alpha blending,
we ignore the alpha value.

Signed-off-by: Jan Kehren <jan.kehren@emteria.com>

drivers: drm: rp1-dsi: Implement more DSI options and flags

Now implementing:
- Per-command selection of LP or HS for commands (previously LP)
- EoTp transmission option (previously EoTp was always disabled)
- Non-continuous clock option (previously always continuous)
- Per-command enabling of ACK request (in command mode only)

Make a plausible (and possibly correct) attempt to measure the
longest LP command that will fit into vertical blanking lines.

DON'T set both "Burst Mode" and "Sync Events" flags together.
This is redundant in the standard IP; in this RP1 variant it
would enable Sync Pulses but may break with some video timings.

Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
 drivers/gpu/drm/Kconfig                   |    2 +
 drivers/gpu/drm/Makefile                  |    1 +
 drivers/gpu/drm/rp1/Kconfig               |    5 +
 drivers/gpu/drm/rp1/Makefile              |    4 +
 drivers/gpu/drm/rp1/rp1-dsi/Kconfig       |   14 +
 drivers/gpu/drm/rp1/rp1-dsi/Makefile      |    5 +
 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c     |  540 +++++++
 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h     |   96 ++
 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c |  455 ++++++
 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 1598 +++++++++++++++++++++
 10 files changed, 2720 insertions(+)
 create mode 100644 drivers/gpu/drm/rp1/Kconfig
 create mode 100644 drivers/gpu/drm/rp1/Makefile
 create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Kconfig
 create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Makefile
 create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
 create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
 create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c
 create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c

--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -441,6 +441,8 @@ source "drivers/gpu/drm/v3d/Kconfig"
 
 source "drivers/gpu/drm/vc4/Kconfig"
 
+source "drivers/gpu/drm/rp1/Kconfig"
+
 source "drivers/gpu/drm/loongson/Kconfig"
 
 source "drivers/gpu/drm/etnaviv/Kconfig"
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -225,3 +225,4 @@ obj-y			+= solomon/
 obj-$(CONFIG_DRM_SPRD) += sprd/
 obj-$(CONFIG_DRM_LOONGSON) += loongson/
 obj-$(CONFIG_DRM_POWERVR) += imagination/
+obj-y			+= rp1/
--- /dev/null
+++ b/drivers/gpu/drm/rp1/Kconfig
@@ -0,0 +1,5 @@
+source "drivers/gpu/drm/rp1/rp1-dsi/Kconfig"
+
+source "drivers/gpu/drm/rp1/rp1-dpi/Kconfig"
+
+source "drivers/gpu/drm/rp1/rp1-vec/Kconfig"
--- /dev/null
+++ b/drivers/gpu/drm/rp1/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_DRM_RP1_DSI) += rp1-dsi/
+obj-$(CONFIG_DRM_RP1_DPI) += rp1-dpi/
+obj-$(CONFIG_DRM_RP1_VEC) += rp1-vec/
+
--- /dev/null
+++ b/drivers/gpu/drm/rp1/rp1-dsi/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DRM_RP1_DSI
+	tristate "DRM Support for RP1 DSI"
+	depends on DRM && MFD_RP1
+	select DRM_GEM_DMA_HELPER
+	select DRM_KMS_HELPER
+	select DRM_MIPI_DSI
+	select DRM_VRAM_HELPER
+	select DRM_TTM
+	select DRM_TTM_HELPER
+	select GENERIC_PHY
+	select GENERIC_PHY_MIPI_DPHY
+	help
+	  Choose this option to enable DSI display on RP1
--- /dev/null
+++ b/drivers/gpu/drm/rp1/rp1-dsi/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+drm-rp1-dsi-y := rp1_dsi.o rp1_dsi_dma.o rp1_dsi_dsi.o
+
+obj-$(CONFIG_DRM_RP1_DSI) += drm-rp1-dsi.o
--- /dev/null
+++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c
@@ -0,0 +1,540 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * DRM Driver for DSI output on Raspberry Pi RP1
+ *
+ * Copyright (c) 2023 Raspberry Pi Limited.
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/string.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fbdev_ttm.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_of.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "rp1_dsi.h"
+
+static inline struct rp1_dsi *
+bridge_to_rp1_dsi(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct rp1_dsi, bridge);
+}
+
+static void rp1_dsi_bridge_pre_enable(struct drm_bridge *bridge,
+				      struct drm_bridge_state *old_state)
+{
+	struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge);
+
+	rp1dsi_dsi_setup(dsi, &dsi->pipe.crtc.state->adjusted_mode);
+	dsi->dsi_running = true;
+}
+
+static void rp1_dsi_bridge_enable(struct drm_bridge *bridge,
+				  struct drm_bridge_state *old_state)
+{
+}
+
+static void rp1_dsi_bridge_disable(struct drm_bridge *bridge,
+				   struct drm_bridge_state *state)
+{
+}
+
+static void rp1_dsi_bridge_post_disable(struct drm_bridge *bridge,
+					struct drm_bridge_state *state)
+{
+	struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge);
+
+	if (dsi->dsi_running) {
+		rp1dsi_dsi_stop(dsi);
+		dsi->dsi_running = false;
+	}
+}
+
+static int rp1_dsi_bridge_attach(struct drm_bridge *bridge,
+				 enum drm_bridge_attach_flags flags)
+{
+	struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge);
+
+	/* Attach the panel or bridge to the dsi bridge */
+	return drm_bridge_attach(bridge->encoder, dsi->out_bridge,
+				 &dsi->bridge, flags);
+	return 0;
+}
+
+static const struct drm_bridge_funcs rp1_dsi_bridge_funcs = {
+	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+	.atomic_reset = drm_atomic_helper_bridge_reset,
+	.atomic_pre_enable = rp1_dsi_bridge_pre_enable,
+	.atomic_enable = rp1_dsi_bridge_enable,
+	.atomic_disable = rp1_dsi_bridge_disable,
+	.atomic_post_disable = rp1_dsi_bridge_post_disable,
+	.attach = rp1_dsi_bridge_attach,
+};
+
+static void rp1dsi_pipe_update(struct drm_simple_display_pipe *pipe,
+			       struct drm_plane_state *old_state)
+{
+	struct drm_pending_vblank_event *event;
+	unsigned long flags;
+	struct drm_framebuffer *fb = pipe->plane.state->fb;
+	struct rp1_dsi *dsi = pipe->crtc.dev->dev_private;
+	struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL;
+	struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL;
+	bool can_update = fb && dma_obj && dsi && dsi->pipe_enabled;
+
+	/* (Re-)start DSI,DMA where required; and update FB address */
+	if (can_update) {
+		if (!dsi->dma_running || fb->format->format != dsi->cur_fmt) {
+			if (dsi->dma_running && fb->format->format != dsi->cur_fmt) {
+				rp1dsi_dma_stop(dsi);
+				dsi->dma_running = false;
+			}
+			if (!dsi->dma_running) {
+				rp1dsi_dma_setup(dsi,
+						 fb->format->format, dsi->display_format,
+						&pipe->crtc.state->adjusted_mode);
+				dsi->dma_running = true;
+			}
+			dsi->cur_fmt  = fb->format->format;
+			drm_crtc_vblank_on(&pipe->crtc);
+		}
+		rp1dsi_dma_update(dsi, dma_obj->dma_addr, fb->offsets[0], fb->pitches[0]);
+	}
+
+	/* Arm VBLANK event (or call it immediately in some error cases) */
+	spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags);
+	event = pipe->crtc.state->event;
+	if (event) {
+		pipe->crtc.state->event = NULL;
+		if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0)
+			drm_crtc_arm_vblank_event(&pipe->crtc, event);
+		else
+			drm_crtc_send_vblank_event(&pipe->crtc, event);
+	}
+	spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags);
+}
+
+static inline struct rp1_dsi *
+encoder_to_rp1_dsi(struct drm_encoder *encoder)
+{
+	struct drm_simple_display_pipe *pipe =
+		container_of(encoder, struct drm_simple_display_pipe, encoder);
+	return container_of(pipe, struct rp1_dsi, pipe);
+}
+
+static void rp1dsi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder);
+
+	/* Put DSI into video mode before starting video */
+	rp1dsi_dsi_set_cmdmode(dsi, 0);
+
+	/* Start DMA -> DPI */
+	dsi->pipe_enabled = true;
+	dsi->cur_fmt = 0xdeadbeef;
+	rp1dsi_pipe_update(&dsi->pipe, 0);
+}
+
+static void rp1dsi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder);
+
+	drm_crtc_vblank_off(&dsi->pipe.crtc);
+	if (dsi->dma_running) {
+		rp1dsi_dma_stop(dsi);
+		dsi->dma_running = false;
+	}
+	dsi->pipe_enabled = false;
+
+	/* Return to command mode after stopping video */
+	rp1dsi_dsi_set_cmdmode(dsi, 1);
+}
+
+static const struct drm_encoder_helper_funcs rp1_dsi_encoder_funcs = {
+	.enable = rp1dsi_encoder_enable,
+	.disable = rp1dsi_encoder_disable,
+};
+
+static void rp1dsi_pipe_enable(struct drm_simple_display_pipe *pipe,
+			       struct drm_crtc_state *crtc_state,
+			       struct drm_plane_state *plane_state)
+{
+}
+
+static void rp1dsi_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+}
+
+static int rp1dsi_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
+{
+	struct rp1_dsi *dsi = pipe->crtc.dev->dev_private;
+
+	if (dsi)
+		rp1dsi_dma_vblank_ctrl(dsi, 1);
+
+	return 0;
+}
+
+static void rp1dsi_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
+{
+	struct rp1_dsi *dsi = pipe->crtc.dev->dev_private;
+
+	if (dsi)
+		rp1dsi_dma_vblank_ctrl(dsi, 0);
+}
+
+static const struct drm_simple_display_pipe_funcs rp1dsi_pipe_funcs = {
+	.enable	    = rp1dsi_pipe_enable,
+	.update	    = rp1dsi_pipe_update,
+	.disable    = rp1dsi_pipe_disable,
+	.enable_vblank  = rp1dsi_pipe_enable_vblank,
+	.disable_vblank = rp1dsi_pipe_disable_vblank,
+};
+
+static const struct drm_mode_config_funcs rp1dsi_mode_funcs = {
+	.fb_create = drm_gem_fb_create,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static const u32 rp1dsi_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_RGB565
+};
+
+static void rp1dsi_stopall(struct drm_device *drm)
+{
+	if (drm->dev_private) {
+		struct rp1_dsi *dsi = drm->dev_private;
+
+		if (dsi->dma_running || rp1dsi_dma_busy(dsi)) {
+			rp1dsi_dma_stop(dsi);
+			dsi->dma_running = false;
+		}
+		if (dsi->dsi_running) {
+			rp1dsi_dsi_stop(dsi);
+			dsi->dsi_running = false;
+		}
+		if (dsi->clocks[RP1DSI_CLOCK_CFG])
+			clk_disable_unprepare(dsi->clocks[RP1DSI_CLOCK_CFG]);
+	}
+}
+
+DEFINE_DRM_GEM_DMA_FOPS(rp1dsi_fops);
+
+static struct drm_driver rp1dsi_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	.fops			= &rp1dsi_fops,
+	.name			= "drm-rp1-dsi",
+	.desc			= "drm-rp1-dsi",
+	.date			= "0",
+	.major			= 1,
+	.minor			= 0,
+	DRM_GEM_DMA_DRIVER_OPS,
+	.release		= rp1dsi_stopall,
+};
+
+static int rp1dsi_bind(struct rp1_dsi *dsi)
+{
+	struct platform_device *pdev = dsi->pdev;
+	struct drm_device *drm = dsi->drm;
+	int ret;
+
+	dsi->out_bridge = drmm_of_get_bridge(drm, pdev->dev.of_node, 0, 0);
+	if (IS_ERR(dsi->out_bridge))
+		return PTR_ERR(dsi->out_bridge);
+
+	ret = drmm_mode_config_init(drm);
+	if (ret)
+		goto rtn;
+
+	drm->mode_config.max_width  = 4096;
+	drm->mode_config.max_height = 4096;
+	drm->mode_config.preferred_depth = 32;
+	drm->mode_config.prefer_shadow	 = 0;
+	drm->mode_config.quirk_addfb_prefer_host_byte_order = true;
+	drm->mode_config.funcs = &rp1dsi_mode_funcs;
+	drm_vblank_init(drm, 1);
+
+	ret = drm_simple_display_pipe_init(drm,
+					   &dsi->pipe,
+					   &rp1dsi_pipe_funcs,
+					   rp1dsi_formats,
+					   ARRAY_SIZE(rp1dsi_formats),
+					   NULL, NULL);
+	if (ret)
+		goto rtn;
+
+	/* We need slightly more complex encoder handling (enabling/disabling
+	 * video mode), so add encoder helper functions.
+	 */
+	drm_encoder_helper_add(&dsi->pipe.encoder, &rp1_dsi_encoder_funcs);
+
+	ret = drm_simple_display_pipe_attach_bridge(&dsi->pipe, &dsi->bridge);
+	if (ret)
+		goto rtn;
+
+	drm_bridge_add(&dsi->bridge);
+
+	drm_mode_config_reset(drm);
+
+	if (dsi->clocks[RP1DSI_CLOCK_CFG])
+		clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_CFG]);
+
+	ret = drm_dev_register(drm, 0);
+
+	if (ret == 0)
+		drm_fbdev_ttm_setup(drm, 32);
+
+rtn:
+	if (ret)
+		dev_err(&pdev->dev, "%s returned %d\n", __func__, ret);
+	else
+		dev_info(&pdev->dev, "%s succeeded", __func__);
+
+	return ret;
+}
+
+static void rp1dsi_unbind(struct rp1_dsi *dsi)
+{
+	struct drm_device *drm = dsi->drm;
+
+	rp1dsi_stopall(drm);
+	drm_dev_unregister(drm);
+	drm_atomic_helper_shutdown(drm);
+}
+
+static int rp1dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev)
+{
+	struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host);
+
+	dev_info(&dsi->pdev->dev, "%s: Attach DSI device name=%s channel=%d lanes=%d format=%d flags=0x%lx hs_rate=%lu lp_rate=%lu",
+		 __func__, dsi_dev->name, dsi_dev->channel, dsi_dev->lanes,
+		 dsi_dev->format, dsi_dev->mode_flags, dsi_dev->hs_rate,
+		 dsi_dev->lp_rate);
+	dsi->vc              = dsi_dev->channel & 3;
+	dsi->lanes           = dsi_dev->lanes;
+
+	switch (dsi_dev->format) {
+	case MIPI_DSI_FMT_RGB666:
+	case MIPI_DSI_FMT_RGB666_PACKED:
+	case MIPI_DSI_FMT_RGB565:
+	case MIPI_DSI_FMT_RGB888:
+		break;
+	default:
+		return -EINVAL;
+	}
+	dsi->display_format  = dsi_dev->format;
+	dsi->display_flags   = dsi_dev->mode_flags;
+	dsi->display_hs_rate = dsi_dev->hs_rate;
+	dsi->display_lp_rate = dsi_dev->lp_rate;
+
+	/*
+	 * Previously, we added a separate component to handle panel/bridge
+	 * discovery and DRM registration, but now it's just a function call.
+	 * The downstream/attaching device should deal with -EPROBE_DEFER
+	 */
+	return rp1dsi_bind(dsi);
+}
+
+static int rp1dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev)
+{
+	struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host);
+
+	/*
+	 * Unregister the DRM driver.
+	 * TODO: Check we are cleaning up correctly and not doing things multiple times!
+	 */
+	rp1dsi_unbind(dsi);
+	return 0;
+}
+
+static ssize_t rp1dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg)
+{
+	struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host);
+	struct mipi_dsi_packet packet;
+	int ret = 0;
+
+	/* Write */
+	ret = mipi_dsi_create_packet(&packet, msg);
+	if (ret) {
+		dev_err(dsi->drm->dev, "RP1DSI: failed to create packet: %d\n", ret);
+		return ret;
+	}
+
+	rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header),
+			packet.payload_length, packet.payload,
+			!!(msg->flags & MIPI_DSI_MSG_USE_LPM),
+			!!(msg->flags & MIPI_DSI_MSG_REQ_ACK));
+
+	/* Optional read back */
+	if (msg->rx_len && msg->rx_buf)
+		ret = rp1dsi_dsi_recv(dsi, msg->rx_len, msg->rx_buf);
+
+	return (ssize_t)ret;
+}
+
+static const struct mipi_dsi_host_ops rp1dsi_mipi_dsi_host_ops = {
+	.attach = rp1dsi_host_attach,
+	.detach = rp1dsi_host_detach,
+	.transfer = rp1dsi_host_transfer
+};
+
+static int rp1dsi_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct drm_device *drm;
+	struct rp1_dsi *dsi;
+	int i, ret;
+
+	drm = drm_dev_alloc(&rp1dsi_driver, dev);
+	if (IS_ERR(drm)) {
+		ret = PTR_ERR(drm);
+		return ret;
+	}
+	dsi = drmm_kzalloc(drm, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi) {
+		ret = -ENOMEM;
+		goto err_free_drm;
+	}
+	init_completion(&dsi->finished);
+	dsi->drm = drm;
+	dsi->pdev = pdev;
+	drm->dev_private = dsi;
+	platform_set_drvdata(pdev, drm);
+
+	dsi->bridge.funcs = &rp1_dsi_bridge_funcs;
+	dsi->bridge.of_node = dev->of_node;
+	dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+
+	/* Safe default values for DSI mode */
+	dsi->lanes = 1;
+	dsi->display_format = MIPI_DSI_FMT_RGB888;
+	dsi->display_flags  = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
+
+	/* Hardware resources */
+	for (i = 0; i < RP1DSI_NUM_CLOCKS; i++) {
+		static const char * const myclocknames[RP1DSI_NUM_CLOCKS] = {
+			"cfgclk", "dpiclk", "byteclk", "refclk", "pllsys"
+		};
+		dsi->clocks[i] = devm_clk_get(dev, myclocknames[i]);
+		if (IS_ERR(dsi->clocks[i])) {
+			ret = PTR_ERR(dsi->clocks[i]);
+			dev_err(dev, "Error getting clocks[%d]\n", i);
+			goto err_free_drm;
+		}
+	}
+
+	for (i = 0; i < RP1DSI_NUM_HW_BLOCKS; i++) {
+		dsi->hw_base[i] =
+			devm_ioremap_resource(dev,
+					      platform_get_resource(dsi->pdev,
+								    IORESOURCE_MEM,
+								    i));
+		if (IS_ERR(dsi->hw_base[i])) {
+			ret = PTR_ERR(dsi->hw_base[i]);
+			dev_err(dev, "Error memory mapping regs[%d]\n", i);
+			goto err_free_drm;
+		}
+	}
+	ret = platform_get_irq(dsi->pdev, 0);
+	if (ret > 0)
+		ret = devm_request_irq(dev, ret, rp1dsi_dma_isr,
+				       IRQF_SHARED, "rp1-dsi", dsi);
+	if (ret) {
+		dev_err(dev, "Unable to request interrupt\n");
+		ret = -EINVAL;
+		goto err_free_drm;
+	}
+	rp1dsi_mipicfg_setup(dsi);
+	dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+
+	/* Create the MIPI DSI Host and wait for the panel/bridge to attach to it */
+	dsi->dsi_host.ops = &rp1dsi_mipi_dsi_host_ops;
+	dsi->dsi_host.dev = dev;
+	ret = mipi_dsi_host_register(&dsi->dsi_host);
+	if (ret)
+		goto err_free_drm;
+
+	return ret;
+
+err_free_drm:
+	dev_err(dev, "%s fail %d\n", __func__, ret);
+	drm_dev_put(drm);
+	return ret;
+}
+
+static void rp1dsi_platform_remove(struct platform_device *pdev)
+{
+	struct drm_device *drm = platform_get_drvdata(pdev);
+	struct rp1_dsi *dsi = drm->dev_private;
+
+	mipi_dsi_host_unregister(&dsi->dsi_host);
+}
+
+static void rp1dsi_platform_shutdown(struct platform_device *pdev)
+{
+	struct drm_device *drm = platform_get_drvdata(pdev);
+
+	rp1dsi_stopall(drm);
+}
+
+static const struct of_device_id rp1dsi_of_match[] = {
+	{
+		.compatible = "raspberrypi,rp1dsi",
+	},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, rp1dsi_of_match);
+
+static struct platform_driver rp1dsi_platform_driver = {
+	.probe		= rp1dsi_platform_probe,
+	.remove		= rp1dsi_platform_remove,
+	.shutdown       = rp1dsi_platform_shutdown,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = rp1dsi_of_match,
+	},
+};
+
+module_platform_driver(rp1dsi_platform_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MIPI DSI driver for Raspberry Pi RP1");
+MODULE_AUTHOR("Nick Hollinghurst");
--- /dev/null
+++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * DRM Driver for DSI output on Raspberry Pi RP1
+ *
+ * Copyright (c) 2023 Raspberry Pi Limited.
+ */
+#ifndef _RP1_DSI_H_
+#define _RP1_DSI_H_
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_device.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#define MODULE_NAME "drm-rp1-dsi"
+#define DRIVER_NAME "drm-rp1-dsi"
+
+/* ---------------------------------------------------------------------- */
+
+#define RP1DSI_HW_BLOCK_DMA   0
+#define RP1DSI_HW_BLOCK_DSI   1
+#define RP1DSI_HW_BLOCK_CFG   2
+#define RP1DSI_NUM_HW_BLOCKS  3
+
+#define RP1DSI_CLOCK_CFG     0
+#define RP1DSI_CLOCK_DPI     1
+#define RP1DSI_CLOCK_BYTE    2
+#define RP1DSI_CLOCK_REF     3
+#define RP1DSI_CLOCK_PLLSYS  4
+#define RP1DSI_NUM_CLOCKS    5
+
+/* ---------------------------------------------------------------------- */
+
+struct rp1_dsi {
+	/* DRM and platform device pointers */
+	struct drm_device *drm;
+	struct platform_device *pdev;
+
+	/* Framework and helper objects */
+	struct drm_simple_display_pipe pipe;
+	struct drm_bridge bridge;
+	struct drm_bridge *out_bridge;
+	struct mipi_dsi_host dsi_host;
+
+	/* Clocks. We need DPI clock; the others are frequency references */
+	struct clk *clocks[RP1DSI_NUM_CLOCKS];
+
+	/* Block (DSI DMA, DSI Host) base addresses, and current state */
+	void __iomem *hw_base[RP1DSI_NUM_HW_BLOCKS];
+	u32 cur_fmt;
+	bool dsi_running, dma_running, pipe_enabled;
+	struct completion finished;
+
+	/* Attached display parameters (from mipi_dsi_device) */
+	unsigned long display_flags, display_hs_rate, display_lp_rate;
+	enum mipi_dsi_pixel_format display_format;
+	u8 vc;
+	u8 lanes;
+
+	/* DPHY */
+	u8 hsfreq_index;
+};
+
+/* ---------------------------------------------------------------------- */
+/* Functions to control the DSI/DPI/DMA block				  */
+
+void rp1dsi_dma_setup(struct rp1_dsi *dsi,
+		      u32 in_format, enum mipi_dsi_pixel_format out_format,
+		      struct drm_display_mode const *mode);
+void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride);
+void rp1dsi_dma_stop(struct rp1_dsi *dsi);
+int rp1dsi_dma_busy(struct rp1_dsi *dsi);
+irqreturn_t rp1dsi_dma_isr(int irq, void *dev);
+void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable);
+
+/* ---------------------------------------------------------------------- */
+/* Functions to control the MIPICFG block and check RP1 platform		  */
+
+void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi);
+
+/* ---------------------------------------------------------------------- */
+/* Functions to control the SNPS D-PHY and DSI block setup		  */
+
+void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode);
+void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf,
+		bool use_lpm, bool req_ack);
+int  rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf);
+void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int cmd_mode);
+void rp1dsi_dsi_stop(struct rp1_dsi *dsi);
+
+#endif
+
--- /dev/null
+++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * DRM Driver for DSI output on Raspberry Pi RP1
+ *
+ * Copyright (c) 2023 Raspberry Pi Limited.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_print.h>
+#include <drm/drm_vblank.h>
+
+#include "rp1_dsi.h"
+
+// --- DPI DMA REGISTERS (derived from Argon firmware, via RP1 drivers/mipi, with corrections) ---
+
+// Control
+#define DPI_DMA_CONTROL				      0x0
+#define DPI_DMA_CONTROL_ARM_SHIFT		      0
+#define DPI_DMA_CONTROL_ARM_MASK		      BIT(DPI_DMA_CONTROL_ARM_SHIFT)
+#define DPI_DMA_CONTROL_ALIGN16_SHIFT		      2
+#define DPI_DMA_CONTROL_ALIGN16_MASK		      BIT(DPI_DMA_CONTROL_ALIGN16_SHIFT)
+#define DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT	      1
+#define DPI_DMA_CONTROL_AUTO_REPEAT_MASK	      BIT(DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT)
+#define DPI_DMA_CONTROL_HIGH_WATER_SHIFT	      3
+#define DPI_DMA_CONTROL_HIGH_WATER_MASK		      (0x1FF << DPI_DMA_CONTROL_HIGH_WATER_SHIFT)
+#define DPI_DMA_CONTROL_DEN_POL_SHIFT		      12
+#define DPI_DMA_CONTROL_DEN_POL_MASK		      BIT(DPI_DMA_CONTROL_DEN_POL_SHIFT)
+#define DPI_DMA_CONTROL_HSYNC_POL_SHIFT		      13
+#define DPI_DMA_CONTROL_HSYNC_POL_MASK		      BIT(DPI_DMA_CONTROL_HSYNC_POL_SHIFT)
+#define DPI_DMA_CONTROL_VSYNC_POL_SHIFT		      14
+#define DPI_DMA_CONTROL_VSYNC_POL_MASK		      BIT(DPI_DMA_CONTROL_VSYNC_POL_SHIFT)
+#define DPI_DMA_CONTROL_COLORM_SHIFT		      15
+#define DPI_DMA_CONTROL_COLORM_MASK		      BIT(DPI_DMA_CONTROL_COLORM_SHIFT)
+#define DPI_DMA_CONTROL_SHUTDN_SHIFT		      16
+#define DPI_DMA_CONTROL_SHUTDN_MASK		      BIT(DPI_DMA_CONTROL_SHUTDN_SHIFT)
+#define DPI_DMA_CONTROL_HBP_EN_SHIFT		      17
+#define DPI_DMA_CONTROL_HBP_EN_MASK		      BIT(DPI_DMA_CONTROL_HBP_EN_SHIFT)
+#define DPI_DMA_CONTROL_HFP_EN_SHIFT		      18
+#define DPI_DMA_CONTROL_HFP_EN_MASK		      BIT(DPI_DMA_CONTROL_HFP_EN_SHIFT)
+#define DPI_DMA_CONTROL_VBP_EN_SHIFT		      19
+#define DPI_DMA_CONTROL_VBP_EN_MASK		      BIT(DPI_DMA_CONTROL_VBP_EN_SHIFT)
+#define DPI_DMA_CONTROL_VFP_EN_SHIFT		      20
+#define DPI_DMA_CONTROL_VFP_EN_MASK		      BIT(DPI_DMA_CONTROL_VFP_EN_SHIFT)
+#define DPI_DMA_CONTROL_HSYNC_EN_SHIFT		      21
+#define DPI_DMA_CONTROL_HSYNC_EN_MASK		      BIT(DPI_DMA_CONTROL_HSYNC_EN_SHIFT)
+#define DPI_DMA_CONTROL_VSYNC_EN_SHIFT		      22
+#define DPI_DMA_CONTROL_VSYNC_EN_MASK		      BIT(DPI_DMA_CONTROL_VSYNC_EN_SHIFT)
+#define DPI_DMA_CONTROL_FORCE_IMMED_SHIFT	      23
+#define DPI_DMA_CONTROL_FORCE_IMMED_MASK	      BIT(DPI_DMA_CONTROL_FORCE_IMMED_SHIFT)
+#define DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT	      24
+#define DPI_DMA_CONTROL_FORCE_DRAIN_MASK	      BIT(DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT)
+#define DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT	      25
+#define DPI_DMA_CONTROL_FORCE_EMPTY_MASK	      BIT(DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT)
+
+// IRQ_ENABLES
+#define DPI_DMA_IRQ_EN				      0x04
+#define DPI_DMA_IRQ_EN_DMA_READY_SHIFT		      0
+#define DPI_DMA_IRQ_EN_DMA_READY_MASK		      BIT(DPI_DMA_IRQ_EN_DMA_READY_SHIFT)
+#define DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT		      1
+#define DPI_DMA_IRQ_EN_UNDERFLOW_MASK		      BIT(DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT)
+#define DPI_DMA_IRQ_EN_FRAME_START_SHIFT	      2
+#define DPI_DMA_IRQ_EN_FRAME_START_MASK		      BIT(DPI_DMA_IRQ_EN_FRAME_START_SHIFT)
+#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT	      3
+#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_MASK		      BIT(DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT)
+#define DPI_DMA_IRQ_EN_TE_SHIFT			      4
+#define DPI_DMA_IRQ_EN_TE_MASK			      BIT(DPI_DMA_IRQ_EN_TE_SHIFT)
+#define DPI_DMA_IRQ_EN_ERROR_SHIFT		      5
+#define DPI_DMA_IRQ_EN_ERROR_MASK		      BIT(DPI_DMA_IRQ_EN_ERROR_SHIFT)
+#define DPI_DMA_IRQ_EN_MATCH_SHIFT		      6
+#define DPI_DMA_IRQ_EN_MATCH_MASK		      BIT(DPI_DMA_IRQ_EN_MATCH_SHIFT)
+#define DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT		      16
+#define DPI_DMA_IRQ_EN_MATCH_LINE_MASK		      (0xFFF << DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT)
+
+// IRQ_FLAGS
+#define DPI_DMA_IRQ_FLAGS			      0x08
+#define DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT	      0
+#define DPI_DMA_IRQ_FLAGS_DMA_READY_MASK	      BIT(DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT)
+#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT	      1
+#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK	      BIT(DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT)
+#define DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT	      2
+#define DPI_DMA_IRQ_FLAGS_FRAME_START_MASK	      BIT(DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT)
+#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT	      3
+#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK	      BIT(DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT)
+#define DPI_DMA_IRQ_FLAGS_TE_SHIFT		      4
+#define DPI_DMA_IRQ_FLAGS_TE_MASK		      BIT(DPI_DMA_IRQ_FLAGS_TE_SHIFT)
+#define DPI_DMA_IRQ_FLAGS_ERROR_SHIFT		      5
+#define DPI_DMA_IRQ_FLAGS_ERROR_MASK		      BIT(DPI_DMA_IRQ_FLAGS_ERROR_SHIFT)
+#define DPI_DMA_IRQ_FLAGS_MATCH_SHIFT		      6
+#define DPI_DMA_IRQ_FLAGS_MATCH_MASK		      BIT(DPI_DMA_IRQ_FLAGS_MATCH_SHIFT)
+
+// QOS
+#define DPI_DMA_QOS				      0xC
+#define DPI_DMA_QOS_DQOS_SHIFT			      0
+#define DPI_DMA_QOS_DQOS_MASK			      (0xF << DPI_DMA_QOS_DQOS_SHIFT)
+#define DPI_DMA_QOS_ULEV_SHIFT			      4
+#define DPI_DMA_QOS_ULEV_MASK			      (0xF << DPI_DMA_QOS_ULEV_SHIFT)
+#define DPI_DMA_QOS_UQOS_SHIFT			      8
+#define DPI_DMA_QOS_UQOS_MASK			      (0xF << DPI_DMA_QOS_UQOS_SHIFT)
+#define DPI_DMA_QOS_LLEV_SHIFT			      12
+#define DPI_DMA_QOS_LLEV_MASK			      (0xF << DPI_DMA_QOS_LLEV_SHIFT)
+#define DPI_DMA_QOS_LQOS_SHIFT			      16
+#define DPI_DMA_QOS_LQOS_MASK			      (0xF << DPI_DMA_QOS_LQOS_SHIFT)
+
+// Panics
+#define DPI_DMA_PANICS				     0x38
+#define DPI_DMA_PANICS_UPPER_COUNT_SHIFT	     0
+#define DPI_DMA_PANICS_UPPER_COUNT_MASK		     \
+				(0x0000FFFF << DPI_DMA_PANICS_UPPER_COUNT_SHIFT)
+#define DPI_DMA_PANICS_LOWER_COUNT_SHIFT	     16
+#define DPI_DMA_PANICS_LOWER_COUNT_MASK		     \
+				(0x0000FFFF << DPI_DMA_PANICS_LOWER_COUNT_SHIFT)
+
+// DMA Address Lower:
+#define DPI_DMA_DMA_ADDR_L			     0x10
+
+// DMA Address Upper:
+#define DPI_DMA_DMA_ADDR_H			     0x40
+
+// DMA stride
+#define DPI_DMA_DMA_STRIDE			     0x14
+
+// Visible Area
+#define DPI_DMA_VISIBLE_AREA			     0x18
+#define DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT     0
+#define DPI_DMA_VISIBLE_AREA_ROWSM1_MASK     (0x0FFF << DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT)
+#define DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT    16
+#define DPI_DMA_VISIBLE_AREA_COLSM1_MASK     (0x0FFF << DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT)
+
+// Sync width
+#define DPI_DMA_SYNC_WIDTH   0x1C
+#define DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT	 0
+#define DPI_DMA_SYNC_WIDTH_ROWSM1_MASK	 (0x0FFF << DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT)
+#define DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT	 16
+#define DPI_DMA_SYNC_WIDTH_COLSM1_MASK	 (0x0FFF << DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT)
+
+// Back porch
+#define DPI_DMA_BACK_PORCH   0x20
+#define DPI_DMA_BACK_PORCH_ROWSM1_SHIFT	 0
+#define DPI_DMA_BACK_PORCH_ROWSM1_MASK	 (0x0FFF << DPI_DMA_BACK_PORCH_ROWSM1_SHIFT)
+#define DPI_DMA_BACK_PORCH_COLSM1_SHIFT	 16
+#define DPI_DMA_BACK_PORCH_COLSM1_MASK	 (0x0FFF << DPI_DMA_BACK_PORCH_COLSM1_SHIFT)
+
+// Front porch
+#define DPI_DMA_FRONT_PORCH  0x24
+#define DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT     0
+#define DPI_DMA_FRONT_PORCH_ROWSM1_MASK	 (0x0FFF << DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT)
+#define DPI_DMA_FRONT_PORCH_COLSM1_SHIFT     16
+#define DPI_DMA_FRONT_PORCH_COLSM1_MASK	 (0x0FFF << DPI_DMA_FRONT_PORCH_COLSM1_SHIFT)
+
+// Input masks
+#define DPI_DMA_IMASK	 0x2C
+#define DPI_DMA_IMASK_R_SHIFT	 0
+#define DPI_DMA_IMASK_R_MASK	 (0x3FF << DPI_DMA_IMASK_R_SHIFT)
+#define DPI_DMA_IMASK_G_SHIFT	 10
+#define DPI_DMA_IMASK_G_MASK	 (0x3FF << DPI_DMA_IMASK_G_SHIFT)
+#define DPI_DMA_IMASK_B_SHIFT	 20
+#define DPI_DMA_IMASK_B_MASK	 (0x3FF << DPI_DMA_IMASK_B_SHIFT)
+
+// Output Masks
+#define DPI_DMA_OMASK	 0x30
+#define DPI_DMA_OMASK_R_SHIFT	 0
+#define DPI_DMA_OMASK_R_MASK	 (0x3FF << DPI_DMA_OMASK_R_SHIFT)
+#define DPI_DMA_OMASK_G_SHIFT	 10
+#define DPI_DMA_OMASK_G_MASK	 (0x3FF << DPI_DMA_OMASK_G_SHIFT)
+#define DPI_DMA_OMASK_B_SHIFT	 20
+#define DPI_DMA_OMASK_B_MASK	 (0x3FF << DPI_DMA_OMASK_B_SHIFT)
+
+// Shifts
+#define DPI_DMA_SHIFT	 0x28
+#define DPI_DMA_SHIFT_IR_SHIFT	 0
+#define DPI_DMA_SHIFT_IR_MASK	 (0x1F << DPI_DMA_SHIFT_IR_SHIFT)
+#define DPI_DMA_SHIFT_IG_SHIFT	 5
+#define DPI_DMA_SHIFT_IG_MASK	 (0x1F << DPI_DMA_SHIFT_IG_SHIFT)
+#define DPI_DMA_SHIFT_IB_SHIFT	 10
+#define DPI_DMA_SHIFT_IB_MASK	 (0x1F << DPI_DMA_SHIFT_IB_SHIFT)
+#define DPI_DMA_SHIFT_OR_SHIFT	 15
+#define DPI_DMA_SHIFT_OR_MASK	 (0x1F << DPI_DMA_SHIFT_OR_SHIFT)
+#define DPI_DMA_SHIFT_OG_SHIFT	 20
+#define DPI_DMA_SHIFT_OG_MASK	 (0x1F << DPI_DMA_SHIFT_OG_SHIFT)
+#define DPI_DMA_SHIFT_OB_SHIFT	 25
+#define DPI_DMA_SHIFT_OB_MASK	 (0x1F << DPI_DMA_SHIFT_OB_SHIFT)
+
+// Scaling
+#define DPI_DMA_RGBSZ	 0x34
+#define DPI_DMA_RGBSZ_BPP_SHIFT	 16
+#define DPI_DMA_RGBSZ_BPP_MASK	 (0x3 << DPI_DMA_RGBSZ_BPP_SHIFT)
+#define DPI_DMA_RGBSZ_R_SHIFT	 0
+#define DPI_DMA_RGBSZ_R_MASK	 (0xF << DPI_DMA_RGBSZ_R_SHIFT)
+#define DPI_DMA_RGBSZ_G_SHIFT	 4
+#define DPI_DMA_RGBSZ_G_MASK	 (0xF << DPI_DMA_RGBSZ_G_SHIFT)
+#define DPI_DMA_RGBSZ_B_SHIFT	 8
+#define DPI_DMA_RGBSZ_B_MASK	 (0xF << DPI_DMA_RGBSZ_B_SHIFT)
+
+// Status
+#define DPI_DMA_STATUS  0x3c
+
+#define BITS(field, val) (((val) << (field ## _SHIFT)) & (field ## _MASK))
+
+static unsigned int rp1dsi_dma_read(struct rp1_dsi *dsi, unsigned int reg)
+{
+	void __iomem *addr = dsi->hw_base[RP1DSI_HW_BLOCK_DMA] + reg;
+
+	return readl(addr);
+}
+
+static void rp1dsi_dma_write(struct rp1_dsi *dsi, unsigned int reg, unsigned int val)
+{
+	void __iomem *addr = dsi->hw_base[RP1DSI_HW_BLOCK_DMA] + reg;
+
+	writel(val, addr);
+}
+
+int rp1dsi_dma_busy(struct rp1_dsi *dsi)
+{
+	return (rp1dsi_dma_read(dsi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0;
+}
+
+/* Table of supported input (in-memory/DMA) pixel formats. */
+struct rp1dsi_ipixfmt {
+	u32 format; /* DRM format code                           */
+	u32 mask;   /* RGB masks (10 bits each, left justified)  */
+	u32 shift;  /* RGB MSB positions in the memory word      */
+	u32 rgbsz;  /* Shifts used for scaling; also (BPP/8-1)   */
+};
+
+#define IMASK_RGB(r, g, b)	(BITS(DPI_DMA_IMASK_R, r) | \
+				 BITS(DPI_DMA_IMASK_G, g) |  \
+				 BITS(DPI_DMA_IMASK_B, b))
+#define ISHIFT_RGB(r, g, b)	(BITS(DPI_DMA_SHIFT_IR, r) | \
+				 BITS(DPI_DMA_SHIFT_IG, g) | \
+				 BITS(DPI_DMA_SHIFT_IB, b))
+
+static const struct rp1dsi_ipixfmt my_formats[] = {
+	{
+		.format = DRM_FORMAT_XRGB8888,
+		.mask   = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
+		.shift  = ISHIFT_RGB(23, 15, 7),
+		.rgbsz  = BITS(DPI_DMA_RGBSZ_BPP, 3),
+	},
+	{
+		.format = DRM_FORMAT_XBGR8888,
+		.mask   = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
+		.shift  = ISHIFT_RGB(7, 15, 23),
+		.rgbsz  = BITS(DPI_DMA_RGBSZ_BPP, 3),
+	},
+	{
+		.format = DRM_FORMAT_ARGB8888,
+		.mask   = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
+		.shift  = ISHIFT_RGB(23, 15, 7),
+		.rgbsz  = BITS(DPI_DMA_RGBSZ_BPP, 3),
+	},
+	{
+		.format = DRM_FORMAT_ABGR8888,
+		.mask   = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
+		.shift  = ISHIFT_RGB(7, 15, 23),
+		.rgbsz  = BITS(DPI_DMA_RGBSZ_BPP, 3),
+	},
+	{
+		.format = DRM_FORMAT_RGB888,
+		.mask   = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
+		.shift  = ISHIFT_RGB(23, 15, 7),
+		.rgbsz  = BITS(DPI_DMA_RGBSZ_BPP, 2),
+	},
+	{
+		.format = DRM_FORMAT_BGR888,
+		.mask   = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
+		.shift  = ISHIFT_RGB(7, 15, 23),
+		.rgbsz  = BITS(DPI_DMA_RGBSZ_BPP, 2),
+	},
+	{
+		.format = DRM_FORMAT_RGB565,
+		.mask   = IMASK_RGB(0x3e0, 0x3f0, 0x3e0),
+		.shift  = ISHIFT_RGB(15, 10, 4),
+		.rgbsz  = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) |
+			  BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1),
+	}
+};
+
+/* Choose the internal on-the-bus DPI format as expected by DSI Host. */
+static u32 get_omask_oshift(enum mipi_dsi_pixel_format fmt, u32 *oshift)
+{
+	switch (fmt) {
+	case MIPI_DSI_FMT_RGB565:
+		*oshift = BITS(DPI_DMA_SHIFT_OR, 15) |
+			  BITS(DPI_DMA_SHIFT_OG, 10) |
+			  BITS(DPI_DMA_SHIFT_OB, 4);
+		return BITS(DPI_DMA_OMASK_R, 0x3e0) |
+		       BITS(DPI_DMA_OMASK_G, 0x3f0) |
+		       BITS(DPI_DMA_OMASK_B, 0x3e0);
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		*oshift = BITS(DPI_DMA_SHIFT_OR, 17) |
+			  BITS(DPI_DMA_SHIFT_OG, 11) |
+			  BITS(DPI_DMA_SHIFT_OB, 5);
+		return BITS(DPI_DMA_OMASK_R, 0x3f0) |
+		       BITS(DPI_DMA_OMASK_G, 0x3f0) |
+		       BITS(DPI_DMA_OMASK_B, 0x3f0);
+	case MIPI_DSI_FMT_RGB666:
+		*oshift = BITS(DPI_DMA_SHIFT_OR, 21) |
+			  BITS(DPI_DMA_SHIFT_OG, 13) |
+			  BITS(DPI_DMA_SHIFT_OB, 5);
+		return BITS(DPI_DMA_OMASK_R, 0x3f0) |
+		       BITS(DPI_DMA_OMASK_G, 0x3f0) |
+		       BITS(DPI_DMA_OMASK_B, 0x3f0);
+	default:
+		*oshift = BITS(DPI_DMA_SHIFT_OR, 23) |
+			  BITS(DPI_DMA_SHIFT_OG, 15) |
+			  BITS(DPI_DMA_SHIFT_OB, 7);
+		return BITS(DPI_DMA_OMASK_R, 0x3fc) |
+		       BITS(DPI_DMA_OMASK_G, 0x3fc) |
+		       BITS(DPI_DMA_OMASK_B, 0x3fc);
+	}
+}
+
+void rp1dsi_dma_setup(struct rp1_dsi *dsi,
+		      u32 in_format, enum mipi_dsi_pixel_format out_format,
+		     struct drm_display_mode const *mode)
+{
+	u32 oshift;
+	int i;
+
+	/*
+	 * Configure all DSI/DPI/DMA block registers, except base address.
+	 * DMA will not actually start until a FB base address is specified
+	 * using rp1dsi_dma_update().
+	 */
+
+	rp1dsi_dma_write(dsi, DPI_DMA_VISIBLE_AREA,
+			 BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) |
+			 BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1));
+
+	rp1dsi_dma_write(dsi, DPI_DMA_SYNC_WIDTH,
+			 BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) |
+			 BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1));
+
+	/* In the DPIDMA registers, "back porch" time includes sync width */
+	rp1dsi_dma_write(dsi, DPI_DMA_BACK_PORCH,
+			 BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) |
+			 BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1));
+
+	rp1dsi_dma_write(dsi, DPI_DMA_FRONT_PORCH,
+			 BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) |
+			 BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1));
+
+	/* Input to output pixel format conversion */
+	for (i = 0; i < ARRAY_SIZE(my_formats); ++i) {
+		if (my_formats[i].format == in_format)
+			break;
+	}
+	if (i >= ARRAY_SIZE(my_formats)) {
+		drm_err(dsi->drm, "%s: bad input format\n", __func__);
+		i = 0;
+	}
+	rp1dsi_dma_write(dsi, DPI_DMA_IMASK, my_formats[i].mask);
+	rp1dsi_dma_write(dsi, DPI_DMA_OMASK, get_omask_oshift(out_format, &oshift));
+	rp1dsi_dma_write(dsi, DPI_DMA_SHIFT, my_formats[i].shift | oshift);
+	if (out_format == MIPI_DSI_FMT_RGB888)
+		rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formats[i].rgbsz);
+	else
+		rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formats[i].rgbsz & DPI_DMA_RGBSZ_BPP_MASK);
+
+	rp1dsi_dma_write(dsi, DPI_DMA_QOS,
+			 BITS(DPI_DMA_QOS_DQOS, 0x0) |
+			 BITS(DPI_DMA_QOS_ULEV, 0xb) |
+			 BITS(DPI_DMA_QOS_UQOS, 0x2) |
+			 BITS(DPI_DMA_QOS_LLEV, 0x8) |
+			 BITS(DPI_DMA_QOS_LQOS, 0x7));
+
+	rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, -1);
+	rp1dsi_dma_vblank_ctrl(dsi, 1);
+
+	i = rp1dsi_dma_busy(dsi);
+	if (i)
+		drm_err(dsi->drm, "RP1DSI: Unexpectedly busy at start!");
+
+	rp1dsi_dma_write(dsi, DPI_DMA_CONTROL,
+			 BITS(DPI_DMA_CONTROL_ARM, (i == 0)) |
+			 BITS(DPI_DMA_CONTROL_AUTO_REPEAT, 1) |
+			 BITS(DPI_DMA_CONTROL_HIGH_WATER, 448) |
+			 BITS(DPI_DMA_CONTROL_DEN_POL, 0) |
+			 BITS(DPI_DMA_CONTROL_HSYNC_POL, 0) |
+			 BITS(DPI_DMA_CONTROL_VSYNC_POL, 0) |
+			 BITS(DPI_DMA_CONTROL_COLORM, 0) |
+			 BITS(DPI_DMA_CONTROL_SHUTDN, 0) |
+			 BITS(DPI_DMA_CONTROL_HBP_EN, 1) |
+			 BITS(DPI_DMA_CONTROL_HFP_EN, 1) |
+			 BITS(DPI_DMA_CONTROL_VBP_EN, 1) |
+			 BITS(DPI_DMA_CONTROL_VFP_EN, 1) |
+			 BITS(DPI_DMA_CONTROL_HSYNC_EN, 1) |
+			 BITS(DPI_DMA_CONTROL_VSYNC_EN, 1));
+}
+
+void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride)
+{
+	/*
+	 * Update STRIDE, DMAH and DMAL only. When called after rp1dsi_dma_setup(),
+	 * DMA starts immediately; if already running, the buffer will flip at
+	 * the next vertical sync event.
+	 */
+	u64 a = addr + offset;
+
+	rp1dsi_dma_write(dsi, DPI_DMA_DMA_STRIDE, stride);
+	rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_H, a >> 32);
+	rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu);
+}
+
+void rp1dsi_dma_stop(struct rp1_dsi *dsi)
+{
+	/*
+	 * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for
+	 * the current and any queued frame to end. "Force drain" flags are not used,
+	 * as they seem to prevent DMA from re-starting properly; it's safer to wait.
+	 */
+	u32 ctrl;
+
+	reinit_completion(&dsi->finished);
+	ctrl = rp1dsi_dma_read(dsi, DPI_DMA_CONTROL);
+	ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK);
+	rp1dsi_dma_write(dsi, DPI_DMA_CONTROL, ctrl);
+	if (!wait_for_completion_timeout(&dsi->finished, HZ / 10))
+		drm_err(dsi->drm, "%s: timed out waiting for idle\n", __func__);
+	rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN, 0);
+}
+
+void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable)
+{
+	rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN,
+			 BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1)      |
+			 BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1)        |
+			 BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) |
+			 BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 4095));
+}
+
+irqreturn_t rp1dsi_dma_isr(int irq, void *dev)
+{
+	struct rp1_dsi *dsi = dev;
+	u32 u = rp1dsi_dma_read(dsi, DPI_DMA_IRQ_FLAGS);
+
+	if (u) {
+		rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, u);
+		if (dsi) {
+			if (u & DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK)
+				drm_err_ratelimited(dsi->drm,
+						    "Underflow! (panics=0x%08x)\n",
+						    rp1dsi_dma_read(dsi, DPI_DMA_PANICS));
+			if (u & DPI_DMA_IRQ_FLAGS_DMA_READY_MASK)
+				drm_crtc_handle_vblank(&dsi->pipe.crtc);
+			if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK)
+				complete(&dsi->finished);
+		}
+	}
+	return u ? IRQ_HANDLED : IRQ_NONE;
+}
--- /dev/null
+++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c
@@ -0,0 +1,1598 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * DRM Driver for DSI output on Raspberry Pi RP1
+ *
+ * Copyright (c) 2023 Raspberry Pi Limited.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/math64.h>
+#include <linux/platform_device.h>
+#include <linux/rp1_platform.h>
+#include "drm/drm_print.h"
+
+#include "rp1_dsi.h"
+
+/* ------------------------------- Synopsis DSI ------------------------ */
+#define     DSI_VERSION_CFG                       0x000
+#define     DSI_PWR_UP                            0x004
+#define     DSI_CLKMGR_CFG                        0x008
+#define     DSI_DPI_VCID                          0x00C
+#define     DSI_DPI_COLOR_CODING                  0x010
+#define     DSI_DPI_CFG_POL                       0x014
+#define     DSI_DPI_LP_CMD_TIM                    0x018
+#define     DSI_DBI_VCID                          0x01C
+#define     DSI_DBI_CFG                           0x020
+#define     DSI_DBI_PARTITIONING_EN               0x024
+#define     DSI_DBI_CMDSIZE                       0x028
+#define     DSI_PCKHDL_CFG                        0x02C
+#define     DSI_GEN_VCID                          0x030
+#define     DSI_MODE_CFG                          0x034
+#define     DSI_VID_MODE_CFG                      0x038
+#define     DSI_VID_PKT_SIZE                      0x03C
+#define     DSI_VID_NUM_CHUNKS                    0x040
+#define     DSI_VID_NULL_SIZE                     0x044
+#define     DSI_VID_HSA_TIME                      0x048
+#define     DSI_VID_HBP_TIME                      0x04C
+#define     DSI_VID_HLINE_TIME                    0x050
+#define     DSI_VID_VSA_LINES                     0x054
+#define     DSI_VID_VBP_LINES                     0x058
+#define     DSI_VID_VFP_LINES                     0x05C
+#define     DSI_VID_VACTIVE_LINES                 0x060
+#define     DSI_EDPI_CMD_SIZE                     0x064
+#define     DSI_CMD_MODE_CFG                      0x068
+#define     DSI_GEN_HDR                           0x06C
+#define     DSI_GEN_PLD_DATA                      0x070
+#define     DSI_CMD_PKT_STATUS                    0x074
+#define     DSI_TO_CNT_CFG                        0x078
+#define     DSI_HS_RD_TO_CNT                      0x07C
+#define     DSI_LP_RD_TO_CNT                      0x080
+#define     DSI_HS_WR_TO_CNT                      0x084
+#define     DSI_LP_WR_TO_CNT                      0x088
+#define     DSI_BTA_TO_CNT                        0x08C
+#define     DSI_SDF_3D                            0x090
+#define     DSI_LPCLK_CTRL                        0x094
+#define     DSI_PHY_TMR_LPCLK_CFG                 0x098
+#define     DSI_PHY_TMR_HS2LP_LSB       16
+#define     DSI_PHY_TMR_LP2HS_LSB       0
+#define     DSI_PHY_TMR_CFG                       0x09C
+#define     DSI_PHY_TMR_RD_CFG                    0x0F4
+#define     DSI_PHYRSTZ                           0x0A0
+#define     DSI_PHY_IF_CFG                        0x0A4
+#define     DSI_PHY_ULPS_CTRL                     0x0A8
+#define     DSI_PHY_TX_TRIGGERS                   0x0AC
+#define     DSI_PHY_STATUS                        0x0B0
+
+#define     DSI_PHY_TST_CTRL0                     0x0B4
+#define     DSI_PHY_TST_CTRL1                     0x0B8
+#define     DSI_INT_ST0                           0x0BC
+#define     DSI_INT_ST1                           0x0C0
+#define     DSI_INT_MASK0_CFG                     0x0C4
+#define     DSI_INT_MASK1_CFG                     0x0C8
+#define     DSI_PHY_CAL                           0x0CC
+#define     DSI_HEXP_NPKT_CLR                     0x104
+#define     DSI_HEXP_NPKT_SIZE                    0x108
+#define     DSI_VID_SHADOW_CTRL                   0x100
+
+#define     DSI_DPI_VCID_ACT                      0x10C
+#define     DSI_DPI_COLOR_CODING_ACT              0x110
+#define     DSI_DPI_LP_CMD_TIM_ACT                0x118
+#define     DSI_VID_MODE_CFG_ACT                  0x138
+#define     DSI_VID_PKT_SIZE_ACT                  0x13C
+#define     DSI_VID_NUM_CHUNKS_ACT                0x140
+#define     DSI_VID_NULL_SIZE_ACT                 0x144
+#define     DSI_VID_HSA_TIME_ACT                  0x148
+#define     DSI_VID_HBP_TIME_ACT                  0x14C
+#define     DSI_VID_HLINE_TIME_ACT                0x150
+#define     DSI_VID_VSA_LINES_ACT                 0x154
+#define     DSI_VID_VBP_LINES_ACT                 0x158
+#define     DSI_VID_VFP_LINES_ACT                 0x15C
+#define     DSI_VID_VACTIVE_LINES_ACT             0x160
+#define     DSI_SDF_3D_CFG_ACT                    0x190
+
+#define     DSI_INT_FORCE0                        0x0D8
+#define     DSI_INT_FORCE1                        0x0DC
+
+#define     DSI_AUTO_ULPS_MODE                    0x0E0
+#define     DSI_AUTO_ULPS_ENTRY_DELAY             0x0E4
+#define     DSI_AUTO_ULPS_WAKEUP_TIME             0x0E8
+#define     DSI_EDPI_ADV_FEATURES                 0x0EC
+
+#define     DSI_DSC_PARAMETER                     0x0F0
+
+/* And some bitfield definitions */
+
+#define DSI_PCKHDL_EOTP_TX_EN  BIT(0)
+#define DSI_PCKHDL_BTA_EN      BIT(2)
+
+#define DSI_VID_MODE_LP_CMD_EN        BIT(15)
+#define DSI_VID_MODE_FRAME_BTA_ACK_EN BIT(14)
+#define DSI_VID_MODE_LP_HFP_EN        BIT(13)
+#define DSI_VID_MODE_LP_HBP_EN        BIT(12)
+#define DSI_VID_MODE_LP_VACT_EN       BIT(11)
+#define DSI_VID_MODE_LP_VFP_EN        BIT(10)
+#define DSI_VID_MODE_LP_VBP_EN        BIT(9)
+#define DSI_VID_MODE_LP_VSA_EN        BIT(8)
+#define DSI_VID_MODE_SYNC_PULSES      0
+#define DSI_VID_MODE_SYNC_EVENTS      1
+#define DSI_VID_MODE_BURST            2
+
+#define DSI_CMD_MODE_ALL_LP           0x10f7f00
+#define DSI_CMD_MODE_ACK_RQST_EN      BIT(1)
+
+#define DPHY_PWR_UP_SHUTDOWNZ_LSB 0
+#define DPHY_PWR_UP_SHUTDOWNZ_BITS BIT(DPHY_PWR_UP_SHUTDOWNZ_LSB)
+
+#define DPHY_CTRL0_PHY_TESTCLK_LSB 1
+#define DPHY_CTRL0_PHY_TESTCLK_BITS BIT(DPHY_CTRL0_PHY_TESTCLK_LSB)
+#define DPHY_CTRL0_PHY_TESTCLR_LSB 0
+#define DPHY_CTRL0_PHY_TESTCLR_BITS BIT(DPHY_CTRL0_PHY_TESTCLR_LSB)
+
+#define DPHY_CTRL1_PHY_TESTDIN_LSB  0
+#define DPHY_CTRL1_PHY_TESTDIN_BITS  (0xff << DPHY_CTRL1_PHY_TESTDIN_LSB)
+#define DPHY_CTRL1_PHY_TESTDOUT_LSB 8
+#define DPHY_CTRL1_PHY_TESTDOUT_BITS (0xff << DPHY_CTRL1_PHY_TESTDOUT_LSB)
+#define DPHY_CTRL1_PHY_TESTEN_LSB 16
+#define DPHY_CTRL1_PHY_TESTEN_BITS BIT(DPHY_CTRL1_PHY_TESTEN_LSB)
+
+#define DSI_PHYRSTZ_SHUTDOWNZ_LSB  0
+#define DSI_PHYRSTZ_SHUTDOWNZ_BITS BIT(DSI_PHYRSTZ_SHUTDOWNZ_LSB)
+#define DSI_PHYRSTZ_RSTZ_LSB  1
+#define DSI_PHYRSTZ_RSTZ_BITS BIT(DSI_PHYRSTZ_RSTZ_LSB)
+#define DSI_PHYRSTZ_ENABLECLK_LSB 2
+#define DSI_PHYRSTZ_ENABLECLK_BITS BIT(DSI_PHYRSTZ_ENABLECLK_LSB)
+#define DSI_PHYRSTZ_FORCEPLL_LSB 3
+#define DSI_PHYRSTZ_FORCEPLL_BITS  BIT(DSI_PHYRSTZ_FORCEPLL_LSB)
+
+#define DPHY_HS_RX_CTRL_LANE0_OFFSET  0x44
+#define DPHY_PLL_INPUT_DIV_OFFSET 0x17
+#define DPHY_PLL_LOOP_DIV_OFFSET 0x18
+#define DPHY_PLL_DIV_CTRL_OFFSET 0x19
+
+#define DPHY_PLL_BIAS_OFFSET 0x10
+#define DPHY_PLL_BIAS_VCO_RANGE_LSB 3
+#define DPHY_PLL_BIAS_USE_PROGRAMMED_VCO_RANGE BIT(7)
+
+#define DPHY_PLL_CHARGE_PUMP_OFFSET 0x11
+#define DPHY_PLL_LPF_OFFSET 0x12
+
+#define DSI_WRITE(reg, val)  writel((val),  dsi->hw_base[RP1DSI_HW_BLOCK_DSI] + (reg))
+#define DSI_READ(reg)        readl(dsi->hw_base[RP1DSI_HW_BLOCK_DSI] + (reg))
+
+// ================================================================================
+// Register block : RPI_MIPICFG
+// Version        : 1
+// Bus type       : apb
+// Description    : Register block to control mipi DPHY
+// ================================================================================
+#define RPI_MIPICFG_REGS_RWTYPE_MSB 13
+#define RPI_MIPICFG_REGS_RWTYPE_LSB 12
+// ================================================================================
+// Register    : RPI_MIPICFG_CLK2FC
+// JTAG access : synchronous
+// Description : None
+#define RPI_MIPICFG_CLK2FC_OFFSET 0x00000000
+#define RPI_MIPICFG_CLK2FC_BITS   0x00000007
+#define RPI_MIPICFG_CLK2FC_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_CLK2FC_SEL
+// Description : select a clock to be sent to the frequency counter
+//               7 = none
+//               6 = none
+//               5 = none
+//               4 = rxbyteclkhs (187.5MHz)
+//               3 = rxclkesc0 (20MHz)
+//               2 = txbyteclkhs (187.5MHz)
+//               1 = txclkesc (125MHz)
+//               0 = none
+#define RPI_MIPICFG_CLK2FC_SEL_RESET  0x0
+#define RPI_MIPICFG_CLK2FC_SEL_BITS   0x00000007
+#define RPI_MIPICFG_CLK2FC_SEL_MSB    2
+#define RPI_MIPICFG_CLK2FC_SEL_LSB    0
+#define RPI_MIPICFG_CLK2FC_SEL_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_CFG
+// JTAG access : asynchronous
+// Description : Top level configuration
+#define RPI_MIPICFG_CFG_OFFSET 0x00000004
+#define RPI_MIPICFG_CFG_BITS   0x00000111
+#define RPI_MIPICFG_CFG_RESET  0x00000001
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_CFG_DPIUPDATE
+// Description : Indicate the DSI block that the next frame will have a new video configuration
+#define RPI_MIPICFG_CFG_DPIUPDATE_RESET  0x0
+#define RPI_MIPICFG_CFG_DPIUPDATE_BITS   0x00000100
+#define RPI_MIPICFG_CFG_DPIUPDATE_MSB    8
+#define RPI_MIPICFG_CFG_DPIUPDATE_LSB    8
+#define RPI_MIPICFG_CFG_DPIUPDATE_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_CFG_SEL_TE_EXT
+// Description : Select the TE source: 1 - ext, 0 - int
+#define RPI_MIPICFG_CFG_SEL_TE_EXT_RESET  0x0
+#define RPI_MIPICFG_CFG_SEL_TE_EXT_BITS   0x00000010
+#define RPI_MIPICFG_CFG_SEL_TE_EXT_MSB    4
+#define RPI_MIPICFG_CFG_SEL_TE_EXT_LSB    4
+#define RPI_MIPICFG_CFG_SEL_TE_EXT_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_CFG_SEL_CSI_DSI_N
+// Description : Select PHY direction: input to CSI, output from DSI. CSI 1 DSI 0
+#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_RESET  0x1
+#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_BITS   0x00000001
+#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_MSB    0
+#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_LSB    0
+#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_TE
+// JTAG access : synchronous
+// Description : Tearing effect processing
+#define RPI_MIPICFG_TE_OFFSET 0x00000008
+#define RPI_MIPICFG_TE_BITS   0x10ffffff
+#define RPI_MIPICFG_TE_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_TE_ARM
+// Description : Tearing effect arm
+#define RPI_MIPICFG_TE_ARM_RESET  0x0
+#define RPI_MIPICFG_TE_ARM_BITS   0x10000000
+#define RPI_MIPICFG_TE_ARM_MSB    28
+#define RPI_MIPICFG_TE_ARM_LSB    28
+#define RPI_MIPICFG_TE_ARM_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_TE_HALT_CYC
+// Description : When arm pulse has been seen, wait for te; then halt the dpi block
+//		 for this many clk_dpi cycles
+#define RPI_MIPICFG_TE_HALT_CYC_RESET  0x000000
+#define RPI_MIPICFG_TE_HALT_CYC_BITS   0x00ffffff
+#define RPI_MIPICFG_TE_HALT_CYC_MSB    23
+#define RPI_MIPICFG_TE_HALT_CYC_LSB    0
+#define RPI_MIPICFG_TE_HALT_CYC_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_DPHY_MONITOR
+// JTAG access : asynchronous
+// Description : DPHY status monitors for analog DFT
+#define RPI_MIPICFG_DPHY_MONITOR_OFFSET 0x00000010
+#define RPI_MIPICFG_DPHY_MONITOR_BITS   0x00111fff
+#define RPI_MIPICFG_DPHY_MONITOR_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_MONITOR_LOCK
+// Description : None
+#define RPI_MIPICFG_DPHY_MONITOR_LOCK_RESET  0x0
+#define RPI_MIPICFG_DPHY_MONITOR_LOCK_BITS   0x00100000
+#define RPI_MIPICFG_DPHY_MONITOR_LOCK_MSB    20
+#define RPI_MIPICFG_DPHY_MONITOR_LOCK_LSB    20
+#define RPI_MIPICFG_DPHY_MONITOR_LOCK_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_MONITOR_BISTOK
+// Description : None
+#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_RESET  0x0
+#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_BITS   0x00010000
+#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_MSB    16
+#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_LSB    16
+#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK
+// Description : None
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_RESET  0x0
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_BITS   0x00001000
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_MSB    12
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_LSB    12
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA
+// Description : None
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_RESET  0x0
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_BITS   0x00000f00
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_MSB    11
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_LSB    8
+#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_MONITOR_TESTDOUT
+// Description : None
+#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_RESET  0x00
+#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_BITS   0x000000ff
+#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_MSB    7
+#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_LSB    0
+#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_ACCESS "RO"
+// ================================================================================
+// Register    : RPI_MIPICFG_DPHY_CTRL_0
+// JTAG access : asynchronous
+// Description : DPHY control for analog DFT
+#define RPI_MIPICFG_DPHY_CTRL_0_OFFSET 0x00000014
+#define RPI_MIPICFG_DPHY_CTRL_0_BITS   0x0000003f
+#define RPI_MIPICFG_DPHY_CTRL_0_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE
+// Description : When set in lpmode, TXCLKESC is driven from clk_vec(driven from clocks block)
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_BITS   0x00000020
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_MSB    5
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_LSB    5
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA
+// Description : When set, drive the DPHY from the test registers
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_BITS   0x00000010
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_MSB    4
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_LSB    4
+#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS
+// Description : When test_ena is set, disable cfg_clk
+#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_BITS   0x00000008
+#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_MSB    3
+#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_LSB    3
+#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS
+// Description : When test_ena is set, disable refclk
+#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_BITS   0x00000004
+#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_MSB    2
+#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_LSB    2
+#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS
+// Description : When test_ena is set, disable txclkesc
+#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_BITS   0x00000002
+#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_MSB    1
+#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_LSB    1
+#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS
+// Description : When test_ena is set, disable txbyteclkhs
+#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_BITS   0x00000001
+#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_MSB    0
+#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_LSB    0
+#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_DPHY_CTRL_1
+// JTAG access : asynchronous
+// Description : DPHY control for analog DFT
+#define RPI_MIPICFG_DPHY_CTRL_1_OFFSET 0x00000018
+#define RPI_MIPICFG_DPHY_CTRL_1_BITS   0x7fffffff
+#define RPI_MIPICFG_DPHY_CTRL_1_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_BITS   0x40000000
+#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_MSB    30
+#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_LSB    30
+#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_BITS   0x20000000
+#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_MSB    29
+#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_LSB    29
+#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_RSTZ
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_BITS   0x10000000
+#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_MSB    28
+#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_LSB    28
+#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_BITS   0x08000000
+#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_MSB    27
+#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_LSB    27
+#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_BISTON
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_BITS   0x04000000
+#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_MSB    26
+#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_LSB    26
+#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_BITS   0x02000000
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_MSB    25
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_LSB    25
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_BITS   0x01000000
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_MSB    24
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_LSB    24
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_BITS   0x00800000
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_MSB    23
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_LSB    23
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_BITS   0x00400000
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_MSB    22
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_LSB    22
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_BITS   0x00200000
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_MSB    21
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_LSB    21
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_BITS   0x00100000
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_MSB    20
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_LSB    20
+#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_BITS   0x00080000
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_MSB    19
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_LSB    19
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_BITS   0x00040000
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_MSB    18
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_LSB    18
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_BITS   0x00020000
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_MSB    17
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_LSB    17
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_BITS   0x00010000
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_MSB    16
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_LSB    16
+#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_BITS   0x00008000
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_MSB    15
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_LSB    15
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_BITS   0x00004000
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_MSB    14
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_LSB    14
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_BITS   0x00002000
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_MSB    13
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_LSB    13
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_BITS   0x00001000
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_MSB    12
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_LSB    12
+#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_BITS   0x00000800
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_MSB    11
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_LSB    11
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_BITS   0x00000400
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_MSB    10
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_LSB    10
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_BITS   0x00000200
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_MSB    9
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_LSB    9
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_BITS   0x00000100
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_MSB    8
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_LSB    8
+#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_BITS   0x00000080
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_MSB    7
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_LSB    7
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_BITS   0x00000040
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_MSB    6
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_LSB    6
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_BITS   0x00000020
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_MSB    5
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_LSB    5
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_BITS   0x00000010
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_MSB    4
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_LSB    4
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_BITS   0x00000008
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_MSB    3
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_LSB    3
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_BITS   0x00000004
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_MSB    2
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_LSB    2
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_BITS   0x00000002
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_MSB    1
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_LSB    1
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_BITS   0x00000001
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_MSB    0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_LSB    0
+#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_DPHY_CTRL_2
+// JTAG access : asynchronous
+// Description : DPHY control for analog DFT
+#define RPI_MIPICFG_DPHY_CTRL_2_OFFSET 0x0000001c
+#define RPI_MIPICFG_DPHY_CTRL_2_BITS   0x000007ff
+#define RPI_MIPICFG_DPHY_CTRL_2_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_2_TESTCLK
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_BITS   0x00000400
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_MSB    10
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_LSB    10
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_2_TESTEN
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_BITS   0x00000200
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_MSB    9
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_LSB    9
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_2_TESTCLR
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_RESET  0x0
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_BITS   0x00000100
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_MSB    8
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_LSB    8
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_2_TESTDIN
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_BITS   0x000000ff
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_MSB    7
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_LSB    0
+#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_DPHY_CTRL_3
+// JTAG access : asynchronous
+// Description : DPHY control for analog DFT
+#define RPI_MIPICFG_DPHY_CTRL_3_OFFSET 0x00000020
+#define RPI_MIPICFG_DPHY_CTRL_3_BITS   0xffffffff
+#define RPI_MIPICFG_DPHY_CTRL_3_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_BITS   0xff000000
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_MSB    31
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_LSB    24
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_BITS   0x00ff0000
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_MSB    23
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_LSB    16
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_BITS   0x0000ff00
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_MSB    15
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_LSB    8
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_BITS   0x000000ff
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_MSB    7
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_LSB    0
+#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_DPHY_CTRL_4
+// JTAG access : asynchronous
+// Description : DPHY control for analog DFT
+#define RPI_MIPICFG_DPHY_CTRL_4_OFFSET 0x00000024
+#define RPI_MIPICFG_DPHY_CTRL_4_BITS   0xffffffff
+#define RPI_MIPICFG_DPHY_CTRL_4_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_BITS   0xff000000
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_MSB    31
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_LSB    24
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_BITS   0x00ff0000
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_MSB    23
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_LSB    16
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_BITS   0x0000ff00
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_MSB    15
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_LSB    8
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0
+// Description : None
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_RESET  0x00
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_BITS   0x000000ff
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_MSB    7
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_LSB    0
+#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_INTR
+// JTAG access : synchronous
+// Description : Raw Interrupts
+#define RPI_MIPICFG_INTR_OFFSET 0x00000028
+#define RPI_MIPICFG_INTR_BITS   0x0000000f
+#define RPI_MIPICFG_INTR_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTR_DSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTR_DSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTR_DSI_HOST_BITS   0x00000008
+#define RPI_MIPICFG_INTR_DSI_HOST_MSB    3
+#define RPI_MIPICFG_INTR_DSI_HOST_LSB    3
+#define RPI_MIPICFG_INTR_DSI_HOST_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTR_CSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTR_CSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTR_CSI_HOST_BITS   0x00000004
+#define RPI_MIPICFG_INTR_CSI_HOST_MSB    2
+#define RPI_MIPICFG_INTR_CSI_HOST_LSB    2
+#define RPI_MIPICFG_INTR_CSI_HOST_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTR_DSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTR_DSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTR_DSI_DMA_BITS   0x00000002
+#define RPI_MIPICFG_INTR_DSI_DMA_MSB    1
+#define RPI_MIPICFG_INTR_DSI_DMA_LSB    1
+#define RPI_MIPICFG_INTR_DSI_DMA_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTR_CSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTR_CSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTR_CSI_DMA_BITS   0x00000001
+#define RPI_MIPICFG_INTR_CSI_DMA_MSB    0
+#define RPI_MIPICFG_INTR_CSI_DMA_LSB    0
+#define RPI_MIPICFG_INTR_CSI_DMA_ACCESS "RO"
+// ================================================================================
+// Register    : RPI_MIPICFG_INTE
+// JTAG access : synchronous
+// Description : Interrupt Enable
+#define RPI_MIPICFG_INTE_OFFSET 0x0000002c
+#define RPI_MIPICFG_INTE_BITS   0x0000000f
+#define RPI_MIPICFG_INTE_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTE_DSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTE_DSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTE_DSI_HOST_BITS   0x00000008
+#define RPI_MIPICFG_INTE_DSI_HOST_MSB    3
+#define RPI_MIPICFG_INTE_DSI_HOST_LSB    3
+#define RPI_MIPICFG_INTE_DSI_HOST_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTE_CSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTE_CSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTE_CSI_HOST_BITS   0x00000004
+#define RPI_MIPICFG_INTE_CSI_HOST_MSB    2
+#define RPI_MIPICFG_INTE_CSI_HOST_LSB    2
+#define RPI_MIPICFG_INTE_CSI_HOST_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTE_DSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTE_DSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTE_DSI_DMA_BITS   0x00000002
+#define RPI_MIPICFG_INTE_DSI_DMA_MSB    1
+#define RPI_MIPICFG_INTE_DSI_DMA_LSB    1
+#define RPI_MIPICFG_INTE_DSI_DMA_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTE_CSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTE_CSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTE_CSI_DMA_BITS   0x00000001
+#define RPI_MIPICFG_INTE_CSI_DMA_MSB    0
+#define RPI_MIPICFG_INTE_CSI_DMA_LSB    0
+#define RPI_MIPICFG_INTE_CSI_DMA_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_INTF
+// JTAG access : synchronous
+// Description : Interrupt Force
+#define RPI_MIPICFG_INTF_OFFSET 0x00000030
+#define RPI_MIPICFG_INTF_BITS   0x0000000f
+#define RPI_MIPICFG_INTF_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTF_DSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTF_DSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTF_DSI_HOST_BITS   0x00000008
+#define RPI_MIPICFG_INTF_DSI_HOST_MSB    3
+#define RPI_MIPICFG_INTF_DSI_HOST_LSB    3
+#define RPI_MIPICFG_INTF_DSI_HOST_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTF_CSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTF_CSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTF_CSI_HOST_BITS   0x00000004
+#define RPI_MIPICFG_INTF_CSI_HOST_MSB    2
+#define RPI_MIPICFG_INTF_CSI_HOST_LSB    2
+#define RPI_MIPICFG_INTF_CSI_HOST_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTF_DSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTF_DSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTF_DSI_DMA_BITS   0x00000002
+#define RPI_MIPICFG_INTF_DSI_DMA_MSB    1
+#define RPI_MIPICFG_INTF_DSI_DMA_LSB    1
+#define RPI_MIPICFG_INTF_DSI_DMA_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTF_CSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTF_CSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTF_CSI_DMA_BITS   0x00000001
+#define RPI_MIPICFG_INTF_CSI_DMA_MSB    0
+#define RPI_MIPICFG_INTF_CSI_DMA_LSB    0
+#define RPI_MIPICFG_INTF_CSI_DMA_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_INTS
+// JTAG access : synchronous
+// Description : Interrupt status after masking & forcing
+#define RPI_MIPICFG_INTS_OFFSET 0x00000034
+#define RPI_MIPICFG_INTS_BITS   0x0000000f
+#define RPI_MIPICFG_INTS_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTS_DSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTS_DSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTS_DSI_HOST_BITS   0x00000008
+#define RPI_MIPICFG_INTS_DSI_HOST_MSB    3
+#define RPI_MIPICFG_INTS_DSI_HOST_LSB    3
+#define RPI_MIPICFG_INTS_DSI_HOST_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTS_CSI_HOST
+// Description : None
+#define RPI_MIPICFG_INTS_CSI_HOST_RESET  0x0
+#define RPI_MIPICFG_INTS_CSI_HOST_BITS   0x00000004
+#define RPI_MIPICFG_INTS_CSI_HOST_MSB    2
+#define RPI_MIPICFG_INTS_CSI_HOST_LSB    2
+#define RPI_MIPICFG_INTS_CSI_HOST_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTS_DSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTS_DSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTS_DSI_DMA_BITS   0x00000002
+#define RPI_MIPICFG_INTS_DSI_DMA_MSB    1
+#define RPI_MIPICFG_INTS_DSI_DMA_LSB    1
+#define RPI_MIPICFG_INTS_DSI_DMA_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_INTS_CSI_DMA
+// Description : None
+#define RPI_MIPICFG_INTS_CSI_DMA_RESET  0x0
+#define RPI_MIPICFG_INTS_CSI_DMA_BITS   0x00000001
+#define RPI_MIPICFG_INTS_CSI_DMA_MSB    0
+#define RPI_MIPICFG_INTS_CSI_DMA_LSB    0
+#define RPI_MIPICFG_INTS_CSI_DMA_ACCESS "RO"
+// ================================================================================
+// Register    : RPI_MIPICFG_BLOCK_ID
+// JTAG access : asynchronous
+// Description : Block Identifier
+#define RPI_MIPICFG_BLOCK_ID_OFFSET 0x00000038
+#define RPI_MIPICFG_BLOCK_ID_BITS   0xffffffff
+#define RPI_MIPICFG_BLOCK_ID_RESET  0x4d495049
+#define RPI_MIPICFG_BLOCK_ID_MSB    31
+#define RPI_MIPICFG_BLOCK_ID_LSB    0
+#define RPI_MIPICFG_BLOCK_ID_ACCESS "RO"
+// ================================================================================
+// Register    : RPI_MIPICFG_INSTANCE_ID
+// JTAG access : asynchronous
+// Description : Block Instance Identifier
+#define RPI_MIPICFG_INSTANCE_ID_OFFSET 0x0000003c
+#define RPI_MIPICFG_INSTANCE_ID_BITS   0x0000000f
+#define RPI_MIPICFG_INSTANCE_ID_RESET  0x00000000
+#define RPI_MIPICFG_INSTANCE_ID_MSB    3
+#define RPI_MIPICFG_INSTANCE_ID_LSB    0
+#define RPI_MIPICFG_INSTANCE_ID_ACCESS "RO"
+// ================================================================================
+// Register    : RPI_MIPICFG_RSTSEQ_AUTO
+// JTAG access : synchronous
+// Description : None
+#define RPI_MIPICFG_RSTSEQ_AUTO_OFFSET 0x00000040
+#define RPI_MIPICFG_RSTSEQ_AUTO_BITS   0x00000007
+#define RPI_MIPICFG_RSTSEQ_AUTO_RESET  0x00000007
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_AUTO_CSI
+// Description : 1 = reset is controlled by the sequencer
+//               0 = reset is controlled by rstseq_ctrl
+#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_RESET  0x1
+#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_BITS   0x00000004
+#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_MSB    2
+#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_LSB    2
+#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_AUTO_DPI
+// Description : 1 = reset is controlled by the sequencer
+//               0 = reset is controlled by rstseq_ctrl
+#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_RESET  0x1
+#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_BITS   0x00000002
+#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_MSB    1
+#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_LSB    1
+#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER
+// Description : 1 = reset is controlled by the sequencer
+//               0 = reset is controlled by rstseq_ctrl
+#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_RESET  0x1
+#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_BITS   0x00000001
+#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_MSB    0
+#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_LSB    0
+#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_RSTSEQ_PARALLEL
+// JTAG access : synchronous
+// Description : None
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_OFFSET 0x00000044
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_BITS   0x00000007
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_RESET  0x00000006
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_PARALLEL_CSI
+// Description : Is this reset parallel (i.e. not part of the sequence)
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_RESET  0x1
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_BITS   0x00000004
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_MSB    2
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_LSB    2
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_PARALLEL_DPI
+// Description : Is this reset parallel (i.e. not part of the sequence)
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_RESET  0x1
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_BITS   0x00000002
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_MSB    1
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_LSB    1
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER
+// Description : Is this reset parallel (i.e. not part of the sequence)
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS   0x00000001
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB    0
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB    0
+#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO"
+// ================================================================================
+// Register    : RPI_MIPICFG_RSTSEQ_CTRL
+// JTAG access : synchronous
+// Description : None
+#define RPI_MIPICFG_RSTSEQ_CTRL_OFFSET 0x00000048
+#define RPI_MIPICFG_RSTSEQ_CTRL_BITS   0x00000007
+#define RPI_MIPICFG_RSTSEQ_CTRL_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_CTRL_CSI
+// Description : 1 = keep the reset asserted
+//               0 = keep the reset deasserted
+//               This is ignored if rstseq_auto=1
+#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_BITS   0x00000004
+#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_MSB    2
+#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_LSB    2
+#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_CTRL_DPI
+// Description : 1 = keep the reset asserted
+//               0 = keep the reset deasserted
+//               This is ignored if rstseq_auto=1
+#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_BITS   0x00000002
+#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_MSB    1
+#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_LSB    1
+#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER
+// Description : 1 = keep the reset asserted
+//               0 = keep the reset deasserted
+//               This is ignored if rstseq_auto=1
+#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_BITS   0x00000001
+#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_MSB    0
+#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_LSB    0
+#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW"
+// ================================================================================
+// Register    : RPI_MIPICFG_RSTSEQ_TRIG
+// JTAG access : synchronous
+// Description : None
+#define RPI_MIPICFG_RSTSEQ_TRIG_OFFSET 0x0000004c
+#define RPI_MIPICFG_RSTSEQ_TRIG_BITS   0x00000007
+#define RPI_MIPICFG_RSTSEQ_TRIG_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_TRIG_CSI
+// Description : Pulses the reset output
+#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_BITS   0x00000004
+#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_MSB    2
+#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_LSB    2
+#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_ACCESS "SC"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_TRIG_DPI
+// Description : Pulses the reset output
+#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_BITS   0x00000002
+#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_MSB    1
+#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_LSB    1
+#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_ACCESS "SC"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER
+// Description : Pulses the reset output
+#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_BITS   0x00000001
+#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_MSB    0
+#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_LSB    0
+#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC"
+// ================================================================================
+// Register    : RPI_MIPICFG_RSTSEQ_DONE
+// JTAG access : synchronous
+// Description : None
+#define RPI_MIPICFG_RSTSEQ_DONE_OFFSET 0x00000050
+#define RPI_MIPICFG_RSTSEQ_DONE_BITS   0x00000007
+#define RPI_MIPICFG_RSTSEQ_DONE_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_DONE_CSI
+// Description : Indicates the current state of the reset
+#define RPI_MIPICFG_RSTSEQ_DONE_CSI_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_DONE_CSI_BITS   0x00000004
+#define RPI_MIPICFG_RSTSEQ_DONE_CSI_MSB    2
+#define RPI_MIPICFG_RSTSEQ_DONE_CSI_LSB    2
+#define RPI_MIPICFG_RSTSEQ_DONE_CSI_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_DONE_DPI
+// Description : Indicates the current state of the reset
+#define RPI_MIPICFG_RSTSEQ_DONE_DPI_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_DONE_DPI_BITS   0x00000002
+#define RPI_MIPICFG_RSTSEQ_DONE_DPI_MSB    1
+#define RPI_MIPICFG_RSTSEQ_DONE_DPI_LSB    1
+#define RPI_MIPICFG_RSTSEQ_DONE_DPI_ACCESS "RO"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER
+// Description : Indicates the current state of the reset
+#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_RESET  0x0
+#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_BITS   0x00000001
+#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_MSB    0
+#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_LSB    0
+#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO"
+// ================================================================================
+// Register    : RPI_MIPICFG_DFTSS
+// JTAG access : asynchronous
+// Description : None
+#define RPI_MIPICFG_DFTSS_OFFSET 0x00000054
+#define RPI_MIPICFG_DFTSS_BITS   0x0000001f
+#define RPI_MIPICFG_DFTSS_RESET  0x00000000
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DFTSS_JTAG_COPY
+// Description : None
+#define RPI_MIPICFG_DFTSS_JTAG_COPY_RESET  0x0
+#define RPI_MIPICFG_DFTSS_JTAG_COPY_BITS   0x00000010
+#define RPI_MIPICFG_DFTSS_JTAG_COPY_MSB    4
+#define RPI_MIPICFG_DFTSS_JTAG_COPY_LSB    4
+#define RPI_MIPICFG_DFTSS_JTAG_COPY_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY
+// Description : None
+#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_RESET  0x0
+#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_BITS   0x00000008
+#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_MSB    3
+#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_LSB    3
+#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS
+// Description : None
+#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_RESET  0x0
+#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_BITS   0x00000004
+#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_MSB    2
+#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_LSB    2
+#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DFTSS_BYPASS_INSYNCS
+// Description : None
+#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_RESET  0x0
+#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_BITS   0x00000002
+#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_MSB    1
+#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_LSB    1
+#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_ACCESS "RW"
+// --------------------------------------------------------------------------------
+// Field       : RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS
+// Description : None
+#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_RESET  0x0
+#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_BITS   0x00000001
+#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_MSB    0
+#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_LSB    0
+#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_ACCESS "RW"
+
+#define CFG_WRITE(reg, val)  writel((val),  dsi->hw_base[RP1DSI_HW_BLOCK_CFG] + (reg ## _OFFSET))
+#define CFG_READ(reg)        readl(dsi->hw_base[RP1DSI_HW_BLOCK_CFG] + (reg ## _OFFSET))
+
+/* ------------------------------- DPHY setup stuff ------------------------ */
+
+static void dphy_transaction(struct rp1_dsi *dsi, uint8_t test_code, uint8_t test_data)
+{
+	/*
+	 * See pg 101 of mipi dphy bidir databook
+	 * Assume we start with testclk high.
+	 * Each APB write takes at least 10ns and we ignore TESTDOUT
+	 * so there is no need for extra delays between the transitions.
+	 */
+
+	DSI_WRITE(DSI_PHY_TST_CTRL1, test_code | DPHY_CTRL1_PHY_TESTEN_BITS);
+	DSI_WRITE(DSI_PHY_TST_CTRL0, 0);
+	DSI_READ(DSI_PHY_TST_CTRL1); /* XXX possibly not needed */
+	DSI_WRITE(DSI_PHY_TST_CTRL1, test_data);
+	DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
+}
+
+static u64 dphy_get_div(u32 refclk, u64 vco_freq, u32 *ptr_m, u32 *ptr_n)
+{
+	/*
+	 * See pg 77-78 of dphy databook
+	 * fvco = m/n * refclk
+	 * with the limit
+	 * 40MHz >= fREFCLK / N >= 5MHz
+	 * M (multiplier) must be an even number between 2 and 300
+	 * N (input divider) must be an integer between 1 and 100
+	 *
+	 * In practice, given a 50MHz reference clock, it can produce any
+	 * multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz
+	 * with < 1% error for all frequencies above 495MHz.
+	 *
+	 * vco_freq should be set to the lane bit rate (not the MIPI clock
+	 * which is half of this). These frequencies are now measured in Hz.
+	 * They should fit within u32, but u64 is needed for calculations.
+	 */
+
+	static const u32 REF_DIVN_MAX = 40000000;
+	static const u32 REF_DIVN_MIN =  5000000;
+	u32 n, best_n, best_m;
+	u64 best_err = vco_freq;
+
+	for (n = 1 + refclk / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk && n < 100; ++n) {
+		u32 half_m = DIV_U64_ROUND_CLOSEST(n * vco_freq, 2 * refclk);
+
+		if (half_m < 150) {
+			u64 f = div_u64(mul_u32_u32(2 * half_m, refclk), n);
+			u64 err = (f > vco_freq) ? f - vco_freq : vco_freq - f;
+
+			if (err < best_err) {
+				best_n = n;
+				best_m = 2 * half_m;
+				best_err = err;
+				if (err == 0)
+					break;
+			}
+		}
+	}
+
+	if (64 * best_err >= vco_freq)
+		return 0;
+
+	*ptr_n = best_n;
+	*ptr_m = best_m;
+	return div_u64(mul_u32_u32(best_m, refclk), best_n);
+}
+
+struct hsfreq_range {
+	u16 mhz_max;
+	u8  hsfreqrange;
+	u8  clk_lp2hs;
+	u8  clk_hs2lp;
+	u8  data_lp2hs; /* excluding clk lane entry */
+	u8  data_hs2lp;
+};
+
+/* See Table A-3 on page 258 of dphy databook */
+static const struct hsfreq_range hsfreq_table[] = {
+	{   89, 0b000000, 32, 20, 26, 13 },
+	{   99, 0b010000, 35, 23, 28, 14 },
+	{  109, 0b100000, 32, 22, 26, 13 },
+	{  129, 0b000001, 31, 20, 27, 13 },
+	{  139, 0b010001, 33, 22, 26, 14 },
+	{  149, 0b100001, 33, 21, 26, 14 },
+	{  169, 0b000010, 32, 20, 27, 13 },
+	{  179, 0b010010, 36, 23, 30, 15 },
+	{  199, 0b100010, 40, 22, 33, 15 },
+	{  219, 0b000011, 40, 22, 33, 15 },
+	{  239, 0b010011, 44, 24, 36, 16 },
+	{  249, 0b100011, 48, 24, 38, 17 },
+	{  269, 0b000100, 48, 24, 38, 17 },
+	{  299, 0b010100, 50, 27, 41, 18 },
+	{  329, 0b000101, 56, 28, 45, 18 },
+	{  359, 0b010101, 59, 28, 48, 19 },
+	{  399, 0b100101, 61, 30, 50, 20 },
+	{  449, 0b000110, 67, 31, 55, 21 },
+	{  499, 0b010110, 73, 31, 59, 22 },
+	{  549, 0b000111, 79, 36, 63, 24 },
+	{  599, 0b010111, 83, 37, 68, 25 },
+	{  649, 0b001000, 90, 38, 73, 27 },
+	{  699, 0b011000, 95, 40, 77, 28 },
+	{  749, 0b001001, 102, 40, 84, 28 },
+	{  799, 0b011001, 106, 42, 87, 30 },
+	{  849, 0b101001, 113, 44, 93, 31 },
+	{  899, 0b111001, 118, 47, 98, 32 },
+	{  949, 0b001010, 124, 47, 102, 34 },
+	{  999, 0b011010, 130, 49, 107, 35 },
+	{ 1049, 0b101010, 135, 51, 111, 37 },
+	{ 1099, 0b111010, 139, 51, 114, 38 },
+	{ 1149, 0b001011, 146, 54, 120, 40 },
+	{ 1199, 0b011011, 153, 57, 125, 41 },
+	{ 1249, 0b101011, 158, 58, 130, 42 },
+	{ 1299, 0b111011, 163, 58, 135, 44 },
+	{ 1349, 0b001100, 168, 60, 140, 45 },
+	{ 1399, 0b011100, 172, 64, 144, 47 },
+	{ 1449, 0b101100, 176, 65, 148, 48 },
+	{ 1500, 0b111100, 181, 66, 153, 50 },
+};
+
+static void dphy_set_hsfreqrange(struct rp1_dsi *dsi, u32 freq_mhz)
+{
+	unsigned int i;
+
+	if (freq_mhz < 80 || freq_mhz > 1500)
+		drm_err(dsi->drm, "DPHY: Frequency %u MHz out of range\n",
+			freq_mhz);
+
+	for (i = 0; i < ARRAY_SIZE(hsfreq_table) - 1; i++) {
+		if (freq_mhz <= hsfreq_table[i].mhz_max)
+			break;
+	}
+
+	dsi->hsfreq_index = i;
+	dphy_transaction(dsi, DPHY_HS_RX_CTRL_LANE0_OFFSET,
+			 hsfreq_table[i].hsfreqrange << 1);
+}
+
+static u32 dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk, u32 vco_freq)
+{
+	u32 m = 0;
+	u32 n = 0;
+	u32 actual_vco_freq = dphy_get_div(refclk, vco_freq, &m, &n);
+
+	if (actual_vco_freq) {
+		dphy_set_hsfreqrange(dsi, actual_vco_freq / 1000000);
+		/* Program m,n from registers */
+		dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30);
+		/* N (program N-1) */
+		dphy_transaction(dsi, DPHY_PLL_INPUT_DIV_OFFSET, n - 1);
+		/* M[8:5] ?? */
+		dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, 0x80 | ((m - 1) >> 5));
+		/* M[4:0] (program M-1) */
+		dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F));
+		drm_dbg_driver(dsi->drm,
+			       "DPHY: vco freq want %uHz got %uHz = %d * (%uHz / %d), hsfreqrange = 0x%02x\n",
+			       vco_freq, actual_vco_freq, m, refclk, n,
+			       hsfreq_table[dsi->hsfreq_index].hsfreqrange);
+	} else {
+		drm_err(dsi->drm,
+			"rp1dsi: Error configuring DPHY PLL %uHz\n", vco_freq);
+	}
+
+	return actual_vco_freq;
+}
+
+static u32 dphy_init(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq)
+{
+	u32 actual_vco_freq;
+
+	/* Reset the PHY */
+	DSI_WRITE(DSI_PHYRSTZ, 0);
+	DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
+	DSI_WRITE(DSI_PHY_TST_CTRL1, 0);
+	DSI_WRITE(DSI_PHY_TST_CTRL0, (DPHY_CTRL0_PHY_TESTCLK_BITS | DPHY_CTRL0_PHY_TESTCLR_BITS));
+	udelay(1);
+	DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS);
+	udelay(1);
+	/* Since we are in DSI (not CSI2) mode here, start the PLL */
+	actual_vco_freq = dphy_configure_pll(dsi, ref_freq, vco_freq);
+	udelay(1);
+	/* Unreset */
+	DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS);
+	udelay(1);
+	DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS));
+	udelay(1); /* so we can see PLL coming up? */
+
+	return actual_vco_freq;
+}
+
+void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi)
+{
+	/* Select DSI rather than CSI-2 */
+	CFG_WRITE(RPI_MIPICFG_CFG, 0);
+	/* Enable DSIDMA interrupt only */
+	CFG_WRITE(RPI_MIPICFG_INTE, RPI_MIPICFG_INTE_DSI_DMA_BITS);
+}
+
+static unsigned long rp1dsi_refclk_freq(struct rp1_dsi *dsi)
+{
+	unsigned long u;
+
+	u = (dsi->clocks[RP1DSI_CLOCK_REF]) ? clk_get_rate(dsi->clocks[RP1DSI_CLOCK_REF]) : 0;
+	if (u < 1 || u >= (1ul << 30))
+		u = 50000000ul; /* default XOSC frequency */
+	return u;
+}
+
+static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, u32 byte_clock,
+				unsigned int bpp, unsigned int lanes)
+{
+	/* Dummy clk_set_rate() to declare the actual DSI byte-clock rate */
+	clk_set_rate(dsi->clocks[RP1DSI_CLOCK_BYTE], byte_clock);
+
+	/*
+	 * Prefer the DSI byte-clock source where possible, so that DSI and DPI
+	 * clocks will be in an exact ratio and downstream devices can recover
+	 * perfect timings. But when DPI clock is faster, fall back on PLL_SYS.
+	 * To defeat rounding errors, specify explicitly which source to use.
+	 */
+	if (bpp >= 8 * lanes)
+		clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_BYTE]);
+	else if (dsi->clocks[RP1DSI_CLOCK_PLLSYS])
+		clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_PLLSYS]);
+
+	clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * byte_clock) / (bpp >> 1));
+	clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]);
+	drm_info(dsi->drm,
+		 "rp1dsi: Nominal Byte clock %u DPI clock %lu (parent rate %lu)\n",
+		 byte_clock,
+		 clk_get_rate(dsi->clocks[RP1DSI_CLOCK_DPI]),
+		 clk_get_rate(clk_get_parent(dsi->clocks[RP1DSI_CLOCK_DPI])));
+}
+
+static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi)
+{
+	if (dsi->clocks[RP1DSI_CLOCK_DPI])
+		clk_disable_unprepare(dsi->clocks[RP1DSI_CLOCK_DPI]);
+}
+
+/* Choose the internal on-the-bus DPI format, and DSI packing flag. */
+static u32 get_colorcode(enum mipi_dsi_pixel_format fmt)
+{
+	switch (fmt) {
+	case MIPI_DSI_FMT_RGB666:
+		return 0x104;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		return 0x003;
+	case MIPI_DSI_FMT_RGB565:
+		return 0x000;
+	case MIPI_DSI_FMT_RGB888:
+		return 0x005;
+	}
+
+	/* This should be impossible as the format is validated in
+	 * rp1dsi_host_attach
+	 */
+	WARN_ONCE(1, "Invalid colour format configured for DSI");
+	return 0x005;
+}
+
+/* Frequency limits for DPI, HS and LP clocks, and some magic numbers */
+#define RP1DSI_DPI_MAX_KHZ     200000
+#define RP1DSI_BYTE_CLK_MIN  10000000
+#define RP1DSI_BYTE_CLK_MAX 187500000
+#define RP1DSI_ESC_CLK_MAX   20000000
+#define RP1DSI_TO_CLK_DIV        0x50
+#define RP1DSI_LPRX_TO_VAL       0x40
+#define RP1DSI_BTA_TO_VAL       0xd00
+
+void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
+{
+	int cmdtim;
+	u32 timeout, mask, clkdiv;
+	unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format);
+	u32 byte_clock = clamp((bpp * 125 * min(mode->clock, RP1DSI_DPI_MAX_KHZ)) / dsi->lanes,
+			       RP1DSI_BYTE_CLK_MIN, RP1DSI_BYTE_CLK_MAX);
+
+	DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1);
+	DSI_WRITE(DSI_DPI_CFG_POL, 0);
+	DSI_WRITE(DSI_GEN_VCID, dsi->vc);
+	DSI_WRITE(DSI_DPI_COLOR_CODING, get_colorcode(dsi->display_format));
+
+	/*
+	 * Flags to configure use of LP, EoTp, Burst Mode, Sync Events/Pulses.
+	 * Note that Burst Mode implies Sync Events; the two flags need not be
+	 * set concurrently, and in this RP1 variant *should not* both be set:
+	 * doing so would (counter-intuitively) enable Sync Pulses and may fail
+	 * if there is not sufficient time to return to LP11 state during HBP.
+	 */
+	mask =  DSI_VID_MODE_LP_HFP_EN  | DSI_VID_MODE_LP_HBP_EN |
+		DSI_VID_MODE_LP_VACT_EN | DSI_VID_MODE_LP_VFP_EN |
+		DSI_VID_MODE_LP_VBP_EN  | DSI_VID_MODE_LP_VSA_EN;
+	if (dsi->display_flags & MIPI_DSI_MODE_LPM)
+		mask |= DSI_VID_MODE_LP_CMD_EN;
+	if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		mask |= DSI_VID_MODE_BURST;
+	else if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
+		mask |= DSI_VID_MODE_SYNC_EVENTS;
+	else if (8 * dsi->lanes > bpp)
+		mask &= ~DSI_VID_MODE_LP_HBP_EN; /* PULSE && inexact DPICLK => fix HBP time */
+	DSI_WRITE(DSI_VID_MODE_CFG, mask);
+	DSI_WRITE(DSI_CMD_MODE_CFG,
+		  (dsi->display_flags & MIPI_DSI_MODE_LPM) ? DSI_CMD_MODE_ALL_LP : 0);
+	DSI_WRITE(DSI_PCKHDL_CFG,
+		  DSI_PCKHDL_BTA_EN |
+		  ((dsi->display_flags & MIPI_DSI_MODE_NO_EOT_PACKET) ? 0 : DSI_PCKHDL_EOTP_TX_EN));
+
+	/* Select Command Mode */
+	DSI_WRITE(DSI_MODE_CFG, 1);
+
+	/* Set timeouts and clock dividers */
+	timeout = (bpp * mode->htotal * mode->vdisplay) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes);
+	if (timeout > 0xFFFFu)
+		timeout = 0;
+	DSI_WRITE(DSI_TO_CNT_CFG, (timeout << 16) | RP1DSI_LPRX_TO_VAL);
+	DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL);
+	clkdiv = max(2u, 1u + byte_clock / RP1DSI_ESC_CLK_MAX); /* byte clocks per escape clock */
+	DSI_WRITE(DSI_CLKMGR_CFG,
+		  (RP1DSI_TO_CLK_DIV << 8) | clkdiv);
+
+	/* Configure video timings */
+	DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay);
+	DSI_WRITE(DSI_VID_NUM_CHUNKS, 0);
+	DSI_WRITE(DSI_VID_NULL_SIZE, 0);
+	DSI_WRITE(DSI_VID_HSA_TIME,
+		  (bpp * (mode->hsync_end - mode->hsync_start)) / (8 * dsi->lanes));
+	DSI_WRITE(DSI_VID_HBP_TIME,
+		  (bpp * (mode->htotal - mode->hsync_end)) / (8 * dsi->lanes));
+	DSI_WRITE(DSI_VID_HLINE_TIME, (bpp * mode->htotal) / (8 * dsi->lanes));
+	DSI_WRITE(DSI_VID_VSA_LINES, (mode->vsync_end - mode->vsync_start));
+	DSI_WRITE(DSI_VID_VBP_LINES, (mode->vtotal - mode->vsync_end));
+	DSI_WRITE(DSI_VID_VFP_LINES, (mode->vsync_start - mode->vdisplay));
+	DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay);
+
+	/* Init PHY */
+	byte_clock = dphy_init(dsi, rp1dsi_refclk_freq(dsi), 8 * byte_clock) >> 3;
+
+	DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG,
+		  (hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
+		  (hsfreq_table[dsi->hsfreq_index].clk_hs2lp << DSI_PHY_TMR_HS2LP_LSB));
+	DSI_WRITE(DSI_PHY_TMR_CFG,
+		  (hsfreq_table[dsi->hsfreq_index].data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
+		  (hsfreq_table[dsi->hsfreq_index].data_hs2lp << DSI_PHY_TMR_HS2LP_LSB));
+
+	/* Estimate how many LP bytes can be sent during vertical blanking (Databook 3.6.2.1) */
+	cmdtim = mode->htotal;
+	if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+		cmdtim -= mode->hsync_end - mode->hsync_start;
+	cmdtim = (bpp * cmdtim - 64) / (8 * dsi->lanes);      /* byte clocks after HSS and EoTp */
+	cmdtim -= hsfreq_table[dsi->hsfreq_index].data_hs2lp;
+	cmdtim -= hsfreq_table[dsi->hsfreq_index].data_lp2hs;
+	cmdtim = (cmdtim / clkdiv) - 24;                      /* escape clocks for commands */
+	cmdtim = max(0, cmdtim >> 4);                         /* bytes (at 2 clocks per bit) */
+	drm_info(dsi->drm, "rp1dsi: Command time (outvact): %d\n", cmdtim);
+	DSI_WRITE(DSI_DPI_LP_CMD_TIM, cmdtim << 16);
+
+	/* Wait for PLL lock */
+	for (timeout = (1 << 14); timeout != 0; --timeout) {
+		usleep_range(10, 50);
+		if (DSI_READ(DSI_PHY_STATUS) & (1 << 0))
+			break;
+	}
+	if (timeout == 0)
+		drm_err(dsi->drm, "RP1DSI: Time out waiting for PLL\n");
+
+	DSI_WRITE(DSI_LPCLK_CTRL,
+		  (dsi->display_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0x3 : 0x1);
+	DSI_WRITE(DSI_PHY_TST_CTRL0, 0x2);
+	DSI_WRITE(DSI_PWR_UP, 0x1);		/* power up */
+
+	/* Now it should be safe to start the external DPI clock divider */
+	rp1dsi_dpiclk_start(dsi, byte_clock, bpp, dsi->lanes);
+
+	/* Wait for all lane(s) to be in Stopstate */
+	mask = (1 << 4);
+	if (dsi->lanes >= 2)
+		mask |= (1 << 7);
+	if (dsi->lanes >= 3)
+		mask |= (1 << 9);
+	if (dsi->lanes >= 4)
+		mask |= (1 << 11);
+	for (timeout = (1 << 10); timeout != 0; --timeout) {
+		usleep_range(10, 50);
+		if ((DSI_READ(DSI_PHY_STATUS) & mask) == mask)
+			break;
+	}
+	if (timeout == 0)
+		drm_err(dsi->drm, "RP1DSI: Time out waiting for lanes (%x %x)\n",
+			mask, DSI_READ(DSI_PHY_STATUS));
+}
+
+void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf,
+		     bool use_lpm, bool req_ack)
+{
+	u32 val;
+
+	/* Wait for both FIFOs empty */
+	for (val = 256; val > 0; --val) {
+		if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5)
+			break;
+		usleep_range(100, 150);
+	}
+
+	/*
+	 * Update global configuration flags for LP/HS and ACK options.
+	 * XXX It's not clear if having empty FIFOs (checked above and below) guarantees that
+	 * the last command has completed and been ACKed, or how closely these control registers
+	 * align with command/payload FIFO writes (as each is an independent clock-crossing)?
+	 */
+	val = DSI_READ(DSI_VID_MODE_CFG);
+	if (use_lpm)
+		val |= DSI_VID_MODE_LP_CMD_EN;
+	else
+		val &= ~DSI_VID_MODE_LP_CMD_EN;
+	DSI_WRITE(DSI_VID_MODE_CFG, val);
+	val = (use_lpm) ? DSI_CMD_MODE_ALL_LP : 0;
+	if (req_ack)
+		val |= DSI_CMD_MODE_ACK_RQST_EN;
+	DSI_WRITE(DSI_CMD_MODE_CFG, val);
+	(void)DSI_READ(DSI_CMD_MODE_CFG);
+
+	/* Write payload (in 32-bit words) and header */
+	for (; len > 0; len -= 4) {
+		val = *buf++;
+		if (len > 1)
+			val |= (*buf++) << 8;
+		if (len > 2)
+			val |= (*buf++) << 16;
+		if (len > 3)
+			val |= (*buf++) << 24;
+		DSI_WRITE(DSI_GEN_PLD_DATA, val);
+	}
+	DSI_WRITE(DSI_GEN_HDR, hdr);
+
+	/* Wait for both FIFOs empty */
+	for (val = 256; val > 0; --val) {
+		if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5)
+			break;
+		usleep_range(100, 150);
+	}
+}
+
+int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf)
+{
+	int i, j;
+	u32 val;
+
+	/* Wait until not busy and FIFO not empty */
+	for (i = 1024; i > 0; --i) {
+		val = DSI_READ(DSI_CMD_PKT_STATUS);
+		if ((val & ((1 << 6) | (1 << 4))) == 0)
+			break;
+		usleep_range(100, 150);
+	}
+	if (!i) {
+		drm_warn(dsi->drm, "Receive failed\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < len; i += 4) {
+		/* Read fifo must not be empty before all bytes are read */
+		if (DSI_READ(DSI_CMD_PKT_STATUS) & (1 << 4))
+			break;
+
+		val = DSI_READ(DSI_GEN_PLD_DATA);
+		for (j = 0; j < 4 && j + i < len; j++)
+			*buf++ = val >> (8 * j);
+	}
+
+	return (i >= len) ? len : (i > 0) ? i : -EIO;
+}
+
+void rp1dsi_dsi_stop(struct rp1_dsi *dsi)
+{
+	DSI_WRITE(DSI_MODE_CFG, 1);	/* Return to Command Mode */
+	DSI_WRITE(DSI_LPCLK_CTRL, 2);	/* Stop the HS clock */
+	DSI_WRITE(DSI_PWR_UP, 0x0);     /* Power down host controller */
+	DSI_WRITE(DSI_PHYRSTZ, 0);      /* PHY into reset. */
+	rp1dsi_dpiclk_stop(dsi);
+}
+
+void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int mode)
+{
+	DSI_WRITE(DSI_MODE_CFG, mode);
+}
