[PATCH 24/42] drm/mediatek: Add support for MediaTek Digital Video Output (DVO)

AngeloGioacchino Del Regno angelogioacchino.delregno at collabora.com
Wed Jul 1 05:20:39 PDT 2026


Add a new driver for the Digital Video Output (DVO) hardware found
in the MT8189, MT8196 Kompanio SoCs and their Dimensity and Genio
variants.

This version currently supports output to Embedded DisplayPort on
MT8189 and MT8196, and to DisplayPort on MT8189.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
---
 drivers/gpu/drm/mediatek/Makefile         |   1 +
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c   |   8 +
 drivers/gpu/drm/mediatek/mtk_disp_drv.h   |   4 +
 drivers/gpu/drm/mediatek/mtk_dpi_common.c |   5 +
 drivers/gpu/drm/mediatek/mtk_dpi_common.h |  23 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.c    |  11 +
 drivers/gpu/drm/mediatek/mtk_drm_drv.h    |   1 +
 drivers/gpu/drm/mediatek/mtk_dvo.c        | 682 ++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dvo_regs.h   | 192 ++++++
 include/linux/soc/mediatek/mtk-mmsys.h    |   1 +
 10 files changed, 928 insertions(+)
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dvo.c
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dvo_regs.h

diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 34a1d4721b70..c48ac3ab08cc 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -17,6 +17,7 @@ mediatek-drm-y := mtk_crtc.o \
 		  mtk_dsi.o \
 		  mtk_dpi_common.o \
 		  mtk_dpi.o \
+		  mtk_dvo.o \
 		  mtk_ethdr.o \
 		  mtk_mdp_rdma.o \
 		  mtk_padding.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 3be891f740d3..f8687f161953 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -290,6 +290,12 @@ static const struct mtk_ddp_comp_funcs ddp_dsi = {
 	.encoder_index = mtk_dsi_encoder_index,
 };
 
+static const struct mtk_ddp_comp_funcs ddp_dvo = {
+	.start = mtk_dvo_start,
+	.stop = mtk_dvo_stop,
+	.encoder_index = mtk_dvo_encoder_index,
+};
+
 static const struct mtk_ddp_comp_funcs ddp_gamma = {
 	.clk_enable = mtk_gamma_clk_enable,
 	.clk_disable = mtk_gamma_clk_disable,
@@ -430,6 +436,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
 	[MTK_DISP_DP_INTF] = "dp-intf",
 	[MTK_DISP_DPI] = "dpi",
 	[MTK_DISP_DSI] = "dsi",
+	[MTK_DISP_DVO] = "dvo",
 };
 
 static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
@@ -453,6 +460,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
 	[MTK_DISP_DPI]			= &ddp_dpi,
 	[MTK_DISP_DP_INTF]		= &ddp_dpi,
 	[MTK_DISP_DSI]			= &ddp_dsi,
+	[MTK_DISP_DVO]			= &ddp_dvo,
 };
 
 static bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index c4b44b761633..abdce23fab17 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -63,6 +63,10 @@ void mtk_dsi_ddp_stop(struct device *dev);
 unsigned int mtk_dsi_encoder_index(struct device *dev);
 struct drm_dsc_config *mtk_dsi_get_dsc_config(struct device *dev);
 
