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 
<[email protected]>
---
 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 
<[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+#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


Reply via email to