+void mtk_dvo_start(struct device *dev);
+void mtk_dvo_stop(struct device *dev);
+unsigned int mtk_dvo_encoder_index(struct device *dev);
+
 int mtk_gamma_clk_enable(struct device *dev);
 void mtk_gamma_clk_disable(struct device *dev);
 void mtk_gamma_config(struct device *dev, unsigned int w,
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_common.c b/drivers/gpu/drm/mediatek/mtk_dpi_common.c
index b9e7b053d278..01bfbe4b5863 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_common.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_common.c
@@ -152,6 +152,11 @@ int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, struct videomode *vm,
 	sync->hsync.front_porch = vm->hfront_porch / dpi->conf->pixels_per_iter;
 	sync->hsync.shift_half_line = false;
 
+	if (dpi->conf->quirk_hfp_bs_fix) {
+		sync->hsync.back_porch += sync->hsync.front_porch;
+		sync->hsync.front_porch = 0;
+	}
+
 	sync->vsync_l_odd.sync_width = vm->vsync_len;
 	sync->vsync_l_odd.back_porch = vm->vback_porch;
 	sync->vsync_l_odd.front_porch = vm->vfront_porch;
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_common.h b/drivers/gpu/drm/mediatek/mtk_dpi_common.h
index c5cc26c7900d..af51efa4c9ea 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_common.h
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_common.h
@@ -17,6 +17,25 @@
 #include <drm/drm_modes.h>
 #include <video/videomode.h>
 
+enum mtk_dpi_golden_setting_level {
+	MTK_DPI_FHD_60FPS_1920 = 0,
+	MTK_DPI_FHD_60FPS_2180,
+	MTK_DPI_FHD_60FPS_2400,
+	MTK_DPI_FHD_60FPS_2520,
+	MTK_DPI_FHD_90FPS,
+	MTK_DPI_FHD_120FPS,
+	MTK_DPI_WQHD_60FPS,
+	MTK_DPI_WQHD_120FPS,
+	MTK_DPI_8K_30FPS,
+	MTK_DPI_GSL_MAX,
+};
+
+struct mtk_dpi_gs_info {
+	u32 dpi_buf_sodi_high;
+	u32 dpi_buf_sodi_low;
+};
+
+
 enum mtk_dpi_out_bit_num {
 	MTK_DPI_OUT_BIT_NUM_8BITS,
 	MTK_DPI_OUT_BIT_NUM_10BITS,
@@ -65,6 +84,7 @@ struct mtk_dpi {
 	enum mtk_dpi_out_yc_map yc_map;
 	enum mtk_dpi_out_bit_num bit_num;
 	enum mtk_dpi_out_channel_swap channel_swap;
+	enum mtk_dpi_golden_setting_level gs_level;
 	struct pinctrl *pinctrl;
 	struct pinctrl_state *pins_gpio;
 	struct pinctrl_state *pins_dpi;
@@ -137,6 +157,8 @@ struct mtk_dpi_factor {
  *		     for DPI registers access.
  * @output_1pixel: Enable outputting one pixel per round; if the input is two pixel per
  *                 round, the DPI hardware will internally transform it to 1T1P.
+ * @quirk_hfp_bs_fix: Set back porch as back+front and use front porch as an adjustment
+ *                    setting (usually zero) to fix DisplayPort BS generation.
  */
 struct mtk_dpi_conf {
 	const struct mtk_dpi_factor *dpi_factor;
@@ -159,6 +181,7 @@ struct mtk_dpi_conf {
 	bool edge_cfg_in_mmsys;
 	bool clocked_by_hdmi;
 	bool output_1pixel;
+	bool quirk_hfp_bs_fix;
 };
 
 static inline struct mtk_dpi *bridge_to_dpi(struct drm_bridge *b)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index f7cbf9b47672..ee835ebbc18c 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -621,8 +621,17 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
 	  .data = (void *)MTK_DISP_DSI },
 	{ .compatible = "mediatek,mt8188-dsi",
 	  .data = (void *)MTK_DISP_DSI },
+<<<<<<< HEAD
 	{ .compatible = "mediatek,mt8196-dsi",
 	  .data = (void *)MTK_DISP_DSI },
+=======
+	{ .compatible = "mediatek,mt8189-dp-dvo",
+	  .data = (void *)MTK_DISP_DVO },
+	{ .compatible = "mediatek,mt8189-edp-dvo",
+	  .data = (void *)MTK_DISP_DVO },
+	{ .compatible = "mediatek,mt8196-edp-dvo",
+	  .data = (void *)MTK_DISP_DVO },
+>>>>>>> 60b3d568ba69 (drm/mediatek: Add support for MediaTek Digital Video Output (DVO))
 	{ }
 };
 
@@ -776,6 +785,7 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
 	case MTK_DISP_DP_INTF:
 	case MTK_DISP_DPI:
 	case MTK_DISP_DSI:
+	case MTK_DISP_DVO:
 		break;
 	default:
 		dev_err(dev, "Invalid display hw pipeline. Last component: %u-%u (ret=%d)\n",
@@ -1059,6 +1069,7 @@ static struct platform_driver * const mtk_drm_drivers[] = {
 	&mtk_disp_rdma_driver,
 	&mtk_disp_wdma_driver,
 	&mtk_dpi_driver,
+	&mtk_dvo_driver,
 	&mtk_drm_platform_driver,
 	&mtk_dsi_driver,
 	&mtk_ethdr_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index d86175180e11..4028268b3cc8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -84,6 +84,7 @@ extern struct platform_driver mtk_disp_rdma_driver;
 extern struct platform_driver mtk_disp_wdma_driver;
 extern struct platform_driver mtk_dpi_driver;
 extern struct platform_driver mtk_dsi_driver;
+extern struct platform_driver mtk_dvo_driver;
 extern struct platform_driver mtk_ethdr_driver;
 extern struct platform_driver mtk_mdp_rdma_driver;
 extern struct platform_driver mtk_padding_driver;
diff --git a/drivers/gpu/drm/mediatek/mtk_dvo.c b/drivers/gpu/drm/mediatek/mtk_dvo.c
new file mode 100644
index 000000000000..a373db355234
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dvo.c
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek Digital Video Out
+ *
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno at collabora.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/media-bus-format.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+#include <linux/types.h>
+
+#include <video/videomode.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_print.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "mtk_drm_drv.h"
+#include "mtk_crtc.h"
+#include "mtk_disp_drv.h"
+#include "mtk_dpi_common.h"
+#include "mtk_dvo_regs.h"
+
+#define MTK_DVO_OUT_PIXITER_1T1P		0
+#define MTK_DVO_OUT_PIXITER_1T2P		1
+#define MTK_DVO_OUT_PIXITER_1T4P		2
+
+/* DVO INPUT default value is 1T2P */
+#define MTK_DVO_INPUT_MODE			2
+/* DVO OUTPUT value is 1T4P*/
+#define MTK_DVO_OUTPUT_MODE			4
+/* 1 unit = 2 group data = 2 * 1T4P = 8P */
+#define MTK_DISP_BUF_SRAM_UNIT_SIZE		8
+#define MTK_DISP_LINE_BUF_DVO_US		40
+#define MTK_BLANKING_RATIO			1
+#define MTK_DVO_EDP_MAX_CLK			297
+#define MTK_DVO_MAX_HACTIVE			3840
+#define MTK_DVO_LINE_BUFFER_SIZE		(MTK_DVO_MAX_HACTIVE / MTK_DISP_BUF_SRAM_UNIT_SIZE)
+#define MTK_DVO_BITS_PER_CYCLE			(8 * 32 * 1000000)
+#define TWAIT_SLEEP				1
+#define TWAKE_UP				5
+#define PREULTRA_HIGH_US			26
+#define PREULTRA_LOW_US				25
+#define ULTRA_HIGH_US				25
+#define ULTRA_LOW_US				23
+#define URGENT_HIGH_US				12
+#define URGENT_LOW_US				11
+
+static struct mtk_dpi_gs_info mtk_dvo_gs[MTK_DPI_GSL_MAX] = {
+	[MTK_DPI_FHD_60FPS_1920] = { 6880, 511 },
+	[MTK_DPI_8K_30FPS] = { 5255, 3899 },
+};
+
+static void mtk_dvo_test_pattern_en(struct mtk_dpi *dpi, u8 type, bool enable)
+{
+	u32 val;
+
+	if (enable)
+		val = FIELD_PREP(PRE_PAT_SEL_MASK, type) | PRE_PAT_EN | PRE_PAT_FORCE_ON;
+	else
+		val = 0;
+
+	mtk_dpi_mask(dpi, DVO_PATTERN_CTRL, val, PRE_PAT_SEL_MASK | PRE_PAT_FORCE_ON | PRE_PAT_EN);
+}
+
+static void mtk_dvo_sw_reset(struct mtk_dpi *dvo, bool reset)
+{
+	mtk_dpi_mask(dvo, DVO_RET, reset ? SWRST : 0, SWRST);
+}
+
+static void mtk_dvo_enable(struct mtk_dpi *dvo)
+{
+	mtk_dpi_mask(dvo, DVO_EN, EN, EN);
+}
+
+static void mtk_dvo_disable(struct mtk_dpi *dvo)
+{
+	mtk_dpi_mask(dvo, DVO_EN, 0, EN);
+}
+
+static void mtk_dvo_irq_enable(struct mtk_dpi *dvo)
+{
+	mtk_dpi_mask(dvo, DVO_INTEN, INT_VDE_END_EN | UNDERFLOW_EN,
+		     INT_VDE_END_EN | UNDERFLOW_EN);
+}
+
+static void mtk_dvo_info_queue_start(struct mtk_dpi *dvo)
+{
+	mtk_dpi_mask(dvo, DVO_TGEN_INFOQ_LATENCY, 0,
+		     INFOQ_START_LATENCY_MASK | INFOQ_END_LATENCY_MASK);
+}
+
+static void mtk_dpi_buffer_ctrl(struct mtk_dpi *dvo)
+{
+	mtk_dpi_mask(dvo, DVO_BUF_CON0, DISP_BUF_EN, DISP_BUF_EN);
+	mtk_dpi_mask(dvo, DVO_BUF_CON0, FIFO_UNDERFLOW_DONE_BLOCK, FIFO_UNDERFLOW_DONE_BLOCK);
+}
+
+static void mtk_dvo_trailing_blank_setting(struct mtk_dpi *dvo)
+{
+	mtk_dpi_mask(dvo, DVO_TGEN_V_LAST_TRAILING_BLANK, 0x20, V_LAST_TRAILING_BLANK_MASK);
+	mtk_dpi_mask(dvo, DVO_TGEN_OUTPUT_DELAY_LINE, 0x20, EXT_TG_DLY_LINE_MASK);
+}
+
+static void mtk_dvo_get_gs_level(struct mtk_dpi *dvo)
+{
+	struct drm_display_mode *mode = &dvo->mode;
+	enum mtk_dpi_golden_setting_level *gsl = &dvo->gs_level;
+
+	if (mode->hdisplay <= 1920 && mode->vdisplay <= 1080)
+		*gsl = MTK_DPI_FHD_60FPS_1920;
+	else
+		*gsl = MTK_DPI_8K_30FPS;
+}
+
+static void mtk_dvo_sodi_setting(struct mtk_dpi *dvo, struct drm_display_mode *mode)
+{
+	const u64 sodi_total = MTK_DVO_BITS_PER_CYCLE * MTK_DISP_BUF_SRAM_UNIT_SIZE * 32ULL;
+	u64 preultra_high, preultra_low, ultra_high, ultra_low, urgent_high, urgent_low;
+	u64 sodi_high, sodi_low, sodi_high_rem, sodi_low_rem, tmp;
+	u64 dvo_fifo_size, fifo_size, total_bit;
+	u64 consume_rate, consume_rate_rem;
+	u64 fill_rate_rem, fill_rate;
+	u64 data_rate;
+	u32 mmsys_clk;
+
+	mmsys_clk = mode->clock / 1000;
+	if (!mmsys_clk) {
+		dev_err(dvo->dev, "mmclk is zero, use default value\n");
+		mmsys_clk = 273;
+	}
+
+	fill_rate = div64_u64_rem(mmsys_clk * MTK_DVO_INPUT_MODE * 30,
+		    		  32ULL * MTK_DISP_BUF_SRAM_UNIT_SIZE, &fill_rate_rem);
+	data_rate = (u64)mode->hdisplay * mode->vdisplay *
+		    div64_u64((u64)mode->clock * 1000, ((u64)mode->htotal * mode->vtotal));
+	consume_rate = div64_u64_rem(((data_rate * 30 * 5) / 4),
+				       MTK_DVO_BITS_PER_CYCLE, &consume_rate_rem);
+	total_bit = (u64)MTK_DVO_EDP_MAX_CLK * MTK_DVO_OUTPUT_MODE * 30 *
+		     MTK_DISP_LINE_BUF_DVO_US;
+
+	fifo_size = total_bit / (MTK_DISP_BUF_SRAM_UNIT_SIZE * 30);
+
+	/* DVO supports MSO mode, so calculate with three line buffers */
+	dvo_fifo_size = fifo_size + (3 * MTK_DVO_LINE_BUFFER_SIZE);
+
+	/* 1 is to round up */
+	sodi_high_rem = (u64)fill_rate_rem * MTK_DVO_BITS_PER_CYCLE;
+	tmp = (u64)consume_rate_rem * (32 * MTK_DISP_BUF_SRAM_UNIT_SIZE);
+
+	if (sodi_high_rem < tmp) {
+		fill_rate -= 1;
+		sodi_high_rem += sodi_total;
+	}
+	sodi_high_rem -= tmp;
+	sodi_high_rem *= 32 * 6;
+	sodi_high_rem /= sodi_total;
+
+	sodi_high = ((dvo_fifo_size * 30 * 5) -
+		    (32 * 6 * (fill_rate - consume_rate)) -
+		    sodi_high_rem + (5 * 32 - 1)) / (5 * 32);
+
+	sodi_low_rem = consume_rate_rem * (ULTRA_LOW_US + TWAKE_UP) + MTK_DVO_BITS_PER_CYCLE - 1;
+	sodi_low_rem /= MTK_DVO_BITS_PER_CYCLE;
+
+	sodi_low = consume_rate * (ULTRA_LOW_US + TWAKE_UP) + sodi_low_rem;
+
+	preultra_high = consume_rate * PREULTRA_HIGH_US;
+	preultra_high += (consume_rate_rem * PREULTRA_HIGH_US + MTK_DVO_BITS_PER_CYCLE - 1)
+			 / MTK_DVO_BITS_PER_CYCLE;
+			
+	preultra_low = consume_rate * PREULTRA_LOW_US;
+	preultra_low += (consume_rate_rem * PREULTRA_LOW_US + MTK_DVO_BITS_PER_CYCLE - 1)
+			/ MTK_DVO_BITS_PER_CYCLE;
+
+	ultra_high = consume_rate * ULTRA_HIGH_US;
+	ultra_high += (consume_rate_rem * ULTRA_HIGH_US + MTK_DVO_BITS_PER_CYCLE - 1)
+		      / MTK_DVO_BITS_PER_CYCLE;
+
+	ultra_low = consume_rate * ULTRA_LOW_US;
+	ultra_low += (consume_rate_rem * ULTRA_LOW_US + MTK_DVO_BITS_PER_CYCLE - 1)
+		     / MTK_DVO_BITS_PER_CYCLE;
+
+	urgent_high = consume_rate * URGENT_HIGH_US;
+	urgent_high += (consume_rate_rem * URGENT_HIGH_US + MTK_DVO_BITS_PER_CYCLE - 1)
+		       / MTK_DVO_BITS_PER_CYCLE;
+
+	urgent_low = consume_rate * URGENT_LOW_US;
+	urgent_low += (consume_rate_rem * URGENT_LOW_US + MTK_DVO_BITS_PER_CYCLE - 1)
+		      / MTK_DVO_BITS_PER_CYCLE;
+
+	mtk_dpi_mask(dvo, DVO_BUF_SODI_HIGHT, sodi_high, DVO_DISP_BUF_MASK);
+	mtk_dpi_mask(dvo, DVO_BUF_SODI_LOW, sodi_low, DVO_DISP_BUF_MASK);
+	mtk_dpi_mask(dvo, DVO_BUF_PREULTRA_HIGHT, preultra_high, DVO_DISP_BUF_MASK);
+	mtk_dpi_mask(dvo, DVO_BUF_PREULTRA_LOW, preultra_low, DVO_DISP_BUF_MASK);
+	mtk_dpi_mask(dvo, DVO_BUF_ULTRA_HIGHT, ultra_high, DVO_DISP_BUF_MASK);
+	mtk_dpi_mask(dvo, DVO_BUF_ULTRA_LOW, ultra_low, DVO_DISP_BUF_MASK);
+	mtk_dpi_mask(dvo, DVO_BUF_URGENT_HIGHT, urgent_high, DVO_DISP_BUF_MASK);
+	mtk_dpi_mask(dvo, DVO_BUF_URGENT_LOW, urgent_low, DVO_DISP_BUF_MASK);
+}
+
+static void mtk_dvo_golden_setting(struct mtk_dpi *dvo)
+{
+	struct mtk_dpi_gs_info *gs_info = NULL;
+
+	if (dvo->gs_level >= MTK_DPI_GSL_MAX) {
+		dev_err(dvo->dev, "Invalid Golden Setting level %d\n", dvo->gs_level);
+		return;
+	}
+
+	gs_info = &mtk_dvo_gs[dvo->gs_level];
+
+	mtk_dpi_mask(dvo, DVO_BUF_SODI_HIGHT, gs_info->dpi_buf_sodi_high, GENMASK(31, 0));
+	mtk_dpi_mask(dvo, DVO_BUF_SODI_LOW, gs_info->dpi_buf_sodi_low, GENMASK(31, 0));
+}
+
+static void mtk_dvo_config_hsync(struct mtk_dpi *dvo,
+				 struct mtk_dpi_sync_param *sync)
+{
+	mtk_dpi_mask(dvo, DVO_TGEN_H0, sync->sync_width << HSYNC,
+		     dvo->conf->dimension_mask << HSYNC);
+	mtk_dpi_mask(dvo, DVO_TGEN_H0, sync->front_porch << HFP,
+		     dvo->conf->dimension_mask << HFP);
+	mtk_dpi_mask(dvo, DVO_TGEN_H1, (sync->back_porch + sync->sync_width) << HSYNC2ACT,
+		     dvo->conf->dimension_mask << HSYNC2ACT);
+}
+
+static void mtk_dvo_config_vsync(struct mtk_dpi *dvo,
+				 struct mtk_dpi_sync_param *sync,
+				 u32 width_addr, u32 porch_addr)
+{
+	mtk_dpi_mask(dvo, width_addr,
+		     sync->sync_width << VSYNC,
+		     dvo->conf->dimension_mask << VSYNC);
+	mtk_dpi_mask(dvo, width_addr,
+		     sync->front_porch << VFP,
+		     dvo->conf->dimension_mask << VFP);
+	mtk_dpi_mask(dvo, porch_addr,
+		     (sync->back_porch + sync->sync_width) << VSYNC2ACT,
+	     dvo->conf->dimension_mask << VSYNC2ACT);
+}
+
+static void mtk_dvo_config_interface(struct mtk_dpi *dvo, bool inter)
+{
+	mtk_dpi_mask(dvo, DVO_CON, inter ? INTL_EN : 0, INTL_EN);
+}
+
+static void mtk_dvo_config_fb_size(struct mtk_dpi *dvo, u32 width, u32 height)
+{
+	mtk_dpi_mask(dvo, DVO_SRC_SIZE, width << SRC_HSIZE,
+		     dvo->conf->hvsize_mask << SRC_HSIZE);
+	mtk_dpi_mask(dvo, DVO_SRC_SIZE, height << SRC_VSIZE,
+		     dvo->conf->hvsize_mask << SRC_VSIZE);
+
+	mtk_dpi_mask(dvo, DVO_PIC_SIZE, width << PIC_HSIZE,
+		     dvo->conf->hvsize_mask << PIC_HSIZE);
+	mtk_dpi_mask(dvo, DVO_PIC_SIZE, height << PIC_VSIZE,
+		     dvo->conf->hvsize_mask << PIC_VSIZE);
+
+	mtk_dpi_mask(dvo, DVO_TGEN_H1, DIV_ROUND_UP(width, dvo->conf->pixels_per_iter) << HACT,
+		     dvo->conf->hvsize_mask << HACT);
+	mtk_dpi_mask(dvo, DVO_TGEN_V1, height << VACT,
+		     dvo->conf->hvsize_mask << VACT);
+}
+
+static void mtk_dvo_config_channel_limit(struct mtk_dpi *dpi, struct mtk_dpi_yc_limit *limit)
+{
+	mtk_dpi_mask(dpi, DVO_Y_LIMIT, FIELD_PREP(Y_LMT_BOT, limit->y_bottom), Y_LMT_BOT);
+	mtk_dpi_mask(dpi, DVO_Y_LIMIT, FIELD_PREP(Y_LMT_TOP, limit->y_top), Y_LMT_TOP);
+	mtk_dpi_mask(dpi, DVO_C_LIMIT, FIELD_PREP(C_LMT_BOT, limit->c_bottom), C_LMT_BOT);
+	mtk_dpi_mask(dpi, DVO_C_LIMIT, FIELD_PREP(C_LMT_TOP, limit->c_top), C_LMT_TOP);
+}
+
+static void mtk_dvo_config_channel_swap(struct mtk_dpi *dpi,
+					enum mtk_dpi_out_channel_swap swap)
+{
+	u32 val;
+
+	switch (swap) {
+	case MTK_DPI_OUT_CHANNEL_SWAP_RGB:
+		val = SWAP_RGB;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_GBR:
+		val = SWAP_GBR;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_BRG:
+		val = SWAP_BRG;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_RBG:
+		val = SWAP_RBG;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_GRB:
+		val = SWAP_GRB;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_BGR:
+		val = SWAP_BGR;
+		break;
+	default:
+		val = SWAP_RGB;
+		break;
+	}
+
+	mtk_dpi_mask(dpi, DVO_OUTPUT_SET, FIELD_PREP(CH_SWAP_MASK, val), CH_SWAP_MASK);
+	return;
+}
+
+static void mtk_dvo_config_csc_enable(struct mtk_dpi *dvo, bool enable)
+{
+	mtk_dpi_mask(dvo, DVO_MATRIX_SET, enable ? BIT(1) : 0, DVO_INT_MTX_SEL_MASK);
+	mtk_dpi_mask(dvo, DVO_MATRIX_SET, enable ? DVO_CSC_EN : 0, DVO_CSC_EN);
+}
+
+static void mtk_dvo_config_yuv422_enable(struct mtk_dpi *dvo, bool enable)
+{
+	mtk_dpi_mask(dvo, DVO_YUV422_SET, enable ? DVO_YUV422_EN : 0, DVO_YUV422_EN);
+	mtk_dpi_mask(dvo, DVO_YUV422_SET, enable ? DVO_CRYCB_MAP : 0, DVO_CRYCB_MAP);
+}
+
+static void mtk_dvo_set_output_pixiter(struct mtk_dpi *dvo)
+{
+	u32 val;
+
+	switch (dvo->conf->pixels_per_iter) {
+	default:
+	case 0:
+	case 1:
+		val = MTK_DVO_OUT_PIXITER_1T1P;
+		break;
+	case 2:
+		val = MTK_DVO_OUT_PIXITER_1T2P;
+		break;
+	case 3:
+	case 4:
+		val = MTK_DVO_OUT_PIXITER_1T4P;
+		break;
+	}
+
+	/* Enable register shadow only when more than 1 pixel per iteration */
+	if (val > MTK_DVO_OUT_PIXITER_1T1P) {
+		mtk_dpi_mask(dvo, DVO_SHADOW_CTRL, 0, BYPASS_SHADOW);
+		mtk_dpi_mask(dvo, DVO_SHADOW_CTRL, FORCE_COMMIT, FORCE_COMMIT);
+	};
+
+	mtk_dpi_mask(dvo, DVO_OUTPUT_SET, val, OUT_NP_SEL);
+	return;
+}
+
+static void mtk_dvo_config_color_format(struct mtk_dpi *dvo,
+					enum mtk_dpi_out_color_format format)
+{
+	mtk_dvo_config_channel_swap(dvo, dvo->channel_swap);
+
+	dev_err(dvo->dev, "[DPTX] format:%d", format);
+
+	switch (format) {
+	case MTK_DPI_COLOR_FORMAT_YCBCR_444:
+		mtk_dvo_config_yuv422_enable(dvo, false);
+		mtk_dvo_config_csc_enable(dvo, true);
+		break;
+	case MTK_DPI_COLOR_FORMAT_YCBCR_422:
+		mtk_dvo_config_yuv422_enable(dvo, true);
+		mtk_dvo_config_csc_enable(dvo, true);
+		break;
+	case MTK_DPI_COLOR_FORMAT_RGB:
+	default:
+		mtk_dvo_config_yuv422_enable(dvo, false);
+		mtk_dvo_config_csc_enable(dvo, false);
+		break;
+	}
+}
+
+static void mtk_dpi_config_pol(struct mtk_dpi *dpi,
+			       struct mtk_dpi_polarities *dpi_pol)
+{
+	u32 pol;
+
+	pol = (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HS_INV) |
+	      (dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VS_INV);
+
+	mtk_dpi_mask(dpi, DVO_OUTPUT_SET, pol, HS_INV | VS_INV);
+}
+
+static void mtk_dvo_config_hw(struct mtk_dpi *dvo,
+			      struct videomode *vm, struct mtk_dpi_sync *sync,
+			      struct mtk_dpi_polarities *dpi_pol,
+			      struct mtk_dpi_yc_limit *limit)
+{
+	struct drm_display_mode *mode = &dvo->mode;
+	u32 vactive = vm->vactive;
+
+	mtk_dvo_sw_reset(dvo, true);
+
+	mtk_dvo_irq_enable(dvo);
+
+	mtk_dpi_config_pol(dvo, dpi_pol);
+
+	mtk_dvo_config_hsync(dvo, &sync->hsync);
+	mtk_dvo_config_vsync(dvo, &sync->vsync_l_odd, DVO_TGEN_V0, DVO_TGEN_V1);
+	mtk_dvo_config_vsync(dvo, &sync->vsync_l_even, DVO_TGEN_V_EVEN0, DVO_TGEN_V_EVEN1);
+
+	mtk_dvo_config_interface(dvo, !!(vm->flags & DISPLAY_FLAGS_INTERLACED));
+
+	if (vm->flags & DISPLAY_FLAGS_INTERLACED)
+		vactive >>= 1;
+
+	mtk_dvo_config_fb_size(dvo, vm->hactive, vactive);
+
+	mtk_dvo_config_channel_limit(dvo, limit);
+	mtk_dvo_config_channel_swap(dvo, dvo->channel_swap);
+	mtk_dvo_config_color_format(dvo, dvo->color_format);
+
+	mtk_dvo_info_queue_start(dvo);
+	mtk_dpi_buffer_ctrl(dvo);
+
+	mtk_dvo_trailing_blank_setting(dvo);
+	mtk_dvo_get_gs_level(dvo);
+	mtk_dvo_golden_setting(dvo);
+	mtk_dvo_sodi_setting(dvo, mode);
+
+	mtk_dvo_set_output_pixiter(dvo);
+
+	mtk_dvo_sw_reset(dvo, false);
+
+	return;
+}
+
+static int mtk_dvo_bridge_attach(struct drm_bridge *bridge,
+				 struct drm_encoder *encoder,
+				 enum drm_bridge_attach_flags flags)
+{
+	struct mtk_dpi *dvo = bridge_to_dpi(bridge);
+	int ret;
+
+	ret = drm_bridge_attach(bridge->encoder, dvo->next_bridge,
+				&dvo->bridge, 1);
+	if (ret)
+		dev_err(dvo->dev, "Failed to attach bridge: %d\n", ret);
+
+	return ret;
+}
+
+static void mtk_dvo_bridge_disable(struct drm_bridge *bridge)
+{
+	struct mtk_dpi *dvo = bridge_to_dpi(bridge);
+
+	mtk_dvo_disable(dvo);
+	mtk_dpi_power_off(dvo);
+}
+
+static void mtk_dvo_bridge_enable(struct drm_bridge *bridge)
+{
+	struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+	struct mtk_dpi_polarities dpi_pol;
+	struct mtk_dpi_sync sync = { 0 };
+	struct mtk_dpi_yc_limit limit;
+	struct videomode vm;
+
+	if (dpi->pinctrl && dpi->pins_dpi)
+		pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
+
+	mtk_dpi_power_on(dpi);
+
+	/* Set pixel clock and initialize parameters to send to the HW */
+	mtk_dpi_set_display_mode(dpi, &vm, &sync, &dpi_pol, &limit);
+
+	/* Format and send the parameters to the HW */
+	mtk_dvo_config_hw(dpi, &vm, &sync, &dpi_pol, &limit);
+
+	mtk_dvo_enable(dpi);
+}
+
+static enum drm_mode_status
+mtk_dvo_bridge_mode_valid(struct drm_bridge *bridge,
+			  const struct drm_display_info *info,
+			  const struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static int mtk_dvo_debug_tp_show(struct seq_file *m, void *arg)
+{
+	struct mtk_dpi *dvo = m->private;
+	bool en;
+	u32 val;
+
+	if (!dvo)
+		return -EINVAL;
+
+	val = readl(dvo->regs + DVO_PATTERN_CTRL);
+	en = (val & (PRE_PAT_EN | PRE_PAT_FORCE_ON)) == (PRE_PAT_EN | PRE_PAT_FORCE_ON);
+	val = FIELD_GET(PRE_PAT_SEL_MASK, val);
+
+	return mtk_dpi_common_debug_tp_show(m, en, val);
+}
+
+static ssize_t mtk_dvo_debug_tp_write(struct file *file, const char __user *ubuf,
+				      size_t len, loff_t *offp)
+{
+	struct seq_file *m = file->private_data;
+	u32 en, type;
+	ssize_t ret;
+
+	/* seq_file and dvo pointers are checked by mtk_dpi_common_debug_tp_write() */
+	ret = mtk_dpi_common_debug_tp_write(file, ubuf, len, offp, &en, &type);
+	if (ret < 0)
+		return ret;
+
+	mtk_dvo_test_pattern_en((struct mtk_dpi *)m->private, type, en);
+	return ret;
+}
+
+static int mtk_dvo_debug_tp_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mtk_dvo_debug_tp_show, inode->i_private);
+}
+
+static const struct file_operations mtk_dvo_debug_tp_fops = {
+	.owner = THIS_MODULE,
+	.open = mtk_dvo_debug_tp_open,
+	.read = seq_read,
+	.write = mtk_dvo_debug_tp_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static void mtk_dvo_debugfs_init(struct drm_bridge *bridge, struct dentry *root)
+{
+	struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+
+	debugfs_create_file("dvo_test_pattern", 0640, root, dpi, &mtk_dvo_debug_tp_fops);
+}
+
+static const struct drm_bridge_funcs mtk_dvo_bridge_funcs = {
+	.attach = mtk_dvo_bridge_attach,
+	.mode_set = mtk_dpi_bridge_mode_set,
+	.mode_valid = mtk_dvo_bridge_mode_valid,
+	.disable = mtk_dvo_bridge_disable,
+	.enable = mtk_dvo_bridge_enable,
+	.atomic_check = mtk_dpi_bridge_atomic_check,
+	.atomic_get_output_bus_fmts = mtk_dpi_bridge_atomic_get_output_bus_fmts,
+	.atomic_get_input_bus_fmts = mtk_dpi_bridge_atomic_get_input_bus_fmts,
+	.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,
+	.debugfs_init = mtk_dvo_debugfs_init,
+};
+
+void mtk_dvo_start(struct device *dev)
+{
+	struct mtk_dpi *dvo = dev_get_drvdata(dev);
+
+	mtk_dpi_power_on(dvo);
+}
+
+void mtk_dvo_stop(struct device *dev)
+{
+	struct mtk_dpi *dvo = dev_get_drvdata(dev);
+
+	mtk_dvo_disable(dvo);
+	mtk_dpi_power_off(dvo);
+}
+
+unsigned int mtk_dvo_encoder_index(struct device *dev)
+{
+	struct mtk_dpi *dvo = dev_get_drvdata(dev);
+
+	return drm_encoder_index(&dvo->encoder);
+}
+
+static const struct component_ops mtk_dvo_component_ops = {
+	.bind = mtk_dpi_common_bind,
+	.unbind = mtk_dpi_common_unbind,
+};
+
+static const struct mtk_dpi_factor dpi_factor_mt8196_dvo[] = {
+	{ 70000 - 1, 4 }, { 200000 - 1, 2 }, { U32_MAX, 1 }
+};
+
+static const u32 mt8196_output_fmts[] = {
+	MEDIA_BUS_FMT_RGB888_1X24,
+	MEDIA_BUS_FMT_RGB888_2X12_LE,
+	MEDIA_BUS_FMT_RGB888_2X12_BE,
+	MEDIA_BUS_FMT_RGB101010_1X30,
+	MEDIA_BUS_FMT_YUYV8_1X16,
+	MEDIA_BUS_FMT_YUYV10_1X20,
+	MEDIA_BUS_FMT_YUYV12_1X24,
+	MEDIA_BUS_FMT_BGR888_1X24,
+	MEDIA_BUS_FMT_YUV8_1X24,
+	MEDIA_BUS_FMT_YUV10_1X30,
+};
+
+static const struct mtk_dpi_conf mt8189_conf = {
+	.dpi_factor = dpi_factor_mt8196_dvo,
+	.num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8196_dvo),
+	.reg_h_fre_con = 0xb0,
+	.max_clock_khz = 640000,
+	.output_fmts = mt8196_output_fmts,
+	.num_output_fmts = ARRAY_SIZE(mt8196_output_fmts),
+	.pixels_per_iter = 4,
+	.dimension_mask = HFP_MASK,
+	.hvsize_mask = PIC_HSIZE_MASK,
+};
+
+static const struct mtk_dpi_conf mt8189_dp_conf = {
+	.dpi_factor = dpi_factor_mt8196_dvo,
+	.num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8196_dvo),
+	.reg_h_fre_con = 0xb0,
+	.max_clock_khz = 640000,
+	.output_fmts = mt8196_output_fmts,
+	.num_output_fmts = ARRAY_SIZE(mt8196_output_fmts),
+	.pixels_per_iter = 4,
+	.dimension_mask = HFP_MASK,
+	.hvsize_mask = PIC_HSIZE_MASK,
+	.quirk_hfp_bs_fix = true,
+};
+
+static const struct mtk_dpi_conf mt8196_conf = {
+	.dpi_factor = dpi_factor_mt8196_dvo,
+	.num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8196_dvo),
+	.reg_h_fre_con = 0xb0,
+	.max_clock_khz = 600000,
+	.output_fmts = mt8196_output_fmts,
+	.num_output_fmts = ARRAY_SIZE(mt8196_output_fmts),
+	.pixels_per_iter = 4,
+	.dimension_mask = HFP_MASK,
+	.hvsize_mask = PIC_HSIZE_MASK,
+};
+
+static int mtk_dvo_probe(struct platform_device *pdev)
+{
+	struct mtk_dpi *dvo;
+	int ret;
+
+	dvo = mtk_dpi_common_probe(pdev, &mtk_dvo_bridge_funcs);
+	if (IS_ERR(dvo))
+		return PTR_ERR(dvo);
+
+	ret = component_add(&pdev->dev, &mtk_dvo_component_ops);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "Failed to add component.\n");
+
+	return 0;
+}
+
+static void mtk_dvo_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &mtk_dvo_component_ops);
+}
+
+static const struct of_device_id mtk_dvo_of_ids[] = {
+	{ .compatible = "mediatek,mt8189-dp-dvo", .data = &mt8189_dp_conf },
+	{ .compatible = "mediatek,mt8189-edp-dvo", .data = &mt8189_conf },
+	{ .compatible = "mediatek,mt8196-edp-dvo", .data = &mt8196_conf },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_dvo_of_ids);
+
+struct platform_driver mtk_dvo_driver = {
+	.probe = mtk_dvo_probe,
+	.remove = mtk_dvo_remove,
+	.driver = {
+		.name = "mediatek-dvo",
+		.of_match_table = mtk_dvo_of_ids,
+	},
+};
+MODULE_IMPORT_NS("DRM_MTK_DPI");
diff --git a/drivers/gpu/drm/mediatek/mtk_dvo_regs.h b/drivers/gpu/drm/mediatek/mtk_dvo_regs.h
new file mode 100644
index 000000000000..42a6f318d991
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dvo_regs.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Jie Qiu <jie.qiu at mediatek.com>
+ */
+#ifndef __MTK_DPI_REGS_H
+#define __MTK_DPI_REGS_H
+
+#define DVO_EN			0x00
+#define EN				BIT(0)
+#define DVO_FORCE_ON			BIT(4)
+#define LINK_OFF			BIT(8)
+#define DVO_RET			0x04
+#define SWRST				BIT(0)
+#define SWRST_SEL			BIT(4)
+#define DVO_INTEN		0x08
+#define INT_VFP_START_EN		BIT(0)
+#define INT_VSYNC_START_EN		BIT(1)
+#define INT_VSYNC_END_EN		BIT(2)
+#define INT_VDE_START_EN		BIT(3)
+#define INT_VDE_END_EN			BIT(4)
+#define INT_WR_INFOQ_REG_EN		BIT(5)
+#define INT_TARGET_LINE0_EN		BIT(6)
+#define INT_TARGET_LINE1_EN		BIT(7)
+#define INT_TARGET_LINE2_EN		BIT(8)
+#define INT_TARGET_LINE3_EN		BIT(9)
+#define INT_WR_INFOQ_START_EN		BIT(10)
+#define INT_WR_INFOQ_END_EN		BIT(11)
+#define EXT_VSYNC_START_EN		BIT(12)
+#define EXT_VSYNC_END_EN		BIT(13)
+#define EXT_VDE_START_EN		BIT(14)
+#define EXT_VDE_END_EN			BIT(15)
+#define EXT_VBLANK_END_EN		BIT(16)
+#define UNDERFLOW_EN			BIT(17)
+#define INFOQ_ABORT_EN			BIT(18)
+
+#define DVO_INTSTA		0x0c
+#define INT_VFP_START_STA		BIT(0)
+#define INT_VSYNC_START_STA		BIT(1)
+#define INT_VSYNC_END_STA		BIT(2)
+#define INT_VDE_START_STA		BIT(3)
+#define INT_VDE_END_STA			BIT(4)
+#define INT_WR_INFOQ_REG_STA		BIT(5)
+#define INT_TARGET_LINE0_STA		BIT(6)
+#define INT_TARGET_LINE1_STA		BIT(7)
+#define INT_TARGET_LINE2_STA		BIT(8)
+#define INT_TARGET_LINE3_STA		BIT(9)
+#define INT_WR_INFOQ_START_STA		BIT(10)
+#define INT_WR_INFOQ_END_STA		BIT(11)
+#define EXT_VSYNC_START_STA		BIT(12)
+#define EXT_VSYNC_END_STA		BIT(13)
+#define EXT_VDE_START_STA		BIT(14)
+#define EXT_VDE_END_STA			BIT(15)
+#define EXT_VBLANK_END_STA		BIT(16)
+#define INT_UNDERFLOW_STA		BIT(17)
+#define INFOQ_ABORT_STA			BIT(18)
+
+#define DVO_CON			0x10
+#define INTL_EN				BIT(0)
+
+#define DVO_OUTPUT_SET		0x18
+#define OUT_NP_SEL			(0x3 << 0)
+#define BIT_SWAP			BIT(4)
+#define CH_SWAP_MASK			GENMASK(7, 5)
+#define SWAP_RGB			0x00
+#define SWAP_GBR			0x01
+#define SWAP_BRG			0x02
+#define SWAP_RBG			0x03
+#define SWAP_GRB			0x04
+#define SWAP_BGR			0x05
+#define PXL_SWAP			BIT(8)
+#define R_MASK				BIT(12)
+#define G_MASK				BIT(13)
+#define B_MASK				BIT(14)
+#define DE_MASK				BIT(16)
+#define HS_MASK				BIT(17)
+#define VS_MASK				BIT(18)
+#define HS_INV				BIT(20)
+#define VS_INV				BIT(21)
+
+#define DVO_SRC_SIZE		0x20
+#define SRC_HSIZE			0
+#define SRC_HSIZE_MASK			(0xffff << 0)
+#define SRC_VSIZE			16
+#define SRC_VSIZE_MASK			(0xffff << 16)
+
+#define DVO_PIC_SIZE		0x24
+#define PIC_HSIZE			0
+#define PIC_HSIZE_MASK			(0xffff << 0)
+#define PIC_VSIZE			16
+#define PIC_VSIZE_MASK			(0xffff << 16)
+
+#define DVO_TGEN_H0		0x50
+#define HFP				0
+#define HFP_MASK			(0xffff << 0)
+#define HSYNC				16
+#define HSYNC_MASK			(0xffff << 16)
+
+#define DVO_TGEN_H1		0x54
+#define HSYNC2ACT			0
+#define HSYNC2ACT_MASK			(0xffff << 0)
+#define HACT				16
+#define HACT_MASK			(0xffff << 16)
+
+#define DVO_TGEN_V0		0x58
+#define DVO_TGEN_V_EVEN0	0x64
+#define VFP				0
+#define VFP_MASK			(0xffff << 0)
+#define VSYNC				16
+#define VSYNC_MASK			(0xffff << 16)
+
+#define DVO_TGEN_V1		0x5c
+#define DVO_TGEN_V_EVEN1	0x68
+#define VSYNC2ACT			0
+#define VSYNC2ACT_MASK			(0xffff << 0)
+#define VACT				16
+#define VACT_MASK			(0xffff << 16)
+
+#define DVO_TGEN_INFOQ_LATENCY	0x80
+#define INFOQ_START_LATENCY		0
+#define INFOQ_START_LATENCY_MASK	(0xffff << 0)
+#define INFOQ_END_LATENCY		16
+#define INFOQ_END_LATENCY_MASK		(0xffff << 16)
+
+#define DVO_BUF_CON0		0x220
+#define DISP_BUF_EN			BIT(0)
+#define FIFO_UNDERFLOW_DONE_BLOCK	BIT(4)
+
+
+#define DVO_TGEN_V_LAST_TRAILING_BLANK	0x6c
+#define V_LAST_TRAILING_BLANK			0
+#define V_LAST_TRAILING_BLANK_MASK		(0xffff << 0)
+
+#define DVO_TGEN_OUTPUT_DELAY_LINE	0x7c
+#define EXT_TG_DLY_LINE				0
+#define EXT_TG_DLY_LINE_MASK			(0xffff << 0)
+
+#define DVO_MUTEX_VSYNC_SET		0x84
+#define MUTEX_VSYNC_SEL				BIT(0)
+#define MUTEX_VFP_MASK				GENMASK(19, 4)
+
+#define DVO_PATTERN_CTRL		0x100
+#define PRE_PAT_EN				BIT(0)
+#define PRE_PAT_SEL_MASK			(0x7 << 4)
+#define COLOR_BAR				(0x4<<4)
+#define PRE_PAT_FORCE_ON			BIT(8)
+
+#define DVO_PATTERN_COLOR		0x104
+#define PAT_R					(0x3ff << 0)
+#define PAT_G					(0x3ff << 10)
+#define PAT_B					(0x3ff << 20)
+
+#define DVO_Y_LIMIT			0x130
+#define Y_LMT_BOT				GENMASK(9, 0)
+#define Y_LMT_TOP				GENMASK(21, 12)
+
+#define DVO_C_LIMIT			0x134
+#define C_LMT_BOT				GENMASK(9, 0)
+#define C_LMT_TOP				GENMASK(21, 12)
+
+#define DVO_SHADOW_CTRL			0x190
+#define FORCE_COMMIT				BIT(0)
+#define BYPASS_SHADOW				BIT(1)
+#define READ_WRK_REG				BIT(2)
+
+#define DVO_SIZE			0x18
+#define DVO_TGEN_VWIDTH			0x28
+#define DVO_TGEN_VPORCH			0x2c
+#define DVO_TGEN_HPORCH			0x24
+#define DVO_TGEN_HWIDTH			0x20
+
+#define DVO_BUF_SODI_HIGHT		0x230
+#define DVO_BUF_SODI_LOW		0x234
+#define DVO_BUF_DVFS_HIGHT		0x238
+#define DVO_BUF_DVFS_LOW		0x23c
+#define DVO_BUF_PREULTRA_HIGHT		0x240
+#define DVO_BUF_PREULTRA_LOW		0x244
+#define DVO_BUF_ULTRA_HIGHT		0x248
+#define DVO_BUF_ULTRA_LOW		0x24c
+#define DVO_BUF_URGENT_HIGHT		0x250
+#define DVO_BUF_URGENT_LOW		0x254
+#define DVO_DISP_BUF_MASK		GENMASK(31,0)
+
+#define DVO_MATRIX_SET			0x140
+#define DVO_CSC_EN			BIT(0)
+#define DVO_INT_MTX_SEL_MASK		GENMASK(8, 4)
+
+#define DVO_YUV422_SET			0x170
+#define DVO_YUV422_EN			BIT(0)
+#define DVO_CRYCB_MAP			BIT(8)
+
+#endif /* __MTK_DPI_REGS_H */
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index f67f21d04163..0b3bef392ab8 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -114,6 +114,7 @@ enum mtk_ddp_comp_type {
 	MTK_DISP_DPI,
 	MTK_DISP_DP_INTF,
 	MTK_DISP_DSI,
+	MTK_DISP_DVO,
 
 	MTK_DDP_COMP_TYPE_MAX
 };
-- 
2.54.0




More information about the linux-arm-kernel mailing list