devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver
@ 2021-06-23  7:35 Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 02/10] media: mtk-mdp3: fix redundant process done caused KE Moudy Ho
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

From: mtk18742 <moudy.ho@mediatek.com>

Add MDP driver for MT8183

Signed-off-by: Moudy Ho <moudy.ho@mediatek.com>
---
 drivers/media/platform/Kconfig                |   17 +
 drivers/media/platform/Makefile               |    2 +
 drivers/media/platform/mtk-mdp3/Makefile      |    9 +
 drivers/media/platform/mtk-mdp3/isp_reg.h     |   37 +
 .../media/platform/mtk-mdp3/mdp-platform.h    |   58 +
 .../media/platform/mtk-mdp3/mdp_reg_ccorr.h   |   75 +
 .../media/platform/mtk-mdp3/mdp_reg_rdma.h    |  206 +++
 drivers/media/platform/mtk-mdp3/mdp_reg_rsz.h |  109 ++
 .../media/platform/mtk-mdp3/mdp_reg_wdma.h    |  125 ++
 .../media/platform/mtk-mdp3/mdp_reg_wrot.h    |  115 ++
 .../media/platform/mtk-mdp3/mmsys_config.h    |  188 +++
 drivers/media/platform/mtk-mdp3/mmsys_mutex.h |   35 +
 .../media/platform/mtk-mdp3/mmsys_reg_base.h  |   38 +
 drivers/media/platform/mtk-mdp3/mtk-img-ipi.h |  282 ++++
 .../media/platform/mtk-mdp3/mtk-mdp3-cmdq.c   |  521 +++++++
 .../media/platform/mtk-mdp3/mtk-mdp3-cmdq.h   |   54 +
 .../media/platform/mtk-mdp3/mtk-mdp3-comp.c   | 1329 +++++++++++++++++
 .../media/platform/mtk-mdp3/mtk-mdp3-comp.h   |  155 ++
 .../media/platform/mtk-mdp3/mtk-mdp3-core.c   |  282 ++++
 .../media/platform/mtk-mdp3/mtk-mdp3-core.h   |   86 ++
 .../media/platform/mtk-mdp3/mtk-mdp3-debug.c  |  973 ++++++++++++
 .../media/platform/mtk-mdp3/mtk-mdp3-debug.h  |   39 +
 .../media/platform/mtk-mdp3/mtk-mdp3-m2m.c    |  804 ++++++++++
 .../media/platform/mtk-mdp3/mtk-mdp3-m2m.h    |   42 +
 .../media/platform/mtk-mdp3/mtk-mdp3-regs.c   |  748 ++++++++++
 .../media/platform/mtk-mdp3/mtk-mdp3-regs.h   |  373 +++++
 .../media/platform/mtk-mdp3/mtk-mdp3-vpu.c    |  313 ++++
 .../media/platform/mtk-mdp3/mtk-mdp3-vpu.h    |   79 +
 28 files changed, 7094 insertions(+)
 create mode 100644 drivers/media/platform/mtk-mdp3/Makefile
 create mode 100644 drivers/media/platform/mtk-mdp3/isp_reg.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mdp-platform.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_ccorr.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_rdma.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_rsz.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_wdma.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_wrot.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mmsys_config.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mmsys_mutex.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mmsys_reg_base.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-img-ipi.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.c
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.c
 create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 157c924686e4..dd2d3f0f732f 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -299,6 +299,23 @@ config VIDEO_MEDIATEK_MDP
 	    To compile this driver as a module, choose M here: the
 	    module will be called mtk-mdp.
 
+config VIDEO_MEDIATEK_MDP3
+	tristate "Mediatek MDP3 driver"
+	depends on MTK_IOMMU || COMPILE_TEST
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+	depends on MTK_SCP && MTK_CMDQ
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	select VIDEO_MEDIATEK_VPU
+	help
+	    It is a v4l2 driver and present in Mediatek MT8183 SoCs.
+	    The driver supports for scaling and color space conversion.
+	    Supports ISP PASS2(DIP) direct link for yuv image output.
+
+	    To compile this driver as a module, choose M here: the
+	    module will be called mtk-mdp3.
+
 config VIDEO_MEDIATEK_VCODEC
 	tristate "Mediatek Video Codec driver"
 	depends on MTK_IOMMU || COMPILE_TEST
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index eedc14aafb32..4d65f8fb75f6 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -76,6 +76,8 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)	+= mtk-vcodec/
 
 obj-$(CONFIG_VIDEO_MEDIATEK_MDP)	+= mtk-mdp/
 
+obj-$(CONFIG_VIDEO_MEDIATEK_MDP3)	+= mtk-mdp3/
+
 obj-$(CONFIG_VIDEO_MEDIATEK_JPEG)	+= mtk-jpeg/
 
 obj-$(CONFIG_VIDEO_QCOM_CAMSS)		+= qcom/camss/
diff --git a/drivers/media/platform/mtk-mdp3/Makefile b/drivers/media/platform/mtk-mdp3/Makefile
new file mode 100644
index 000000000000..3c1ccb36ea9f
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+mtk-mdp3-y += mtk-mdp3-core.o mtk-mdp3-vpu.o mtk-mdp3-regs.o
+mtk-mdp3-y += mtk-mdp3-m2m.o
+mtk-mdp3-y += mtk-mdp3-comp.o mtk-mdp3-cmdq.o
+
+mtk-mdp3-y += mtk-mdp3-debug.o
+
+obj-$(CONFIG_VIDEO_MEDIATEK_MDP3) += mtk-mdp3.o
+
diff --git a/drivers/media/platform/mtk-mdp3/isp_reg.h b/drivers/media/platform/mtk-mdp3/isp_reg.h
new file mode 100644
index 000000000000..a8b2f22bae8c
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/isp_reg.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __ISP_REG_H__
+#define __ISP_REG_H__
+
+enum ISP_DIP_CQ {
+	ISP_DRV_DIP_CQ_THRE0 = 0,
+	ISP_DRV_DIP_CQ_THRE1,
+	ISP_DRV_DIP_CQ_THRE2,
+	ISP_DRV_DIP_CQ_THRE3,
+	ISP_DRV_DIP_CQ_THRE4,
+	ISP_DRV_DIP_CQ_THRE5,
+	ISP_DRV_DIP_CQ_THRE6,
+	ISP_DRV_DIP_CQ_THRE7,
+	ISP_DRV_DIP_CQ_THRE8,
+	ISP_DRV_DIP_CQ_THRE9,
+	ISP_DRV_DIP_CQ_THRE10,
+	ISP_DRV_DIP_CQ_THRE11,
+	ISP_DRV_DIP_CQ_NUM,
+	ISP_DRV_DIP_CQ_NONE,
+	/* we only need 12 CQ threads in this chip,
+	 *so we move the following enum behind ISP_DRV_DIP_CQ_NUM
+	 */
+	ISP_DRV_DIP_CQ_THRE12,
+	ISP_DRV_DIP_CQ_THRE13,
+	ISP_DRV_DIP_CQ_THRE14,
+	ISP_DRV_DIP_CQ_THRE15,	/* CQ_THREAD15 does not connect to GCE */
+	ISP_DRV_DIP_CQ_THRE16,	/* CQ_THREAD16 does not connect to GCE */
+	ISP_DRV_DIP_CQ_THRE17,	/* CQ_THREAD17 does not connect to GCE */
+	ISP_DRV_DIP_CQ_THRE18,	/* CQ_THREAD18 does not connect to GCE */
+};
+
+#endif  // __ISP_REG_H__
diff --git a/drivers/media/platform/mtk-mdp3/mdp-platform.h b/drivers/media/platform/mtk-mdp3/mdp-platform.h
new file mode 100644
index 000000000000..d474580306b7
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mdp-platform.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MDP_PLATFORM_H__
+#define __MDP_PLATFORM_H__
+
+#include "mtk-mdp3-comp.h"
+
+/* CAM */
+#define MDP_WPEI           MDP_COMP_WPEI
+#define MDP_WPEO           MDP_COMP_WPEO
+#define MDP_WPEI2          MDP_COMP_WPEI2
+#define MDP_WPEO2          MDP_COMP_WPEO2
+#define MDP_IMGI           MDP_COMP_ISP_IMGI
+#define MDP_IMGO           MDP_COMP_ISP_IMGO
+#define MDP_IMG2O          MDP_COMP_ISP_IMG2O
+
+/* IPU */
+#define MDP_IPUI           MDP_COMP_NONE
+#define MDP_IPUO           MDP_COMP_NONE
+
+/* MDP */
+#define MDP_CAMIN          MDP_COMP_CAMIN
+#define MDP_CAMIN2         MDP_COMP_CAMIN2
+#define MDP_RDMA0          MDP_COMP_RDMA0
+#define MDP_RDMA1          MDP_COMP_NONE
+#define MDP_AAL0           MDP_COMP_AAL0
+#define MDP_CCORR0         MDP_COMP_CCORR0
+#define MDP_SCL0           MDP_COMP_RSZ0
+#define MDP_SCL1           MDP_COMP_RSZ1
+#define MDP_SCL2           MDP_COMP_NONE
+#define MDP_TDSHP0         MDP_COMP_TDSHP0
+#define MDP_COLOR0         MDP_COMP_COLOR0
+#define MDP_WROT0          MDP_COMP_WROT0
+#define MDP_WROT1          MDP_COMP_NONE
+#define MDP_WDMA           MDP_COMP_WDMA
+#define MDP_PATH0_SOUT     MDP_COMP_PATH0_SOUT
+#define MDP_PATH1_SOUT     MDP_COMP_PATH1_SOUT
+
+#define MDP_TOTAL          (MDP_COMP_WDMA + 1)
+
+/* Platform options */
+#define ESL_SETTING			1
+#define RDMA_SUPPORT_10BIT		1
+#define RDMA0_RSZ1_SRAM_SHARING		1
+#define RDMA_UPSAMPLE_REPEAT_ONLY	1
+#define RSZ_DISABLE_DCM_SMALL_TILE	0
+#define WROT_FILTER_CONSTRAINT		0
+#define WROT0_DISP_SRAM_SHARING		0
+
+#define MM_MUTEX_MOD_OFFSET	0x30
+#define MM_MUTEX_SOF_OFFSET	0x2c
+
+#endif  /* __MDP_PLATFORM_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mdp_reg_ccorr.h b/drivers/media/platform/mtk-mdp3/mdp_reg_ccorr.h
new file mode 100644
index 000000000000..2e8624446502
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mdp_reg_ccorr.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MDP_REG_CCORR_H__
+#define __MDP_REG_CCORR_H__
+
+#include "mmsys_reg_base.h"
+
+#define MDP_CCORR_EN                0x000
+#define MDP_CCORR_RESET             0x004
+#define MDP_CCORR_INTEN             0x008
+#define MDP_CCORR_INTSTA            0x00c
+#define MDP_CCORR_STATUS            0x010
+#define MDP_CCORR_CFG               0x020
+#define MDP_CCORR_INPUT_COUNT       0x024
+#define MDP_CCORR_OUTPUT_COUNT      0x028
+#define MDP_CCORR_CHKSUM            0x02c
+#define MDP_CCORR_SIZE              0x030
+#define MDP_CCORR_Y2R_00            0x034
+#define MDP_CCORR_Y2R_01            0x038
+#define MDP_CCORR_Y2R_02            0x03c
+#define MDP_CCORR_Y2R_03            0x040
+#define MDP_CCORR_Y2R_04            0x044
+#define MDP_CCORR_Y2R_05            0x048
+#define MDP_CCORR_R2Y_00            0x04c
+#define MDP_CCORR_R2Y_01            0x050
+#define MDP_CCORR_R2Y_02            0x054
+#define MDP_CCORR_R2Y_03            0x058
+#define MDP_CCORR_R2Y_04            0x05c
+#define MDP_CCORR_R2Y_05            0x060
+#define MDP_CCORR_COEF_0            0x080
+#define MDP_CCORR_COEF_1            0x084
+#define MDP_CCORR_COEF_2            0x088
+#define MDP_CCORR_COEF_3            0x08c
+#define MDP_CCORR_COEF_4            0x090
+#define MDP_CCORR_SHADOW            0x0a0
+#define MDP_CCORR_DUMMY_REG         0x0c0
+#define MDP_CCORR_ATPG              0x0fc
+
+/* MASK */
+#define MDP_CCORR_EN_MASK           0x00000001
+#define MDP_CCORR_RESET_MASK        0x00000001
+#define MDP_CCORR_INTEN_MASK        0x00000003
+#define MDP_CCORR_INTSTA_MASK       0x00000003
+#define MDP_CCORR_STATUS_MASK       0xfffffff3
+#define MDP_CCORR_CFG_MASK          0x70001317
+#define MDP_CCORR_INPUT_COUNT_MASK  0x1fff1fff
+#define MDP_CCORR_OUTPUT_COUNT_MASK 0x1fff1fff
+#define MDP_CCORR_CHKSUM_MASK       0xffffffff
+#define MDP_CCORR_SIZE_MASK         0x1fff1fff
+#define MDP_CCORR_Y2R_00_MASK       0x01ff01ff
+#define MDP_CCORR_Y2R_01_MASK       0x1fff01ff
+#define MDP_CCORR_Y2R_02_MASK       0x1fff1fff
+#define MDP_CCORR_Y2R_03_MASK       0x1fff1fff
+#define MDP_CCORR_Y2R_04_MASK       0x1fff1fff
+#define MDP_CCORR_Y2R_05_MASK       0x1fff1fff
+#define MDP_CCORR_R2Y_00_MASK       0x01ff01ff
+#define MDP_CCORR_R2Y_01_MASK       0x07ff01ff
+#define MDP_CCORR_R2Y_02_MASK       0x07ff07ff
+#define MDP_CCORR_R2Y_03_MASK       0x07ff07ff
+#define MDP_CCORR_R2Y_04_MASK       0x07ff07ff
+#define MDP_CCORR_R2Y_05_MASK       0x07ff07ff
+#define MDP_CCORR_COEF_0_MASK       0x1fff1fff
+#define MDP_CCORR_COEF_1_MASK       0x1fff1fff
+#define MDP_CCORR_COEF_2_MASK       0x1fff1fff
+#define MDP_CCORR_COEF_3_MASK       0x1fff1fff
+#define MDP_CCORR_COEF_4_MASK       0x1fff1fff
+#define MDP_CCORR_SHADOW_MASK       0x00000007
+#define MDP_CCORR_DUMMY_REG_MASK    0xffffffff
+#define MDP_CCORR_ATPG_MASK         0x00000003
+
+#endif  // __MDP_REG_CCORR_H__
diff --git a/drivers/media/platform/mtk-mdp3/mdp_reg_rdma.h b/drivers/media/platform/mtk-mdp3/mdp_reg_rdma.h
new file mode 100644
index 000000000000..d7f5d9275d6d
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mdp_reg_rdma.h
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MDP_REG_RDMA_H__
+#define __MDP_REG_RDMA_H__
+
+#include "mmsys_reg_base.h"
+
+#define MDP_RDMA_EN                     0x000
+#define MDP_RDMA_RESET                  0x008
+#define MDP_RDMA_INTERRUPT_ENABLE       0x010
+#define MDP_RDMA_INTERRUPT_STATUS       0x018
+#define MDP_RDMA_CON                    0x020
+#define MDP_RDMA_GMCIF_CON              0x028
+#define MDP_RDMA_SRC_CON                0x030
+#define MDP_RDMA_SRC_BASE_0             0xf00
+#define MDP_RDMA_SRC_BASE_1             0xf08
+#define MDP_RDMA_SRC_BASE_2             0xf10
+#define MDP_RDMA_UFO_DEC_LENGTH_BASE_Y  0xf20
+#define MDP_RDMA_UFO_DEC_LENGTH_BASE_C  0xf28
+#define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE   0x060
+#define MDP_RDMA_MF_BKGD_SIZE_IN_PXL    0x068
+#define MDP_RDMA_MF_SRC_SIZE            0x070
+#define MDP_RDMA_MF_CLIP_SIZE           0x078
+#define MDP_RDMA_MF_OFFSET_1            0x080
+#define MDP_RDMA_MF_PAR                 0x088
+#define MDP_RDMA_SF_BKGD_SIZE_IN_BYTE   0x090
+#define MDP_RDMA_SF_PAR                 0x0b8
+#define MDP_RDMA_MB_DEPTH               0x0c0
+#define MDP_RDMA_MB_BASE                0x0c8
+#define MDP_RDMA_MB_CON                 0x0d0
+#define MDP_RDMA_SB_DEPTH               0x0d8
+#define MDP_RDMA_SB_BASE                0x0e0
+#define MDP_RDMA_SB_CON                 0x0e8
+#define MDP_RDMA_VC1_RANGE              0x0f0
+#define MDP_RDMA_SRC_END_0              0x100
+#define MDP_RDMA_SRC_END_1              0x108
+#define MDP_RDMA_SRC_END_2              0x110
+#define MDP_RDMA_SRC_OFFSET_0           0x118
+#define MDP_RDMA_SRC_OFFSET_1           0x120
+#define MDP_RDMA_SRC_OFFSET_2           0x128
+#define MDP_RDMA_SRC_OFFSET_W_0         0x130
+#define MDP_RDMA_SRC_OFFSET_W_1         0x138
+#define MDP_RDMA_SRC_OFFSET_W_2         0x140
+#define MDP_RDMA_SRC_OFFSET_0_P         0x148
+#define MDP_RDMA_TRANSFORM_0            0x200
+#define MDP_RDMA_TRANSFORM_1            0x208
+#define MDP_RDMA_TRANSFORM_2            0x210
+#define MDP_RDMA_TRANSFORM_3            0x218
+#define MDP_RDMA_TRANSFORM_4            0x220
+#define MDP_RDMA_TRANSFORM_5            0x228
+#define MDP_RDMA_TRANSFORM_6            0x230
+#define MDP_RDMA_TRANSFORM_7            0x238
+#define MDP_RDMA_DMABUF_CON_0           0x240
+#define MDP_RDMA_DMAULTRA_CON_0         0x248
+#define MDP_RDMA_DMABUF_CON_1           0x250
+#define MDP_RDMA_DMAULTRA_CON_1         0x258
+#define MDP_RDMA_DMABUF_CON_2           0x260
+#define MDP_RDMA_DMAULTRA_CON_2         0x268
+#define MDP_RDMA_DITHER_CON             0x288
+#define MDP_RDMA_RESV_DUMMY_0           0x2a0
+#define MDP_RDMA_CHKS_EXTR              0x300
+#define MDP_RDMA_CHKS_INTW              0x308
+#define MDP_RDMA_CHKS_INTR              0x310
+#define MDP_RDMA_CHKS_ROTO              0x318
+#define MDP_RDMA_CHKS_SRIY              0x320
+#define MDP_RDMA_CHKS_SRIU              0x328
+#define MDP_RDMA_CHKS_SRIV              0x330
+#define MDP_RDMA_CHKS_SROY              0x338
+#define MDP_RDMA_CHKS_SROU              0x340
+#define MDP_RDMA_CHKS_SROV              0x348
+#define MDP_RDMA_CHKS_VUPI              0x350
+#define MDP_RDMA_CHKS_VUPO              0x358
+#define MDP_RDMA_DEBUG_CON              0x380
+#define MDP_RDMA_MON_STA_0              0x400
+#define MDP_RDMA_MON_STA_1              0x408
+#define MDP_RDMA_MON_STA_2              0x410
+#define MDP_RDMA_MON_STA_3              0x418
+#define MDP_RDMA_MON_STA_4              0x420
+#define MDP_RDMA_MON_STA_5              0x428
+#define MDP_RDMA_MON_STA_6              0x430
+#define MDP_RDMA_MON_STA_7              0x438
+#define MDP_RDMA_MON_STA_8              0x440
+#define MDP_RDMA_MON_STA_9              0x448
+#define MDP_RDMA_MON_STA_10             0x450
+#define MDP_RDMA_MON_STA_11             0x458
+#define MDP_RDMA_MON_STA_12             0x460
+#define MDP_RDMA_MON_STA_13             0x468
+#define MDP_RDMA_MON_STA_14             0x470
+#define MDP_RDMA_MON_STA_15             0x478
+#define MDP_RDMA_MON_STA_16             0x480
+#define MDP_RDMA_MON_STA_17             0x488
+#define MDP_RDMA_MON_STA_18             0x490
+#define MDP_RDMA_MON_STA_19             0x498
+#define MDP_RDMA_MON_STA_20             0x4a0
+#define MDP_RDMA_MON_STA_21             0x4a8
+#define MDP_RDMA_MON_STA_22             0x4b0
+#define MDP_RDMA_MON_STA_23             0x4b8
+#define MDP_RDMA_MON_STA_24             0x4c0
+#define MDP_RDMA_MON_STA_25             0x4c8
+#define MDP_RDMA_MON_STA_26             0x4d0
+#define MDP_RDMA_MON_STA_27             0x4d8
+#define MDP_RDMA_MON_STA_28             0x4e0
+
+/* MASK */
+#define MDP_RDMA_EN_MASK                    0x00000001
+#define MDP_RDMA_RESET_MASK                 0x00000001
+#define MDP_RDMA_INTERRUPT_ENABLE_MASK      0x00000007
+#define MDP_RDMA_INTERRUPT_STATUS_MASK      0x00000007
+#define MDP_RDMA_CON_MASK                   0x00001110
+#define MDP_RDMA_GMCIF_CON_MASK             0xfffb3771
+#define MDP_RDMA_SRC_CON_MASK               0xf3ffffff
+#define MDP_RDMA_SRC_BASE_0_MASK            0xffffffff
+#define MDP_RDMA_SRC_BASE_1_MASK            0xffffffff
+#define MDP_RDMA_SRC_BASE_2_MASK            0xffffffff
+#define MDP_RDMA_UFO_DEC_LENGTH_BASE_Y_MASK 0xffffffff
+#define MDP_RDMA_UFO_DEC_LENGTH_BASE_C_MASK 0xffffffff
+#define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE_MASK  0x001fffff
+#define MDP_RDMA_MF_BKGD_SIZE_IN_PXL_MASK   0x001fffff
+#define MDP_RDMA_MF_SRC_SIZE_MASK           0x1fff1fff
+#define MDP_RDMA_MF_CLIP_SIZE_MASK          0x1fff1fff
+#define MDP_RDMA_MF_OFFSET_1_MASK           0x003f001f
+#define MDP_RDMA_MF_PAR_MASK                0x1ffff3ff
+#define MDP_RDMA_SF_BKGD_SIZE_IN_BYTE_MASK  0x001fffff
+#define MDP_RDMA_SF_PAR_MASK                0x1ffff3ff
+#define MDP_RDMA_MB_DEPTH_MASK              0x0000007f
+#define MDP_RDMA_MB_BASE_MASK               0x0000ffff
+#define MDP_RDMA_MB_CON_MASK                0x3fff1fff
+#define MDP_RDMA_SB_DEPTH_MASK              0x0000007f
+#define MDP_RDMA_SB_BASE_MASK               0x0000ffff
+#define MDP_RDMA_SB_CON_MASK                0x3fff1fff
+#define MDP_RDMA_VC1_RANGE_MASK             0x001f1f11
+#define MDP_RDMA_SRC_END_0_MASK             0xffffffff
+#define MDP_RDMA_SRC_END_1_MASK             0xffffffff
+#define MDP_RDMA_SRC_END_2_MASK             0xffffffff
+#define MDP_RDMA_SRC_OFFSET_0_MASK          0xffffffff
+#define MDP_RDMA_SRC_OFFSET_1_MASK          0xffffffff
+#define MDP_RDMA_SRC_OFFSET_2_MASK          0xffffffff
+#define MDP_RDMA_SRC_OFFSET_W_0_MASK        0x0000ffff
+#define MDP_RDMA_SRC_OFFSET_W_1_MASK        0x0000ffff
+#define MDP_RDMA_SRC_OFFSET_W_2_MASK        0x0000ffff
+#define MDP_RDMA_SRC_OFFSET_0_P_MASK        0xffffffff
+#define MDP_RDMA_TRANSFORM_0_MASK           0xff110777
+#define MDP_RDMA_TRANSFORM_1_MASK           0x1ff7fdff
+#define MDP_RDMA_TRANSFORM_2_MASK           0x1ff7fdff
+#define MDP_RDMA_TRANSFORM_3_MASK           0x1fff1fff
+#define MDP_RDMA_TRANSFORM_4_MASK           0x1fff1fff
+#define MDP_RDMA_TRANSFORM_5_MASK           0x1fff1fff
+#define MDP_RDMA_TRANSFORM_6_MASK           0x1fff1fff
+#define MDP_RDMA_TRANSFORM_7_MASK           0x00001fff
+#define MDP_RDMA_DMABUF_CON_0_MASK          0x077f007f
+#define MDP_RDMA_DMAULTRA_CON_0_MASK        0x7f7f7f7f
+#define MDP_RDMA_DMABUF_CON_1_MASK          0x073f003f
+#define MDP_RDMA_DMAULTRA_CON_1_MASK        0x3f3f3f3f
+#define MDP_RDMA_DMABUF_CON_2_MASK          0x071f001f
+#define MDP_RDMA_DMAULTRA_CON_2_MASK        0x1f1f1f1f
+
+#define MDP_RDMA_DITHER_CON_MASK            0xffffffff
+#define MDP_RDMA_RESV_DUMMY_0_MASK          0xffffffff
+#define MDP_RDMA_CHKS_EXTR_MASK             0xffffff01
+#define MDP_RDMA_CHKS_INTW_MASK             0xffffff01
+#define MDP_RDMA_CHKS_INTR_MASK             0xffffff01
+#define MDP_RDMA_CHKS_ROTO_MASK             0xffffff01
+#define MDP_RDMA_CHKS_SRIY_MASK             0xffffff01
+#define MDP_RDMA_CHKS_SRIU_MASK             0xffffff01
+#define MDP_RDMA_CHKS_SRIV_MASK             0xffffff01
+#define MDP_RDMA_CHKS_SROY_MASK             0xffffff01
+#define MDP_RDMA_CHKS_SROU_MASK             0xffffff01
+#define MDP_RDMA_CHKS_SROV_MASK             0xffffff01
+#define MDP_RDMA_CHKS_VUPI_MASK             0xffffff01
+#define MDP_RDMA_CHKS_VUPO_MASK             0xffffff01
+#define MDP_RDMA_DEBUG_CON_MASK             0x00001f11
+#define MDP_RDMA_MON_STA_0_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_1_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_2_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_3_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_4_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_5_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_6_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_7_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_8_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_9_MASK             0xffffffff
+#define MDP_RDMA_MON_STA_10_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_11_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_12_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_13_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_14_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_15_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_16_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_17_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_18_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_19_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_20_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_21_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_22_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_23_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_24_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_25_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_26_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_27_MASK            0xffffffff
+#define MDP_RDMA_MON_STA_28_MASK            0xffffffff
+
+#endif  // __MDP_REG_RDMA_H__
diff --git a/drivers/media/platform/mtk-mdp3/mdp_reg_rsz.h b/drivers/media/platform/mtk-mdp3/mdp_reg_rsz.h
new file mode 100644
index 000000000000..7f0683f3c60d
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mdp_reg_rsz.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MDP_REG_RSZ_H__
+#define __MDP_REG_RSZ_H__
+
+#include "mmsys_reg_base.h"
+
+#define PRZ_ENABLE                                        0x000
+#define PRZ_CONTROL_1                                     0x004
+#define PRZ_CONTROL_2                                     0x008
+#define PRZ_INT_FLAG                                      0x00c
+#define PRZ_INPUT_IMAGE                                   0x010
+#define PRZ_OUTPUT_IMAGE                                  0x014
+#define PRZ_HORIZONTAL_COEFF_STEP                         0x018
+#define PRZ_VERTICAL_COEFF_STEP                           0x01c
+#define PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET                0x020
+#define PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET               0x024
+#define PRZ_LUMA_VERTICAL_INTEGER_OFFSET                  0x028
+#define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET                 0x02c
+#define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET              0x030
+#define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET             0x034
+#define PRZ_RSV                                           0x040
+#define PRZ_DEBUG_SEL                                     0x044
+#define PRZ_DEBUG                                         0x048
+#define PRZ_TAP_ADAPT                                     0x04c
+#define PRZ_IBSE_SOFTCLIP                                 0x050
+#define PRZ_IBSE_YLEVEL_1                                 0x054
+#define PRZ_IBSE_YLEVEL_2                                 0x058
+#define PRZ_IBSE_YLEVEL_3                                 0x05c
+#define PRZ_IBSE_YLEVEL_4                                 0x060
+#define PRZ_IBSE_YLEVEL_5                                 0x064
+#define PRZ_IBSE_GAINCONTROL_1                            0x068
+#define PRZ_IBSE_GAINCONTROL_2                            0x06c
+#define PRZ_DEMO_IN_HMASK                                 0x070
+#define PRZ_DEMO_IN_VMASK                                 0x074
+#define PRZ_DEMO_OUT_HMASK                                0x078
+#define PRZ_DEMO_OUT_VMASK                                0x07c
+#define PRZ_ATPG                                          0x0fc
+#define PRZ_PAT1_GEN_SET                                  0x100
+#define PRZ_PAT1_GEN_FRM_SIZE                             0x104
+#define PRZ_PAT1_GEN_COLOR0                               0x108
+#define PRZ_PAT1_GEN_COLOR1                               0x10c
+#define PRZ_PAT1_GEN_COLOR2                               0x110
+#define PRZ_PAT1_GEN_POS                                  0x114
+#define PRZ_PAT1_GEN_TILE_POS                             0x124
+#define PRZ_PAT1_GEN_TILE_OV                              0x128
+#define PRZ_PAT2_GEN_SET                                  0x200
+#define PRZ_PAT2_GEN_COLOR0                               0x208
+#define PRZ_PAT2_GEN_COLOR1                               0x20c
+#define PRZ_PAT2_GEN_POS                                  0x214
+#define PRZ_PAT2_GEN_CURSOR_RB0                           0x218
+#define PRZ_PAT2_GEN_CURSOR_RB1                           0x21c
+#define PRZ_PAT2_GEN_TILE_POS                             0x224
+#define PRZ_PAT2_GEN_TILE_OV                              0x228
+
+/* MASK */
+#define PRZ_ENABLE_MASK                                   0x00010001
+#define PRZ_CONTROL_1_MASK                                0xfffffff3
+#define PRZ_CONTROL_2_MASK                                0x0ffffaff
+#define PRZ_INT_FLAG_MASK                                 0x00000033
+#define PRZ_INPUT_IMAGE_MASK                              0xffffffff
+#define PRZ_OUTPUT_IMAGE_MASK                             0xffffffff
+#define PRZ_HORIZONTAL_COEFF_STEP_MASK                    0x007fffff
+#define PRZ_VERTICAL_COEFF_STEP_MASK                      0x007fffff
+#define PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET_MASK           0x0000ffff
+#define PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET_MASK          0x001fffff
+#define PRZ_LUMA_VERTICAL_INTEGER_OFFSET_MASK             0x0000ffff
+#define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET_MASK            0x001fffff
+#define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET_MASK         0x0000ffff
+#define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET_MASK        0x001fffff
+#define PRZ_RSV_MASK                                      0xffffffff
+#define PRZ_DEBUG_SEL_MASK                                0x0000000f
+#define PRZ_DEBUG_MASK                                    0xffffffff
+#define PRZ_TAP_ADAPT_MASK                                0x03ffffff
+#define PRZ_IBSE_SOFTCLIP_MASK                            0x000fffff
+#define PRZ_IBSE_YLEVEL_1_MASK                            0xffffffff
+#define PRZ_IBSE_YLEVEL_2_MASK                            0xffffffff
+#define PRZ_IBSE_YLEVEL_3_MASK                            0xffffffff
+#define PRZ_IBSE_YLEVEL_4_MASK                            0xffffffff
+#define PRZ_IBSE_YLEVEL_5_MASK                            0x0000ff3f
+#define PRZ_IBSE_GAINCONTROL_1_MASK                       0xffffffff
+#define PRZ_IBSE_GAINCONTROL_2_MASK                       0x0fffff0f
+#define PRZ_DEMO_IN_HMASK_MASK                            0xffffffff
+#define PRZ_DEMO_IN_VMASK_MASK                            0xffffffff
+#define PRZ_DEMO_OUT_HMASK_MASK                           0xffffffff
+#define PRZ_DEMO_OUT_VMASK_MASK                           0xffffffff
+#define PRZ_ATPG_MASK                                     0x00000003
+#define PRZ_PAT1_GEN_SET_MASK                             0x00ff00fd
+#define PRZ_PAT1_GEN_FRM_SIZE_MASK                        0x1fff1fff
+#define PRZ_PAT1_GEN_COLOR0_MASK                          0x00ff00ff
+#define PRZ_PAT1_GEN_COLOR1_MASK                          0x00ff00ff
+#define PRZ_PAT1_GEN_COLOR2_MASK                          0x00ff00ff
+#define PRZ_PAT1_GEN_POS_MASK                             0x1fff1fff
+#define PRZ_PAT1_GEN_TILE_POS_MASK                        0x1fff1fff
+#define PRZ_PAT1_GEN_TILE_OV_MASK                         0x0000ffff
+#define PRZ_PAT2_GEN_SET_MASK                             0x00ff0003
+#define PRZ_PAT2_GEN_COLOR0_MASK                          0x00ff00ff
+#define PRZ_PAT2_GEN_COLOR1_MASK                          0x000000ff
+#define PRZ_PAT2_GEN_POS_MASK                             0x1fff1fff
+#define PRZ_PAT2_GEN_CURSOR_RB0_MASK                      0x00ff00ff
+#define PRZ_PAT2_GEN_CURSOR_RB1_MASK                      0x000000ff
+#define PRZ_PAT2_GEN_TILE_POS_MASK                        0x1fff1fff
+#define PRZ_PAT2_GEN_TILE_OV_MASK                         0x0000ffff
+
+#endif // __MDP_REG_RSZ_H__
diff --git a/drivers/media/platform/mtk-mdp3/mdp_reg_wdma.h b/drivers/media/platform/mtk-mdp3/mdp_reg_wdma.h
new file mode 100644
index 000000000000..c274b54c1f18
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mdp_reg_wdma.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MDP_REG_WDMA_H__
+#define __MDP_REG_WDMA_H__
+
+#include "mmsys_reg_base.h"
+
+#define WDMA_INTEN              0x000
+#define WDMA_INTSTA             0x004
+#define WDMA_EN                 0x008
+#define WDMA_RST                0x00c
+#define WDMA_SMI_CON            0x010
+#define WDMA_CFG                0x014
+#define WDMA_SRC_SIZE           0x018
+#define WDMA_CLIP_SIZE          0x01c
+#define WDMA_CLIP_COORD         0x020
+#define WDMA_DST_ADDR           0xf00
+#define WDMA_DST_W_IN_BYTE      0x028
+#define WDMA_ALPHA              0x02c
+#define WDMA_BUF_CON1           0x038
+#define WDMA_BUF_CON2           0x03c
+#define WDMA_C00                0x040
+#define WDMA_C02                0x044
+#define WDMA_C10                0x048
+#define WDMA_C12                0x04c
+#define WDMA_C20                0x050
+#define WDMA_C22                0x054
+#define WDMA_PRE_ADD0           0x058
+#define WDMA_PRE_ADD2           0x05c
+#define WDMA_POST_ADD0          0x060
+#define WDMA_POST_ADD2          0x064
+#define WDMA_DST_U_ADDR         0xf04
+#define WDMA_DST_V_ADDR         0xf08
+#define WDMA_DST_UV_PITCH       0x078
+#define WDMA_DST_ADDR_OFFSET    0x080
+#define WDMA_DST_U_ADDR_OFFSET  0x084
+#define WDMA_DST_V_ADDR_OFFSET  0x088
+#define PROC_TRACK_CON_0        0x090
+#define PROC_TRACK_CON_1        0x094
+#define PROC_TRACK_CON_2        0x098
+#define WDMA_FLOW_CTRL_DBG      0x0a0
+#define WDMA_EXEC_DBG           0x0a4
+#define WDMA_CT_DBG             0x0a8
+#define WDMA_SMI_TRAFFIC_DBG    0x0ac
+#define WDMA_PROC_TRACK_DBG_0   0x0b0
+#define WDMA_PROC_TRACK_DBG_1   0x0b4
+#define WDMA_DEBUG              0x0b8
+#define WDMA_DUMMY              0x100
+#define WDMA_DITHER_0           0xe00
+#define WDMA_DITHER_5           0xe14
+#define WDMA_DITHER_6           0xe18
+#define WDMA_DITHER_7           0xe1c
+#define WDMA_DITHER_8           0xe20
+#define WDMA_DITHER_9           0xe24
+#define WDMA_DITHER_10          0xe28
+#define WDMA_DITHER_11          0xe2c
+#define WDMA_DITHER_12          0xe30
+#define WDMA_DITHER_13          0xe34
+#define WDMA_DITHER_14          0xe38
+#define WDMA_DITHER_15          0xe3c
+#define WDMA_DITHER_16          0xe40
+#define WDMA_DITHER_17          0xe44
+
+/* MASK */
+#define WDMA_INTEN_MASK             0x00000003
+#define WDMA_INTSTA_MASK            0x00000003
+#define WDMA_EN_MASK                0x00000001
+#define WDMA_RST_MASK               0x00000001
+#define WDMA_SMI_CON_MASK           0x0fffffff
+#define WDMA_CFG_MASK               0xff03bff0
+#define WDMA_SRC_SIZE_MASK          0x3fff3fff
+#define WDMA_CLIP_SIZE_MASK         0x3fff3fff
+#define WDMA_CLIP_COORD_MASK        0x3fff3fff
+#define WDMA_DST_ADDR_MASK          0xffffffff
+#define WDMA_DST_W_IN_BYTE_MASK     0x0000ffff
+#define WDMA_ALPHA_MASK             0x800000ff
+#define WDMA_BUF_CON1_MASK          0xd1ff01ff
+#define WDMA_BUF_CON2_MASK          0xffffffff
+#define WDMA_C00_MASK               0x1fff1fff
+#define WDMA_C02_MASK               0x00001fff
+#define WDMA_C10_MASK               0x1fff1fff
+#define WDMA_C12_MASK               0x00001fff
+#define WDMA_C20_MASK               0x1fff1fff
+#define WDMA_C22_MASK               0x00001fff
+#define WDMA_PRE_ADD0_MASK          0x01ff01ff
+#define WDMA_PRE_ADD2_MASK          0x000001ff
+#define WDMA_POST_ADD0_MASK         0x01ff01ff
+#define WDMA_POST_ADD2_MASK         0x000001ff
+#define WDMA_DST_U_ADDR_MASK        0xffffffff
+#define WDMA_DST_V_ADDR_MASK        0xffffffff
+#define WDMA_DST_UV_PITCH_MASK      0x0000ffff
+#define WDMA_DST_ADDR_OFFSET_MASK   0x0fffffff
+#define WDMA_DST_U_ADDR_OFFSET_MASK 0x0fffffff
+#define WDMA_DST_V_ADDR_OFFSET_MASK 0x0fffffff
+#define PROC_TRACK_CON_0_MASK       0x70000fff
+#define PROC_TRACK_CON_1_MASK       0x00ffffff
+#define PROC_TRACK_CON_2_MASK       0x00ffffff
+#define WDMA_FLOW_CTRL_DBG_MASK     0x0000f3ff
+#define WDMA_EXEC_DBG_MASK          0x003f003f
+#define WDMA_CT_DBG_MASK            0x3fff3fff
+#define WDMA_SMI_TRAFFIC_DBG_MASK   0xffffffff
+#define WDMA_PROC_TRACK_DBG_0_MASK  0xffffffff
+#define WDMA_PROC_TRACK_DBG_1_MASK  0xffffffff
+#define WDMA_DEBUG_MASK             0xffffffff
+#define WDMA_DUMMY_MASK             0xffffffff
+#define WDMA_DITHER_0_MASK          0x0111ff11
+#define WDMA_DITHER_5_MASK          0x0000ffff
+#define WDMA_DITHER_6_MASK          0x0001f3ff
+#define WDMA_DITHER_7_MASK          0x00000333
+#define WDMA_DITHER_8_MASK          0x03ff0001
+#define WDMA_DITHER_9_MASK          0x03ff03ff
+#define WDMA_DITHER_10_MASK         0x00000733
+#define WDMA_DITHER_11_MASK         0x00003331
+#define WDMA_DITHER_12_MASK         0xffff0031
+#define WDMA_DITHER_13_MASK         0x00000777
+#define WDMA_DITHER_14_MASK         0x00000371
+#define WDMA_DITHER_15_MASK         0x77770001
+#define WDMA_DITHER_16_MASK         0x77777777
+#define WDMA_DITHER_17_MASK         0x0001ffff
+
+#endif  // __MDP_REG_WDMA_H__
diff --git a/drivers/media/platform/mtk-mdp3/mdp_reg_wrot.h b/drivers/media/platform/mtk-mdp3/mdp_reg_wrot.h
new file mode 100644
index 000000000000..b757a288267d
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mdp_reg_wrot.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MDP_REG_WROT_H__
+#define __MDP_REG_WROT_H__
+
+#include "mmsys_reg_base.h"
+
+#define VIDO_CTRL                   0x000
+#define VIDO_DMA_PERF               0x004
+#define VIDO_MAIN_BUF_SIZE          0x008
+#define VIDO_SOFT_RST               0x010
+#define VIDO_SOFT_RST_STAT          0x014
+#define VIDO_INT_EN                 0x018
+#define VIDO_INT                    0x01c
+#define VIDO_CROP_OFST              0x020
+#define VIDO_TAR_SIZE               0x024
+#define VIDO_BASE_ADDR              0xf00
+#define VIDO_OFST_ADDR              0x02c
+#define VIDO_STRIDE                 0x030
+#define VIDO_BASE_ADDR_C            0xf04
+#define VIDO_OFST_ADDR_C            0x038
+#define VIDO_STRIDE_C               0x03c
+#define VIDO_DITHER                 0x054
+#define VIDO_BASE_ADDR_V            0xf08
+#define VIDO_OFST_ADDR_V            0x068
+#define VIDO_STRIDE_V               0x06c
+#define VIDO_RSV_1                  0x070
+#define VIDO_DMA_PREULTRA           0x074
+#define VIDO_IN_SIZE                0x078
+#define VIDO_ROT_EN                 0x07c
+#define VIDO_FIFO_TEST              0x080
+#define VIDO_MAT_CTRL               0x084
+#define VIDO_MAT_RMY                0x088
+#define VIDO_MAT_RMV                0x08c
+#define VIDO_MAT_GMY                0x090
+#define VIDO_MAT_BMY                0x094
+#define VIDO_MAT_BMV                0x098
+#define VIDO_MAT_PREADD             0x09c
+#define VIDO_MAT_POSTADD            0x0a0
+#define VIDO_DITHER_00              0x0a4
+#define VIDO_DITHER_02              0x0ac
+#define VIDO_DITHER_03              0x0b0
+#define VIDO_DITHER_04              0x0b4
+#define VIDO_DITHER_05              0x0b8
+#define VIDO_DITHER_06              0x0bc
+#define VIDO_DITHER_07              0x0c0
+#define VIDO_DITHER_08              0x0c4
+#define VIDO_DITHER_09              0x0c8
+#define VIDO_DITHER_10              0x0cc
+#define VIDO_DEBUG                  0x0d0
+#define VIDO_ARB_SW_CTL             0x0d4
+#define MDP_WROT_TRACK_CTL          0x0e0
+#define MDP_WROT_TRACK_WINDOW       0x0e4
+#define MDP_WROT_TRACK_TARGET       0x0e8
+#define MDP_WROT_TRACK_STOP         0x0ec
+#define MDP_WROT_TRACK_PROC_CNT0    0x0f0
+#define MDP_WROT_TRACK_PROC_CNT1    0x0f4
+
+/* MASK */
+#define VIDO_CTRL_MASK                  0xf530711f
+#define VIDO_DMA_PERF_MASK              0x3fffffff
+#define VIDO_MAIN_BUF_SIZE_MASK         0x1fff7f77
+#define VIDO_SOFT_RST_MASK              0x00000001
+#define VIDO_SOFT_RST_STAT_MASK         0x00000001
+#define VIDO_INT_EN_MASK                0x00003f07
+#define VIDO_INT_MASK                   0x00000007
+#define VIDO_CROP_OFST_MASK             0x1fff1fff
+#define VIDO_TAR_SIZE_MASK              0x1fff1fff
+#define VIDO_BASE_ADDR_MASK             0xffffffff
+#define VIDO_OFST_ADDR_MASK             0x0fffffff
+#define VIDO_STRIDE_MASK                0x0000ffff
+#define VIDO_BASE_ADDR_C_MASK           0xffffffff
+#define VIDO_OFST_ADDR_C_MASK           0x0fffffff
+#define VIDO_STRIDE_C_MASK              0x0000ffff
+#define VIDO_DITHER_MASK                0xff000001
+#define VIDO_BASE_ADDR_V_MASK           0xffffffff
+#define VIDO_OFST_ADDR_V_MASK           0x0fffffff
+#define VIDO_STRIDE_V_MASK              0x0000ffff
+#define VIDO_RSV_1_MASK                 0xffffffff
+#define VIDO_DMA_PREULTRA_MASK          0x00ffffff
+#define VIDO_IN_SIZE_MASK               0x1fff1fff
+#define VIDO_ROT_EN_MASK                0x00000001
+#define VIDO_FIFO_TEST_MASK             0x00000fff
+#define VIDO_MAT_CTRL_MASK              0x000000f3
+#define VIDO_MAT_RMY_MASK               0x1fff1fff
+#define VIDO_MAT_RMV_MASK               0x1fff1fff
+#define VIDO_MAT_GMY_MASK               0x1fff1fff
+#define VIDO_MAT_BMY_MASK               0x1fff1fff
+#define VIDO_MAT_BMV_MASK               0x00001fff
+#define VIDO_MAT_PREADD_MASK            0x1ff7fdff
+#define VIDO_MAT_POSTADD_MASK           0x1ff7fdff
+#define VIDO_DITHER_00_MASK             0x0000ff3f
+#define VIDO_DITHER_02_MASK             0xffff3fff
+#define VIDO_DITHER_03_MASK             0x0000003f
+#define VIDO_DITHER_04_MASK             0xbfffffff
+#define VIDO_DITHER_05_MASK             0xffff7fff
+#define VIDO_DITHER_06_MASK             0x003ff773
+#define VIDO_DITHER_07_MASK             0x00007777
+#define VIDO_DITHER_08_MASK             0x00007777
+#define VIDO_DITHER_09_MASK             0x00007777
+#define VIDO_DITHER_10_MASK             0x0001ffff
+#define VIDO_DEBUG_MASK                 0xffffffff
+#define VIDO_ARB_SW_CTL_MASK            0x00000007
+#define MDP_WROT_TRACK_CTL_MASK         0x0000001f
+#define MDP_WROT_TRACK_WINDOW_MASK      0x00000fff
+#define MDP_WROT_TRACK_TARGET_MASK      0x00ffffff
+#define MDP_WROT_TRACK_STOP_MASK        0x00ffffff
+#define MDP_WROT_TRACK_PROC_CNT0_MASK   0xffffffff
+#define MDP_WROT_TRACK_PROC_CNT1_MASK   0x00000001
+
+#endif  // __MDP_REG_WROT_H__
diff --git a/drivers/media/platform/mtk-mdp3/mmsys_config.h b/drivers/media/platform/mtk-mdp3/mmsys_config.h
new file mode 100644
index 000000000000..5cdfb864dadf
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mmsys_config.h
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MMSYS_CONFIG_H__
+#define __MMSYS_CONFIG_H__
+
+#include "mmsys_reg_base.h"
+
+#define MMSYS_INTEN                   0x000
+#define MMSYS_INTSTA                  0x004
+#define MJC_APB_TX_CON                0x00c
+
+#define ISP_MOUT_EN                   0xf80
+#define MDP_RDMA0_MOUT_EN             0xf84
+#define MDP_RDMA1_MOUT_EN             0xf88
+#define MDP_PRZ0_MOUT_EN              0xf8c
+#define MDP_PRZ1_MOUT_EN              0xf90
+#define MDP_COLOR_MOUT_EN             0xf94
+#define IPU_MOUT_EN                   0xf98
+#define DISP_TO_WROT_SOUT_SEL         0xfa0
+#define MDP_COLOR_IN_SOUT_SEL         0xfa4
+#define MDP_PATH0_SOUT_SEL            0xfa8
+#define MDP_PATH1_SOUT_SEL            0xfac
+#define MDP_TDSHP_SOUT_SEL            0xfb0
+
+#define DISP_OVL0_MOUT_EN             0xf00
+#define DISP_OVL0_2L_MOUT_EN          0xf04
+#define DISP_OVL1_2L_MOUT_EN          0xf08
+#define DISP_DITHER0_MOUT_EN          0xf0c
+#define DISP_RSZ_MOUT_EN              0xf10
+
+#define MMSYS_MOUT_RST                0x048
+#define MDP_PRZ0_SEL_IN               0xfc0
+#define MDP_PRZ1_SEL_IN               0xfc4
+#define MDP_TDSHP_SEL_IN              0xfc8
+#define DISP_WDMA0_SEL_IN             0xfcc
+#define MDP_WROT0_SEL_IN              0xfd0
+#define MDP_WDMA_SEL_IN               0xfd4
+#define MDP_COLOR_OUT_SEL_IN          0xfd8
+#define MDP_COLOR_SEL_IN              0xfdc
+#define MDP_PATH0_SEL_IN              0xfe0
+#define MDP_PATH1_SEL_IN              0xfe4
+
+#define DISP_COLOR_OUT_SEL_IN         0xf20
+#define DISP_PATH0_SEL_IN             0xf24
+#define DISP_WDMA0_PRE_SEL_IN         0xf28
+#define DSI0_SEL_IN                   0xf2c
+#define DSI1_SEL_IN                   0xf30
+#define DISP_OVL0_SEL_IN              0xf34
+#define DISP_OVL0_2L_SEL_IN           0xf38
+#define OVL_TO_RSZ_SEL_IN             0xf3c
+#define OVL_TO_WDMA_SEL_IN            0xf40
+#define OVL_TO_WROT_SEL_IN            0xf44
+#define DISP_RSZ_SEL_IN               0xf48
+#define DISP_RDMA0_SOUT_SEL_IN        0xf50
+#define DISP_RDMA1_SOUT_SEL_IN        0xf54
+#define MDP_TO_DISP0_SOUT_SEL_IN      0xf58
+#define MDP_TO_DISP1_SOUT_SEL_IN      0xf5c
+#define DISP_RDMA0_RSZ_IN_SOUT_SEL_IN 0xf60
+#define DISP_RDMA0_RSZ_OUT_SEL_IN     0xf64
+#define MDP_AAL_MOUT_EN               0xfe8
+#define MDP_AAL_SEL_IN                0xfec
+#define MDP_CCORR_SEL_IN              0xff0
+#define MDP_CCORR_SOUT_SEL            0xff4
+
+#define MMSYS_MISC                    0x0f0
+#define MMSYS_SMI_LARB_SEL            0x0f4
+#define MMSYS_SODI_REQ_MASK           0x0f8
+#define MMSYS_CG_CON0                 0x100
+#define MMSYS_CG_SET0                 0x104
+#define MMSYS_CG_CLR0                 0x108
+#define MMSYS_CG_CON1                 0x110
+#define MMSYS_CG_SET1                 0x114
+#define MMSYS_CG_CLR1                 0x118
+#define MMSYS_HW_DCM_DIS0             0x120
+#define MMSYS_HW_DCM_DIS_SET0         0x124
+#define MMSYS_HW_DCM_DIS_CLR0         0x128
+#define MMSYS_HW_DCM_DIS1             0x130
+#define MMSYS_HW_DCM_DIS_SET1         0x134
+#define MMSYS_HW_DCM_DIS_CLR1         0x138
+#define MMSYS_HW_DCM_EVENT_CTL1       0x13c
+#define MMSYS_SW0_RST_B               0x140
+#define MMSYS_SW1_RST_B               0x144
+#define MMSYS_LCM_RST_B               0x150
+#define LARB6_AXI_ASIF_CFG_WD         0x180
+#define LARB6_AXI_ASIF_CFG_RD         0x184
+#define PROC_TRACK_EMI_BUSY_CON       0x190
+#define DISP_FAKE_ENG_EN              0x200
+#define DISP_FAKE_ENG_RST             0x204
+#define DISP_FAKE_ENG_CON0            0x208
+#define DISP_FAKE_ENG_CON1            0x20c
+#define DISP_FAKE_ENG_RD_ADDR         0x210
+#define DISP_FAKE_ENG_WR_ADDR         0x214
+#define DISP_FAKE_ENG_STATE           0x218
+#define DISP_FAKE_ENG2_EN             0x220
+#define DISP_FAKE_ENG2_RST            0x224
+#define DISP_FAKE_ENG2_CON0           0x228
+#define DISP_FAKE_ENG2_CON1           0x22c
+#define DISP_FAKE_ENG2_RD_ADDR        0x230
+#define DISP_FAKE_ENG2_WR_ADDR        0x234
+#define DISP_FAKE_ENG2_STATE          0x238
+#define MMSYS_MBIST_CON               0x800
+#define MMSYS_MBIST_DONE              0x804
+#define MMSYS_MBIST_HOLDB             0x808
+#define MMSYS_MBIST_MODE              0x80c
+#define MMSYS_MBIST_FAIL0             0x810
+#define MMSYS_MBIST_FAIL1             0x814
+#define MMSYS_MBIST_FAIL2             0x818
+#define MMSYS_MBIST_DEBUG             0x820
+#define MMSYS_MBIST_DIAG_SCANOUT      0x824
+#define MMSYS_MBIST_PRE_FUSE          0x828
+#define MMSYS_MBIST_BSEL0             0x82c
+#define MMSYS_MBIST_BSEL1             0x830
+#define MMSYS_MBIST_BSEL2             0x834
+#define MMSYS_MBIST_BSEL3             0x838
+#define MMSYS_MBIST_HDEN              0x83c
+#define MDP_RDMA0_MEM_DELSEL          0x840
+#define MDP_RDMA1_MEM_DELSEL          0x844
+#define MDP_RSZ_MEM_DELSEL            0x848
+#define MDP_TDSHP_MEM_DELSEL          0x84c
+#define MDP_AAL_MEM_DELSEL            0x850
+
+#define MDP_WROT0_MEM_DELSEL          0x854
+#define MDP_WDMA_MEM_DELSEL           0x858
+#define DISP_OVL_MEM_DELSEL           0x85c
+#define DISP_OVL_2L_MEM_DELSEL        0x860
+#define DISP_RDMA_MEM_DELSEL          0x864
+#define DISP_WDMA0_MEM_DELSEL         0x868
+#define DISP_GAMMA_MEM_DELSEL         0x870
+#define DSI_MEM_DELSEL                0x874
+#define DISP_SPLIT_MEM_DELSEL         0x878
+#define DISP_DSC_MEM_DELSEL           0x87c
+#define MMSYS_DEBUG_OUT_SEL           0x88c
+#define MMSYS_MBIST_RP_RST_B          0x890
+#define MMSYS_MBIST_RP_FAIL0          0x894
+#define MMSYS_MBIST_RP_FAIL1          0x898
+#define MMSYS_MBIST_RP_OK0            0x89c
+#define MMSYS_MBIST_RP_OK1            0x8a0
+#define MMSYS_DUMMY0                  0x8a4
+#define MMSYS_DUMMY1                  0x8a8
+#define MMSYS_DUMMY2                  0x8ac
+#define MMSYS_DUMMY3                  0x8b0
+#define DISP_DL_VALID_0               0x8b4
+#define DISP_DL_VALID_1               0x8b8
+#define DISP_DL_VALID_2               0x8bc
+#define DISP_DL_READY_0               0x8c0
+#define DISP_DL_READY_1               0x8c4
+#define DISP_DL_READY_2               0x8C8
+#define MDP_DL_VALID_0                0x8cc
+#define MDP_DL_VALID_1                0x8d0
+#define MDP_DL_READY_0                0x8d4
+#define MDP_DL_READY_1                0x8d8
+#define SMI_LARB0_GREQ                0x8dc
+#define DISP_MOUT_MASK                0x8e0
+#define DISP_MOUT_MASK1               0x8e4
+#define MDP_MOUT_MASK                 0x8e8
+#define MMSYS_POWER_READ              0x8ec
+#define TOP_RELAY_FSM_RD              0x960
+#define MDP_ASYNC_CFG_WD              0x934
+#define MDP_ASYNC_CFG_RD              0x938
+#define MDP_ASYNC_IPU_CFG_WD          0x93C
+#define MDP_ASYNC_CFG_IPU_RD          0x940
+#define MDP_ASYNC_CFG_OUT_RD          0x958
+#define MDP_ASYNC_IPU_CFG_OUT_RD      0x95C
+#define ISP_RELAY_CFG_WD              0x994
+#define ISP_RELAY_CNT_RD              0x998
+#define ISP_RELAY_CNT_LATCH_RD        0x99c
+#define IPU_RELAY_CFG_WD              0x9a0
+#define IPU_RELAY_CNT_RD              0x9a4
+#define IPU_RELAY_CNT_LATCH_RD        0x9a8
+
+/* MASK */
+#define MMSYS_SW0_RST_B_MASK          0xffffffff
+#define MMSYS_SW1_RST_B_MASK          0xffffffff
+#define MDP_COLOR_IN_SOUT_SEL_MASK    0x0000000f
+#define DISP_COLOR_OUT_SEL_IN_MASK    0xffffffff
+#define MDP_ASYNC_CFG_WD_MASK         0xffffffff
+#define MDP_ASYNC_IPU_CFG_WD_MASK     0xffffffff
+#define MMSYS_HW_DCM_DIS0_MASK        0xffffffff
+#define MMSYS_HW_DCM_DIS1_MASK        0xffffffff
+#define MDP_ASYNC_CFG_WD_MASK         0xffffffff
+#define ISP_RELAY_CFG_WD_MASK         0xffffffff
+#define IPU_RELAY_CFG_WD_MASK         0xffffffff
+
+#endif  // __MMSYS_CONFIG_H__
diff --git a/drivers/media/platform/mtk-mdp3/mmsys_mutex.h b/drivers/media/platform/mtk-mdp3/mmsys_mutex.h
new file mode 100644
index 000000000000..fb8c179f11af
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mmsys_mutex.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MMSYS_MUTEX_H__
+#define __MMSYS_MUTEX_H__
+
+#include "mmsys_reg_base.h"
+#include "mdp-platform.h"
+
+#define MM_MUTEX_INTEN              0x00
+#define MM_MUTEX_INTSTA             0x04
+#define MM_MUTEX_CFG                0x08
+
+#define MM_MUTEX_EN                 (0x20 + mutex_id * 0x20)
+#define MM_MUTEX_GET                (0x24 + mutex_id * 0x20)
+#define MM_MUTEX_RST                (0x28 + mutex_id * 0x20)
+#define MM_MUTEX_MOD                (MM_MUTEX_MOD_OFFSET + mutex_id * 0x20)
+#define MM_MUTEX_SOF                (MM_MUTEX_SOF_OFFSET + mutex_id * 0x20)
+
+// MASK
+#define MM_MUTEX_INTEN_MASK         0x0fff
+#define MM_MUTEX_INTSTA_MASK        0x0fff
+#define MM_MUTEX_DEBUG_OUT_SEL_MASK 0x03
+#define MM_MUTEX_CFG_MASK           0x01
+
+#define MM_MUTEX_EN_MASK            0x01
+#define MM_MUTEX_GET_MASK           0x03
+#define MM_MUTEX_RST_MASK           0x01
+#define MM_MUTEX_MOD_MASK           0x07ffffff
+#define MM_MUTEX_SOF_MASK           0x0f
+
+#endif  // __MMSYS_MUTEX_H__
diff --git a/drivers/media/platform/mtk-mdp3/mmsys_reg_base.h b/drivers/media/platform/mtk-mdp3/mmsys_reg_base.h
new file mode 100644
index 000000000000..d79b82eea61b
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mmsys_reg_base.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MMSYS_REG_BASE_H__
+#define __MMSYS_REG_BASE_H__
+
+#define MM_REG_WRITE_MASK(cmd, id, base, ofst, val, mask, ...) \
+	cmdq_pkt_write_mask(cmd->pkt, id, \
+		(base) + (ofst), (val), (mask), ##__VA_ARGS__)
+#define MM_REG_WRITE(cmd, id, base, ofst, val, mask, ...) \
+	MM_REG_WRITE_MASK(cmd, id, base, ofst, val, \
+		(((mask) & (ofst##_MASK)) == (ofst##_MASK)) ? \
+			(0xffffffff) : (mask), ##__VA_ARGS__)
+
+#define MM_REG_WAIT(cmd, evt) \
+	cmdq_pkt_wfe(cmd->pkt, cmd->event[(evt)])
+
+#define MM_REG_WAIT_NO_CLEAR(cmd, evt) \
+	cmdq_pkt_wait_no_clear(cmd->pkt, cmd->event[(evt)])
+
+#define MM_REG_CLEAR(cmd, evt) \
+	cmdq_pkt_clear_event(cmd->pkt, cmd->event[(evt)])
+
+#define MM_REG_SET_EVENT(cmd, evt) \
+	cmdq_pkt_set_event(cmd->pkt, cmd->event[(evt)])
+
+#define MM_REG_POLL_MASK(cmd, id, base, ofst, val, mask, ...) \
+	cmdq_pkt_poll_mask(cmd->pkt, id, \
+		(base) + (ofst), (val), (mask), ##__VA_ARGS__)
+#define MM_REG_POLL(cmd, id, base, ofst, val, mask, ...) \
+	MM_REG_POLL_MASK(cmd, id, base, ofst, val, \
+		(((mask) & (ofst##_MASK)) == (ofst##_MASK)) ? \
+			(0xffffffff) : (mask), ##__VA_ARGS__)
+
+#endif  // __MM_REG_BASE_H__
diff --git a/drivers/media/platform/mtk-mdp3/mtk-img-ipi.h b/drivers/media/platform/mtk-mdp3/mtk-img-ipi.h
new file mode 100644
index 000000000000..1c9b0e95658d
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-img-ipi.h
@@ -0,0 +1,282 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Holmes Chiou <holmes.chiou@mediatek.com>
+ *         Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_IMG_IPI_H__
+#define __MTK_IMG_IPI_H__
+
+#include <linux/types.h>
+
+/* ISP-MDP generic input information */
+
+#define IMG_MAX_HW_INPUTS	3
+
+#define IMG_MAX_HW_OUTPUTS	4
+
+#define IMG_MAX_PLANES		3
+
+#define IMG_IPI_INIT    1
+#define IMG_IPI_DEINIT  2
+#define IMG_IPI_FRAME   3
+#define IMG_IPI_DEBUG   4
+
+struct img_addr {
+	u64 va; /* Used by Linux OS access */
+	u32 pa; /* Used by CM4 access */
+	u32 iova; /* Used by IOMMU HW access */
+} __attribute__ ((__packed__));
+
+struct tuning_addr {
+	u64	present;
+	u32	pa;	/* Used by CM4 access */
+	u32	iova;	/* Used by IOMMU HW access */
+} __attribute__ ((__packed__));
+
+
+struct img_sw_addr {
+	u64 va; /* Used by APMCU access */
+	u32 pa; /* Used by CM4 access */
+} __attribute__ ((__packed__));
+
+struct img_plane_format {
+	u32 size;
+	u16 stride;
+} __attribute__ ((__packed__));
+
+struct img_pix_format {
+	u16 width;
+	u16 height;
+	u32 colorformat; /* enum mdp_color */
+	u16 ycbcr_prof; /* enum mdp_ycbcr_profile */
+	struct img_plane_format plane_fmt[IMG_MAX_PLANES];
+} __attribute__ ((__packed__));
+
+struct img_image_buffer {
+	struct img_pix_format format;
+	u32 iova[IMG_MAX_PLANES];
+	/* enum mdp_buffer_usage, FD or advanced ISP usages */
+	u32 usage;
+} __attribute__ ((__packed__));
+
+#define IMG_SUBPIXEL_SHIFT	20
+
+struct img_crop {
+	s16 left;
+	s16 top;
+	u16 width;
+	u16 height;
+	u32 left_subpix;
+	u32 top_subpix;
+	u32 width_subpix;
+	u32 height_subpix;
+} __attribute__ ((__packed__));
+
+#define IMG_CTRL_FLAG_HFLIP	BIT(0)
+#define IMG_CTRL_FLAG_DITHER	BIT(1)
+#define IMG_CTRL_FLAG_SHARPNESS	BIT(4)
+#define IMG_CTRL_FLAG_HDR	BIT(5)
+#define IMG_CTRL_FLAG_DRE	BIT(6)
+
+struct img_input {
+	struct img_image_buffer buffer;
+	u16 flags; /* HDR, DRE, dither */
+} __attribute__ ((__packed__));
+
+struct img_output {
+	struct img_image_buffer buffer;
+	struct img_crop crop;
+	s16 rotation;
+	u16 flags; /* H-flip, sharpness, dither */
+} __attribute__ ((__packed__));
+
+struct img_ipi_frameparam {
+	u32 index;
+	u32 frame_no;
+	u64 timestamp;
+	u8 type; /* enum mdp_stream_type */
+	u8 state;
+	u8 num_inputs;
+	u8 num_outputs;
+	u64 drv_data;
+	struct img_input inputs[IMG_MAX_HW_INPUTS];
+	struct img_output outputs[IMG_MAX_HW_OUTPUTS];
+	struct tuning_addr tuning_data;
+	struct img_addr subfrm_data;
+	struct img_sw_addr config_data;
+	struct img_sw_addr self_data;
+} __attribute__ ((__packed__));
+
+struct img_sw_buffer {
+	u64	handle;		/* Used by APMCU access */
+	u32	scp_addr;	/* Used by CM4 access */
+} __attribute__ ((__packed__));
+
+struct img_ipi_param {
+	u8 usage;
+	struct img_sw_buffer frm_param;
+} __attribute__ ((__packed__));
+
+struct img_frameparam {
+	struct list_head list_entry;
+	struct img_ipi_frameparam frameparam;
+};
+
+/* ISP-MDP generic output information */
+
+struct img_comp_frame {
+	u32 output_disable:1;
+	u32 bypass:1;
+	u16 in_width;
+	u16 in_height;
+	u16 out_width;
+	u16 out_height;
+	struct img_crop crop;
+	u16 in_total_width;
+	u16 out_total_width;
+} __attribute__ ((__packed__));
+
+struct img_region {
+	s16 left;
+	s16 right;
+	s16 top;
+	s16 bottom;
+} __attribute__ ((__packed__));
+
+struct img_offset {
+	s16 left;
+	s16 top;
+	u32 left_subpix;
+	u32 top_subpix;
+} __attribute__ ((__packed__));
+
+struct img_comp_subfrm {
+	u32 tile_disable:1;
+	struct img_region in;
+	struct img_region out;
+	struct img_offset luma;
+	struct img_offset chroma;
+	s16 out_vertical; /* Output vertical index */
+	s16 out_horizontal; /* Output horizontal index */
+} __attribute__ ((__packed__));
+
+#define IMG_MAX_SUBFRAMES	14
+
+struct mdp_rdma_subfrm {
+	u32 offset[IMG_MAX_PLANES];
+	u32 offset_0_p;
+	u32 src;
+	u32 clip;
+	u32 clip_ofst;
+} __attribute__ ((__packed__));
+
+struct mdp_rdma_data {
+	u32 src_ctrl;
+	u32 control;
+	u32 iova[IMG_MAX_PLANES];
+	u32 iova_end[IMG_MAX_PLANES];
+	u32 mf_bkgd;
+	u32 mf_bkgd_in_pxl;
+	u32 sf_bkgd;
+	u32 ufo_dec_y;
+	u32 ufo_dec_c;
+	u32 transform;
+	struct mdp_rdma_subfrm subfrms[IMG_MAX_SUBFRAMES];
+} __attribute__ ((__packed__));
+
+struct mdp_rsz_subfrm {
+	u32 control2;
+	u32 src;
+	u32 clip;
+} __attribute__ ((__packed__));
+
+struct mdp_rsz_data {
+	u32 coeff_step_x;
+	u32 coeff_step_y;
+	u32 control1;
+	u32 control2;
+	struct mdp_rsz_subfrm subfrms[IMG_MAX_SUBFRAMES];
+} __attribute__ ((__packed__));
+
+struct mdp_wrot_subfrm {
+	u32 offset[IMG_MAX_PLANES];
+	u32 src;
+	u32 clip;
+	u32 clip_ofst;
+	u32 main_buf;
+} __attribute__ ((__packed__));
+
+struct mdp_wrot_data {
+	u32 iova[IMG_MAX_PLANES];
+	u32 control;
+	u32 stride[IMG_MAX_PLANES];
+	u32 mat_ctrl;
+	u32 fifo_test;
+	u32 filter;
+	struct mdp_wrot_subfrm subfrms[IMG_MAX_SUBFRAMES];
+} __attribute__ ((__packed__));
+
+struct mdp_wdma_subfrm {
+	u32 offset[IMG_MAX_PLANES];
+	u32 src;
+	u32 clip;
+	u32 clip_ofst;
+} __attribute__ ((__packed__));
+
+struct mdp_wdma_data {
+	u32 wdma_cfg;
+	u32 iova[IMG_MAX_PLANES];
+	u32 w_in_byte;
+	u32 uv_stride;
+	struct mdp_wdma_subfrm subfrms[IMG_MAX_SUBFRAMES];
+} __attribute__ ((__packed__));
+
+struct isp_data {
+	u64 dl_flags; /* 1 << (enum mdp_comp_type) */
+	u32 smxi_iova[4];
+	u32 cq_idx;
+	u32 cq_iova;
+	u32 tpipe_iova[IMG_MAX_SUBFRAMES];
+} __attribute__ ((__packed__));
+
+struct img_compparam {
+	u16 type; /* enum mdp_comp_type */
+	u16 id; /* enum mdp_comp_id */
+	u32 input;
+	u32 outputs[IMG_MAX_HW_OUTPUTS];
+	u32 num_outputs;
+	struct img_comp_frame frame;
+	struct img_comp_subfrm subfrms[IMG_MAX_SUBFRAMES];
+	u32 num_subfrms;
+	union {
+		struct mdp_rdma_data rdma;
+		struct mdp_rsz_data rsz;
+		struct mdp_wrot_data wrot;
+		struct mdp_wdma_data wdma;
+		struct isp_data isp;
+	};
+} __attribute__ ((__packed__));
+
+#define IMG_MAX_COMPONENTS	20
+
+struct img_mux {
+	u32 reg;
+	u32 value;
+};
+
+struct img_mmsys_ctrl {
+	struct img_mux sets[IMG_MAX_COMPONENTS * 2];
+	u32 num_sets;
+};
+
+struct img_config {
+	struct img_compparam components[IMG_MAX_COMPONENTS];
+	u32 num_components;
+	struct img_mmsys_ctrl ctrls[IMG_MAX_SUBFRAMES];
+	u32 num_subfrms;
+} __attribute__ ((__packed__));
+
+#endif  /* __MTK_IMG_IPI_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
new file mode 100644
index 000000000000..ee81a3387cf9
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include "mtk-mdp3-cmdq.h"
+#include "mtk-mdp3-comp.h"
+#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-debug.h"
+#include "mtk-mdp3-m2m.h"
+
+#include "mdp-platform.h"
+#include "mmsys_mutex.h"
+
+#define DISP_MUTEX_MDP_FIRST	(5)
+#define DISP_MUTEX_MDP_COUNT	(5)
+
+#define MDP_PATH_MAX_COMPS	IMG_MAX_COMPONENTS
+
+struct mdp_path {
+	struct mdp_dev		*mdp_dev;
+	struct mdp_comp_ctx	comps[MDP_PATH_MAX_COMPS];
+	u32			num_comps;
+	const struct img_config	*config;
+	const struct img_ipi_frameparam *param;
+	const struct v4l2_rect	*composes[IMG_MAX_HW_OUTPUTS];
+	struct v4l2_rect	bounds[IMG_MAX_HW_OUTPUTS];
+};
+
+#define has_op(ctx, op) \
+	(ctx->comp->ops && ctx->comp->ops->op)
+#define call_op(ctx, op, ...) \
+	(has_op(ctx, op) ? ctx->comp->ops->op(ctx, ##__VA_ARGS__) : 0)
+
+struct mdp_path_subfrm {
+	s32	mutex_id;
+	u32	mutex_mod;
+	s32	sofs[MDP_PATH_MAX_COMPS];
+	u32	num_sofs;
+};
+
+static bool is_output_disable(const struct img_compparam *param, u32 count)
+{
+	return (count < param->num_subfrms) ?
+		(param->frame.output_disable ||
+		param->subfrms[count].tile_disable) :
+		true;
+}
+
+static int mdp_path_subfrm_require(struct mdp_path_subfrm *subfrm,
+				   const struct mdp_path *path,
+				   struct mdp_cmd *cmd, u32 count)
+{
+	const struct img_config *config = path->config;
+	const struct mdp_comp_ctx *ctx;
+	phys_addr_t mm_mutex = path->mdp_dev->mm_mutex.reg_base;
+	s32 mutex_id = -1;
+	u32 mutex_sof = 0;
+	int mdp_color = 0;
+	int index;
+	u8 subsys_id = path->mdp_dev->mm_mutex.subsys_id;
+
+	/* Default value */
+	memset(subfrm, 0, sizeof(*subfrm));
+
+	for (index = 0; index < config->num_components; index++) {
+		ctx = &path->comps[index];
+		if (is_output_disable(ctx->param, count))
+			continue;
+		switch (ctx->comp->id) {
+		/**********************************************
+		 * Name            MSB LSB
+		 * DISP_MUTEX_MOD   23   0
+		 *
+		 * Specifies which modules are in this mutex.
+		 * Every bit denotes a module. Bit definition:
+		 *  2 mdp_rdma0
+		 *  4 mdp_rsz0
+		 *  5 mdp_rsz1
+		 *  6 mdp_tdshp
+		 *  7 mdp_wrot0
+		 *  8 mdp_wdma
+		 *  13 mdp_color
+		 *  23 mdp_aal
+		 *  24 mdp_ccorr
+		 **********************************************/
+		case MDP_AAL0:
+			subfrm->mutex_mod |= 1 << 23;
+			break;
+		case MDP_CCORR0:
+			subfrm->mutex_mod |= 1 << 24;
+			break;
+		case MDP_COLOR0:
+			if (mdp_color)
+				subfrm->mutex_mod |= 1 << 13;
+			break;
+		case MDP_WDMA:
+			subfrm->mutex_mod |= 1 << 8;
+			subfrm->sofs[subfrm->num_sofs++] = MDP_WDMA;
+			break;
+		case MDP_WROT0:
+			subfrm->mutex_mod |= 1 << 7;
+			subfrm->sofs[subfrm->num_sofs++] = MDP_WROT0;
+			break;
+		case MDP_TDSHP0:
+			subfrm->mutex_mod |= 1 << 6;
+			subfrm->sofs[subfrm->num_sofs++] = MDP_TDSHP0;
+			break;
+		case MDP_SCL1:
+			subfrm->mutex_mod |= 1 << 5;
+			subfrm->sofs[subfrm->num_sofs++] = MDP_SCL1;
+			break;
+		case MDP_SCL0:
+			subfrm->mutex_mod |= 1 << 4;
+			subfrm->sofs[subfrm->num_sofs++] = MDP_SCL0;
+			break;
+		case MDP_RDMA0:
+			mutex_id = DISP_MUTEX_MDP_FIRST + 1;
+			subfrm->mutex_mod |= 1 << 2;
+			subfrm->sofs[subfrm->num_sofs++] = MDP_RDMA0;
+			break;
+		case MDP_IMGI:
+			mutex_id = DISP_MUTEX_MDP_FIRST;
+			break;
+		case MDP_WPEI:
+			mutex_id = DISP_MUTEX_MDP_FIRST + 3;
+			break;
+		case MDP_WPEI2:
+			mutex_id = DISP_MUTEX_MDP_FIRST + 4;
+			break;
+		default:
+			break;
+		}
+	}
+
+	subfrm->mutex_id = mutex_id;
+	if (-1 == mutex_id) {
+		mdp_err("No mutex assigned");
+		return -EINVAL;
+	}
+
+	if (subfrm->mutex_mod) {
+		/* Set mutex modules */
+		MM_REG_WRITE(cmd, subsys_id, mm_mutex, MM_MUTEX_MOD,
+			     subfrm->mutex_mod, 0x07FFFFFF);
+		MM_REG_WRITE(cmd, subsys_id, mm_mutex, MM_MUTEX_SOF,
+			     mutex_sof, 0x00000007);
+	}
+	return 0;
+}
+
+static int mdp_path_subfrm_run(const struct mdp_path_subfrm *subfrm,
+			       const struct mdp_path *path,
+			       struct mdp_cmd *cmd)
+{
+	phys_addr_t mm_mutex = path->mdp_dev->mm_mutex.reg_base;
+	s32 mutex_id = subfrm->mutex_id;
+	u8 subsys_id = path->mdp_dev->mm_mutex.subsys_id;
+
+	if (-1 == mutex_id) {
+		mdp_err("Incorrect mutex id");
+		return -EINVAL;
+	}
+
+	if (subfrm->mutex_mod) {
+		int index;
+
+		/* Wait WROT SRAM shared to DISP RDMA */
+		/* Clear SOF event for each engine */
+		for (index = 0; index < subfrm->num_sofs; index++) {
+			switch (subfrm->sofs[index]) {
+			case MDP_RDMA0:
+				MM_REG_CLEAR(cmd, RDMA0_SOF);
+				break;
+			case MDP_TDSHP0:
+				MM_REG_CLEAR(cmd, TDSHP0_SOF);
+				break;
+			case MDP_SCL0:
+				MM_REG_CLEAR(cmd, RSZ0_SOF);
+				break;
+			case MDP_SCL1:
+				MM_REG_CLEAR(cmd, RSZ1_SOF);
+				break;
+			case MDP_WDMA:
+				MM_REG_CLEAR(cmd, WDMA0_SOF);
+				break;
+			case MDP_WROT0:
+#if WROT0_DISP_SRAM_SHARING
+				MM_REG_WAIT_NO_CLEAR(cmd, WROT0_SRAM_READY);
+#endif
+				MM_REG_CLEAR(cmd, WROT0_SOF);
+				break;
+			default:
+				break;
+			}
+		}
+
+		/* Enable the mutex */
+		MM_REG_WRITE(cmd, subsys_id, mm_mutex, MM_MUTEX_EN, 0x1,
+			     0x00000001);
+
+		/* Wait SOF events and clear mutex modules (optional) */
+		for (index = 0; index < subfrm->num_sofs; index++) {
+			switch (subfrm->sofs[index]) {
+			case MDP_RDMA0:
+				MM_REG_WAIT(cmd, RDMA0_SOF);
+				break;
+			case MDP_TDSHP0:
+				MM_REG_WAIT(cmd, TDSHP0_SOF);
+				break;
+			case MDP_SCL0:
+				MM_REG_WAIT(cmd, RSZ0_SOF);
+				break;
+			case MDP_SCL1:
+				MM_REG_WAIT(cmd, RSZ1_SOF);
+				break;
+			case MDP_WDMA:
+				MM_REG_WAIT(cmd, WDMA0_SOF);
+				break;
+			case MDP_WROT0:
+				MM_REG_WAIT(cmd, WROT0_SOF);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+static int mdp_path_config_subfrm(struct mdp_cmd *cmd, struct mdp_path *path,
+				  u32 count)
+{
+	struct mdp_path_subfrm subfrm;
+	const struct img_config *config = path->config;
+	const struct img_mmsys_ctrl *ctrl = &config->ctrls[count];
+	const struct img_mux *set;
+	struct mdp_comp_ctx *ctx;
+	phys_addr_t mmsys = path->mdp_dev->mmsys.reg_base;
+	int index, ret;
+	u8 subsys_id = path->mdp_dev->mmsys.subsys_id;
+
+	/* Acquire components */
+	ret = mdp_path_subfrm_require(&subfrm, path, cmd, count);
+	if (ret)
+		return ret;
+	/* Enable mux settings */
+	for (index = 0; index < ctrl->num_sets; index++) {
+		set = &ctrl->sets[index];
+		MM_REG_WRITE_MASK(cmd, subsys_id, mmsys, set->reg, set->value,
+				  0xFFFFFFFF);
+	}
+	/* Config sub-frame information */
+	for (index = (config->num_components - 1); index >= 0; index--) {
+		ctx = &path->comps[index];
+		if (is_output_disable(ctx->param, count))
+			continue;
+		ret = call_op(ctx, config_subfrm, cmd, count);
+		if (ret)
+			return ret;
+	}
+	/* Run components */
+	ret = mdp_path_subfrm_run(&subfrm, path, cmd);
+	if (ret)
+		return ret;
+	/* Wait components done */
+	for (index = 0; index < config->num_components; index++) {
+		ctx = &path->comps[index];
+		if (is_output_disable(ctx->param, count))
+			continue;
+		ret = call_op(ctx, wait_comp_event, cmd);
+		if (ret)
+			return ret;
+	}
+	/* Advance to the next sub-frame */
+	for (index = 0; index < config->num_components; index++) {
+		ctx = &path->comps[index];
+		ret = call_op(ctx, advance_subfrm, cmd, count);
+		if (ret)
+			return ret;
+	}
+	/* Disable mux settings */
+	for (index = 0; index < ctrl->num_sets; index++) {
+		set = &ctrl->sets[index];
+		MM_REG_WRITE_MASK(cmd, subsys_id, mmsys, set->reg, 0,
+				  0xFFFFFFFF);
+	}
+	return 0;
+}
+
+static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmd *cmd,
+			   struct mdp_path *path)
+{
+	const struct img_config *config = path->config;
+	struct mdp_comp_ctx *ctx;
+	int index, count, ret;
+
+	for (index = 0; index < config->num_components; index++) {
+		ret = mdp_comp_ctx_init(mdp, &path->comps[index],
+					&config->components[index],
+					path->param);
+		if (ret)
+			return ret;
+	}
+
+	/* Config path frame */
+	/* Reset components */
+	for (index = 0; index < config->num_components; index++) {
+		ctx = &path->comps[index];
+		ret = call_op(ctx, init_comp, cmd);
+		if (ret)
+			return ret;
+	}
+	/* Config frame mode */
+	for (index = 0; index < config->num_components; index++) {
+		const struct v4l2_rect *compose =
+			path->composes[ctx->param->outputs[0]];
+
+		ctx = &path->comps[index];
+		ret = call_op(ctx, config_frame, cmd, compose);
+		if (ret)
+			return ret;
+	}
+
+	/* Config path sub-frames */
+	for (count = 0; count < config->num_subfrms; count++) {
+		ret = mdp_path_config_subfrm(cmd, path, count);
+		if (ret)
+			return ret;
+	}
+	/* Post processing information */
+	for (index = 0; index < config->num_components; index++) {
+		ctx = &path->comps[index];
+		ret = call_op(ctx, post_process, cmd);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static void mdp_auto_release_work(struct work_struct *work)
+{
+	struct mdp_cmdq_cb_param *cb_param;
+	struct mdp_dev *mdp;
+
+	cb_param = container_of(work, struct mdp_cmdq_cb_param,
+				auto_release_work);
+	mdp = cb_param->mdp;
+
+	if (cb_param->comps && cb_param->num_comps) {
+		int i;
+
+		for (i = 0; i < cb_param->num_comps; i++)
+			mdp_comp_clock_off(&mdp->pdev->dev,
+					   &cb_param->comps[i]);
+	}
+
+	kfree(cb_param->comps);
+	kfree(cb_param);
+
+	atomic_dec(&mdp->job_count);
+	wake_up(&mdp->callback_wq);
+}
+
+static void mdp_handle_cmdq_callback(struct cmdq_cb_data data)
+{
+	struct mdp_cmdq_cb_param *cb_param;
+	struct mdp_dev *mdp;
+
+	if (!data.data) {
+		mdp_err("%s:no callback data\n", __func__);
+		return;
+	}
+
+	cb_param = (struct mdp_cmdq_cb_param *)data.data;
+	mdp = cb_param->mdp;
+
+	if (cb_param->mdp_ctx)
+		mdp_m2m_job_finish(cb_param->mdp_ctx);
+#ifdef MDP_DEBUG
+	if (data.sta == CMDQ_CB_ERROR) {
+		struct mdp_func_struct *p_func = mdp_get_func();
+
+		p_func->mdp_dump_mmsys_config();
+		mdp_dump_info(~0, 1);
+	}
+#endif
+
+	if (cb_param->user_cmdq_cb) {
+		struct cmdq_cb_data user_cb_data;
+
+		user_cb_data.sta = data.sta;
+		user_cb_data.data = cb_param->user_cb_data;
+		cb_param->user_cmdq_cb(user_cb_data);
+	}
+
+	cmdq_pkt_destroy(cb_param->pkt);
+	INIT_WORK(&cb_param->auto_release_work, mdp_auto_release_work);
+	queue_work(mdp->clock_wq, &cb_param->auto_release_work);
+}
+
+int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
+{
+	struct mdp_cmd cmd;
+	struct mdp_path path;
+	int i, ret;
+
+	if (atomic_read(&mdp->suspended))
+		return -ECANCELED;
+
+	atomic_inc(&mdp->job_count);
+
+	cmd.pkt = cmdq_pkt_create(mdp->cmdq_clt, SZ_16K);
+	if (IS_ERR(cmd.pkt)) {
+		atomic_dec(&mdp->job_count);
+		wake_up(&mdp->callback_wq);
+		return PTR_ERR(cmd.pkt);
+	}
+	cmd.event = &mdp->event[0];
+
+	path.mdp_dev = mdp;
+	path.config = param->config;
+	path.param = param->param;
+	for (i = 0; i < param->param->num_outputs; i++) {
+		path.bounds[i].left = 0;
+		path.bounds[i].top = 0;
+		path.bounds[i].width =
+			param->param->outputs[i].buffer.format.width;
+		path.bounds[i].height =
+			param->param->outputs[i].buffer.format.height;
+		path.composes[i] = param->composes[i] ?
+			param->composes[i] : &path.bounds[i];
+	}
+	ret = mdp_path_config(mdp, &cmd, &path);
+	if (ret) {
+		atomic_dec(&mdp->job_count);
+		wake_up(&mdp->callback_wq);
+		return ret;
+	}
+
+	// TODO: engine conflict dispatch
+	for (i = 0; i < param->config->num_components; i++)
+		mdp_comp_clock_on(&mdp->pdev->dev, path.comps[i].comp);
+
+	if (param->wait) {
+		ret = cmdq_pkt_flush(cmd.pkt);
+#ifdef MDP_DEBUG
+		if (ret) {
+			struct mdp_func_struct *p_func = mdp_get_func();
+
+			p_func->mdp_dump_mmsys_config();
+			mdp_dump_info(~0, 1);
+		}
+#endif
+		if (param->mdp_ctx)
+			mdp_m2m_job_finish(param->mdp_ctx);
+		cmdq_pkt_destroy(cmd.pkt);
+		for (i = 0; i < param->config->num_components; i++)
+			mdp_comp_clock_off(&mdp->pdev->dev, path.comps[i].comp);
+
+		atomic_dec(&mdp->job_count);
+		wake_up(&mdp->callback_wq);
+	} else {
+		struct mdp_cmdq_cb_param *cb_param;
+		struct mdp_comp *comps;
+
+		cb_param = kzalloc(sizeof(*cb_param), GFP_KERNEL);
+		if (!cb_param)
+			return -ENOMEM;
+		comps = kcalloc(param->config->num_components, sizeof(*comps),
+				GFP_KERNEL);
+		if (!comps) {
+			kfree(cb_param);
+			mdp_err("%s:comps alloc fail!\n", __func__);
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < param->config->num_components; i++)
+			memcpy(&comps[i], path.comps[i].comp,
+			       sizeof(struct mdp_comp));
+		cb_param->mdp = mdp;
+		cb_param->user_cmdq_cb = param->cmdq_cb;
+		cb_param->user_cb_data = param->cb_data;
+		cb_param->pkt = cmd.pkt;
+		cb_param->comps = comps;
+		cb_param->num_comps = param->config->num_components;
+		cb_param->mdp_ctx = param->mdp_ctx;
+
+		ret = cmdq_pkt_flush_async(cmd.pkt,
+					   mdp_handle_cmdq_callback,
+					   (void *)cb_param);
+		if (ret) {
+			mdp_err("%s:cmdq_pkt_flush_async fail!\n", __func__);
+			kfree(cb_param);
+			kfree(comps);
+		}
+	}
+	return ret;
+}
+
+int mdp_cmdq_sendtask(struct platform_device *pdev, struct img_config *config,
+		      struct img_ipi_frameparam *param,
+		      struct v4l2_rect *compose, unsigned int wait,
+		      void (*cmdq_cb)(struct cmdq_cb_data data), void *cb_data)
+{
+	struct mdp_dev *mdp = platform_get_drvdata(pdev);
+	struct mdp_cmdq_param task = {
+		.config = config,
+		.param = param,
+		.composes[0] = compose,
+		.wait = wait,
+		.cmdq_cb = cmdq_cb,
+		.cb_data = cb_data,
+	};
+
+	return mdp_cmdq_send(mdp, &task);
+}
+EXPORT_SYMBOL_GPL(mdp_cmdq_sendtask);
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
new file mode 100644
index 000000000000..6b8b0f6b4bb5
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_CMDQ_H__
+#define __MTK_MDP3_CMDQ_H__
+
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+#include "mtk-img-ipi.h"
+
+struct platform_device *mdp_get_plat_device(struct platform_device *pdev);
+
+int mdp_cmdq_sendtask(struct platform_device *pdev, struct img_config *config,
+		      struct img_ipi_frameparam *param,
+		      struct v4l2_rect *compose, unsigned int wait,
+		      void (*cmdq_cb)(struct cmdq_cb_data data), void *cb_data);
+
+struct mdp_cmd {
+	struct cmdq_pkt *pkt;
+	s32 *event;
+};
+
+struct mdp_cmdq_param {
+	struct img_config *config;
+	struct img_ipi_frameparam *param;
+	const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS];
+	unsigned int wait;
+
+	void (*cmdq_cb)(struct cmdq_cb_data data);
+	void *cb_data;
+	void *mdp_ctx;
+};
+
+struct mdp_cmdq_cb_param {
+	struct work_struct auto_release_work;
+	struct mdp_dev *mdp;
+	void (*user_cmdq_cb)(struct cmdq_cb_data data);
+	void *user_cb_data;
+	struct cmdq_pkt *pkt;
+	struct mdp_comp *comps;
+	u8 num_comps;
+	void *mdp_ctx;
+};
+
+struct mdp_dev;
+
+int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param);
+
+#endif  /* __MTK_MDP3_CMDQ_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
new file mode 100644
index 000000000000..3033cd32340c
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
@@ -0,0 +1,1329 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include "mtk-mdp3-comp.h"
+#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-regs.h"
+
+#include "mdp-platform.h"
+#include "mmsys_config.h"
+#include "mdp_reg_rdma.h"
+#include "mdp_reg_ccorr.h"
+#include "mdp_reg_rsz.h"
+#include "mdp_reg_wrot.h"
+#include "mdp_reg_wdma.h"
+#include "isp_reg.h"
+
+static s64 get_comp_flag(const struct mdp_comp_ctx *ctx)
+{
+#if RDMA0_RSZ1_SRAM_SHARING
+	if (ctx->comp->id == MDP_RDMA0)
+		return (1 << MDP_RDMA0) | (1 << MDP_SCL1);
+#endif
+	return 1 << ctx->comp->id;
+}
+
+static int init_rdma(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+#if RDMA0_RSZ1_SRAM_SHARING
+	struct mdp_comp *prz1 = ctx->comp->mdp_dev->comp[MDP_SCL1];
+
+	/* Disable RSZ1 */
+	if (ctx->comp->id == MDP_RDMA0 && prz1)
+		MM_REG_WRITE(cmd, subsys_id, prz1->reg_base, PRZ_ENABLE,
+			     0x00000000, 0x00000001);
+#endif
+	/* Reset RDMA */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_RESET, 0x00000001,
+		     0x00000001);
+	MM_REG_POLL(cmd, subsys_id, base, MDP_RDMA_MON_STA_1, 0x00000100,
+		    0x00000100);
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_RESET, 0x00000000,
+		     0x00000001);
+	return 0;
+}
+
+static int config_rdma_frame(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd,
+			     const struct v4l2_rect *compose)
+{
+	const struct mdp_rdma_data *rdma = &ctx->param->rdma;
+	u32 colorformat = ctx->input->buffer.format.colorformat;
+	bool block10bit = MDP_COLOR_IS_10BIT_PACKED(colorformat);
+	bool en_ufo = MDP_COLOR_IS_UFP(colorformat);
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+#if RDMA_SUPPORT_10BIT
+	if (block10bit)
+		MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_RESV_DUMMY_0,
+			     0x00000007, 0x00000007);
+	else
+		MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_RESV_DUMMY_0,
+			     0x00000000, 0x00000007);
+#endif
+
+	/* Setup smi control */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_GMCIF_CON,
+		     (1 <<  0) +
+		     (7 <<  4) + //burst type to 8
+		     (1 << 16),  //enable pre-ultra
+		     0x00030071);
+
+	/* Setup source frame info */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_CON, rdma->src_ctrl,
+		     0x03C8FE0F);
+#if RDMA_SUPPORT_10BIT
+	if (en_ufo) {
+		/* Setup source buffer base */
+		MM_REG_WRITE(cmd, subsys_id,
+			     base, MDP_RDMA_UFO_DEC_LENGTH_BASE_Y,
+			     rdma->ufo_dec_y, 0xFFFFFFFF);
+		MM_REG_WRITE(cmd, subsys_id,
+			     base, MDP_RDMA_UFO_DEC_LENGTH_BASE_C,
+			     rdma->ufo_dec_c, 0xFFFFFFFF);
+		/* Set 10bit source frame pitch */
+		if (block10bit)
+			MM_REG_WRITE(cmd, subsys_id,
+				     base, MDP_RDMA_MF_BKGD_SIZE_IN_PXL,
+				     rdma->mf_bkgd_in_pxl, 0x001FFFFF);
+	}
+#endif
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_CON, rdma->control,
+		     0x00001110);
+	/* Setup source buffer base */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_0, rdma->iova[0],
+		     0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_1, rdma->iova[1],
+		     0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_2, rdma->iova[2],
+		     0xFFFFFFFF);
+	/* Setup source buffer end */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_0,
+		     rdma->iova_end[0], 0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_1,
+		     rdma->iova_end[1], 0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_2,
+		     rdma->iova_end[2], 0xFFFFFFFF);
+	/* Setup source frame pitch */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_BKGD_SIZE_IN_BYTE,
+		     rdma->mf_bkgd, 0x001FFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SF_BKGD_SIZE_IN_BYTE,
+		     rdma->sf_bkgd, 0x001FFFFF);
+	/* Setup color transform */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_TRANSFORM_0,
+		     rdma->transform, 0x0F110000);
+
+	return 0;
+}
+
+static int config_rdma_subfrm(struct mdp_comp_ctx *ctx,
+			      struct mdp_cmd *cmd, u32 index)
+{
+	const struct mdp_rdma_subfrm *subfrm = &ctx->param->rdma.subfrms[index];
+	const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
+	u32 colorformat = ctx->input->buffer.format.colorformat;
+	bool block10bit = MDP_COLOR_IS_10BIT_PACKED(colorformat);
+	bool en_ufo = MDP_COLOR_IS_UFP(colorformat);
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* Enable RDMA */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_EN, 0x00000001,
+		     0x00000001);
+
+	/* Set Y pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_0,
+		     subfrm->offset[0], 0xFFFFFFFF);
+#if RDMA_SUPPORT_10BIT
+	/* Set 10bit UFO mode */
+	if (block10bit && en_ufo)
+		MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_0_P,
+			     subfrm->offset_0_p, 0xFFFFFFFF);
+#endif
+	/* Set U pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_1,
+		     subfrm->offset[1], 0xFFFFFFFF);
+	/* Set V pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_2,
+		     subfrm->offset[2], 0xFFFFFFFF);
+	/* Set source size */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_SRC_SIZE, subfrm->src,
+		     0x1FFF1FFF);
+	/* Set target size */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_CLIP_SIZE,
+		     subfrm->clip, 0x1FFF1FFF);
+	/* Set crop offset */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_OFFSET_1,
+		     subfrm->clip_ofst, 0x003F001F);
+
+#if RDMA_UPSAMPLE_REPEAT_ONLY
+	if ((csf->in.right - csf->in.left + 1) > 320)
+		MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_RESV_DUMMY_0,
+			     0x00000004, 0x00000004);
+#endif
+
+	return 0;
+}
+
+static int wait_rdma_event(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	if (ctx->comp->alias_id == 0)
+		MM_REG_WAIT(cmd, RDMA0_DONE);
+	else
+		pr_err("Do not support RDMA1_DONE event\n");
+
+	/* Disable RDMA */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_EN, 0x00000000,
+		     0x00000001);
+	return 0;
+}
+
+static const struct mdp_comp_ops rdma_ops = {
+	.get_comp_flag = get_comp_flag,
+	.init_comp = init_rdma,
+	.config_frame = config_rdma_frame,
+	.config_subfrm = config_rdma_subfrm,
+	/* .reconfig_frame = reconfig_rdma_frame, */
+	/* .reconfig_subfrms = reconfig_rdma_subfrms, */
+	.wait_comp_event = wait_rdma_event,
+	.advance_subfrm = NULL,
+	.post_process = NULL,
+};
+
+static int init_rsz(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* Reset RSZ */
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x00010000,
+		     0x00010000);
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x00000000,
+		     0x00010000);
+	/* Enable RSZ */
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x00000001,
+		     0x00000001);
+	return 0;
+}
+
+static int config_rsz_frame(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd,
+			    const struct v4l2_rect *compose)
+{
+	const struct mdp_rsz_data *rsz = &ctx->param->rsz;
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	if (ctx->param->frame.bypass) {
+		/* Disable RSZ */
+		MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x00000000,
+			     0x00000001);
+
+		return 0;
+	}
+
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, rsz->control1,
+		     0x03FFFDF3);
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, rsz->control2,
+		     0x0FFFC290);
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_HORIZONTAL_COEFF_STEP,
+		     rsz->coeff_step_x, 0x007FFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_VERTICAL_COEFF_STEP,
+		     rsz->coeff_step_y, 0x007FFFFF);
+	return 0;
+}
+
+static int config_rsz_subfrm(struct mdp_comp_ctx *ctx,
+			     struct mdp_cmd *cmd, u32 index)
+{
+	const struct mdp_rsz_subfrm *subfrm = &ctx->param->rsz.subfrms[index];
+	const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, subfrm->control2,
+		     0x00003800);
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_INPUT_IMAGE, subfrm->src,
+		     0xFFFFFFFF);
+#if RSZ_DISABLE_DCM_SMALL_TILE
+	if ((csf->in.right - csf->in.left + 1) <= 16)
+		MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, 1 << 27,
+			     1 << 27);
+#endif
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET,
+		     csf->luma.left, 0x0000FFFF);
+	MM_REG_WRITE(cmd, subsys_id,
+		     base, PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET,
+		     csf->luma.left_subpix, 0x001FFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_INTEGER_OFFSET,
+		     csf->luma.top, 0x0000FFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET,
+		     csf->luma.top_subpix, 0x001FFFFF);
+	MM_REG_WRITE(cmd, subsys_id,
+		     base, PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET,
+		     csf->chroma.left, 0x0000FFFF);
+	MM_REG_WRITE(cmd, subsys_id,
+		     base, PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET,
+		     csf->chroma.left_subpix, 0x001FFFFF);
+
+	MM_REG_WRITE(cmd, subsys_id, base, PRZ_OUTPUT_IMAGE, subfrm->clip,
+		     0xFFFFFFFF);
+
+	return 0;
+}
+
+static int advance_rsz_subfrm(struct mdp_comp_ctx *ctx,
+			      struct mdp_cmd *cmd, u32 index)
+{
+#if RSZ_DISABLE_DCM_SMALL_TILE
+	const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	if ((csf->in.right - csf->in.left + 1) <= 16)
+		MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, 0, 1 << 27);
+#endif
+	return 0;
+}
+
+static const struct mdp_comp_ops rsz_ops = {
+	.get_comp_flag = get_comp_flag,
+	.init_comp = init_rsz,
+	.config_frame = config_rsz_frame,
+	.config_subfrm = config_rsz_subfrm,
+	/* .reconfig_frame = NULL, */
+	/* .reconfig_subfrms = NULL, */
+	.wait_comp_event = NULL,
+	.advance_subfrm = advance_rsz_subfrm,
+	.post_process = NULL,
+};
+
+static int init_wrot(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+#if WROT_FILTER_CONSTRAINT
+	/* Wait WROT SRAM shared to DISP RDMA */
+	if (ctx->comp->alias_id == 0)
+		pr_err("Do not support WROT0_SRAM_READY event\n");
+	else
+		pr_err("Do not support WROT1_SRAM_READY event\n");
+#endif
+	/* Reset WROT */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_SOFT_RST, 0x01, 0x00000001);
+	MM_REG_POLL(cmd, subsys_id, base, VIDO_SOFT_RST_STAT, 0x01,
+		    0x00000001);
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_SOFT_RST, 0x00, 0x00000001);
+	MM_REG_POLL(cmd, subsys_id, base, VIDO_SOFT_RST_STAT, 0x00,
+		    0x00000001);
+	return 0;
+}
+
+static int config_wrot_frame(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd,
+			     const struct v4l2_rect *compose)
+{
+	const struct mdp_wrot_data *wrot = &ctx->param->wrot;
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* Write frame base address */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR, wrot->iova[0],
+		     0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_C, wrot->iova[1],
+		     0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_V, wrot->iova[2],
+		     0xFFFFFFFF);
+	/* Write frame related registers */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_CTRL, wrot->control,
+		     0xF131510F);
+	/* Write frame Y pitch */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE, wrot->stride[0],
+		     0x0000FFFF);
+	/* Write frame UV pitch */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_C, wrot->stride[1],
+		     0x0000FFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_V, wrot->stride[2],
+		     0x0000FFFF);
+	/* Write matrix control */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAT_CTRL, wrot->mat_ctrl,
+		     0x000000F3);
+
+	/* Set the fixed ALPHA as 0xFF */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_DITHER, 0xFF000000,
+		     0xFF000000);
+	/* Set VIDO_EOL_SEL */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_RSV_1, 0x80000000,
+		     0x80000000);
+	/* Set VIDO_FIFO_TEST */
+	if (wrot->fifo_test != 0)
+		MM_REG_WRITE(cmd, subsys_id, base, VIDO_FIFO_TEST,
+			     wrot->fifo_test, 0x00000FFF);
+
+#if WROT_FILTER_CONSTRAINT
+	/* Filter enable */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE, wrot->filter,
+		     0x00000077);
+#endif
+
+	return 0;
+}
+
+static int config_wrot_subfrm(struct mdp_comp_ctx *ctx,
+			      struct mdp_cmd *cmd, u32 index)
+{
+	const struct mdp_wrot_subfrm *subfrm = &ctx->param->wrot.subfrms[index];
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* Write Y pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR,
+		     subfrm->offset[0], 0x0FFFFFFF);
+	/* Write U pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_C,
+		     subfrm->offset[1], 0x0FFFFFFF);
+	/* Write V pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_V,
+		     subfrm->offset[2], 0x0FFFFFFF);
+	/* Write source size */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_IN_SIZE, subfrm->src,
+		     0x1FFF1FFF);
+	/* Write target size */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_TAR_SIZE, subfrm->clip,
+		     0x1FFF1FFF);
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_CROP_OFST, subfrm->clip_ofst,
+		     0x1FFF1FFF);
+
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE,
+		     subfrm->main_buf, 0x1FFF7F00);
+
+	/* Enable WROT */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_ROT_EN, 0x01, 0x00000001);
+
+	return 0;
+}
+
+static int wait_wrot_event(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	if (ctx->comp->alias_id == 0)
+		MM_REG_WAIT(cmd, WROT0_DONE);
+	else
+		pr_err("Do not support WROT1_DONE event\n");
+#if WROT_FILTER_CONSTRAINT
+	/* Filter disable */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE,
+		     (0 << 4) +
+		(0 << 0),
+		0x00000077);
+#endif
+	/* Disable WROT */
+	MM_REG_WRITE(cmd, subsys_id, base, VIDO_ROT_EN, 0x00, 0x00000001);
+
+	return 0;
+}
+
+static const struct mdp_comp_ops wrot_ops = {
+	.get_comp_flag = get_comp_flag,
+	.init_comp = init_wrot,
+	.config_frame = config_wrot_frame,
+	.config_subfrm = config_wrot_subfrm,
+	/* .reconfig_frame = reconfig_wrot_frame, */
+	/* .reconfig_subfrms = reconfig_wrot_subfrms, */
+	.wait_comp_event = wait_wrot_event,
+	.advance_subfrm = NULL,
+	.post_process = NULL,
+};
+
+static int init_wdma(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* Reset WDMA */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_RST, 0x1, 0x00000001);
+	MM_REG_POLL(cmd, subsys_id, base, WDMA_FLOW_CTRL_DBG, 0x01,
+		    0x00000001);
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_RST, 0x0, 0x00000001);
+	return 0;
+}
+
+static int config_wdma_frame(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd,
+			     const struct v4l2_rect *compose)
+{
+	const struct mdp_wdma_data *wdma = &ctx->param->wdma;
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_BUF_CON2, 0x10101050,
+		     0xFFFFFFFF);
+
+	/* Setup frame information */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_CFG, wdma->wdma_cfg,
+		     0x0F01B8F0);
+	/* Setup frame base address */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_ADDR,   wdma->iova[0],
+		     0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_U_ADDR, wdma->iova[1],
+		     0xFFFFFFFF);
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_V_ADDR, wdma->iova[2],
+		     0xFFFFFFFF);
+	/* Setup Y pitch */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_W_IN_BYTE,
+		     wdma->w_in_byte, 0x0000FFFF);
+	/* Setup UV pitch */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_UV_PITCH,
+		     wdma->uv_stride, 0x0000FFFF);
+	/* Set the fixed ALPHA as 0xFF */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_ALPHA, 0x800000FF,
+		     0x800000FF);
+
+	return 0;
+}
+
+static int config_wdma_subfrm(struct mdp_comp_ctx *ctx,
+			      struct mdp_cmd *cmd, u32 index)
+{
+	const struct mdp_wdma_subfrm *subfrm = &ctx->param->wdma.subfrms[index];
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* Write Y pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_ADDR_OFFSET,
+		     subfrm->offset[0], 0x0FFFFFFF);
+	/* Write U pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_U_ADDR_OFFSET,
+		     subfrm->offset[1], 0x0FFFFFFF);
+	/* Write V pixel offset */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_V_ADDR_OFFSET,
+		     subfrm->offset[2], 0x0FFFFFFF);
+	/* Write source size */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_SRC_SIZE, subfrm->src,
+		     0x3FFF3FFF);
+	/* Write target size */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_SIZE, subfrm->clip,
+		     0x3FFF3FFF);
+	/* Write clip offset */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_COORD, subfrm->clip_ofst,
+		     0x3FFF3FFF);
+
+	/* Enable WDMA */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_EN, 0x01, 0x00000001);
+
+	return 0;
+}
+
+static int wait_wdma_event(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	MM_REG_WAIT(cmd, WDMA0_DONE);
+	/* Disable WDMA */
+	MM_REG_WRITE(cmd, subsys_id, base, WDMA_EN, 0x00, 0x00000001);
+	return 0;
+}
+
+static const struct mdp_comp_ops wdma_ops = {
+	.get_comp_flag = get_comp_flag,
+	.init_comp = init_wdma,
+	.config_frame = config_wdma_frame,
+	.config_subfrm = config_wdma_subfrm,
+	/* .reconfig_frame = reconfig_wdma_frame, */
+	/* .reconfig_subfrms = reconfig_wdma_subfrms, */
+	.wait_comp_event = wait_wdma_event,
+	.advance_subfrm = NULL,
+	.post_process = NULL,
+};
+
+static int init_ccorr(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* CCORR enable */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_CCORR_EN, 0x1, 0x1);
+	/* Relay mode */
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_CCORR_CFG, 0x1, 0x1);
+	return 0;
+}
+
+static int config_ccorr_frame(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd,
+			      const struct v4l2_rect *compose)
+{
+	/* Disabled function */
+	return 0;
+}
+
+static int config_ccorr_subfrm(struct mdp_comp_ctx *ctx,
+			       struct mdp_cmd *cmd, u32 index)
+{
+	const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+	u32 hsize, vsize;
+
+	hsize = csf->in.right - csf->in.left + 1;
+	vsize = csf->in.bottom - csf->in.top + 1;
+	MM_REG_WRITE(cmd, subsys_id, base, MDP_CCORR_SIZE,
+		     (hsize << 16) + (vsize <<  0), 0x1FFF1FFF);
+	return 0;
+}
+
+static const struct mdp_comp_ops ccorr_ops = {
+	.get_comp_flag = get_comp_flag,
+	.init_comp = init_ccorr,
+	.config_frame = config_ccorr_frame,
+	.config_subfrm = config_ccorr_subfrm,
+	/* .reconfig_frame = NULL, */
+	/* .reconfig_subfrms = NULL, */
+	.wait_comp_event = NULL,
+	.advance_subfrm = NULL,
+	.post_process = NULL,
+};
+
+static int init_isp(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	const struct isp_data *isp = &ctx->param->isp;
+	phys_addr_t mmsys = ctx->comp->mdp_dev->mmsys.reg_base;
+	u8 subsys_id = ctx->comp->mdp_dev->mmsys.subsys_id;
+
+	/* Direct link */
+	if (isp->dl_flags & (1 << MDP_CAMIN)) {
+		mdp_dbg(2, "SW_RST ASYNC");
+		/* Reset MDP_DL_ASYNC_TX */
+		/* Bit  3: MDP_DL_ASYNC_TX / MDP_RELAY */
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW0_RST_B, 0x0,
+			     0x00000008);
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW0_RST_B, 1 << 3,
+			     0x00000008);
+		/* Reset MDP_DL_ASYNC_RX */
+		/* Bit  10: MDP_DL_ASYNC_RX */
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW1_RST_B, 0x0,
+			     0x00000400);
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW1_RST_B, 1 << 10,
+			     0x00000400);
+
+		/* Enable sof mode */
+		MM_REG_WRITE(cmd, subsys_id, mmsys, ISP_RELAY_CFG_WD, 0 << 31,
+			     0x80000000);
+	}
+
+	if (isp->dl_flags & (1 << MDP_CAMIN2)) {
+		mdp_dbg(2, "SW_RST ASYNC2");
+		/* Reset MDP_DL_ASYNC2_TX */
+		/* Bit  4: MDP_DL_ASYNC2_TX / MDP_RELAY2 */
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW0_RST_B, 0x0,
+			     0x00000010);
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW0_RST_B, 1 << 4,
+			     0x00000010);
+		/* Reset MDP_DL_ASYNC2_RX */
+		/* Bit  11: MDP_DL_ASYNC2_RX */
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW1_RST_B, 0x0,
+			     0x00000800);
+		MM_REG_WRITE(cmd, subsys_id, mmsys, MMSYS_SW1_RST_B, 1 << 11,
+			     0x00000800);
+
+		/* Enable sof mode */
+		MM_REG_WRITE(cmd, subsys_id, mmsys, IPU_RELAY_CFG_WD, 0 << 31,
+			     0x80000000);
+	}
+
+	return 0;
+}
+
+static int config_isp_frame(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd,
+			    const struct v4l2_rect *compose)
+{
+	const struct isp_data *isp = &ctx->param->isp;
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* DIP_X_SMX1I_BASE_ADDR, DIP_X_SMX1O_BASE_ADDR */
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2890, isp->smxi_iova[0],
+			  0xFFFFFFFF);
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x27D0, isp->smxi_iova[0],
+			  0xFFFFFFFF);
+	/* DIP_X_SMX2I_BASE_ADDR, DIP_X_SMX2O_BASE_ADDR */
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x28C0, isp->smxi_iova[1],
+			  0xFFFFFFFF);
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2800, isp->smxi_iova[1],
+			  0xFFFFFFFF);
+	/* DIP_X_SMX3I_BASE_ADDR, DIP_X_SMX3O_BASE_ADDR */
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x28F0, isp->smxi_iova[2],
+			  0xFFFFFFFF);
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2830, isp->smxi_iova[2],
+			  0xFFFFFFFF);
+	/* DIP_X_SMX4I_BASE_ADDR, DIP_X_SMX4O_BASE_ADDR */
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2920, isp->smxi_iova[3],
+			  0xFFFFFFFF);
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2860, isp->smxi_iova[3],
+			  0xFFFFFFFF);
+
+	switch (isp->cq_idx) {
+	case ISP_DRV_DIP_CQ_THRE0:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2208,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE1:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2214,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE2:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2220,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE3:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x222C,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE4:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2238,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE5:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2244,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE6:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2250,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE7:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x225C,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE8:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2268,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE9:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2274,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE10:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2280,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE11:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x228C,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE12:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2298,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE13:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x22A4,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	case ISP_DRV_DIP_CQ_THRE14:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x22B0,
+				  isp->cq_iova, 0xFFFFFFFF);
+		break;
+	/* From CQ15 to CQ18, these do not connect to GCE */
+	default:
+		mdp_err("Do not support this cq (%d)", isp->cq_idx);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int config_isp_subfrm(struct mdp_comp_ctx *ctx,
+			     struct mdp_cmd *cmd, u32 index)
+{
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2304,
+			  ctx->param->isp.tpipe_iova[index], 0xFFFFFFFF);
+	return 0;
+}
+
+static int wait_isp_event(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd)
+{
+	const struct isp_data *isp = &ctx->param->isp;
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+
+	/* MDP_DL_SEL: select MDP_CROP */
+	if (isp->dl_flags & (1 << MDP_CAMIN))
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x0030, 0x00000000,
+				  0x00000200);
+	/* MDP2_DL_SEL: select MDP_CROP2 */
+	if (isp->dl_flags & (1 << MDP_CAMIN2))
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x0030, 0x00000000,
+				  0x00000C00);
+
+	switch (isp->cq_idx) {
+	case ISP_DRV_DIP_CQ_THRE0:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0001,
+				  0x00000001);
+		MM_REG_WAIT(cmd, ISP_P2_0_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE1:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0002,
+				  0x00000002);
+		MM_REG_WAIT(cmd, ISP_P2_1_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE2:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0004,
+				  0x00000004);
+		MM_REG_WAIT(cmd, ISP_P2_2_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE3:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0008,
+				  0x00000008);
+		MM_REG_WAIT(cmd, ISP_P2_3_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE4:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0010,
+				  0x00000010);
+		MM_REG_WAIT(cmd, ISP_P2_4_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE5:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0020,
+				  0x00000020);
+		MM_REG_WAIT(cmd, ISP_P2_5_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE6:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0040,
+				  0x00000040);
+		MM_REG_WAIT(cmd, ISP_P2_6_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE7:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0080,
+				  0x00000080);
+		MM_REG_WAIT(cmd, ISP_P2_7_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE8:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0100,
+				  0x00000100);
+		MM_REG_WAIT(cmd, ISP_P2_8_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE9:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0200,
+				  0x00000200);
+		MM_REG_WAIT(cmd, ISP_P2_9_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE10:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0400,
+				  0x00000400);
+		MM_REG_WAIT(cmd, ISP_P2_10_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE11:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x0800,
+				  0x00000800);
+		MM_REG_WAIT(cmd, ISP_P2_11_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE12:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x1000,
+				  0x00001000);
+		MM_REG_WAIT(cmd, ISP_P2_12_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE13:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x2000,
+				  0x00002000);
+		MM_REG_WAIT(cmd, ISP_P2_13_DONE);
+		break;
+	case ISP_DRV_DIP_CQ_THRE14:
+		MM_REG_WRITE_MASK(cmd, subsys_id, base, 0x2000, 0x4000,
+				  0x00004000);
+		MM_REG_WAIT(cmd, ISP_P2_14_DONE);
+		break;
+	/* From CQ15 to CQ18, these do not connect to GCE */
+	default:
+		mdp_err("Do not support this cq (%d)", isp->cq_idx);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct mdp_comp_ops imgi_ops = {
+	.get_comp_flag = get_comp_flag,
+	.init_comp = init_isp,
+	.config_frame = config_isp_frame,
+	.config_subfrm = config_isp_subfrm,
+	/* .reconfig_frame = reconfig_isp_frame, */
+	/* .reconfig_subfrms = reconfig_isp_subfrms, */
+	.wait_comp_event = wait_isp_event,
+	.advance_subfrm = NULL,
+	.post_process = NULL,
+};
+
+static int config_camin_subfrm(struct mdp_comp_ctx *ctx,
+			       struct mdp_cmd *cmd, u32 index)
+{
+	const struct img_comp_subfrm *csf = &ctx->param->subfrms[index];
+	phys_addr_t base = ctx->comp->reg_base;
+	u8 subsys_id = ctx->comp->subsys_id;
+	u32 isp_dl_w, isp_dl_h;
+
+	isp_dl_w = csf->in.right - csf->in.left + 1;
+	isp_dl_h = csf->in.bottom - csf->in.top + 1;
+
+	/* Config for direct link */
+	if (ctx->comp->alias_id == 0) {
+#ifdef MDP_ASYNC_CFG_WD
+		MM_REG_WRITE(cmd, subsys_id, base, MDP_ASYNC_CFG_WD,
+			     (isp_dl_h << 16) + isp_dl_w, 0x3FFF3FFF);
+#endif
+#ifdef ISP_RELAY_CFG_WD
+		MM_REG_WRITE(cmd, subsys_id, base, ISP_RELAY_CFG_WD,
+			     (isp_dl_h << 16) + isp_dl_w, 0x3FFF3FFF);
+#endif
+	} else {
+#ifdef MDP_ASYNC_IPU_CFG_WD
+		MM_REG_WRITE(cmd, subsys_id, base, MDP_ASYNC_IPU_CFG_WD,
+			     (isp_dl_h << 16) + isp_dl_w, 0x3FFF3FFF);
+#endif
+#ifdef IPU_RELAY_CFG_WD
+		MM_REG_WRITE(cmd, subsys_id, base, IPU_RELAY_CFG_WD,
+			     (isp_dl_h << 16) + isp_dl_w, 0x3FFF3FFF);
+#endif
+	}
+
+	return 0;
+}
+
+static const struct mdp_comp_ops camin_ops = {
+	.get_comp_flag = get_comp_flag,
+	.init_comp = NULL,
+	.config_frame = NULL,
+	.config_subfrm = config_camin_subfrm,
+	/* .reconfig_frame = NULL, */
+	/* .reconfig_subfrms = NULL, */
+	.wait_comp_event = NULL,
+	.advance_subfrm = NULL,
+	.post_process = NULL,
+};
+
+static const struct mdp_comp_ops *mdp_comp_ops[MDP_COMP_TYPE_COUNT] = {
+	[MDP_COMP_TYPE_RDMA] =		&rdma_ops,
+	[MDP_COMP_TYPE_RSZ] =		&rsz_ops,
+	[MDP_COMP_TYPE_WROT] =		&wrot_ops,
+	[MDP_COMP_TYPE_WDMA] =		&wdma_ops,
+	[MDP_COMP_TYPE_PATH] =		NULL,
+
+	[MDP_COMP_TYPE_CCORR] =		&ccorr_ops,
+
+	[MDP_COMP_TYPE_IMGI] =		&imgi_ops,
+	[MDP_COMP_TYPE_EXTO] =		NULL,
+	[MDP_COMP_TYPE_DL_PATH] =	&camin_ops,
+};
+
+struct mdp_comp_match {
+	enum mdp_comp_type	type;
+	u32			alias_id;
+};
+
+static const struct mdp_comp_match mdp_comp_matches[MDP_MAX_COMP_COUNT] = {
+	[MDP_COMP_WPEI] =	{ MDP_COMP_TYPE_WPEI, 0 },
+	[MDP_COMP_WPEO] =	{ MDP_COMP_TYPE_EXTO, 2 },
+	[MDP_COMP_WPEI2] =	{ MDP_COMP_TYPE_WPEI, 1 },
+	[MDP_COMP_WPEO2] =	{ MDP_COMP_TYPE_EXTO, 3 },
+	[MDP_COMP_ISP_IMGI] =	{ MDP_COMP_TYPE_IMGI, 0 },
+	[MDP_COMP_ISP_IMGO] =	{ MDP_COMP_TYPE_EXTO, 0 },
+	[MDP_COMP_ISP_IMG2O] =	{ MDP_COMP_TYPE_EXTO, 1 },
+
+	[MDP_COMP_CAMIN] =	{ MDP_COMP_TYPE_DL_PATH, 0 },
+	[MDP_COMP_CAMIN2] =	{ MDP_COMP_TYPE_DL_PATH, 1 },
+	[MDP_COMP_RDMA0] =	{ MDP_COMP_TYPE_RDMA, 0 },
+	[MDP_COMP_CCORR0] =	{ MDP_COMP_TYPE_CCORR, 0 },
+	[MDP_COMP_RSZ0] =	{ MDP_COMP_TYPE_RSZ, 0 },
+	[MDP_COMP_RSZ1] =	{ MDP_COMP_TYPE_RSZ, 1 },
+	[MDP_COMP_PATH0_SOUT] =	{ MDP_COMP_TYPE_PATH, 0 },
+	[MDP_COMP_PATH1_SOUT] =	{ MDP_COMP_TYPE_PATH, 1 },
+	[MDP_COMP_WROT0] =	{ MDP_COMP_TYPE_WROT, 0 },
+	[MDP_COMP_WDMA] =	{ MDP_COMP_TYPE_WDMA, 0 },
+};
+
+static const char * const gce_event_names[MDP_MAX_EVENT_COUNT] = {
+	[RDMA0_SOF] = "rdma0_sof",
+	[RDMA0_DONE] = "rdma0_done",
+	[RSZ0_SOF] = "rsz0_sof",
+	[RSZ1_SOF] = "rsz1_sof",
+	[TDSHP0_SOF] = "tdshp0_sof",
+	[WROT0_SOF] = "wrot0_sof",
+	[WROT0_DONE] = "wrot0_done",
+	[WDMA0_SOF] = "wdma0_sof",
+	[WDMA0_DONE] = "wdma0_done",
+
+	[ISP_P2_0_DONE] = "isp_p2_0_done",
+	[ISP_P2_1_DONE] = "isp_p2_1_done",
+	[ISP_P2_2_DONE] = "isp_p2_2_done",
+	[ISP_P2_3_DONE] = "isp_p2_3_done",
+	[ISP_P2_4_DONE] = "isp_p2_4_done",
+	[ISP_P2_5_DONE] = "isp_p2_5_done",
+	[ISP_P2_6_DONE] = "isp_p2_6_done",
+	[ISP_P2_7_DONE] = "isp_p2_7_done",
+	[ISP_P2_8_DONE] = "isp_p2_8_done",
+	[ISP_P2_9_DONE] = "isp_p2_9_done",
+	[ISP_P2_10_DONE] = "isp_p2_10_done",
+	[ISP_P2_11_DONE] = "isp_p2_11_done",
+	[ISP_P2_12_DONE] = "isp_p2_12_done",
+	[ISP_P2_13_DONE] = "isp_p2_13_done",
+	[ISP_P2_14_DONE] = "isp_p2_14_done",
+
+	[WPE_DONE] = "wpe_done",
+	[WPE_B_DONE] = "wpe_b_done",
+};
+
+static const struct of_device_id mdp_comp_dt_ids[] = {
+	{
+		.compatible = "mediatek,mt8183-mdp-rdma",
+		.data = (void *)MDP_COMP_TYPE_RDMA,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-ccorr",
+		.data = (void *)MDP_COMP_TYPE_CCORR,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-rsz",
+		.data = (void *)MDP_COMP_TYPE_RSZ,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-wrot",
+		.data = (void *)MDP_COMP_TYPE_WROT,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-wdma",
+		.data = (void *)MDP_COMP_TYPE_WDMA,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-path",
+		.data = (void *)MDP_COMP_TYPE_PATH,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-imgi",
+		.data = (void *)MDP_COMP_TYPE_IMGI,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-exto",
+		.data = (void *)MDP_COMP_TYPE_EXTO,
+	}, {
+		.compatible = "mediatek,mt8183-mdp-dl",
+		.data = (void *)MDP_COMP_TYPE_DL_PATH,
+	},
+	{}
+};
+
+static int mdp_comp_get_id(struct device *dev, struct device_node *node,
+			   enum mdp_comp_type type)
+{
+	u32 alias_id;
+	int i, ret;
+
+	ret = of_property_read_u32(node, "mediatek,mdp-id", &alias_id);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(mdp_comp_matches); i++)
+		if (mdp_comp_matches[i].type == type &&
+		    mdp_comp_matches[i].alias_id == alias_id)
+			return i;
+
+	dev_err(dev, "Failed to get id. type: %d, alias: %d\n", type, alias_id);
+	return -EINVAL;
+}
+
+void mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
+{
+	int i, err;
+
+	if (comp->larb_dev) {
+		err = pm_runtime_get_sync(comp->larb_dev);
+		if (err < 0)
+			dev_err(dev,
+				"Failed to get larb, err %d. type:%d id:%d\n",
+				err, comp->type, comp->id);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(comp->clks); i++) {
+		if (IS_ERR(comp->clks[i]))
+			break;
+		err = clk_prepare_enable(comp->clks[i]);
+		if (err)
+			dev_err(dev,
+				"Failed to enable clock %d, err %d. type:%d id:%d\n",
+				i, err, comp->type, comp->id);
+	}
+}
+
+void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(comp->clks); i++) {
+		if (IS_ERR(comp->clks[i]))
+			break;
+		clk_disable_unprepare(comp->clks[i]);
+	}
+
+	if (comp->larb_dev)
+		pm_runtime_put(comp->larb_dev);
+}
+
+static int mdp_get_subsys_id(struct device *dev, struct device_node *node,
+			     struct mdp_comp *comp)
+{
+	struct platform_device *comp_pdev;
+	struct cmdq_client_reg  *cmdq_reg;
+	int ret = 0;
+
+	if (!dev || !node || !comp)
+		return -EINVAL;
+
+	comp_pdev = of_find_device_by_node(node);
+
+	if (!comp_pdev) {
+		dev_err(dev, "get comp_pdev fail! comp id=%d type=%d\n",
+			comp->id, comp->type);
+		return -ENODEV;
+	}
+
+	cmdq_reg = kzalloc(sizeof(*cmdq_reg), GFP_KERNEL);
+	if (!cmdq_reg)
+		return -ENOMEM;
+
+	ret = cmdq_dev_get_client_reg(&comp_pdev->dev, cmdq_reg, 0);
+	if (ret != 0) {
+		dev_err(&comp_pdev->dev,
+			"cmdq_dev_get_subsys fail!\n");
+		kfree(cmdq_reg);
+		return -EINVAL;
+	}
+
+	comp->subsys_id = cmdq_reg->subsys;
+	dev_err(&comp_pdev->dev, "subsys id=%d\n", cmdq_reg->subsys);
+
+	kfree(cmdq_reg);
+
+	return 0;
+}
+
+static void __mdp_comp_init(struct mdp_dev *mdp, struct device_node *node,
+			    struct mdp_comp *comp)
+{
+	struct resource res;
+	phys_addr_t base;
+
+	if (of_address_to_resource(node, 0, &res) < 0)
+		base = 0L;
+	else
+		base = 0L | res.start;
+
+	comp->mdp_dev = mdp;
+	/* comp->dev_node = of_node_get(node); */
+	comp->regs = of_iomap(node, 0);
+	comp->reg_base = base;
+}
+
+static int mdp_mm_init(struct mdp_dev *mdp,
+		       struct mdp_comp *comp, const char *ref_name)
+{
+	struct device_node *node;
+	struct device *dev = &mdp->pdev->dev;
+
+	node = of_parse_phandle(dev->of_node, ref_name, 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse dt %s\n", ref_name);
+		return -EINVAL;
+	}
+
+	__mdp_comp_init(mdp, node, comp);
+	mdp_get_subsys_id(dev, node, comp);
+	of_node_put(node);
+	if (!comp->reg_base) {
+		dev_err(dev, "Failed to init %s base\n", ref_name);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mdp_comp_init(struct device *dev, struct mdp_dev *mdp,
+			 struct device_node *node, struct mdp_comp *comp,
+			 enum mdp_comp_id id)
+{
+	struct device_node *larb_node;
+	struct platform_device *larb_pdev;
+	int i;
+
+	if (id < 0 || id >= MDP_MAX_COMP_COUNT) {
+		dev_err(dev, "Invalid component id %d\n", id);
+		return -EINVAL;
+	}
+
+	__mdp_comp_init(mdp, node, comp);
+	comp->type = mdp_comp_matches[id].type;
+	comp->id = id;
+	comp->alias_id = mdp_comp_matches[id].alias_id;
+	comp->ops = mdp_comp_ops[comp->type];
+
+	for (i = 0; i < ARRAY_SIZE(comp->clks); i++) {
+		comp->clks[i] = of_clk_get(node, i);
+		if (IS_ERR(comp->clks[i]))
+			break;
+	}
+
+	mdp_get_subsys_id(dev, node, comp);
+
+	/* Only DMA capable components need the LARB property */
+	comp->larb_dev = NULL;
+	if (comp->type != MDP_COMP_TYPE_RDMA &&
+	    comp->type != MDP_COMP_TYPE_WROT &&
+		comp->type != MDP_COMP_TYPE_WDMA)
+		return 0;
+
+	larb_node = of_parse_phandle(node, "mediatek,larb", 0);
+	if (!larb_node) {
+		dev_err(dev, "Missing mediatek,larb phandle in %pOF node\n",
+			node);
+		return -EINVAL;
+	}
+
+	larb_pdev = of_find_device_by_node(larb_node);
+	if (!larb_pdev) {
+		dev_warn(dev, "Waiting for larb device %pOF\n", larb_node);
+		of_node_put(larb_node);
+		return -EPROBE_DEFER;
+	}
+	of_node_put(larb_node);
+
+	comp->larb_dev = &larb_pdev->dev;
+
+	return 0;
+}
+
+static void mdp_comp_deinit(struct mdp_comp *comp)
+{
+	iounmap(comp->regs);
+	/* of_node_put(comp->dev_node); */
+}
+
+void mdp_component_deinit(struct mdp_dev *mdp)
+{
+	int i;
+
+	mdp_comp_deinit(&mdp->mmsys);
+	mdp_comp_deinit(&mdp->mm_mutex);
+	for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) {
+		if (mdp->comp[i]) {
+			mdp_comp_deinit(mdp->comp[i]);
+			kfree(mdp->comp[i]);
+		}
+	}
+}
+
+int mdp_component_init(struct mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	struct device_node *node, *parent;
+	int i, ret;
+
+	for (i = RDMA0_SOF; i < MDP_MAX_EVENT_COUNT; i++) {
+		s32 event_id;
+
+		if (!dev)
+			return -EINVAL;
+		if (of_property_read_u32_index(dev->of_node,
+					       "mediatek,gce-events",
+					       i, &event_id)) {
+			dev_err(dev, "can't parse gce-events property");
+
+			return -ENODEV;
+		}
+		mdp->event[i] = (event_id < 0) ? -i : event_id;
+		dev_info(dev, "Get event %s id:%d\n",
+			 gce_event_names[i], mdp->event[i]);
+	}
+
+	ret = mdp_mm_init(mdp, &mdp->mmsys, "mediatek,mmsys");
+	if (ret)
+		goto err_init_mm;
+
+	ret = mdp_mm_init(mdp, &mdp->mm_mutex, "mediatek,mm-mutex");
+	if (ret)
+		goto err_init_mm;
+
+	parent = dev->of_node->parent;
+	/* Iterate over sibling MDP function blocks */
+	for_each_child_of_node(parent, node) {
+		const struct of_device_id *of_id;
+		enum mdp_comp_type type;
+		int id;
+		struct mdp_comp *comp;
+
+		of_id = of_match_node(mdp_comp_dt_ids, node);
+		if (!of_id)
+			continue;
+
+		if (!of_device_is_available(node)) {
+			dev_info(dev, "Skipping disabled component %pOF\n",
+				 node);
+			continue;
+		}
+
+		type = (enum mdp_comp_type)of_id->data;
+		id = mdp_comp_get_id(dev, node, type);
+		if (id < 0) {
+			dev_warn(dev, "Skipping unknown component %pOF\n",
+				 node);
+			continue;
+		}
+
+		comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+		if (!comp) {
+			ret = -ENOMEM;
+			goto err_init_comps;
+		}
+		mdp->comp[id] = comp;
+
+		ret = mdp_comp_init(dev, mdp, node, comp, id);
+		if (ret)
+			goto err_init_comps;
+
+		dev_info(dev, "%s type:%d alias:%d id:%d base:%#x regs:%p\n",
+			 of_id->compatible, type, comp->alias_id, id,
+			(u32)comp->reg_base, comp->regs);
+	}
+	return 0;
+
+err_init_comps:
+	mdp_component_deinit(mdp);
+err_init_mm:
+	return ret;
+}
+
+int mdp_comp_ctx_init(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx,
+		      const struct img_compparam *param,
+	const struct img_ipi_frameparam *frame)
+{
+	int i;
+
+	if (param->type < 0 || param->type >= MDP_MAX_COMP_COUNT) {
+		mdp_err("Invalid component id %d", param->type);
+		return -EINVAL;
+	}
+
+	ctx->comp = mdp->comp[param->type];
+	if (!ctx->comp) {
+		mdp_err("Uninit component id %d", param->type);
+		return -EINVAL;
+	}
+
+	ctx->param = param;
+	ctx->input = &frame->inputs[param->input];
+	for (i = 0; i < param->num_outputs; i++)
+		ctx->outputs[i] = &frame->outputs[param->outputs[i]];
+	return 0;
+}
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
new file mode 100644
index 000000000000..77d2c3e989c4
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_COMP_H__
+#define __MTK_MDP3_COMP_H__
+
+#include "mtk-mdp3-cmdq.h"
+
+enum mdp_comp_type {
+	MDP_COMP_TYPE_INVALID = 0,
+
+	MDP_COMP_TYPE_RDMA,
+	MDP_COMP_TYPE_RSZ,
+	MDP_COMP_TYPE_WROT,
+	MDP_COMP_TYPE_WDMA,
+	MDP_COMP_TYPE_PATH,
+
+	MDP_COMP_TYPE_TDSHP,
+	MDP_COMP_TYPE_COLOR,
+	MDP_COMP_TYPE_DRE,
+	MDP_COMP_TYPE_CCORR,
+	MDP_COMP_TYPE_HDR,
+
+	MDP_COMP_TYPE_IMGI,
+	MDP_COMP_TYPE_WPEI,
+	MDP_COMP_TYPE_EXTO,	/* External path */
+	MDP_COMP_TYPE_DL_PATH,	/* Direct-link path */
+
+	MDP_COMP_TYPE_COUNT	/* ALWAYS keep at the end */
+};
+
+enum mdp_comp_id {
+	MDP_COMP_NONE = -1,	/* Invalid engine */
+
+	/* ISP */
+	MDP_COMP_WPEI = 0,
+	MDP_COMP_WPEO,		/* 1 */
+	MDP_COMP_WPEI2,		/* 2 */
+	MDP_COMP_WPEO2,		/* 3 */
+	MDP_COMP_ISP_IMGI,	/* 4 */
+	MDP_COMP_ISP_IMGO,	/* 5 */
+	MDP_COMP_ISP_IMG2O,	/* 6 */
+
+	/* IPU */
+	MDP_COMP_IPUI,		/* 7 */
+	MDP_COMP_IPUO,		/* 8 */
+
+	/* MDP */
+	MDP_COMP_CAMIN,		/* 9 */
+	MDP_COMP_CAMIN2,	/* 10 */
+	MDP_COMP_RDMA0,		/* 11 */
+	MDP_COMP_AAL0,		/* 12 */
+	MDP_COMP_CCORR0,	/* 13 */
+	MDP_COMP_RSZ0,		/* 14 */
+	MDP_COMP_RSZ1,		/* 15 */
+	MDP_COMP_TDSHP0,	/* 16 */
+	MDP_COMP_COLOR0,	/* 17 */
+	MDP_COMP_PATH0_SOUT,	/* 18 */
+	MDP_COMP_PATH1_SOUT,	/* 19 */
+	MDP_COMP_WROT0,		/* 20 */
+	MDP_COMP_WDMA,		/* 21 */
+
+	/* Dummy Engine */
+	MDP_COMP_RDMA1,		/* 22 */
+	MDP_COMP_RSZ2,		/* 23 */
+	MDP_COMP_TDSHP1,	/* 24 */
+	MDP_COMP_WROT1,		/* 25 */
+
+	MDP_MAX_COMP_COUNT	/* ALWAYS keep at the end */
+};
+
+enum mdp_comp_event {
+	RDMA0_SOF,
+	RDMA0_DONE,
+	RSZ0_SOF,
+	RSZ1_SOF,
+	TDSHP0_SOF,
+	WROT0_SOF,
+	WROT0_DONE,
+	WDMA0_SOF,
+	WDMA0_DONE,
+
+	ISP_P2_0_DONE,
+	ISP_P2_1_DONE,
+	ISP_P2_2_DONE,
+	ISP_P2_3_DONE,
+	ISP_P2_4_DONE,
+	ISP_P2_5_DONE,
+	ISP_P2_6_DONE,
+	ISP_P2_7_DONE,
+	ISP_P2_8_DONE,
+	ISP_P2_9_DONE,
+	ISP_P2_10_DONE,
+	ISP_P2_11_DONE,
+	ISP_P2_12_DONE,
+	ISP_P2_13_DONE,
+	ISP_P2_14_DONE,
+
+	WPE_DONE,
+	WPE_B_DONE,
+
+	MDP_MAX_EVENT_COUNT	/* ALWAYS keep at the end */
+};
+
+struct mdp_comp_ops;
+
+struct mdp_comp {
+	struct mdp_dev			*mdp_dev;
+	void __iomem			*regs;
+	phys_addr_t			reg_base;
+	u8				subsys_id;
+	struct clk			*clks[2];
+	struct device			*larb_dev;
+	enum mdp_comp_type		type;
+	enum mdp_comp_id		id;
+	u32				alias_id;
+	const struct mdp_comp_ops	*ops;
+};
+
+struct mdp_comp_ctx {
+	struct mdp_comp			*comp;
+	const struct img_compparam	*param;
+	const struct img_input		*input;
+	const struct img_output		*outputs[IMG_MAX_HW_OUTPUTS];
+};
+
+struct mdp_comp_ops {
+	s64 (*get_comp_flag)(const struct mdp_comp_ctx *ctx);
+	int (*init_comp)(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd);
+	int (*config_frame)(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd,
+			    const struct v4l2_rect *compose);
+	int (*config_subfrm)(struct mdp_comp_ctx *ctx,
+			     struct mdp_cmd *cmd, u32 index);
+	int (*wait_comp_event)(struct mdp_comp_ctx *ctx,
+			       struct mdp_cmd *cmd);
+	int (*advance_subfrm)(struct mdp_comp_ctx *ctx,
+			      struct mdp_cmd *cmd, u32 index);
+	int (*post_process)(struct mdp_comp_ctx *ctx, struct mdp_cmd *cmd);
+};
+
+struct mdp_dev;
+
+int mdp_component_init(struct mdp_dev *mdp);
+void mdp_component_deinit(struct mdp_dev *mdp);
+void mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp);
+void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp);
+int mdp_comp_ctx_init(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx,
+		      const struct img_compparam *param,
+	const struct img_ipi_frameparam *frame);
+
+#endif  /* __MTK_MDP3_COMP_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
new file mode 100644
index 000000000000..4a59dec8cfd9
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/mtk_scp.h>
+#include <media/videobuf2-dma-contig.h>
+#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-debug.h"
+#include "mtk-mdp3-m2m.h"
+
+/* MDP debug log level (0-3). 3 shows all the logs. */
+int mtk_mdp_debug;
+EXPORT_SYMBOL(mtk_mdp_debug);
+module_param_named(debug, mtk_mdp_debug, int, 0644);
+
+static const struct of_device_id mdp_of_ids[] = {
+	{ .compatible = "mediatek,mt8183-mdp3", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mdp_of_ids);
+
+struct platform_device *mdp_get_plat_device(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *mdp_node;
+	struct platform_device *mdp_pdev;
+
+	mdp_node = of_parse_phandle(dev->of_node, "mediatek,mdp3", 0);
+	if (!mdp_node) {
+		dev_err(dev, "can't get mdp node\n");
+		return NULL;
+	}
+
+	mdp_pdev = of_find_device_by_node(mdp_node);
+	if (WARN_ON(!mdp_pdev)) {
+		dev_err(dev, "mdp pdev failed\n");
+		of_node_put(mdp_node);
+		return NULL;
+	}
+
+	return mdp_pdev;
+}
+EXPORT_SYMBOL_GPL(mdp_get_plat_device);
+
+int mdp_vpu_get_locked(struct mdp_dev *mdp)
+{
+	int ret = 0;
+
+	if (mdp->vpu_count++ == 0) {
+		ret = rproc_boot(mdp->rproc_handle);
+		if (ret) {
+			dev_err(&mdp->pdev->dev,
+				"vpu_load_firmware failed %d\n", ret);
+			goto err_load_vpu;
+		}
+		ret = mdp_vpu_register(mdp);
+		if (ret) {
+			dev_err(&mdp->pdev->dev,
+				"mdp_vpu register failed %d\n", ret);
+			goto err_reg_vpu;
+		}
+		ret = mdp_vpu_dev_init(&mdp->vpu, mdp->scp, &mdp->vpu_lock);
+		if (ret) {
+			dev_err(&mdp->pdev->dev,
+				"mdp_vpu device init failed %d\n", ret);
+			goto err_init_vpu;
+		}
+	}
+	return 0;
+
+err_init_vpu:
+	mdp_vpu_unregister(mdp);
+err_reg_vpu:
+err_load_vpu:
+	mdp->vpu_count--;
+	return ret;
+}
+
+void mdp_vpu_put_locked(struct mdp_dev *mdp)
+{
+	if (--mdp->vpu_count == 0) {
+		mdp_vpu_dev_deinit(&mdp->vpu);
+		mdp_vpu_unregister(mdp);
+	}
+}
+
+static int mdp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mdp_dev *mdp;
+	int ret;
+
+	mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL);
+	if (!mdp)
+		return -ENOMEM;
+
+	mdp->pdev = pdev;
+	ret = mdp_component_init(mdp);
+	if (ret) {
+		dev_err(dev, "Failed to initialize mdp components\n");
+		goto err_return;
+	}
+
+	mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
+	if (!mdp->job_wq) {
+		dev_err(dev, "Unable to create job workqueue\n");
+		ret = -ENOMEM;
+		goto err_destroy_job_wq;
+	}
+
+	mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE,
+					0);
+	if (!mdp->clock_wq) {
+		dev_err(dev, "Unable to create clock workqueue\n");
+		ret = -ENOMEM;
+		goto err_destroy_clock_wq;
+	}
+
+	mdp->scp = scp_get(pdev);
+	if (!mdp->scp) {
+		dev_err(&pdev->dev, "Could not get scp device\n");
+		ret = -ENODEV;
+		goto err_destroy_clock_wq;
+	}
+
+	mdp->rproc_handle = scp_get_rproc(mdp->scp);
+	dev_info(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle);
+
+	mutex_init(&mdp->vpu_lock);
+	mutex_init(&mdp->m2m_lock);
+
+	mdp->cmdq_clt = cmdq_mbox_create(dev, 0, 1200);
+	if (IS_ERR(mdp->cmdq_clt)) {
+		ret = PTR_ERR(mdp->cmdq_clt);
+		goto err_put_scp;
+	}
+
+	init_waitqueue_head(&mdp->callback_wq);
+	ida_init(&mdp->mdp_ida);
+	platform_set_drvdata(pdev, mdp);
+
+#ifdef MDP_DEBUG
+	mdp_debug_init(pdev);
+#endif
+
+	vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
+	pm_runtime_enable(dev);
+
+	ret = v4l2_device_register(dev, &mdp->v4l2_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register v4l2 device\n");
+		ret = -EINVAL;
+		goto err_mbox_destroy;
+	}
+
+	ret = mdp_m2m_device_register(mdp);
+	if (ret) {
+		v4l2_err(&mdp->v4l2_dev, "Failed to register m2m device\n");
+		goto err_unregister_device;
+	}
+
+	dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id);
+	return 0;
+
+err_unregister_device:
+	v4l2_device_unregister(&mdp->v4l2_dev);
+err_mbox_destroy:
+	cmdq_mbox_destroy(mdp->cmdq_clt);
+err_put_scp:
+	scp_put(mdp->scp);
+err_destroy_clock_wq:
+	destroy_workqueue(mdp->clock_wq);
+err_destroy_job_wq:
+	destroy_workqueue(mdp->job_wq);
+err_return:
+	dev_dbg(dev, "Errno %d\n", ret);
+	return ret;
+}
+
+static int mdp_remove(struct platform_device *pdev)
+{
+	struct mdp_dev *mdp = platform_get_drvdata(pdev);
+
+	mdp_m2m_device_unregister(mdp);
+	v4l2_device_unregister(&mdp->v4l2_dev);
+
+	scp_put(mdp->scp);
+
+	destroy_workqueue(mdp->job_wq);
+	destroy_workqueue(mdp->clock_wq);
+
+	pm_runtime_disable(&pdev->dev);
+
+	vb2_dma_contig_clear_max_seg_size(&pdev->dev);
+	mdp_component_deinit(mdp);
+
+#ifdef MDP_DEBUG
+	mdp_debug_deinit();
+#endif
+
+	mdp_vpu_shared_mem_free(&mdp->vpu);
+
+	dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
+	return 0;
+}
+
+static int __maybe_unused mdp_pm_suspend(struct device *dev)
+{
+	struct mdp_dev *mdp = dev_get_drvdata(dev);
+	int ret;
+
+	atomic_set(&mdp->suspended, 1);
+
+	if (atomic_read(&mdp->job_count)) {
+		ret = wait_event_timeout(mdp->callback_wq,
+					 !atomic_read(&mdp->job_count),
+					 HZ);
+		if (ret == 0)
+			dev_err(dev,
+				"%s:flushed cmdq task incomplete\n",
+				__func__);
+		else//need to remove
+			pr_err("%s:ret=%d\n", __func__, ret);
+	}
+
+	return 0;
+}
+
+static int __maybe_unused mdp_pm_resume(struct device *dev)
+{
+	struct mdp_dev *mdp = dev_get_drvdata(dev);
+
+	atomic_set(&mdp->suspended, 0);
+
+	return 0;
+}
+
+static int __maybe_unused mdp_suspend(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return mdp_pm_suspend(dev);
+}
+
+static int __maybe_unused mdp_resume(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return mdp_pm_resume(dev);
+}
+
+static const struct dev_pm_ops mdp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume)
+	SET_RUNTIME_PM_OPS(mdp_pm_suspend, mdp_pm_resume, NULL)
+};
+
+static struct platform_driver mdp_driver = {
+	.probe		= mdp_probe,
+	.remove		= mdp_remove,
+	.driver = {
+		.name	= MDP_MODULE_NAME,
+		.pm	= &mdp_pm_ops,
+		.of_match_table = of_match_ptr(mdp_of_ids),
+	},
+};
+
+module_platform_driver(mdp_driver);
+
+MODULE_AUTHOR("Ping-Hsun Wu <ping-hsun.wu@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek image processor 3 driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
new file mode 100644
index 000000000000..98cf54b1d92b
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_CORE_H__
+#define __MTK_MDP3_CORE_H__
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include "mtk-mdp3-comp.h"
+#include "mtk-mdp3-vpu.h"
+
+#define MDP_MODULE_NAME	"mtk-mdp3"
+
+enum mdp_buffer_usage {
+	MDP_BUFFER_USAGE_HW_READ,
+	MDP_BUFFER_USAGE_MDP,
+	MDP_BUFFER_USAGE_MDP2,
+	MDP_BUFFER_USAGE_ISP,
+	MDP_BUFFER_USAGE_WPE,
+};
+
+struct mdp_dev {
+	struct platform_device	*pdev;
+	struct mdp_comp		mmsys;
+	struct mdp_comp		mm_mutex;
+	struct mdp_comp		*comp[MDP_MAX_COMP_COUNT];
+	s32			event[MDP_MAX_EVENT_COUNT];
+
+	struct workqueue_struct	*job_wq;
+	struct workqueue_struct	*clock_wq;
+	struct mdp_vpu_dev	vpu;
+	struct mtk_scp		*scp;
+	struct rproc		*rproc_handle;
+	/* synchronization protect for accessing vpu working buffer info */
+	struct mutex		vpu_lock;
+	s32			vpu_count;
+	u32			id_count;
+	struct ida		mdp_ida;
+	struct cmdq_client	*cmdq_clt;
+	wait_queue_head_t	callback_wq;
+
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*m2m_vdev;
+	struct v4l2_m2m_dev	*m2m_dev;
+	/* synchronization protect for m2m device operation */
+	struct mutex		m2m_lock;
+	atomic_t		suspended;
+	atomic_t		job_count;
+};
+
+int mdp_vpu_get_locked(struct mdp_dev *mdp);
+void mdp_vpu_put_locked(struct mdp_dev *mdp);
+int mdp_vpu_register(struct mdp_dev *mdp);
+void mdp_vpu_unregister(struct mdp_dev *mdp);
+
+extern int mtk_mdp_debug;
+
+#define DEBUG
+#if defined(DEBUG)
+
+#define mdp_dbg(level, fmt, ...)\
+	do {\
+		if (mtk_mdp_debug >= (level))\
+			pr_info("[MTK-MDP3] %d %s:%d: " fmt "\n",\
+				level, __func__, __LINE__, ##__VA_ARGS__);\
+	} while (0)
+
+#define mdp_err(fmt, ...)\
+	pr_err("[MTK-MDP3][ERR] %s:%d: " fmt "\n", __func__, __LINE__,\
+		##__VA_ARGS__)
+
+#else
+
+#define mdp_dbg(level, fmt, ...)	do {} while (0)
+#define mdp_err(fmt, ...)		do {} while (0)
+
+#endif
+
+#define mdp_dbg_enter() mdp_dbg(3, "+")
+#define mdp_dbg_leave() mdp_dbg(3, "-")
+
+#endif  /* __MTK_MDP3_CORE_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.c
new file mode 100644
index 000000000000..98f3f77bd591
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Daoyuan Huang <daoyuan.huang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/compiler_types.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+
+#include "mmsys_reg_base.h"
+#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-debug.h"
+#include "mtk-mdp3-regs.h"
+
+struct mdp_module_base_va {
+	void __iomem *MDP_RDMA0;
+	void __iomem *MDP_RSZ0;
+	void __iomem *MDP_RSZ1;
+	void __iomem *MDP_TDSHP;
+	void __iomem *MDP_COLOR;
+	void __iomem *MDP_AAL;
+	void __iomem *MDP_CCORR;
+	void __iomem *MDP_WROT0;
+	void __iomem *MDP_WDMA;
+	void __iomem *SMI_LARB0;
+};
+
+struct RegDef {
+	int offset;
+	const char *name;
+};
+
+struct mdp_debug_context {
+	struct platform_device *mdp_device;
+	struct mdp_func_struct mdp_func_pointer;
+	struct mdp_module_base_va mdp_mod_base_va;
+	void __iomem *mdp_mmsys_base_va;
+};
+
+static struct mdp_debug_context g_mdp_debug;
+
+#define MMSYS_CONFIG_BASE	g_mdp_debug.mdp_mmsys_base_va
+#define MDP_RDMA0_BASE		g_mdp_debug.mdp_mod_base_va.MDP_RDMA0
+#define MDP_RSZ0_BASE		g_mdp_debug.mdp_mod_base_va.MDP_RSZ0
+#define MDP_RSZ1_BASE		g_mdp_debug.mdp_mod_base_va.MDP_RSZ1
+#define MDP_TDSHP_BASE		g_mdp_debug.mdp_mod_base_va.MDP_TDSHP
+#define MDP_COLOR_BASE		g_mdp_debug.mdp_mod_base_va.MDP_COLOR
+#define MDP_AAL_BASE		g_mdp_debug.mdp_mod_base_va.MDP_AAL
+#define MDP_CCORR_BASE		g_mdp_debug.mdp_mod_base_va.MDP_CCORR
+#define MDP_WROT0_BASE		g_mdp_debug.mdp_mod_base_va.MDP_WROT0
+#define MDP_WDMA_BASE		g_mdp_debug.mdp_mod_base_va.MDP_WDMA
+
+#define MDP_REG_GET32(addr)	(readl((void *)addr) & 0xffffffff)
+#define MDP_REG_SET32(addr, val)	writel(val, addr)
+
+static const char *mdp_get_rsz_state(const uint32_t state);
+
+struct mdp_func_struct *mdp_get_func(void)
+{
+	return &g_mdp_debug.mdp_func_pointer;
+}
+
+static void __iomem *mdp_alloc_reference_VA_by_name(const char *ref_name)
+{
+	struct device_node *node;
+	struct device *dev = &(g_mdp_debug.mdp_device->dev);
+	void __iomem *VA;
+
+	node = of_parse_phandle(dev->of_node, ref_name, 0);
+	if (!node) {
+		mdp_err("DEV: cannot parse node name:%s\n", ref_name);
+		return 0;
+	}
+
+	VA = of_iomap(node, 0);
+	of_node_put(node);
+	mdp_dbg(2, "DEV: VA ref(%s): 0x%p\n", ref_name, VA);
+
+	return VA;
+}
+
+static void mdp_free_module_base_VA(void __iomem *VA)
+{
+	iounmap(VA);
+}
+
+static void mdp_init_module_base_VA(void)
+{
+	struct mdp_module_base_va *mod_base_va = &(g_mdp_debug.mdp_mod_base_va);
+	struct device_node *rdma_node = g_mdp_debug.mdp_device->dev.of_node;
+	void __iomem *va;
+
+	if (rdma_node) {
+		va = of_iomap(rdma_node, 0);
+		of_node_put(rdma_node);
+		mod_base_va->MDP_RDMA0 = va;
+		mdp_dbg(2, "MDP_RDMA va: 0x%p\n", va);
+	} else
+		mdp_err("%s:MDP_RDMA node missing!\n", __func__);
+
+	mod_base_va->MDP_RSZ0 = mdp_alloc_reference_VA_by_name("mdp_rsz0");
+	mod_base_va->MDP_RSZ1 = mdp_alloc_reference_VA_by_name("mdp_rsz1");
+	mod_base_va->MDP_WROT0 = mdp_alloc_reference_VA_by_name("mdp_wrot0");
+	mod_base_va->MDP_WDMA = mdp_alloc_reference_VA_by_name("mdp_wdma0");
+	mod_base_va->MDP_TDSHP = mdp_alloc_reference_VA_by_name("mdp_tdshp0");
+	mod_base_va->MDP_COLOR = mdp_alloc_reference_VA_by_name("mdp_color0");
+	mod_base_va->MDP_AAL = mdp_alloc_reference_VA_by_name("mdp_aal0");
+	mod_base_va->MDP_CCORR = mdp_alloc_reference_VA_by_name("mdp_ccorr0");
+	mod_base_va->SMI_LARB0 =
+		mdp_alloc_reference_VA_by_name("mediatek,larb");
+}
+
+static void mdp_deinit_module_base_VA(void)
+{
+	struct mdp_module_base_va *mod_base_va = &(g_mdp_debug.mdp_mod_base_va);
+
+	mdp_free_module_base_VA(mod_base_va->MDP_RDMA0);
+	mdp_free_module_base_VA(mod_base_va->MDP_RSZ0);
+	mdp_free_module_base_VA(mod_base_va->MDP_RSZ1);
+	mdp_free_module_base_VA(mod_base_va->MDP_WROT0);
+	mdp_free_module_base_VA(mod_base_va->MDP_WDMA);
+	mdp_free_module_base_VA(mod_base_va->MDP_TDSHP);
+	mdp_free_module_base_VA(mod_base_va->MDP_COLOR);
+	mdp_free_module_base_VA(mod_base_va->MDP_AAL);
+	mdp_free_module_base_VA(mod_base_va->MDP_CCORR);
+	mdp_free_module_base_VA(mod_base_va->SMI_LARB0);
+	memset(mod_base_va, 0, sizeof(struct mdp_module_base_va));
+}
+
+static void mdp_map_mmsys_VA(void)
+{
+	g_mdp_debug.mdp_mmsys_base_va =
+		mdp_alloc_reference_VA_by_name("mediatek,mmsys");
+}
+
+static void mdp_unmap_mmsys_VA(void)
+{
+	mdp_free_module_base_VA(g_mdp_debug.mdp_mmsys_base_va);
+}
+
+static uint32_t mdp_rdma_get_reg_offset_src_addr_virtual(void)
+{
+	return 0;
+}
+
+static uint32_t mdp_wrot_get_reg_offset_dst_addr_virtual(void)
+{
+	return 0;
+}
+
+static uint32_t mdp_wdma_get_reg_offset_dst_addr_virtual(void)
+{
+	return 0;
+}
+
+/* MDP engine dump */
+static void mdp_dump_rsz_common(void __iomem *base, const char *label)
+{
+	uint32_t value[8];
+	uint32_t request[8];
+	uint32_t state;
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x004);
+	value[1] = MDP_REG_GET32(base + 0x00C);
+	value[2] = MDP_REG_GET32(base + 0x010);
+	value[3] = MDP_REG_GET32(base + 0x014);
+	value[4] = MDP_REG_GET32(base + 0x018);
+	MDP_REG_SET32(base + 0x040, 0x00000001);
+	value[5] = MDP_REG_GET32(base + 0x044);
+	MDP_REG_SET32(base + 0x040, 0x00000002);
+	value[6] = MDP_REG_GET32(base + 0x044);
+	MDP_REG_SET32(base + 0x040, 0x00000003);
+	value[7] = MDP_REG_GET32(base + 0x044);
+
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("RSZ_CONTROL: 0x%08x, RSZ_INPUT_IMAGE: 0x%08x\n",
+		 value[0], value[1]);
+	mdp_err("RSZ_OUTPUT_IMAGE: 0x%08x RSZ_VERTICAL_COEFF_STEP: 0x%08x\n",
+		 value[2], value[3]);
+	mdp_err("RSZ_HORIZONTAL_COEFF_STEP: 0x%08x, RSZ_DEBUG_1: 0x%08x\n",
+		 value[4], value[5]);
+	mdp_err(", RSZ_DEBUG_2: 0x%08x, RSZ_DEBUG_3: 0x%08x\n",
+		 value[6], value[7]);
+
+	/* parse state */
+	/* .valid=1/request=1: upstream module sends data */
+	/* .ready=1: downstream module receives data */
+	state = value[6] & 0xF;
+	request[0] = state & (0x1);	/* out valid */
+	request[1] = (state & (0x1 << 1)) >> 1;	/* out ready */
+	request[2] = (state & (0x1 << 2)) >> 2;	/* in valid */
+	request[3] = (state & (0x1 << 3)) >> 3;	/* in ready */
+	request[4] = (value[1] & 0x1FFF);	/* input_width */
+	request[5] = (value[1] >> 16) & 0x1FFF;	/* input_height */
+	request[6] = (value[2] & 0x1FFF);	/* output_width */
+	request[7] = (value[2] >> 16) & 0x1FFF;	/* output_height */
+
+	mdp_err("RSZ inRdy,inRsq,outRdy,outRsq: %d,%d,%d,%d (%s)\n",
+		request[3], request[2], request[1], request[0],
+		mdp_get_rsz_state(state));
+	mdp_err("RSZ input_width,input_height,output_width,output_height:");
+	mdp_err("%d,%d,%d,%d\n",
+		 request[4], request[5], request[6], request[7]);
+}
+
+static void mdp_dump_tdshp_common(void __iomem *base, const char *label)
+{
+	uint32_t value[8];
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x114);
+	value[1] = MDP_REG_GET32(base + 0x11C);
+	value[2] = MDP_REG_GET32(base + 0x104);
+	value[3] = MDP_REG_GET32(base + 0x108);
+	value[4] = MDP_REG_GET32(base + 0x10C);
+	value[5] = MDP_REG_GET32(base + 0x120);
+	value[6] = MDP_REG_GET32(base + 0x128);
+	value[7] = MDP_REG_GET32(base + 0x110);
+
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("TDSHP INPUT_CNT: 0x%08x, OUTPUT_CNT: 0x%08x\n",
+		value[0], value[1]);
+	mdp_err("TDSHP INTEN: 0x%08x, INTSTA: 0x%08x, 0x10C: 0x%08x\n",
+		value[2], value[3], value[4]);
+	mdp_err("TDSHP CFG: 0x%08x, IN_SIZE: 0x%08x, OUT_SIZE: 0x%08x\n",
+		value[7], value[5], value[6]);
+}
+
+static void mdp_virtual_function_setting(void)
+{
+	struct mdp_func_struct *pfunc = mdp_get_func();
+
+	pfunc->mdp_dump_rsz = mdp_dump_rsz_common;
+	pfunc->mdp_dump_tdshp = mdp_dump_tdshp_common;
+	pfunc->mdp_rdma_get_src_base_addr =
+		mdp_rdma_get_reg_offset_src_addr_virtual;
+	pfunc->mdp_wrot_get_reg_offset_dst_addr =
+		mdp_wrot_get_reg_offset_dst_addr_virtual;
+	pfunc->mdp_wdma_get_reg_offset_dst_addr =
+		mdp_wdma_get_reg_offset_dst_addr_virtual;
+}
+
+static void mdp_dump_mmsys_config(void)
+{
+	int i;
+	uint32_t value;
+	static const struct RegDef configRegisters[] = {
+		{0xF80, "ISP_MOUT_EN"},
+		{0xF84, "MDP_RDMA0_MOUT_EN"},
+		{0xF8C, "MDP_PRZ0_MOUT_EN"},
+		{0xF90, "MDP_PRZ1_MOUT_EN"},
+		{0xF94, "MDP_COLOR_MOUT_EN"},
+		{0xF98, "IPU_MOUT_EN"},
+		{0xFE8, "MDP_AAL_MOUT_EN"},
+		/* {0x02C, "MDP_TDSHP_MOUT_EN"}, */
+		{0xF00, "DISP_OVL0_MOUT_EN"},
+		{0xF04, "DISP_OVL0_2L_MOUT_EN"},
+		{0xF08, "DISP_OVL1_2L_MOUT_EN"},
+		{0xF0C, "DISP_DITHER0_MOUT_EN"},
+		{0xF10, "DISP_RSZ_MOUT_EN"},
+		/* {0x040, "DISP_UFOE_MOUT_EN"}, */
+		/* {0x040, "MMSYS_MOUT_RST"}, */
+		{0xFA0, "DISP_TO_WROT_SOUT_SEL"},
+		{0xFA4, "MDP_COLOR_IN_SOUT_SEL"},
+		{0xFA8, "MDP_PATH0_SOUT_SEL"},
+		{0xFAC, "MDP_PATH1_SOUT_SEL"},
+		{0xFB0, "MDP_TDSHP_SOUT_SEL"},
+		{0xFC0, "MDP_PRZ0_SEL_IN"},
+		{0xFC4, "MDP_PRZ1_SEL_IN"},
+		{0xFC8, "MDP_TDSHP_SEL_IN"},
+		{0xFCC, "DISP_WDMA0_SEL_IN"},
+		{0xFDC, "MDP_COLOR_SEL_IN"},
+		{0xF20, "DISP_COLOR_OUT_SEL_IN"},
+		{0xFD0, "MDP_WROT0_SEL_IN"},
+		{0xFD4, "MDP_WDMA_SEL_IN"},
+		{0xFD8, "MDP_COLOR_OUT_SEL_IN"},
+		{0xFDC, "MDP_COLOR_SEL_IN "},
+		/* {0xFDC, "DISP_COLOR_SEL_IN"}, */
+		{0xFE0, "MDP_PATH0_SEL_IN"},
+		{0xFE4, "MDP_PATH1_SEL_IN"},
+		{0xFEC, "MDP_AAL_SEL_IN"},
+		{0xFF0, "MDP_CCORR_SEL_IN"},
+		{0xFF4, "MDP_CCORR_SOUT_SEL"},
+		/* {0x070, "DISP_WDMA1_SEL_IN"}, */
+		/* {0x074, "DISP_UFOE_SEL_IN"}, */
+		{0xF2C, "DSI0_SEL_IN"},
+		{0xF30, "DSI1_SEL_IN"},
+		{0xF50, "DISP_RDMA0_SOUT_SEL_IN"},
+		{0xF54, "DISP_RDMA1_SOUT_SEL_IN"},
+		{0x0F0, "MMSYS_MISC"},
+		/* ACK and REQ related */
+		{0x8B4, "DISP_DL_VALID_0"},
+		{0x8B8, "DISP_DL_VALID_1"},
+		{0x8C0, "DISP_DL_READY_0"},
+		{0x8C4, "DISP_DL_READY_1"},
+		{0x8CC, "MDP_DL_VALID_0"},
+		{0x8D0, "MDP_DL_VALID_1"},
+		{0x8D4, "MDP_DL_READY_0"},
+		{0x8D8, "MDP_DL_READY_1"},
+		{0x8E8, "MDP_MOUT_MASK"},
+		{0x948, "MDP_DL_VALID_2"},
+		{0x94C, "MDP_DL_READY_2"},
+		{0x950, "DISP_DL_VALID_2"},
+		{0x954, "DISP_DL_READY_2"},
+		{0x100, "MMSYS_CG_CON0"},
+		{0x110, "MMSYS_CG_CON1"},
+		/* Async DL related */
+		{0x960, "TOP_RELAY_FSM_RD"},
+		{0x934, "MDP_ASYNC_CFG_WD"},
+		{0x938, "MDP_ASYNC_CFG_RD"},
+		{0x958, "MDP_ASYNC_CFG_OUT_RD"},
+		{0x95C, "MDP_ASYNC_IPU_CFG_OUT_RD"},
+		{0x994, "ISP_RELAY_CFG_WD"},
+		{0x998, "ISP_RELAY_CNT_RD"},
+		{0x99C, "ISP_RELAY_CNT_LATCH_RD"},
+		{0x9A0, "IPU_RELAY_CFG_WD"},
+		{0x9A4, "IPU_RELAY_CNT_RD"},
+		{0x9A8, "IPU_RELAY_CNT_LATCH_RD"}
+	};
+
+	if (!MMSYS_CONFIG_BASE) {
+		mdp_err("%s:MMSYS_CONFIG_BASE=0!\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(configRegisters); i++) {
+		value = MDP_REG_GET32(MMSYS_CONFIG_BASE +
+			configRegisters[i].offset);
+		mdp_err("%s: 0x%08x\n", configRegisters[i].name, value);
+	}
+}
+
+static const char *mdp_get_rdma_state(uint32_t state)
+{
+	switch (state) {
+	case 0x1:
+		return "idle";
+	case 0x2:
+		return "wait sof";
+	case 0x4:
+		return "reg update";
+	case 0x8:
+		return "clear0";
+	case 0x10:
+		return "clear1";
+	case 0x20:
+		return "int0";
+	case 0x40:
+		return "int1";
+	case 0x80:
+		return "data running";
+	case 0x100:
+		return "wait done";
+	case 0x200:
+		return "warm reset";
+	case 0x400:
+		return "wait reset";
+	default:
+		return "";
+	}
+}
+
+static const char *mdp_get_rsz_state(const uint32_t state)
+{
+	switch (state) {
+	case 0x5:
+		return "downstream hang";	/* 0,1,0,1 */
+	case 0xa:
+		return "upstream hang";	/* 1,0,1,0 */
+	default:
+		return "";
+	}
+}
+
+static const char *mdp_get_wdma_state(uint32_t state)
+{
+	switch (state) {
+	case 0x1:
+		return "idle";
+	case 0x2:
+		return "clear";
+	case 0x4:
+		return "prepare";
+	case 0x8:
+		return "prepare";
+	case 0x10:
+		return "data running";
+	case 0x20:
+		return "eof wait";
+	case 0x40:
+		return "soft reset wait";
+	case 0x80:
+		return "eof done";
+	case 0x100:
+		return "sof reset done";
+	case 0x200:
+		return "frame complete";
+	default:
+		return "";
+	}
+}
+
+static void mdp_dump_rdma_common(void __iomem *base, const char *label)
+{
+	uint32_t value[17];
+	uint32_t state;
+	uint32_t grep;
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x030);
+	value[1] = MDP_REG_GET32(base +
+		   mdp_get_func()->mdp_rdma_get_src_base_addr());
+	value[2] = MDP_REG_GET32(base + 0x060);
+	value[3] = MDP_REG_GET32(base + 0x070);
+	value[4] = MDP_REG_GET32(base + 0x078);
+	value[5] = MDP_REG_GET32(base + 0x080);
+	value[6] = MDP_REG_GET32(base + 0x100);
+	value[7] = MDP_REG_GET32(base + 0x118);
+	value[8] = MDP_REG_GET32(base + 0x130);
+	value[9] = MDP_REG_GET32(base + 0x400);
+	value[10] = MDP_REG_GET32(base + 0x408);
+	value[11] = MDP_REG_GET32(base + 0x410);
+	value[12] = MDP_REG_GET32(base + 0x420);
+	value[13] = MDP_REG_GET32(base + 0x430);
+	value[14] = MDP_REG_GET32(base + 0x440);
+	value[15] = MDP_REG_GET32(base + 0x4D0);
+	value[16] = MDP_REG_GET32(base + 0x0);
+
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err
+	    ("RDMA_SRC_CON: 0x%08x, RDMA_SRC_BASE_0: 0x%08x\n",
+	     value[0], value[1]);
+	mdp_err
+	    ("RDMA_MF_BKGD_SIZE_IN_BYTE: 0x%08x RDMA_MF_SRC_SIZE: 0x%08x\n",
+	     value[2], value[3]);
+	mdp_err("RDMA_MF_CLIP_SIZE: 0x%08x, RDMA_MF_OFFSET_1: 0x%08x\n",
+		value[4], value[5]);
+	mdp_err("RDMA_SRC_END_0: 0x%08x, RDMA_SRC_OFFSET_0: 0x%08x\n",
+		 value[6], value[7]);
+	mdp_err("RDMA_SRC_OFFSET_W_0: 0x%08x, RDMA_MON_STA_0: 0x%08x\n",
+		 value[8], value[9]);
+	mdp_err("RDMA_MON_STA_1: 0x%08x, RDMA_MON_STA_2: 0x%08x\n",
+		 value[10], value[11]);
+	mdp_err("RDMA_MON_STA_4: 0x%08x, RDMA_MON_STA_6: 0x%08x\n",
+		 value[12], value[13]);
+	mdp_err("RDMA_MON_STA_8: 0x%08x, RDMA_MON_STA_26: 0x%08x\n",
+		 value[14], value[15]);
+	mdp_err("RDMA_EN: 0x%08x\n",
+		 value[16]);
+
+	/* parse state */
+	mdp_err("RDMA ack:%d req:%d\n", (value[9] & (1 << 11)) >> 11,
+		 (value[9] & (1 << 10)) >> 10);
+	state = (value[10] >> 8) & 0x7FF;
+	grep = (value[10] >> 20) & 0x1;
+	mdp_err("RDMA state: 0x%x (%s)\n", state, mdp_get_rdma_state(state));
+	mdp_err("RDMA horz_cnt: %d vert_cnt:%d\n",
+		value[15] & 0xFFF, (value[15] >> 16) & 0xFFF);
+
+	mdp_err("RDMA grep:%d => suggest to ask SMI help:%d\n", grep, grep);
+}
+
+static void mdp_dump_rot_common(void __iomem *base, const char *label)
+{
+	uint32_t value[47];
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x000);
+	value[1] = MDP_REG_GET32(base + 0x008);
+	value[2] = MDP_REG_GET32(base + 0x00C);
+	value[3] = MDP_REG_GET32(base + 0x024);
+	value[4] = MDP_REG_GET32(base +
+		   mdp_get_func()->mdp_wrot_get_reg_offset_dst_addr());
+	value[5] = MDP_REG_GET32(base + 0x02C);
+	value[6] = MDP_REG_GET32(base + 0x004);
+	value[7] = MDP_REG_GET32(base + 0x030);
+	value[8] = MDP_REG_GET32(base + 0x078);
+	value[9] = MDP_REG_GET32(base + 0x070);
+	MDP_REG_SET32(base + 0x018, 0x00000100);
+	value[10] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000200);
+	value[11] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000300);
+	value[12] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000400);
+	value[13] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000500);
+	value[14] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000600);
+	value[15] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000700);
+	value[16] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000800);
+	value[17] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000900);
+	value[18] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000A00);
+	value[19] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000B00);
+	value[20] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000C00);
+	value[21] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000D00);
+	value[22] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000E00);
+	value[23] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00000F00);
+	value[24] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001000);
+	value[25] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001100);
+	value[26] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001200);
+	value[27] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001300);
+	value[28] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001400);
+	value[29] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001500);
+	value[30] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001600);
+	value[31] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001700);
+	value[32] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001800);
+	value[33] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001900);
+	value[34] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001A00);
+	value[35] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001B00);
+	value[36] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001C00);
+	value[37] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001D00);
+	value[38] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001E00);
+	value[39] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00001F00);
+	value[40] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00002000);
+	value[41] = MDP_REG_GET32(base + 0x0D0);
+	MDP_REG_SET32(base + 0x018, 0x00002100);
+	value[42] = MDP_REG_GET32(base + 0x0D0);
+	value[43] = MDP_REG_GET32(base + 0x01C);
+	value[44] = MDP_REG_GET32(base + 0x07C);
+	value[45] = MDP_REG_GET32(base + 0x010);
+	value[46] = MDP_REG_GET32(base + 0x014);
+
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("ROT_CTRL: 0x%08x, ROT_MAIN_BUF_SIZE: 0x%08x\n",
+		 value[0], value[1]);
+	mdp_err("ROT_SUB_BUF_SIZE: 0x%08x, ROT_TAR_SIZE: 0x%08x\n",
+		 value[2], value[3]);
+	mdp_err("ROT_BASE_ADDR: 0x%08x, ROT_OFST_ADDR: 0x%08x\n",
+		 value[4], value[5]);
+	mdp_err("ROT_DMA_PERF: 0x%08x, ROT_STRIDE: 0x%08x\n",
+		 value[6], value[7]);
+	mdp_err("ROT_IN_SIZE: 0x%08x, ROT_EOL: 0x%08x\n",
+		 value[8], value[9]);
+	mdp_err("ROT_DBUGG_1: 0x%08x, ROT_DEBUBG_2: 0x%08x\n",
+		 value[10], value[11]);
+	mdp_err("ROT_DBUGG_3: 0x%08x, ROT_DBUGG_4: 0x%08x\n",
+		 value[12], value[13]);
+	mdp_err("ROT_DEBUBG_5: 0x%08x, ROT_DBUGG_6: 0x%08x\n",
+		 value[14], value[15]);
+	mdp_err("ROT_DBUGG_7: 0x%08x, ROT_DEBUBG_8: 0x%08x\n",
+		 value[16], value[17]);
+	mdp_err("ROT_DBUGG_9: 0x%08x, ROT_DBUGG_A: 0x%08x\n",
+		 value[18], value[19]);
+	mdp_err("ROT_DEBUBG_B: 0x%08x, ROT_DBUGG_C: 0x%08x\n",
+		 value[20], value[21]);
+	mdp_err("ROT_DBUGG_D: 0x%08x, ROT_DEBUBG_E: 0x%08x\n",
+		 value[22], value[23]);
+	mdp_err("ROT_DBUGG_F: 0x%08x, ROT_DBUGG_10: 0x%08x\n",
+		 value[24], value[25]);
+	mdp_err("ROT_DEBUBG_11: 0x%08x, ROT_DEBUG_12: 0x%08x\n",
+		 value[26], value[27]);
+	mdp_err("ROT_DBUGG_13: 0x%08x, ROT_DBUGG_14: 0x%08x\n",
+		 value[28], value[29]);
+	mdp_err("ROT_DEBUG_15: 0x%08x, ROT_DBUGG_16: 0x%08x\n",
+		 value[30], value[31]);
+	mdp_err("ROT_DBUGG_17: 0x%08x, ROT_DEBUG_18: 0x%08x\n",
+		 value[32], value[33]);
+	mdp_err("ROT_DBUGG_19: 0x%08x, ROT_DBUGG_1A: 0x%08x\n",
+		 value[34], value[35]);
+	mdp_err("ROT_DEBUG_1B: 0x%08x, ROT_DBUGG_1C: 0x%08x\n",
+		 value[36], value[37]);
+	mdp_err("ROT_DBUGG_1D: 0x%08x, ROT_DEBUG_1E: 0x%08x\n",
+		 value[38], value[39]);
+	mdp_err("ROT_DBUGG_1F: 0x%08x, ROT_DBUGG_20: 0x%08x\n",
+		 value[40], value[41]);
+	mdp_err("ROT_DEBUG_21: 0x%08x\n",
+		 value[42]);
+	mdp_err("VIDO_INT: 0x%08x, VIDO_ROT_EN: 0x%08x\n",
+		value[43], value[44]);
+	mdp_err("VIDO_SOFT_RST: 0x%08x, VIDO_SOFT_RST_STAT: 0x%08x\n",
+		value[45], value[46]);
+}
+
+static void mdp_dump_color_common(void __iomem *base, const char *label)
+{
+	uint32_t value[13];
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x400);
+	value[1] = MDP_REG_GET32(base + 0x404);
+	value[2] = MDP_REG_GET32(base + 0x408);
+	value[3] = MDP_REG_GET32(base + 0x40C);
+	value[4] = MDP_REG_GET32(base + 0x410);
+	value[5] = MDP_REG_GET32(base + 0x420);
+	value[6] = MDP_REG_GET32(base + 0xC00);
+	value[7] = MDP_REG_GET32(base + 0xC04);
+	value[8] = MDP_REG_GET32(base + 0xC08);
+	value[9] = MDP_REG_GET32(base + 0xC0C);
+	value[10] = MDP_REG_GET32(base + 0xC10);
+	value[11] = MDP_REG_GET32(base + 0xC50);
+	value[12] = MDP_REG_GET32(base + 0xC54);
+
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("COLOR CFG_MAIN: 0x%08x\n", value[0]);
+	mdp_err("COLOR PXL_CNT_MAIN: 0x%08x, LINE_CNT_MAIN: 0x%08x\n",
+		value[1], value[2]);
+	mdp_err("COLOR WIN_X_MAIN: 0x%08x, WIN_Y_MAIN: 0x%08x\n",
+		value[3], value[4]);
+	mdp_err("DBG_CFG_MAIN: 0x%08x, COLOR START: 0x%08x\n",
+		value[5], value[6]);
+	mdp_err("INTEN: 0x%08x, INTSTA: 0x%08x\n",
+		value[7], value[8]);
+	mdp_err("COLOR OUT_SEL: 0x%08x, FRAME_DONE_DEL: 0x%08x\n",
+		value[9], value[10]);
+	mdp_err
+	    ("COLOR INTERNAL_IP_WIDTH: 0x%08x, INTERNAL_IP_HEIGHT: 0x%08x\n",
+	     value[11], value[12]);
+}
+
+static void mdp_dump_wdma_common(void __iomem *base, const char *label)
+{
+	uint32_t value[56];
+	uint32_t state;
+	/* grep bit = 1, WDMA has sent request to SMI,
+	 *and not receive done yet
+	 */
+	uint32_t grep;
+	uint32_t isFIFOFull;	/* 1 for WDMA FIFO full */
+	int i;
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x014);
+	value[1] = MDP_REG_GET32(base + 0x018);
+	value[2] = MDP_REG_GET32(base + 0x028);
+	value[3] = MDP_REG_GET32(base +
+		   mdp_get_func()->mdp_wdma_get_reg_offset_dst_addr());
+	value[4] = MDP_REG_GET32(base + 0x078);
+	value[5] = MDP_REG_GET32(base + 0x080);
+	value[6] = MDP_REG_GET32(base + 0x0A0);
+	value[7] = MDP_REG_GET32(base + 0x0A8);
+
+	for (i = 0; i < 16; i++) {
+		MDP_REG_SET32(base + 0x014, (0x10000000 * i) |
+			      (value[0] & (0x0FFFFFFF)));
+		value[8 + (3 * i)] = MDP_REG_GET32(base + 0x014);
+		value[9 + (3 * i)] = MDP_REG_GET32(base + 0x0AC);
+		value[10 + (3 * i)] = MDP_REG_GET32(base + 0x0B8);
+	}
+
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("[MDP]WDMA_CFG: 0x%08x, WDMA_SRC_SIZE: 0x%08x\n",
+		 value[0], value[1]);
+	mdp_err("WDMA_DST_W_IN_BYTE = 0x%08x, [MDP]WDMA_DST_ADDR0: 0x%08x\n",
+		 value[2], value[3]);
+	mdp_err
+	    ("WDMA_DST_UV_PITCH: 0x%08x, WDMA_DST_ADDR_OFFSET0 = 0x%08x\n",
+	     value[4], value[5]);
+	mdp_err("[MDP]WDMA_STATUS: 0x%08x, WDMA_INPUT_CNT: 0x%08x\n",
+		value[6], value[7]);
+
+	/* Dump Addtional WDMA debug info */
+	for (i = 0; i < 16; i++) {
+		mdp_err("WDMA_DEBUG_%x 014:0x%08x, 0ac:0x%08x, 0b8:0x%08x\n",
+			i, value[8 + (3 * i)], value[9 + (3 * i)],
+			value[10 + (3 * i)]);
+	}
+
+	/* parse WDMA state */
+	state = value[6] & 0x3FF;
+	grep = (value[6] >> 13) & 0x1;
+	isFIFOFull = (value[6] >> 12) & 0x1;
+
+	mdp_err("WDMA state:0x%x (%s)\n", state, mdp_get_wdma_state(state));
+	mdp_err("WDMA in_req:%d in_ack:%d\n", (value[6] >> 15) & 0x1,
+		(value[6] >> 14) & 0x1);
+
+	/* note WDMA send request(i.e command) to SMI first,
+	 * then SMI takes request data from WDMA FIFO
+	 */
+	/* if SMI dose not process request and upstream HWs */
+	/* such as MDP_RSZ send data to WDMA, WDMA FIFO will full finally */
+	mdp_err("WDMA grep:%d, FIFO full:%d\n", grep, isFIFOFull);
+	mdp_err("WDMA suggest: Need SMI help:%d, Need check WDMA config:%d\n",
+		(grep), ((grep == 0) && (isFIFOFull == 1)));
+}
+
+static void mdp_dump_rsz(void __iomem *base, const char *label)
+{
+	uint32_t value[11];
+	uint32_t request[4];
+	uint32_t state;
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x004);
+	value[1] = MDP_REG_GET32(base + 0x008);
+	value[2] = MDP_REG_GET32(base + 0x010);
+	value[3] = MDP_REG_GET32(base + 0x014);
+	value[4] = MDP_REG_GET32(base + 0x018);
+	value[5] = MDP_REG_GET32(base + 0x01C);
+	MDP_REG_SET32(base + 0x044, 0x00000001);
+	value[6] = MDP_REG_GET32(base + 0x048);
+	MDP_REG_SET32(base + 0x044, 0x00000002);
+	value[7] = MDP_REG_GET32(base + 0x048);
+	MDP_REG_SET32(base + 0x044, 0x00000003);
+	value[8] = MDP_REG_GET32(base + 0x048);
+	value[9] = MDP_REG_GET32(base + 0x100);
+	value[10] = MDP_REG_GET32(base + 0x200);
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("RSZ_CONTROL_1: 0x%08x, RSZ_CONTROL_2: 0x%08x\n",
+		 value[0], value[1]);
+	mdp_err("RSZ_INPUT_IMAGE: 0x%08x, RSZ_OUTPUT_IMAGE: 0x%08x\n",
+		 value[2], value[3]);
+	mdp_err("RSZ_HORIZONTAL_COEFF_STEP: 0x%08x\n", value[4]);
+	mdp_err("RSZ_VERTICAL_COEFF_STEP: 0x%08x\n", value[5]);
+	mdp_err
+	    ("RSZ_DEBUG_1: 0x%08x, RSZ_DEBUG_2: 0x%08x, RSZ_DEBUG_3: 0x%08x\n",
+	     value[6], value[7], value[8]);
+	mdp_err("PAT1_GEN_SET: 0x%08x, PAT2_GEN_SET: 0x%08x\n",
+		value[9], value[10]);
+	/* parse state */
+	/* .valid=1/request=1: upstream module sends data */
+	/* .ready=1: downstream module receives data */
+	state = value[7] & 0xF;
+	request[0] = state & (0x1);	/* out valid */
+	request[1] = (state & (0x1 << 1)) >> 1;	/* out ready */
+	request[2] = (state & (0x1 << 2)) >> 2;	/* in valid */
+	request[3] = (state & (0x1 << 3)) >> 3;	/* in ready */
+	mdp_err("RSZ inRdy,inRsq,outRdy,outRsq: %d,%d,%d,%d (%s)\n",
+		request[3], request[2], request[1], request[0],
+		mdp_get_rsz_state(state));
+}
+
+static void mdp_dump_tdshp(void __iomem *base, const char *label)
+{
+	uint32_t value[10];
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x114);
+	value[1] = MDP_REG_GET32(base + 0x11C);
+	value[2] = MDP_REG_GET32(base + 0x104);
+	value[3] = MDP_REG_GET32(base + 0x108);
+	value[4] = MDP_REG_GET32(base + 0x10C);
+	value[5] = MDP_REG_GET32(base + 0x110);
+	value[6] = MDP_REG_GET32(base + 0x120);
+	value[7] = MDP_REG_GET32(base + 0x124);
+	value[8] = MDP_REG_GET32(base + 0x128);
+	value[9] = MDP_REG_GET32(base + 0x12C);
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("TDSHP INPUT_CNT: 0x%08x, OUTPUT_CNT: 0x%08x\n",
+		value[0], value[1]);
+	mdp_err("TDSHP INTEN: 0x%08x, INTSTA: 0x%08x, STATUS: 0x%08x\n",
+		value[2], value[3], value[4]);
+	mdp_err("TDSHP CFG: 0x%08x, IN_SIZE: 0x%08x, OUT_SIZE: 0x%08x\n",
+		value[5], value[6], value[8]);
+	mdp_err("TDSHP OUTPUT_OFFSET: 0x%08x, BLANK_WIDTH: 0x%08x\n",
+		value[7], value[9]);
+}
+
+static void mdp_dump_aal(void __iomem *base, const char *label)
+{
+	uint32_t value[9];
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x00C);    /* MDP_AAL_INTSTA       */
+	value[1] = MDP_REG_GET32(base + 0x010);    /* MDP_AAL_STATUS       */
+	value[2] = MDP_REG_GET32(base + 0x024);    /* MDP_AAL_INPUT_COUNT  */
+	value[3] = MDP_REG_GET32(base + 0x028);    /* MDP_AAL_OUTPUT_COUNT */
+	value[4] = MDP_REG_GET32(base + 0x030);    /* MDP_AAL_SIZE         */
+	value[5] = MDP_REG_GET32(base + 0x034);    /* MDP_AAL_OUTPUT_SIZE  */
+	value[6] = MDP_REG_GET32(base + 0x038);    /* MDP_AAL_OUTPUT_OFFSET*/
+	value[7] = MDP_REG_GET32(base + 0x4EC);    /* MDP_AAL_TILE_00      */
+	value[8] = MDP_REG_GET32(base + 0x4F0);    /* MDP_AAL_TILE_01      */
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("AAL_INTSTA: 0x%08x, AAL_STATUS: 0x%08x\n",
+		value[0], value[1]);
+	mdp_err("AAL_INPUT_COUNT: 0x%08x, AAL_OUTPUT_COUNT: 0x%08x\n",
+		value[2], value[3]);
+	mdp_err("AAL_SIZE: 0x%08x\n", value[4]);
+	mdp_err("AAL_OUTPUT_SIZE: 0x%08x, AAL_OUTPUT_OFFSET: 0x%08x\n",
+		value[5], value[6]);
+	mdp_err("AAL_TILE_00: 0x%08x, AAL_TILE_01: 0x%08x\n",
+		value[7], value[8]);
+}
+
+static void mdp_dump_ccorr(void __iomem *base, const char *label)
+{
+	uint32_t value[5];
+
+	if (!base) {
+		mdp_err("=============== [MDP] %s Status ===============\n",
+			label);
+		mdp_err("%s:base=0!\n", __func__);
+		return;
+	}
+
+	value[0] = MDP_REG_GET32(base + 0x00C);/* MDP_CCORR_INTSTA         */
+	value[1] = MDP_REG_GET32(base + 0x010);/* MDP_CCORR_STATUS         */
+	value[2] = MDP_REG_GET32(base + 0x024);/* MDP_CCORR_INPUT_COUNT    */
+	value[3] = MDP_REG_GET32(base + 0x028);/* MDP_CCORR_OUTPUT_COUNT   */
+	value[4] = MDP_REG_GET32(base + 0x030);/* MDP_CCORR_SIZE       */
+	mdp_err("=============== [MDP] %s Status ===============\n",
+		label);
+	mdp_err("CCORR_INTSTA: 0x%08x, CCORR_STATUS: 0x%08x\n",
+		value[0], value[1]);
+	mdp_err("CCORR_INPUT_COUNT: 0x%08x, CCORR_OUTPUT_COUNT: 0x%08x\n",
+		value[2], value[3]);
+	mdp_err("CCORR_SIZE: 0x%08x\n",
+		value[4]);
+}
+
+static uint32_t mdp_rdma_get_reg_offset_src_addr(void)
+{
+	return 0xF00;
+}
+
+static uint32_t mdp_wrot_get_reg_offset_dst_addr(void)
+{
+	return 0xF00;
+}
+
+static uint32_t mdp_wdma_get_reg_offset_dst_addr(void)
+{
+	return 0xF00;
+}
+
+static void mdp_platform_function_setting(void)
+{
+	struct mdp_func_struct *pFunc = mdp_get_func();
+
+	pFunc->mdp_dump_mmsys_config = mdp_dump_mmsys_config;
+	pFunc->mdp_dump_rsz = mdp_dump_rsz;
+	pFunc->mdp_dump_tdshp = mdp_dump_tdshp;
+	pFunc->mdp_rdma_get_src_base_addr = mdp_rdma_get_reg_offset_src_addr;
+	pFunc->mdp_wrot_get_reg_offset_dst_addr =
+		mdp_wrot_get_reg_offset_dst_addr;
+	pFunc->mdp_wdma_get_reg_offset_dst_addr =
+		mdp_wdma_get_reg_offset_dst_addr;
+}
+
+int32_t mdp_dump_info(uint64_t comp_flag, int log_level)
+{
+	if (comp_flag & (1LL << MDP_COMP_RDMA0))
+		mdp_dump_rdma_common(MDP_RDMA0_BASE, "RDMA0");
+	if (comp_flag & (1LL << MDP_COMP_AAL0))
+		mdp_dump_aal(MDP_AAL_BASE, "AAL0");
+	if (comp_flag & (1LL << MDP_COMP_CCORR0))
+		mdp_dump_ccorr(MDP_CCORR_BASE, "CCORR0");
+	if (comp_flag & (1LL << MDP_COMP_RSZ0))
+		mdp_get_func()->mdp_dump_rsz(MDP_RSZ0_BASE, "RSZ0");
+	if (comp_flag & (1LL << MDP_COMP_RSZ1))
+		mdp_get_func()->mdp_dump_rsz(MDP_RSZ1_BASE, "RSZ1");
+	if (comp_flag & (1LL << MDP_COMP_TDSHP0))
+		mdp_get_func()->mdp_dump_tdshp(MDP_TDSHP_BASE, "TDSHP");
+	if (comp_flag & (1LL << MDP_COMP_COLOR0))
+		mdp_dump_color_common(MDP_COLOR_BASE, "COLOR0");
+	if (comp_flag & (1LL << MDP_COMP_WROT0))
+		mdp_dump_rot_common(MDP_WROT0_BASE, "WROT0");
+	if (comp_flag & (1LL << MDP_COMP_WDMA))
+		mdp_dump_wdma_common(MDP_WDMA_BASE, "WDMA");
+
+	return 0;
+}
+
+void mdp_debug_init(struct platform_device *pDevice)
+{
+	pr_err("%s:start\n", __func__);
+	g_mdp_debug.mdp_device = pDevice;
+
+	mdp_init_module_base_VA();
+	mdp_map_mmsys_VA();
+	mdp_virtual_function_setting();
+	mdp_platform_function_setting();
+
+	pr_err("%s:end\n", __func__);
+}
+
+void mdp_debug_deinit(void)
+{
+	mdp_deinit_module_base_VA();
+	mdp_unmap_mmsys_VA();
+}
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.h
new file mode 100644
index 000000000000..083f03367809
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Daoyuan Huang <daoyuan.huang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MTK_MDP3_DEBUG_H__
+#define __MTK_MDP3_DEBUG_H__
+
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#define MDP_DEBUG
+
+struct mdp_func_struct {
+	void (*mdp_dump_mmsys_config)(void);
+	void (*mdp_dump_rsz)(void __iomem *base, const char *label);
+	void (*mdp_dump_tdshp)(void __iomem *base, const char *label);
+	uint32_t (*mdp_rdma_get_src_base_addr)(void);
+	uint32_t (*mdp_wrot_get_reg_offset_dst_addr)(void);
+	uint32_t (*mdp_wdma_get_reg_offset_dst_addr)(void);
+};
+
+void mdp_debug_init(struct platform_device *pDevice);
+void mdp_debug_deinit(void);
+struct mdp_func_struct *mdp_get_func(void);
+int32_t mdp_dump_info(uint64_t comp_flag, int log_level);
+
+
+#endif  /* __MTK_MDP3_DEBUG_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
new file mode 100644
index 000000000000..1ae499f6c84b
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
@@ -0,0 +1,804 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+#include "mtk-mdp3-m2m.h"
+
+static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct mdp_m2m_ctx, fh);
+}
+
+static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler);
+}
+
+static inline struct mdp_frame *ctx_get_frame(struct mdp_m2m_ctx *ctx,
+					      enum v4l2_buf_type type)
+{
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return &ctx->curr_param.output;
+	else
+		return &ctx->curr_param.captures[0];
+}
+
+static void mdp_m2m_ctx_set_state(struct mdp_m2m_ctx *ctx, u32 state)
+{
+	mutex_lock(&ctx->curr_param.state_lock);
+	ctx->curr_param.state |= state;
+	mutex_unlock(&ctx->curr_param.state_lock);
+}
+
+static bool mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx *ctx, u32 mask)
+{
+	bool ret;
+
+	mutex_lock(&ctx->curr_param.state_lock);
+	ret = (ctx->curr_param.state & mask) == mask;
+	mutex_unlock(&ctx->curr_param.state_lock);
+	return ret;
+}
+
+static void mdp_m2m_ctx_lock(struct vb2_queue *q)
+{
+	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
+
+	mutex_lock(&ctx->mdp_dev->m2m_lock);
+}
+
+static void mdp_m2m_ctx_unlock(struct vb2_queue *q)
+{
+	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
+
+	mutex_unlock(&ctx->mdp_dev->m2m_lock);
+}
+
+static void mdp_m2m_job_abort(void *priv)
+{
+}
+
+static void mdp_m2m_process_done(void *priv, int vb_state)
+{
+	struct mdp_m2m_ctx *ctx = priv;
+	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
+	u32 valid_output_flags = V4L2_BUF_FLAG_TIMECODE |
+				 V4L2_BUF_FLAG_TSTAMP_SRC_MASK |
+				 V4L2_BUF_FLAG_KEYFRAME |
+				 V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME;
+
+	src_vbuf = (struct vb2_v4l2_buffer *)
+			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	dst_vbuf = (struct vb2_v4l2_buffer *)
+			v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+	src_vbuf->sequence = ctx->frame_count;
+	dst_vbuf->sequence = src_vbuf->sequence;
+	dst_vbuf->timecode = src_vbuf->timecode;
+	dst_vbuf->flags &= ~valid_output_flags;
+	dst_vbuf->flags |= src_vbuf->flags & valid_output_flags;
+
+	v4l2_m2m_buf_done(src_vbuf, vb_state);
+	v4l2_m2m_buf_done(dst_vbuf, vb_state);
+	v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
+
+	ctx->curr_param.frame_no = ctx->frame_count++;
+}
+
+static void mdp_m2m_worker(struct work_struct *work)
+{
+	struct mdp_m2m_ctx *ctx = container_of(work, struct mdp_m2m_ctx, work);
+	struct mdp_frame *frame;
+	struct vb2_v4l2_buffer *src_vb, *dst_vb;
+	struct img_ipi_frameparam param = {0};
+	struct mdp_cmdq_param task = {0};
+	enum vb2_buffer_state vb_state = VB2_BUF_STATE_ERROR;
+	int ret;
+
+	if (mdp_m2m_ctx_is_state_set(ctx, MDP_M2M_CTX_ERROR)) {
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"mdp_m2m_ctx is in error state\n");
+		goto worker_end;
+	}
+
+	param.frame_no = ctx->curr_param.frame_no;
+	param.type = ctx->curr_param.type;
+	param.num_inputs = 1;
+	param.num_outputs = 1;
+
+	frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+	src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	mdp_set_src_config(&param.inputs[0], frame, &src_vb->vb2_buf);
+
+	frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	mdp_set_dst_config(&param.outputs[0], frame, &dst_vb->vb2_buf);
+
+	dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
+	param.timestamp = src_vb->vb2_buf.timestamp;
+
+	ret = mdp_vpu_process(&ctx->vpu, &param);
+	if (ret) {
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"VPU MDP process failed: %d\n", ret);
+		goto worker_end;
+	}
+
+	task.config = ctx->vpu.config;
+	task.param = &param;
+	task.composes[0] = &frame->compose;
+	task.wait = 1;
+	task.cmdq_cb = NULL;
+	task.cb_data = NULL;
+	task.mdp_ctx = ctx;
+
+	ret = mdp_cmdq_send(ctx->mdp_dev, &task);
+	if (ret) {
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"CMDQ sendtask failed: %d\n", ret);
+		goto worker_end;
+	}
+
+	return;
+
+worker_end:
+	mdp_m2m_process_done(ctx, vb_state);
+}
+
+static void mdp_m2m_device_run(void *priv)
+{
+	struct mdp_m2m_ctx *ctx = priv;
+
+	queue_work(ctx->mdp_dev->job_wq, &ctx->work);
+}
+
+static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
+	int ret;
+
+	ret = 0;//pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
+	if (ret < 0)
+		mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d", ctx->id, ret);
+
+	ctx->frame_count = 0;
+
+	return 0;
+}
+
+static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx,
+						  unsigned int type)
+{
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return (struct vb2_v4l2_buffer *)
+			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+	else
+		return (struct vb2_v4l2_buffer *)
+			v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+}
+
+static void mdp_m2m_stop_streaming(struct vb2_queue *q)
+{
+	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
+	struct vb2_v4l2_buffer *vb;
+
+	vb = mdp_m2m_buf_remove(ctx, q->type);
+	while (vb) {
+		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
+		vb = mdp_m2m_buf_remove(ctx, q->type);
+	}
+
+	//pm_runtime_put(&ctx->mdp_dev->pdev->dev);
+}
+
+static int mdp_m2m_queue_setup(struct vb2_queue *q,
+			       unsigned int *num_buffers,
+			       unsigned int *num_planes, unsigned int sizes[],
+			       struct device *alloc_devs[])
+{
+	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
+	struct v4l2_pix_format_mplane *pix_mp;
+	u32 i;
+
+	pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp;
+
+	/* from VIDIOC_CREATE_BUFS */
+	if (*num_planes) {
+		if (*num_planes != pix_mp->num_planes)
+			return -EINVAL;
+		for (i = 0; i < pix_mp->num_planes; ++i)
+			if (sizes[i] < pix_mp->plane_fmt[i].sizeimage)
+				return -EINVAL;
+	} else {/* from VIDIOC_REQBUFS */
+		*num_planes = pix_mp->num_planes;
+		for (i = 0; i < pix_mp->num_planes; ++i)
+			sizes[i] = pix_mp->plane_fmt[i].sizeimage;
+	}
+
+	mdp_dbg(2, "[%d] type:%d, planes:%u, buffers:%u, size:%u,%u,%u",
+		ctx->id, q->type, *num_planes, *num_buffers,
+		sizes[0], sizes[1], sizes[2]);
+	return 0;
+}
+
+static int mdp_m2m_buf_prepare(struct vb2_buffer *vb)
+{
+	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct v4l2_pix_format_mplane *pix_mp;
+	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
+	u32 i;
+
+	v4l2_buf->field = V4L2_FIELD_NONE;
+
+	if (!V4L2_TYPE_IS_OUTPUT(vb->type)) {
+		pix_mp = &ctx_get_frame(ctx, vb->type)->format.fmt.pix_mp;
+		for (i = 0; i < pix_mp->num_planes; ++i) {
+			vb2_set_plane_payload(vb, i,
+					      pix_mp->plane_fmt[i].sizeimage);
+		}
+	}
+	return 0;
+}
+
+static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
+
+	v4l2_buf->field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static void mdp_m2m_buf_queue(struct vb2_buffer *vb)
+{
+	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
+
+	v4l2_buf->field = V4L2_FIELD_NONE;
+
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static const struct vb2_ops mdp_m2m_qops = {
+	.queue_setup	= mdp_m2m_queue_setup,
+	.wait_prepare	= mdp_m2m_ctx_unlock,
+	.wait_finish	= mdp_m2m_ctx_lock,
+	.buf_prepare	= mdp_m2m_buf_prepare,
+	.start_streaming = mdp_m2m_start_streaming,
+	.stop_streaming	= mdp_m2m_stop_streaming,
+	.buf_queue	= mdp_m2m_buf_queue,
+	.buf_out_validate = mdp_m2m_buf_out_validate,
+};
+
+static int mdp_m2m_querycap(struct file *file, void *fh,
+			    struct v4l2_capability *cap)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+
+	strlcpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, ctx->mdp_dev->pdev->name, sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:mt8183", sizeof(cap->bus_info));
+	cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
+			V4L2_CAP_DEVICE_CAPS; /* | V4L2_CAP_META_OUTPUT */
+	cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,
+				   struct v4l2_fmtdesc *f)
+{
+	return mdp_enum_fmt_mplane(f);
+}
+
+static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+	struct mdp_frame *frame;
+	struct v4l2_pix_format_mplane *pix_mp;
+
+	frame = ctx_get_frame(ctx, f->type);
+	*f = frame->format;
+	pix_mp = &f->fmt.pix_mp;
+	pix_mp->colorspace = ctx->curr_param.colorspace;
+	pix_mp->xfer_func = ctx->curr_param.xfer_func;
+	pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc;
+	pix_mp->quantization = ctx->curr_param.quant;
+
+	mdp_dbg(2, "[%d] type:%d, frame:%ux%u colorspace=%d", ctx->id, f->type,
+		f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+		f->fmt.pix_mp.colorspace);
+	return 0;
+}
+
+static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+	struct mdp_frame *frame = ctx_get_frame(ctx, f->type);
+	struct mdp_frame *capture;
+	const struct mdp_format *fmt;
+	struct vb2_queue *vq;
+
+	mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
+
+	fmt = mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id);
+	if (!fmt) {
+		mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type);
+		return -EINVAL;
+	}
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (vb2_is_streaming(vq)) {
+		dev_info(&ctx->mdp_dev->pdev->dev, "Queue %d busy\n", f->type);
+		return -EBUSY;
+	}
+
+	frame->format = *f;
+	frame->mdp_fmt = fmt;
+	frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color);
+	frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ?
+		MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP;
+
+	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+		capture->crop.c.left = 0;
+		capture->crop.c.top = 0;
+		capture->crop.c.width = f->fmt.pix_mp.width;
+		capture->crop.c.height = f->fmt.pix_mp.height;
+		ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace;
+		ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+		ctx->curr_param.quant = f->fmt.pix_mp.quantization;
+		ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func;
+	} else {
+		capture->compose.left = 0;
+		capture->compose.top = 0;
+		capture->compose.width = f->fmt.pix_mp.width;
+		capture->compose.height = f->fmt.pix_mp.height;
+	}
+
+	ctx->frame_count = 0;
+
+	mdp_dbg(2, "[%d] type:%d, frame:%ux%u", ctx->id, f->type,
+		f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+	return 0;
+}
+
+static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
+				  struct v4l2_format *f)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+
+	if (!mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mdp_m2m_reqbufs(struct file *file, void *fh,
+			   struct v4l2_requestbuffers *reqbufs)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int mdp_m2m_streamon(struct file *file, void *fh,
+			    enum v4l2_buf_type type)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+	struct mdp_frame *capture;
+	int ret;
+	bool out_streaming, cap_streaming;
+
+	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	out_streaming = ctx->m2m_ctx->out_q_ctx.q.streaming;
+	cap_streaming = ctx->m2m_ctx->cap_q_ctx.q.streaming;
+
+	/* Check to see if scaling ratio is within supported range */
+	if ((V4L2_TYPE_IS_OUTPUT(type) && cap_streaming) ||
+	    (!V4L2_TYPE_IS_OUTPUT(type) && out_streaming)) {
+		ret = mdp_check_scaling_ratio(&capture->crop.c,
+					      &capture->compose,
+					      capture->rotation,
+					      ctx->curr_param.limit);
+		if (ret) {
+			dev_info(&ctx->mdp_dev->pdev->dev,
+				 "Out of scaling range\n");
+			return ret;
+		}
+	}
+
+	if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
+		ret = mdp_vpu_get_locked(ctx->mdp_dev);
+		if (ret)
+			return ret;
+
+		ret = mdp_vpu_ctx_init(&ctx->vpu, &ctx->mdp_dev->vpu,
+				       MDP_DEV_M2M);
+		if (ret) {
+			dev_err(&ctx->mdp_dev->pdev->dev,
+				"VPU init failed %d\n", ret);
+			return -EINVAL;
+		}
+		mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT);
+	}
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int mdp_m2m_g_selection(struct file *file, void *fh,
+			       struct v4l2_selection *s)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+	struct mdp_frame *frame;
+	bool valid = false;
+
+	if (s->type <= V4L2_BUF_TYPE_META_OUTPUT) {
+		if (V4L2_TYPE_IS_OUTPUT(s->type))
+			valid = mdp_target_is_crop(s->target);
+		else
+			valid = mdp_target_is_compose(s->target);
+	}
+
+	if (!valid) {
+		mdp_dbg(1, "[%d] invalid type:%u target:%u", ctx->id, s->type,
+			s->target);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		s->r = frame->crop.c;
+		return 0;
+	case V4L2_SEL_TGT_COMPOSE:
+		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		s->r = frame->compose;
+		return 0;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		frame = ctx_get_frame(ctx, s->type);
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = frame->format.fmt.pix_mp.width;
+		s->r.height = frame->format.fmt.pix_mp.height;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int mdp_m2m_s_selection(struct file *file, void *fh,
+			       struct v4l2_selection *s)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
+	struct mdp_frame *frame = ctx_get_frame(ctx, s->type);
+	struct mdp_frame *capture;
+	struct v4l2_rect r;
+	bool valid = false;
+	int ret;
+
+	if (s->type <= V4L2_BUF_TYPE_META_OUTPUT) {
+		if (V4L2_TYPE_IS_OUTPUT(s->type))
+			valid = (s->target == V4L2_SEL_TGT_CROP);
+		else
+			valid = (s->target == V4L2_SEL_TGT_COMPOSE);
+	}
+	if (!valid) {
+		mdp_dbg(1, "[%d] invalid type:%u target:%u", ctx->id, s->type,
+			s->target);
+		return -EINVAL;
+	}
+
+	ret = mdp_try_crop(&r, s, frame, ctx->id);
+	if (ret)
+		return ret;
+	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+	if (mdp_target_is_crop(s->target))
+		capture->crop.c = r;
+	else
+		capture->compose = r;
+
+	s->r = r;
+	memset(s->reserved, 0, sizeof(s->reserved));
+
+	ctx->frame_count = 0;
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = {
+	.vidioc_querycap		= mdp_m2m_querycap,
+	.vidioc_enum_fmt_vid_cap	= mdp_m2m_enum_fmt_mplane,
+	.vidioc_enum_fmt_vid_out	= mdp_m2m_enum_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= mdp_m2m_g_fmt_mplane,
+	.vidioc_g_fmt_vid_out_mplane	= mdp_m2m_g_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= mdp_m2m_s_fmt_mplane,
+	.vidioc_s_fmt_vid_out_mplane	= mdp_m2m_s_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= mdp_m2m_try_fmt_mplane,
+	.vidioc_try_fmt_vid_out_mplane	= mdp_m2m_try_fmt_mplane,
+	.vidioc_reqbufs			= mdp_m2m_reqbufs,
+	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
+	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
+	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
+	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
+	.vidioc_streamon		= mdp_m2m_streamon,
+	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
+	.vidioc_g_selection		= mdp_m2m_g_selection,
+	.vidioc_s_selection		= mdp_m2m_s_selection,
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+static int mdp_m2m_queue_init(void *priv,
+			      struct vb2_queue *src_vq,
+			      struct vb2_queue *dst_vq)
+{
+	struct mdp_m2m_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->ops = &mdp_m2m_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->dev = &ctx->mdp_dev->pdev->dev;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->ops = &mdp_m2m_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->dev = &ctx->mdp_dev->pdev->dev;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl);
+	struct mdp_frame *capture;
+
+	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+		return 0;
+
+	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		capture->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		capture->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		capture->rotation = ctrl->val;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {
+	.s_ctrl	= mdp_m2m_s_ctrl,
+};
+
+static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx)
+{
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS);
+	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					     &mdp_m2m_ctrl_ops, V4L2_CID_HFLIP,
+					     0, 1, 1, 0);
+	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					     &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP,
+					     0, 1, 1, 0);
+	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+					      &mdp_m2m_ctrl_ops,
+					      V4L2_CID_ROTATE, 0, 270, 90, 0);
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		dev_err(&ctx->mdp_dev->pdev->dev,
+			"Failed to register controls\n");
+		return err;
+	}
+	return 0;
+}
+
+static int mdp_m2m_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct mdp_dev *mdp = video_get_drvdata(vdev);
+	struct mdp_m2m_ctx *ctx;
+	int ret;
+	struct v4l2_format default_format;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (mutex_lock_interruptible(&mdp->m2m_lock)) {
+		ret = -ERESTARTSYS;
+		goto err_free_ctx;
+	}
+
+	ctx->id = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
+	ctx->mdp_dev = mdp;
+
+	v4l2_fh_init(&ctx->fh, vdev);
+	vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+	file->private_data = &ctx->fh;
+	ret = mdp_m2m_ctrls_create(ctx);
+	if (ret)
+		goto err_exit_fh;
+
+	/* Use separate control handler per file handle */
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	v4l2_fh_add(&ctx->fh);
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		dev_err(&mdp->pdev->dev, "Failed to initialize m2m context\n");
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto err_release_handler;
+	}
+	ctx->fh.m2m_ctx = ctx->m2m_ctx;
+
+	INIT_WORK(&ctx->work, mdp_m2m_worker);
+
+	ret = mdp_frameparam_init(&ctx->curr_param);
+	if (ret) {
+		dev_err(&mdp->pdev->dev,
+			"Failed to initialize mdp parameter\n");
+		goto err_release_m2m_ctx;
+	}
+
+	mutex_unlock(&mdp->m2m_lock);
+
+	/* Default format */
+	memset(&default_format, 0, sizeof(default_format));
+	default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	default_format.fmt.pix_mp.width = 32;
+	default_format.fmt.pix_mp.height = 32;
+	default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
+	mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
+	default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
+
+	mdp_dbg(1, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
+
+	return 0;
+
+err_release_m2m_ctx:
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+err_release_handler:
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+err_exit_fh:
+	v4l2_fh_exit(&ctx->fh);
+	mutex_unlock(&mdp->m2m_lock);
+err_free_ctx:
+	kfree(ctx);
+
+	return ret;
+}
+
+static int mdp_m2m_release(struct file *file)
+{
+	struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mdp_dev *mdp = video_drvdata(file);
+
+	mutex_lock(&mdp->m2m_lock);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
+		mdp_vpu_ctx_deinit(&ctx->vpu);
+		mdp_vpu_put_locked(mdp);
+	}
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	ida_free(&mdp->mdp_ida, ctx->id);
+	mutex_unlock(&mdp->m2m_lock);
+
+	mdp_dbg(1, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
+	kfree(ctx);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations mdp_m2m_fops = {
+	.owner		= THIS_MODULE,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+	.open		= mdp_m2m_open,
+	.release	= mdp_m2m_release,
+};
+
+static const struct v4l2_m2m_ops mdp_m2m_ops = {
+	.device_run	= mdp_m2m_device_run,
+	.job_abort	= mdp_m2m_job_abort,
+};
+
+int mdp_m2m_device_register(struct mdp_dev *mdp)
+{
+	struct device *dev = &mdp->pdev->dev;
+	int ret = 0;
+
+	mdp->m2m_vdev = video_device_alloc();
+	if (!mdp->m2m_vdev) {
+		dev_err(dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto err_video_alloc;
+	}
+	//mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
+	//	V4L2_CAP_STREAMING;
+	mdp->m2m_vdev->fops = &mdp_m2m_fops;
+	mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops;
+	mdp->m2m_vdev->release = video_device_release;
+	mdp->m2m_vdev->lock = &mdp->m2m_lock;
+	mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M;
+	mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev;
+	snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m",
+		 MDP_MODULE_NAME);
+	video_set_drvdata(mdp->m2m_vdev, mdp);
+
+	mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops);
+	if (IS_ERR(mdp->m2m_dev)) {
+		dev_err(dev, "Failed to initialize v4l2-m2m device\n");
+		ret = PTR_ERR(mdp->m2m_dev);
+		goto err_m2m_init;
+	}
+
+	ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_GRABBER, 2);
+	if (ret) {
+		dev_err(dev, "Failed to register video device\n");
+		goto err_video_register;
+	}
+
+	v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d",
+		  mdp->m2m_vdev->num);
+	return 0;
+
+err_video_register:
+	v4l2_m2m_release(mdp->m2m_dev);
+err_m2m_init:
+	video_device_release(mdp->m2m_vdev);
+err_video_alloc:
+
+	return ret;
+}
+
+void mdp_m2m_device_unregister(struct mdp_dev *mdp)
+{
+	video_unregister_device(mdp->m2m_vdev);
+	video_device_release(mdp->m2m_vdev);
+	v4l2_m2m_release(mdp->m2m_dev);
+}
+
+void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx)
+{
+	enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE;
+
+	mdp_m2m_process_done(ctx, vb_state);
+}
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.h
new file mode 100644
index 000000000000..c3f340f7ec49
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_M2M_H__
+#define __MTK_MDP3_M2M_H__
+
+#include <media/v4l2-ctrls.h>
+#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-vpu.h"
+#include "mtk-mdp3-regs.h"
+
+#define MDP_MAX_CTRLS	10
+
+struct mdp_m2m_ctrls {
+	struct v4l2_ctrl	*hflip;
+	struct v4l2_ctrl	*vflip;
+	struct v4l2_ctrl	*rotate;
+};
+
+struct mdp_m2m_ctx {
+	u32				id;
+	struct mdp_dev			*mdp_dev;
+	struct v4l2_fh			fh;
+	struct v4l2_ctrl_handler	ctrl_handler;
+	struct mdp_m2m_ctrls		ctrls;
+	struct v4l2_m2m_ctx		*m2m_ctx;
+	struct mdp_vpu_ctx		vpu;
+	struct work_struct		work;
+	u32				frame_count;
+
+	struct mdp_frameparam		curr_param;
+};
+
+int mdp_m2m_device_register(struct mdp_dev *mdp);
+void mdp_m2m_device_unregister(struct mdp_dev *mdp);
+void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx);
+
+#endif  /* __MTK_MDP3_M2M_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
new file mode 100644
index 000000000000..5c48a7e75efd
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
@@ -0,0 +1,748 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#include <media/v4l2-common.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include "mtk-mdp3-core.h"
+#include "mtk-mdp3-regs.h"
+
+static const struct mdp_format mdp_formats[] = {
+	{
+		.pixelformat	= V4L2_PIX_FMT_GREY,
+		.mdp_color	= MDP_COLOR_GREY,
+		.depth		= { 8 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_RGB565X,
+		.mdp_color	= MDP_COLOR_RGB565,
+		.depth		= { 16 },
+		.row_depth	= { 16 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_RGB565,
+		.mdp_color	= MDP_COLOR_BGR565,
+		.depth		= { 16 },
+		.row_depth	= { 16 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_RGB24,
+		.mdp_color	= MDP_COLOR_RGB888,
+		.depth		= { 24 },
+		.row_depth	= { 24 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_BGR24,
+		.mdp_color	= MDP_COLOR_BGR888,
+		.depth		= { 24 },
+		.row_depth	= { 24 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_ABGR32,
+		.mdp_color	= MDP_COLOR_BGRA8888,
+		.depth		= { 32 },
+		.row_depth	= { 32 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_ARGB32,
+		.mdp_color	= MDP_COLOR_ARGB8888,
+		.depth		= { 32 },
+		.row_depth	= { 32 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_UYVY,
+		.mdp_color	= MDP_COLOR_UYVY,
+		.depth		= { 16 },
+		.row_depth	= { 16 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_VYUY,
+		.mdp_color	= MDP_COLOR_VYUY,
+		.depth		= { 16 },
+		.row_depth	= { 16 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_YUYV,
+		.mdp_color	= MDP_COLOR_YUYV,
+		.depth		= { 16 },
+		.row_depth	= { 16 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_YVYU,
+		.mdp_color	= MDP_COLOR_YVYU,
+		.depth		= { 16 },
+		.row_depth	= { 16 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_YUV420,
+		.mdp_color	= MDP_COLOR_I420,
+		.depth		= { 12 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_YVU420,
+		.mdp_color	= MDP_COLOR_YV12,
+		.depth		= { 12 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV12,
+		.mdp_color	= MDP_COLOR_NV12,
+		.depth		= { 12 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV21,
+		.mdp_color	= MDP_COLOR_NV21,
+		.depth		= { 12 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV16,
+		.mdp_color	= MDP_COLOR_NV16,
+		.depth		= { 16 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV61,
+		.mdp_color	= MDP_COLOR_NV61,
+		.depth		= { 16 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV24,
+		.mdp_color	= MDP_COLOR_NV24,
+		.depth		= { 24 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV42,
+		.mdp_color	= MDP_COLOR_NV42,
+		.depth		= { 24 },
+		.row_depth	= { 8 },
+		.num_planes	= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_MT21C,
+		.mdp_color	= MDP_COLOR_420_BLK_UFO,
+		.depth		= { 8, 4 },
+		.row_depth	= { 8, 8 },
+		.num_planes	= 2,
+		.walign		= 4,
+		.halign		= 5,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_MM21,
+		.mdp_color	= MDP_COLOR_420_BLK,
+		.depth		= { 8, 4 },
+		.row_depth	= { 8, 8 },
+		.num_planes	= 2,
+		.walign		= 4,
+		.halign		= 5,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV12M,
+		.mdp_color	= MDP_COLOR_NV12,
+		.depth		= { 8, 4 },
+		.row_depth	= { 8, 8 },
+		.num_planes	= 2,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV21M,
+		.mdp_color	= MDP_COLOR_NV21,
+		.depth		= { 8, 4 },
+		.row_depth	= { 8, 8 },
+		.num_planes	= 2,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV16M,
+		.mdp_color	= MDP_COLOR_NV16,
+		.depth		= { 8, 8 },
+		.row_depth	= { 8, 8 },
+		.num_planes	= 2,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_NV61M,
+		.mdp_color	= MDP_COLOR_NV61,
+		.depth		= { 8, 8 },
+		.row_depth	= { 8, 8 },
+		.num_planes	= 2,
+		.walign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_YUV420M,
+		.mdp_color	= MDP_COLOR_I420,
+		.depth		= { 8, 2, 2 },
+		.row_depth	= { 8, 4, 4 },
+		.num_planes	= 3,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}, {
+		.pixelformat	= V4L2_PIX_FMT_YVU420M,
+		.mdp_color	= MDP_COLOR_YV12,
+		.depth		= { 8, 2, 2 },
+		.row_depth	= { 8, 4, 4 },
+		.num_planes	= 3,
+		.walign		= 1,
+		.halign		= 1,
+		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
+	}
+};
+
+static const struct mdp_limit mdp_def_limit = {
+	.out_limit = {
+		.wmin	= 16,
+		.hmin	= 16,
+		.wmax	= 8176,
+		.hmax	= 8176,
+	},
+	.cap_limit = {
+		.wmin	= 2,
+		.hmin	= 2,
+		.wmax	= 8176,
+		.hmax	= 8176,
+	},
+	.h_scale_up_max = 32,
+	.v_scale_up_max = 32,
+	.h_scale_down_max = 20,
+	.v_scale_down_max = 128,
+};
+
+static const struct mdp_format *mdp_find_fmt(u32 pixelformat, u32 type)
+{
+	u32 i, flag;
+
+	flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
+					MDP_FMT_FLAG_CAPTURE;
+	for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
+		if (!(mdp_formats[i].flags & flag))
+			continue;
+		if (mdp_formats[i].pixelformat == pixelformat)
+			return &mdp_formats[i];
+	}
+	return NULL;
+}
+
+static const struct mdp_format *mdp_find_fmt_by_index(u32 index, u32 type)
+{
+	u32 i, flag, num = 0;
+
+	flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
+					MDP_FMT_FLAG_CAPTURE;
+	for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
+		if (!(mdp_formats[i].flags & flag))
+			continue;
+		if (index == num)
+			return &mdp_formats[i];
+		num++;
+	}
+	return NULL;
+}
+
+enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f,
+						 u32 mdp_color)
+{
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+
+	if (MDP_COLOR_IS_RGB(mdp_color))
+		return MDP_YCBCR_PROFILE_FULL_BT601;
+
+	switch (pix_mp->colorspace) {
+	case V4L2_COLORSPACE_JPEG:
+		return MDP_YCBCR_PROFILE_JPEG;
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_DCI_P3:
+		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
+			return MDP_YCBCR_PROFILE_FULL_BT709;
+		return MDP_YCBCR_PROFILE_BT709;
+	case V4L2_COLORSPACE_BT2020:
+		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
+			return MDP_YCBCR_PROFILE_FULL_BT2020;
+		return MDP_YCBCR_PROFILE_BT2020;
+	default:
+		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
+			return MDP_YCBCR_PROFILE_FULL_BT601;
+		return MDP_YCBCR_PROFILE_BT601;
+	}
+}
+
+static void mdp_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
+				  unsigned int walign,
+				u32 *h, unsigned int hmin, unsigned int hmax,
+				unsigned int halign, unsigned int salign)
+{
+	unsigned int org_w, org_h, wstep, hstep;
+
+	org_w = *w;
+	org_h = *h;
+	v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign,
+			      salign);
+
+	wstep = 1 << walign;
+	hstep = 1 << halign;
+	if (*w < org_w && (*w + wstep) <= wmax)
+		*w += wstep;
+	if (*h < org_h && (*h + hstep) <= hmax)
+		*h += hstep;
+}
+
+static int mdp_clamp_align(s32 *x, int min, int max, unsigned int align)
+{
+	unsigned int mask;
+
+	if (min < 0 || max < 0)
+		return -ERANGE;
+
+	/* Bits that must be zero to be aligned */
+	mask = ~((1 << align) - 1);
+
+	min = 0 ? 0 : ((min + ~mask) & mask);
+	max = max & mask;
+	if ((unsigned int)min > (unsigned int)max)
+		return -ERANGE;
+
+	/* Clamp to aligned min and max */
+	*x = clamp(*x, min, max);
+
+	/* Round to nearest aligned value */
+	if (align)
+		*x = (*x + (1 << (align - 1))) & mask;
+	return 0;
+}
+
+int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f)
+{
+	const struct mdp_format *fmt;
+
+	if (!V4L2_TYPE_IS_MULTIPLANAR(f->type))
+		return -EINVAL;
+
+	fmt = mdp_find_fmt_by_index(f->index, f->type);
+	if (!fmt)
+		return -EINVAL;
+
+	/* f->description */
+	f->pixelformat = fmt->pixelformat;
+	return 0;
+}
+
+const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
+					    struct mdp_frameparam *param,
+					    u32 ctx_id)
+{
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+	const struct mdp_format *fmt;
+	const struct mdp_pix_limit *pix_limit;
+	u32 wmin, wmax, hmin, hmax, org_w, org_h;
+	unsigned int i;
+
+	if (!V4L2_TYPE_IS_MULTIPLANAR(f->type))
+		return NULL;
+
+	fmt = mdp_find_fmt(pix_mp->pixelformat, f->type);
+	if (!fmt)
+		fmt = mdp_find_fmt_by_index(0, f->type);
+	if (!fmt) {
+		mdp_dbg(0, "[%d] pixelformat %c%c%c%c invalid", ctx_id,
+			(pix_mp->pixelformat & 0xff),
+			(pix_mp->pixelformat >>  8) & 0xff,
+			(pix_mp->pixelformat >> 16) & 0xff,
+			(pix_mp->pixelformat >> 24) & 0xff);
+		return NULL;
+	}
+
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->flags = 0;
+	pix_mp->pixelformat = fmt->pixelformat;
+	if (!V4L2_TYPE_IS_OUTPUT(f->type)) {
+		pix_mp->colorspace = param->colorspace;
+		pix_mp->xfer_func = param->xfer_func;
+		pix_mp->ycbcr_enc = param->ycbcr_enc;
+		pix_mp->quantization = param->quant;
+	}
+	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+
+	pix_limit = V4L2_TYPE_IS_OUTPUT(f->type) ? &param->limit->out_limit :
+		&param->limit->cap_limit;
+	wmin = pix_limit->wmin;
+	wmax = pix_limit->wmax;
+	hmin = pix_limit->hmin;
+	hmax = pix_limit->hmax;
+	org_w = pix_mp->width;
+	org_h = pix_mp->height;
+
+	mdp_bound_align_image(&pix_mp->width, wmin, wmax, fmt->walign,
+			      &pix_mp->height, hmin, hmax, fmt->halign,
+				fmt->salign);
+	if (org_w != pix_mp->width || org_h != pix_mp->height)
+		mdp_dbg(1, "[%d] size change: %ux%u to %ux%u", ctx_id,
+			org_w, org_h, pix_mp->width, pix_mp->height);
+
+	if (pix_mp->num_planes && pix_mp->num_planes != fmt->num_planes)
+		mdp_dbg(1, "[%d] num of planes change: %u to %u", ctx_id,
+			pix_mp->num_planes, fmt->num_planes);
+	pix_mp->num_planes = fmt->num_planes;
+
+	for (i = 0; i < pix_mp->num_planes; ++i) {
+		u32 min_bpl = (pix_mp->width * fmt->row_depth[i]) / 8;
+		u32 bpl = pix_mp->plane_fmt[i].bytesperline;
+		u32 si;
+
+		if (bpl < min_bpl)
+			bpl = min_bpl;
+		si = (bpl * pix_mp->height * fmt->depth[i]) / fmt->row_depth[i];
+
+		pix_mp->plane_fmt[i].bytesperline = bpl;
+		if (pix_mp->plane_fmt[i].sizeimage < si)
+			pix_mp->plane_fmt[i].sizeimage = si;
+		memset(pix_mp->plane_fmt[i].reserved, 0,
+		       sizeof(pix_mp->plane_fmt[i].reserved));
+		mdp_dbg(2, "[%d] p%u, bpl:%u (%u), sizeimage:%u (%u)", ctx_id,
+			i, bpl, min_bpl, pix_mp->plane_fmt[i].sizeimage, si);
+	}
+
+	return fmt;
+}
+
+static int mdp_clamp_start(s32 *x, int min, int max, unsigned int align,
+			   u32 flags)
+{
+	if (flags & V4L2_SEL_FLAG_GE)
+		max = *x;
+	if (flags & V4L2_SEL_FLAG_LE)
+		min = *x;
+	return mdp_clamp_align(x, min, max, align);
+}
+
+static int mdp_clamp_end(s32 *x, int min, int max, unsigned int align,
+			 u32 flags)
+{
+	if (flags & V4L2_SEL_FLAG_GE)
+		min = *x;
+	if (flags & V4L2_SEL_FLAG_LE)
+		max = *x;
+	return mdp_clamp_align(x, min, max, align);
+}
+
+int mdp_try_crop(struct v4l2_rect *r, const struct v4l2_selection *s,
+		 struct mdp_frame *frame, u32 ctx_id)
+{
+	s32 left, top, right, bottom;
+	u32 framew, frameh, walign, halign;
+	int ret;
+
+	mdp_dbg(2, "[%d] target:%d, set:(%d,%d) %ux%u", ctx_id, s->target,
+		s->r.left, s->r.top, s->r.width, s->r.height);
+
+	left = s->r.left;
+	top = s->r.top;
+	right = s->r.left + s->r.width;
+	bottom = s->r.top + s->r.height;
+	framew = frame->format.fmt.pix_mp.width;
+	frameh = frame->format.fmt.pix_mp.height;
+
+	if (mdp_target_is_crop(s->target)) {
+		walign = 1;
+		halign = 1;
+	} else {
+		walign = frame->mdp_fmt->walign;
+		halign = frame->mdp_fmt->halign;
+	}
+
+	mdp_dbg(2, "[%d] align:%u,%u, bound:%ux%u", ctx_id,
+		walign, halign, framew, frameh);
+
+	ret = mdp_clamp_start(&left, 0, right, walign, s->flags);
+	if (ret)
+		return ret;
+	ret = mdp_clamp_start(&top, 0, bottom, halign, s->flags);
+	if (ret)
+		return ret;
+	ret = mdp_clamp_end(&right, left, framew, walign, s->flags);
+	if (ret)
+		return ret;
+	ret = mdp_clamp_end(&bottom, top, frameh, halign, s->flags);
+	if (ret)
+		return ret;
+
+	r->left = left;
+	r->top = top;
+	r->width = right - left;
+	r->height = bottom - top;
+
+	mdp_dbg(2, "[%d] crop:(%d,%d) %ux%u", ctx_id,
+		r->left, r->top, r->width, r->height);
+	return 0;
+}
+
+int mdp_check_scaling_ratio(const struct v4l2_rect *crop,
+			    const struct v4l2_rect *compose, s32 rotation,
+	const struct mdp_limit *limit)
+{
+	u32 crop_w, crop_h, comp_w, comp_h;
+
+	crop_w = crop->width;
+	crop_h = crop->height;
+	if (90 == rotation || 270 == rotation) {
+		comp_w = compose->height;
+		comp_h = compose->width;
+	} else {
+		comp_w = compose->width;
+		comp_h = compose->height;
+	}
+
+	if ((crop_w / comp_w) > limit->h_scale_down_max ||
+	    (crop_h / comp_h) > limit->v_scale_down_max ||
+	    (comp_w / crop_w) > limit->h_scale_up_max ||
+	    (comp_h / crop_h) > limit->v_scale_up_max)
+		return -ERANGE;
+	return 0;
+}
+
+/* Stride that is accepted by MDP HW */
+static u32 mdp_fmt_get_stride(const struct mdp_format *fmt,
+			      u32 bytesperline, unsigned int plane)
+{
+	enum mdp_color c = fmt->mdp_color;
+	u32 stride;
+
+	stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c))
+		/ fmt->row_depth[0];
+	if (plane == 0)
+		return stride;
+	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
+		if (MDP_COLOR_IS_BLOCK_MODE(c))
+			stride = stride / 2;
+		return stride;
+	}
+	return 0;
+}
+
+/* Stride that is accepted by MDP HW of format with contiguous planes */
+static u32 mdp_fmt_get_stride_contig(const struct mdp_format *fmt,
+				     u32 pix_stride, unsigned int plane)
+{
+	enum mdp_color c = fmt->mdp_color;
+	u32 stride = pix_stride;
+
+	if (plane == 0)
+		return stride;
+	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
+		stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c);
+		if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c))
+			stride = stride * 2;
+		return stride;
+	}
+	return 0;
+}
+
+/* Plane size that is accepted by MDP HW */
+static u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt,
+				  u32 stride, u32 height, unsigned int plane)
+{
+	enum mdp_color c = fmt->mdp_color;
+	u32 bytesperline;
+
+	bytesperline = (stride * fmt->row_depth[0])
+		/ MDP_COLOR_BITS_PER_PIXEL(c);
+	if (plane == 0)
+		return bytesperline * height;
+	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
+		height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c);
+		if (MDP_COLOR_IS_BLOCK_MODE(c))
+			bytesperline = bytesperline * 2;
+		return bytesperline * height;
+	}
+	return 0;
+}
+
+static void mdp_prepare_buffer(struct img_image_buffer *b,
+			       struct mdp_frame *frame, struct vb2_buffer *vb)
+{
+	struct v4l2_pix_format_mplane *pix_mp = &frame->format.fmt.pix_mp;
+	unsigned int i;
+
+	b->format.colorformat = frame->mdp_fmt->mdp_color;
+	b->format.ycbcr_prof = frame->ycbcr_prof;
+	for (i = 0; i < pix_mp->num_planes; ++i) {
+		u32 stride = mdp_fmt_get_stride(frame->mdp_fmt,
+			pix_mp->plane_fmt[i].bytesperline, i);
+
+		b->format.plane_fmt[i].stride = stride;
+		/*
+		 * TODO(crbug.com/901264): The way to pass an offset within a
+		 * DMA-buf is not defined in V4L2 specification, so we abuse
+		 * data_offset for now. Fix it when we have the right interface,
+		 * including any necessary validation and potential alignment
+		 * issues.
+		 */
+		b->format.plane_fmt[i].size =
+			mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
+					       pix_mp->height, i) -
+					       vb->planes[i].data_offset;
+		b->iova[i] = vb2_dma_contig_plane_dma_addr(vb, i) +
+			     vb->planes[i].data_offset;
+	}
+	for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) {
+		u32 stride = mdp_fmt_get_stride_contig(frame->mdp_fmt,
+			b->format.plane_fmt[0].stride, i);
+
+		b->format.plane_fmt[i].stride = stride;
+		b->format.plane_fmt[i].size =
+			mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
+					       pix_mp->height, i);
+		b->iova[i] = b->iova[i - 1] + b->format.plane_fmt[i - 1].size;
+	}
+	b->usage = frame->usage;
+}
+
+void mdp_set_src_config(struct img_input *in,
+			struct mdp_frame *frame, struct vb2_buffer *vb)
+{
+	in->buffer.format.width = frame->format.fmt.pix_mp.width;
+	in->buffer.format.height = frame->format.fmt.pix_mp.height;
+	mdp_prepare_buffer(&in->buffer, frame, vb);
+
+	/* in->flags |= ; */	/* HDR, DRE, dither */
+}
+
+static u32 mdp_to_fixed(u32 *r, struct v4l2_fract *f)
+{
+	u32 q;
+
+	if (f->denominator == 0) {
+		*r = 0;
+		return 0;
+	}
+
+	q = f->numerator / f->denominator;
+	*r = div_u64(((u64)f->numerator - q * f->denominator) <<
+		     IMG_SUBPIXEL_SHIFT, f->denominator);
+	return q;
+}
+
+static void mdp_set_src_crop(struct img_crop *c, struct mdp_crop *crop)
+{
+	c->left = crop->c.left
+		+ mdp_to_fixed(&c->left_subpix, &crop->left_subpix);
+	c->top = crop->c.top
+		+ mdp_to_fixed(&c->top_subpix, &crop->top_subpix);
+	c->width = crop->c.width
+		+ mdp_to_fixed(&c->width_subpix, &crop->width_subpix);
+	c->height = crop->c.height
+		+ mdp_to_fixed(&c->height_subpix, &crop->height_subpix);
+}
+
+static void mdp_set_orientation(struct img_output *out,
+				s32 rotation, bool hflip, bool vflip)
+{
+	u8 flip = 0;
+
+	if (hflip)
+		flip ^= 1;
+	if (vflip) {
+		/*
+		 * A vertical flip is equivalent to
+		 * a 180-degree rotation with a horizontal flip
+		 */
+		rotation += 180;
+		flip ^= 1;
+	}
+
+	out->rotation = rotation % 360;
+	if (flip != 0)
+		out->flags |= IMG_CTRL_FLAG_HFLIP;
+	else
+		out->flags &= ~IMG_CTRL_FLAG_HFLIP;
+}
+
+void mdp_set_dst_config(struct img_output *out,
+			struct mdp_frame *frame, struct vb2_buffer *vb)
+{
+	out->buffer.format.width = frame->compose.width;
+	out->buffer.format.height = frame->compose.height;
+	mdp_prepare_buffer(&out->buffer, frame, vb);
+	mdp_set_src_crop(&out->crop, &frame->crop);
+	mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip);
+
+	/* out->flags |= ; */	/* sharpness, dither */
+}
+
+int mdp_frameparam_init(struct mdp_frameparam *param)
+{
+	struct mdp_frame *frame;
+
+	if (!param)
+		return -EINVAL;
+
+	INIT_LIST_HEAD(&param->list);
+	mutex_init(&param->state_lock);
+	param->limit = &mdp_def_limit;
+	param->type = MDP_STREAM_TYPE_BITBLT;
+
+	frame = &param->output;
+	frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
+	frame->ycbcr_prof =
+		mdp_map_ycbcr_prof_mplane(&frame->format,
+					  frame->mdp_fmt->mdp_color);
+	frame->usage = MDP_BUFFER_USAGE_HW_READ;
+
+	param->num_captures = 1;
+	frame = &param->captures[0];
+	frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
+	frame->ycbcr_prof =
+		mdp_map_ycbcr_prof_mplane(&frame->format,
+					  frame->mdp_fmt->mdp_color);
+	frame->usage = MDP_BUFFER_USAGE_MDP;
+	frame->crop.c.width = param->output.format.fmt.pix_mp.width;
+	frame->crop.c.height = param->output.format.fmt.pix_mp.height;
+	frame->compose.width = frame->format.fmt.pix_mp.width;
+	frame->compose.height = frame->format.fmt.pix_mp.height;
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h
new file mode 100644
index 000000000000..b41c419afb10
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h
@@ -0,0 +1,373 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_REGS_H__
+#define __MTK_MDP3_REGS_H__
+
+#include <linux/videodev2.h>
+#include <media/videobuf2-core.h>
+#include "mtk-img-ipi.h"
+
+/*
+ * MDP native color code
+ * Plane count: 1, 2, 3
+ * H-subsample: 0, 1, 2
+ * V-subsample: 0, 1
+ * Color group: 0-RGB, 1-YUV, 2-raw
+ */
+#define MDP_COLOR(PACKED, LOOSE, VIDEO, PLANE, HF, VF, BITS, GROUP, SWAP, ID)\
+	(((PACKED) << 27) | ((LOOSE) << 26) | ((VIDEO) << 23) |\
+	 ((PLANE) << 21) | ((HF) << 19) | ((VF) << 18) | ((BITS) << 8) |\
+	 ((GROUP) << 6) | ((SWAP) << 5) | ((ID) << 0))
+
+#define MDP_COLOR_IS_10BIT_PACKED(c)    ((0x08000000 & (c)) >> 27)
+#define MDP_COLOR_IS_10BIT_LOOSE(c)    (((0x0c000000 & (c)) >> 26) == 1)
+#define MDP_COLOR_IS_10BIT_TILE(c)     (((0x0c000000 & (c)) >> 26) == 3)
+#define MDP_COLOR_IS_UFP(c)             ((0x02000000 & (c)) >> 25)
+#define MDP_COLOR_IS_INTERLACED(c)      ((0x01000000 & (c)) >> 24)
+#define MDP_COLOR_IS_BLOCK_MODE(c)      ((0x00800000 & (c)) >> 23)
+#define MDP_COLOR_GET_PLANE_COUNT(c)    ((0x00600000 & (c)) >> 21)
+#define MDP_COLOR_GET_H_SUBSAMPLE(c)    ((0x00180000 & (c)) >> 19)
+#define MDP_COLOR_GET_V_SUBSAMPLE(c)    ((0x00040000 & (c)) >> 18)
+#define MDP_COLOR_BITS_PER_PIXEL(c)     ((0x0003ff00 & (c)) >>  8)
+#define MDP_COLOR_GET_GROUP(c)          ((0x000000c0 & (c)) >>  6)
+#define MDP_COLOR_IS_SWAPPED(c)         ((0x00000020 & (c)) >>  5)
+#define MDP_COLOR_GET_UNIQUE_ID(c)      ((0x0000001f & (c)) >>  0)
+#define MDP_COLOR_GET_HW_FORMAT(c)      ((0x0000001f & (c)) >>  0)
+
+#define MDP_COLOR_IS_RGB(c)		(MDP_COLOR_GET_GROUP(c) == 0)
+#define MDP_COLOR_IS_YUV(c)		(MDP_COLOR_GET_GROUP(c) == 1)
+#define MDP_COLOR_IS_UV_COPLANE(c)	((MDP_COLOR_GET_PLANE_COUNT(c) == 2) &&\
+					 MDP_COLOR_IS_YUV(c))
+
+enum mdp_color {
+	MDP_COLOR_UNKNOWN	= 0,
+
+	//MDP_COLOR_FULLG8,
+	MDP_COLOR_FULLG8_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0,  8, 2,  0, 21),
+	MDP_COLOR_FULLG8_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1,  8, 2,  0, 21),
+	MDP_COLOR_FULLG8_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0,  8, 2,  0, 21),
+	MDP_COLOR_FULLG8_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1,  8, 2,  0, 21),
+	MDP_COLOR_FULLG8	= MDP_COLOR_FULLG8_BGGR,
+
+	//MDP_COLOR_FULLG10,
+	MDP_COLOR_FULLG10_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2,  0, 21),
+	MDP_COLOR_FULLG10_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1, 10, 2,  0, 21),
+	MDP_COLOR_FULLG10_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0, 10, 2,  0, 21),
+	MDP_COLOR_FULLG10_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1, 10, 2,  0, 21),
+	MDP_COLOR_FULLG10	= MDP_COLOR_FULLG10_BGGR,
+
+	//MDP_COLOR_FULLG12,
+	MDP_COLOR_FULLG12_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2,  0, 21),
+	MDP_COLOR_FULLG12_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1, 12, 2,  0, 21),
+	MDP_COLOR_FULLG12_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0, 12, 2,  0, 21),
+	MDP_COLOR_FULLG12_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1, 12, 2,  0, 21),
+	MDP_COLOR_FULLG12	= MDP_COLOR_FULLG12_BGGR,
+
+	//MDP_COLOR_FULLG14,
+	MDP_COLOR_FULLG14_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2,  0, 21),
+	MDP_COLOR_FULLG14_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1, 14, 2,  0, 21),
+	MDP_COLOR_FULLG14_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0, 14, 2,  0, 21),
+	MDP_COLOR_FULLG14_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1, 14, 2,  0, 21),
+	MDP_COLOR_FULLG14	= MDP_COLOR_FULLG14_BGGR,
+
+	MDP_COLOR_UFO10		= MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2,  0, 24),
+
+	//MDP_COLOR_BAYER8,
+	MDP_COLOR_BAYER8_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0,  8, 2,  0, 20),
+	MDP_COLOR_BAYER8_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1,  8, 2,  0, 20),
+	MDP_COLOR_BAYER8_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0,  8, 2,  0, 20),
+	MDP_COLOR_BAYER8_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1,  8, 2,  0, 20),
+	MDP_COLOR_BAYER8	= MDP_COLOR_BAYER8_BGGR,
+
+	//MDP_COLOR_BAYER10,
+	MDP_COLOR_BAYER10_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2,  0, 20),
+	MDP_COLOR_BAYER10_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1, 10, 2,  0, 20),
+	MDP_COLOR_BAYER10_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0, 10, 2,  0, 20),
+	MDP_COLOR_BAYER10_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1, 10, 2,  0, 20),
+	MDP_COLOR_BAYER10	= MDP_COLOR_BAYER10_BGGR,
+
+	//MDP_COLOR_BAYER12,
+	MDP_COLOR_BAYER12_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2,  0, 20),
+	MDP_COLOR_BAYER12_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1, 12, 2,  0, 20),
+	MDP_COLOR_BAYER12_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0, 12, 2,  0, 20),
+	MDP_COLOR_BAYER12_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1, 12, 2,  0, 20),
+	MDP_COLOR_BAYER12	= MDP_COLOR_BAYER12_BGGR,
+
+	//MDP_COLOR_BAYER14,
+	MDP_COLOR_BAYER14_RGGB	= MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2,  0, 20),
+	MDP_COLOR_BAYER14_GRBG	= MDP_COLOR(0, 0, 0, 1, 0, 1, 14, 2,  0, 20),
+	MDP_COLOR_BAYER14_GBRG	= MDP_COLOR(0, 0, 0, 1, 1, 0, 14, 2,  0, 20),
+	MDP_COLOR_BAYER14_BGGR	= MDP_COLOR(0, 0, 0, 1, 1, 1, 14, 2,  0, 20),
+	MDP_COLOR_BAYER14	= MDP_COLOR_BAYER14_BGGR,
+
+	MDP_COLOR_RGB48		= MDP_COLOR(0, 0, 0, 1, 0, 0, 48, 0,  0, 23),
+	/* For bayer+mono raw-16 */
+	MDP_COLOR_RGB565_RAW	= MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 2,  0, 0),
+
+	MDP_COLOR_BAYER8_UNPAK	= MDP_COLOR(0, 0, 0, 1, 0, 0,  8, 2,  0, 22),
+	MDP_COLOR_BAYER10_UNPAK	= MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2,  0, 22),
+	MDP_COLOR_BAYER12_UNPAK	= MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2,  0, 22),
+	MDP_COLOR_BAYER14_UNPAK	= MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2,  0, 22),
+
+	/* Unified formats */
+	MDP_COLOR_GREY		= MDP_COLOR(0, 0, 0, 1, 0, 0,  8, 1,  0, 7),
+
+	MDP_COLOR_RGB565	= MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 0,  0, 0),
+	MDP_COLOR_BGR565	= MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 0,  1, 0),
+	MDP_COLOR_RGB888	= MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 0,  1, 1),
+	MDP_COLOR_BGR888	= MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 0,  0, 1),
+	MDP_COLOR_RGBA8888	= MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0,  1, 2),
+	MDP_COLOR_BGRA8888	= MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0,  0, 2),
+	MDP_COLOR_ARGB8888	= MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0,  1, 3),
+	MDP_COLOR_ABGR8888	= MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0,  0, 3),
+
+	MDP_COLOR_UYVY		= MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1,  0, 4),
+	MDP_COLOR_VYUY		= MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1,  1, 4),
+	MDP_COLOR_YUYV		= MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1,  0, 5),
+	MDP_COLOR_YVYU		= MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1,  1, 5),
+
+	MDP_COLOR_I420		= MDP_COLOR(0, 0, 0, 3, 1, 1,  8, 1,  0, 8),
+	MDP_COLOR_YV12		= MDP_COLOR(0, 0, 0, 3, 1, 1,  8, 1,  1, 8),
+	MDP_COLOR_I422		= MDP_COLOR(0, 0, 0, 3, 1, 0,  8, 1,  0, 9),
+	MDP_COLOR_YV16		= MDP_COLOR(0, 0, 0, 3, 1, 0,  8, 1,  1, 9),
+	MDP_COLOR_I444		= MDP_COLOR(0, 0, 0, 3, 0, 0,  8, 1,  0, 10),
+	MDP_COLOR_YV24		= MDP_COLOR(0, 0, 0, 3, 0, 0,  8, 1,  1, 10),
+
+	MDP_COLOR_NV12		= MDP_COLOR(0, 0, 0, 2, 1, 1,  8, 1,  0, 12),
+	MDP_COLOR_NV21		= MDP_COLOR(0, 0, 0, 2, 1, 1,  8, 1,  1, 12),
+	MDP_COLOR_NV16		= MDP_COLOR(0, 0, 0, 2, 1, 0,  8, 1,  0, 13),
+	MDP_COLOR_NV61		= MDP_COLOR(0, 0, 0, 2, 1, 0,  8, 1,  1, 13),
+	MDP_COLOR_NV24		= MDP_COLOR(0, 0, 0, 2, 0, 0,  8, 1,  0, 14),
+	MDP_COLOR_NV42		= MDP_COLOR(0, 0, 0, 2, 0, 0,  8, 1,  1, 14),
+
+	/* Mediatek proprietary formats */
+	/* UFO encoded block mode */
+	MDP_COLOR_420_BLK_UFO	= MDP_COLOR(0, 0, 5, 2, 1, 1, 256, 1, 0, 12),
+	/* Block mode */
+	MDP_COLOR_420_BLK	= MDP_COLOR(0, 0, 1, 2, 1, 1, 256, 1, 0, 12),
+	/* Block mode + field mode */
+	MDP_COLOR_420_BLKI	= MDP_COLOR(0, 0, 3, 2, 1, 1, 256, 1, 0, 12),
+	/* Block mode */
+	MDP_COLOR_422_BLK	= MDP_COLOR(0, 0, 1, 1, 1, 0, 512, 1, 0, 4),
+
+	MDP_COLOR_IYU2		= MDP_COLOR(0, 0, 0, 1, 0, 0, 24,  1, 0, 25),
+	MDP_COLOR_YUV444	= MDP_COLOR(0, 0, 0, 1, 0, 0, 24,  1, 0, 30),
+
+	/* Packed 10-bit formats */
+	MDP_COLOR_RGBA1010102	= MDP_COLOR(1, 0, 0, 1, 0, 0, 32,  0, 1, 2),
+	MDP_COLOR_BGRA1010102	= MDP_COLOR(1, 0, 0, 1, 0, 0, 32,  0, 0, 2),
+	/* Packed 10-bit UYVY */
+	MDP_COLOR_UYVY_10P	= MDP_COLOR(1, 0, 0, 1, 1, 0, 20,  1, 0, 4),
+	/* Packed 10-bit NV21 */
+	MDP_COLOR_NV21_10P	= MDP_COLOR(1, 0, 0, 2, 1, 1, 10,  1, 1, 12),
+	/* 10-bit block mode */
+	MDP_COLOR_420_BLK_10_H	= MDP_COLOR(1, 0, 1, 2, 1, 1, 320, 1, 0, 12),
+	/* 10-bit HEVC tile mode */
+	MDP_COLOR_420_BLK_10_V	= MDP_COLOR(1, 1, 1, 2, 1, 1, 320, 1, 0, 12),
+	/* UFO encoded 10-bit block mode */
+	MDP_COLOR_420_BLK_U10_H	= MDP_COLOR(1, 0, 5, 2, 1, 1, 320, 1, 0, 12),
+	/* UFO encoded 10-bit HEVC tile mode */
+	MDP_COLOR_420_BLK_U10_V	= MDP_COLOR(1, 1, 5, 2, 1, 1, 320, 1, 0, 12),
+
+	/* Loose 10-bit formats */
+	MDP_COLOR_UYVY_10L	= MDP_COLOR(0, 1, 0, 1, 1, 0, 20,  1, 0, 4),
+	MDP_COLOR_VYUY_10L	= MDP_COLOR(0, 1, 0, 1, 1, 0, 20,  1, 1, 4),
+	MDP_COLOR_YUYV_10L	= MDP_COLOR(0, 1, 0, 1, 1, 0, 20,  1, 0, 5),
+	MDP_COLOR_YVYU_10L	= MDP_COLOR(0, 1, 0, 1, 1, 0, 20,  1, 1, 5),
+	MDP_COLOR_NV12_10L	= MDP_COLOR(0, 1, 0, 2, 1, 1, 10,  1, 0, 12),
+	MDP_COLOR_NV21_10L	= MDP_COLOR(0, 1, 0, 2, 1, 1, 10,  1, 1, 12),
+	MDP_COLOR_NV16_10L	= MDP_COLOR(0, 1, 0, 2, 1, 0, 10,  1, 0, 13),
+	MDP_COLOR_NV61_10L	= MDP_COLOR(0, 1, 0, 2, 1, 0, 10,  1, 1, 13),
+	MDP_COLOR_YV12_10L	= MDP_COLOR(0, 1, 0, 3, 1, 1, 10,  1, 1, 8),
+	MDP_COLOR_I420_10L	= MDP_COLOR(0, 1, 0, 3, 1, 1, 10,  1, 0, 8),
+};
+
+/* Minimum Y stride that is accepted by MDP HW */
+static inline u32 mdp_color_get_min_y_stride(enum mdp_color c, u32 width)
+{
+	return ((MDP_COLOR_BITS_PER_PIXEL(c) * width) + 4) >> 3;
+}
+
+/* Minimum UV stride that is accepted by MDP HW */
+static inline u32 mdp_color_get_min_uv_stride(enum mdp_color c, u32 width)
+{
+	u32 min_stride;
+
+	if (MDP_COLOR_GET_PLANE_COUNT(c) == 1)
+		return 0;
+	min_stride = mdp_color_get_min_y_stride(c, width)
+		>> MDP_COLOR_GET_H_SUBSAMPLE(c);
+	if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c))
+		min_stride = min_stride * 2;
+	return min_stride;
+}
+
+/* Minimum Y plane size that is necessary in buffer */
+static inline u32 mdp_color_get_min_y_size(enum mdp_color c,
+					   u32 width, u32 height)
+{
+	if (MDP_COLOR_IS_BLOCK_MODE(c))
+		return ((MDP_COLOR_BITS_PER_PIXEL(c) * width) >> 8) * height;
+	return mdp_color_get_min_y_stride(c, width) * height;
+}
+
+/* Minimum UV plane size that is necessary in buffer */
+static inline u32 mdp_color_get_min_uv_size(enum mdp_color c,
+					    u32 width, u32 height)
+{
+	height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c);
+	if (MDP_COLOR_IS_BLOCK_MODE(c) && (MDP_COLOR_GET_PLANE_COUNT(c) > 1))
+		return ((MDP_COLOR_BITS_PER_PIXEL(c) * width) >> 8) * height;
+	return mdp_color_get_min_uv_stride(c, width) * height;
+}
+
+/* Combine colorspace, xfer_func, ycbcr_encoding, and quantization */
+enum mdp_ycbcr_profile {
+	/* V4L2_YCBCR_ENC_601 and V4L2_QUANTIZATION_LIM_RANGE */
+	MDP_YCBCR_PROFILE_BT601,
+	/* V4L2_YCBCR_ENC_709 and V4L2_QUANTIZATION_LIM_RANGE */
+	MDP_YCBCR_PROFILE_BT709,
+	/* V4L2_YCBCR_ENC_601 and V4L2_QUANTIZATION_FULL_RANGE */
+	MDP_YCBCR_PROFILE_JPEG,
+	MDP_YCBCR_PROFILE_FULL_BT601 = MDP_YCBCR_PROFILE_JPEG,
+
+	/* Colorspaces not support for capture */
+	/* V4L2_YCBCR_ENC_BT2020 and V4L2_QUANTIZATION_LIM_RANGE */
+	MDP_YCBCR_PROFILE_BT2020,
+	/* V4L2_YCBCR_ENC_709 and V4L2_QUANTIZATION_FULL_RANGE */
+	MDP_YCBCR_PROFILE_FULL_BT709,
+	/* V4L2_YCBCR_ENC_BT2020 and V4L2_QUANTIZATION_FULL_RANGE */
+	MDP_YCBCR_PROFILE_FULL_BT2020,
+};
+
+#define MDP_FMT_FLAG_OUTPUT	BIT(0)
+#define MDP_FMT_FLAG_CAPTURE	BIT(1)
+
+struct mdp_format {
+	u32	pixelformat;
+	u32	mdp_color;
+	u8	depth[VIDEO_MAX_PLANES];
+	u8	row_depth[VIDEO_MAX_PLANES];
+	u8	num_planes;
+	u8	walign;
+	u8	halign;
+	u8	salign;
+	u32	flags;
+};
+
+struct mdp_pix_limit {
+	u32	wmin;
+	u32	hmin;
+	u32	wmax;
+	u32	hmax;
+};
+
+struct mdp_limit {
+	struct mdp_pix_limit	out_limit;
+	struct mdp_pix_limit	cap_limit;
+	u32			h_scale_up_max;
+	u32			v_scale_up_max;
+	u32			h_scale_down_max;
+	u32			v_scale_down_max;
+};
+
+enum mdp_stream_type {
+	MDP_STREAM_TYPE_UNKNOWN,
+	MDP_STREAM_TYPE_BITBLT,
+	MDP_STREAM_TYPE_GPU_BITBLT,
+	MDP_STREAM_TYPE_DUAL_BITBLT,
+	MDP_STREAM_TYPE_2ND_BITBLT,
+	MDP_STREAM_TYPE_ISP_IC,
+	MDP_STREAM_TYPE_ISP_VR,
+	MDP_STREAM_TYPE_ISP_ZSD,
+	MDP_STREAM_TYPE_ISP_IP,
+	MDP_STREAM_TYPE_ISP_VSS,
+	MDP_STREAM_TYPE_ISP_ZSD_SLOW,
+	MDP_STREAM_TYPE_WPE,
+	MDP_STREAM_TYPE_WPE2,
+};
+
+struct mdp_crop {
+	struct v4l2_rect	c;
+	struct v4l2_fract	left_subpix;
+	struct v4l2_fract	top_subpix;
+	struct v4l2_fract	width_subpix;
+	struct v4l2_fract	height_subpix;
+};
+
+struct mdp_frame {
+	struct v4l2_format	format;
+	const struct mdp_format	*mdp_fmt;
+	u32			ycbcr_prof;	/* enum mdp_ycbcr_profile */
+	u32			usage;		/* enum mdp_buffer_usage */
+	struct mdp_crop		crop;
+	struct v4l2_rect	compose;
+	s32			rotation;
+	u32			hflip:1;
+	u32			vflip:1;
+	u32			hdr:1;
+	u32			dre:1;
+	u32			sharpness:1;
+	u32			dither:1;
+};
+
+static inline bool mdp_target_is_crop(u32 target)
+{
+	return (target == V4L2_SEL_TGT_CROP) ||
+		(target == V4L2_SEL_TGT_CROP_DEFAULT) ||
+		(target == V4L2_SEL_TGT_CROP_BOUNDS);
+}
+
+static inline bool mdp_target_is_compose(u32 target)
+{
+	return (target == V4L2_SEL_TGT_COMPOSE) ||
+		(target == V4L2_SEL_TGT_COMPOSE_DEFAULT) ||
+		(target == V4L2_SEL_TGT_COMPOSE_BOUNDS);
+}
+
+#define MDP_MAX_CAPTURES	IMG_MAX_HW_OUTPUTS
+
+#define MDP_VPU_INIT		BIT(0)
+#define MDP_M2M_CTX_ERROR	BIT(1)
+
+struct mdp_frameparam {
+	struct list_head	list;
+	/* synchronization protect for m2m context state */
+	struct mutex		state_lock;
+	u32			state;
+	const struct mdp_limit	*limit;
+	u32			type;	/* enum mdp_stream_type */
+	u32			frame_no;
+	struct mdp_frame	output;
+	struct mdp_frame	captures[MDP_MAX_CAPTURES];
+	u32			num_captures;
+	enum v4l2_colorspace		colorspace;
+	enum v4l2_ycbcr_encoding	ycbcr_enc;
+	enum v4l2_xfer_func		xfer_func;
+	enum v4l2_quantization		quant;
+};
+
+int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f);
+const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
+					    struct mdp_frameparam *param,
+					    u32 ctx_id);
+enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f,
+						 u32 mdp_color);
+int mdp_try_crop(struct v4l2_rect *r, const struct v4l2_selection *s,
+		 struct mdp_frame *frame, u32 ctx_id);
+int mdp_check_scaling_ratio(const struct v4l2_rect *crop,
+			    const struct v4l2_rect *compose, s32 rotation,
+	const struct mdp_limit *limit);
+void mdp_set_src_config(struct img_input *in,
+			struct mdp_frame *frame, struct vb2_buffer *vb);
+void mdp_set_dst_config(struct img_output *out,
+			struct mdp_frame *frame, struct vb2_buffer *vb);
+
+int mdp_frameparam_init(struct mdp_frameparam *param);
+
+#endif  /* __MTK_MDP3_REGS_H__ */
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.c
new file mode 100644
index 000000000000..a1b2065aabbd
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/mtk_scp.h>
+#include "mtk-mdp3-vpu.h"
+#include "mtk-mdp3-core.h"
+
+#define MDP_VPU_MESSAGE_TIMEOUT 500U
+#define vpu_alloc_size		0x600000
+
+static inline struct mdp_dev *vpu_to_mdp(struct mdp_vpu_dev *vpu)
+{
+	return container_of(vpu, struct mdp_dev, vpu);
+}
+
+static int mdp_vpu_shared_mem_alloc(struct mdp_vpu_dev *vpu)
+{
+	if (vpu->work && vpu->work_addr)
+		return 0;
+
+	vpu->work = dma_alloc_coherent(scp_get_device(vpu->scp), vpu_alloc_size,
+				       &vpu->work_addr, GFP_KERNEL);
+
+	if (!vpu->work)
+		return -ENOMEM;
+	else
+		return 0;
+}
+
+void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu)
+{
+	if (vpu->work && vpu->work_addr)
+		dma_free_coherent(scp_get_device(vpu->scp), vpu_alloc_size,
+				  vpu->work, vpu->work_addr);
+}
+
+static void mdp_vpu_ipi_handle_init_ack(void *data, unsigned int len,
+					void *priv)
+{
+	struct mdp_ipi_init_msg *msg = (struct mdp_ipi_init_msg *)data;
+	struct mdp_vpu_dev *vpu =
+		(struct mdp_vpu_dev *)(unsigned long)msg->drv_data;
+
+	if (!vpu->work_size)
+		vpu->work_size = msg->work_size;
+
+	vpu->status = msg->status;
+	complete(&vpu->ipi_acked);
+}
+
+static void mdp_vpu_ipi_handle_deinit_ack(void *data, unsigned int len,
+					  void *priv)
+{
+	struct mdp_ipi_deinit_msg *msg = (struct mdp_ipi_deinit_msg *)data;
+	struct mdp_vpu_dev *vpu =
+		(struct mdp_vpu_dev *)(unsigned long)msg->drv_data;
+
+	vpu->status = msg->status;
+	complete(&vpu->ipi_acked);
+}
+
+static void mdp_vpu_ipi_handle_frame_ack(void *data, unsigned int len,
+					 void *priv)
+{
+	struct img_sw_addr *addr = (struct img_sw_addr *)data;
+	struct img_ipi_frameparam *param =
+		(struct img_ipi_frameparam *)(unsigned long)addr->va;
+	struct mdp_vpu_ctx *ctx =
+		(struct mdp_vpu_ctx *)(unsigned long)param->drv_data;
+
+	if (param->state) {
+		struct mdp_dev *mdp = vpu_to_mdp(ctx->vpu_dev);
+
+		dev_info(&mdp->pdev->dev, "VPU MDP failure:%d\n", param->state);
+	}
+	complete(&ctx->vpu_dev->ipi_acked);
+}
+
+int mdp_vpu_register(struct mdp_dev *mdp)
+{
+	int err;
+	struct mtk_scp *scp = mdp->scp;
+	struct device *dev = &mdp->pdev->dev;
+
+	err = scp_ipi_register(scp, SCP_IPI_MDP_INIT,
+			       mdp_vpu_ipi_handle_init_ack, NULL);
+	if (err) {
+		dev_err(dev, "scp_ipi_register failed %d\n", err);
+		goto err_ipi_init;
+	}
+	err = scp_ipi_register(scp, SCP_IPI_MDP_DEINIT,
+			       mdp_vpu_ipi_handle_deinit_ack, NULL);
+	if (err) {
+		dev_err(dev, "scp_ipi_register failed %d\n", err);
+		goto err_ipi_deinit;
+	}
+	err = scp_ipi_register(scp, SCP_IPI_MDP_FRAME,
+			       mdp_vpu_ipi_handle_frame_ack, NULL);
+	if (err) {
+		dev_err(dev, "scp_ipi_register failed %d\n", err);
+		goto err_ipi_frame;
+	}
+	return 0;
+
+err_ipi_frame:
+	scp_ipi_unregister(scp, SCP_IPI_MDP_DEINIT);
+err_ipi_deinit:
+	scp_ipi_unregister(scp, SCP_IPI_MDP_INIT);
+err_ipi_init:
+
+	return err;
+}
+
+void mdp_vpu_unregister(struct mdp_dev *mdp)
+{
+	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_INIT);
+	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_DEINIT);
+	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_FRAME);
+}
+
+static int mdp_vpu_sendmsg(struct mdp_vpu_dev *vpu, enum scp_ipi_id id,
+			   void *buf, unsigned int len)
+{
+	struct mdp_dev *mdp = vpu_to_mdp(vpu);
+	int ret;
+
+	if (!vpu->scp) {
+		dev_dbg(&mdp->pdev->dev, "vpu scp is NULL");
+		return -EINVAL;
+	}
+	ret = scp_ipi_send(vpu->scp, id, buf, len, 2000);
+
+	if (ret) {
+		dev_err(&mdp->pdev->dev, "scp_ipi_send failed %d\n", ret);
+		return -EPERM;
+	}
+	ret = wait_for_completion_timeout(
+		&vpu->ipi_acked, msecs_to_jiffies(MDP_VPU_MESSAGE_TIMEOUT));
+	if (!ret)
+		ret = -ETIME;
+	else if (vpu->status)
+		ret = -EINVAL;
+	else
+		ret = 0;
+	return ret;
+}
+
+int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp,
+		     struct mutex *lock)
+{
+	struct mdp_ipi_init_msg msg = {
+		.drv_data = (unsigned long)vpu,
+	};
+	size_t mem_size;
+	phys_addr_t pool;
+	const size_t pool_size = sizeof(struct mdp_config_pool);
+	struct mdp_dev *mdp = vpu_to_mdp(vpu);
+	int err;
+
+	init_completion(&vpu->ipi_acked);
+	vpu->scp = scp;
+	vpu->lock = lock;
+	vpu->work_size = 0;
+	err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg));
+	if (err)
+		goto err_work_size;
+	/* vpu work_size was set in mdp_vpu_ipi_handle_init_ack */
+
+	mem_size = vpu_alloc_size;
+	if (mdp_vpu_shared_mem_alloc(vpu)) {
+		dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
+		goto err_mem_alloc;
+	}
+
+	pool = ALIGN((phys_addr_t)vpu->work + vpu->work_size, 8);
+	if (pool + pool_size - (phys_addr_t)vpu->work > mem_size) {
+		dev_err(&mdp->pdev->dev,
+			"VPU memory insufficient: %zx + %zx > %zx",
+			vpu->work_size, pool_size, mem_size);
+		err = -ENOMEM;
+		goto err_mem_size;
+	}
+
+	dev_dbg(&mdp->pdev->dev,
+		"VPU work:%pK pa:%pad sz:%zx pool:%pa sz:%zx (mem sz:%zx)",
+		vpu->work, &vpu->work_addr, vpu->work_size,
+		&pool, pool_size, mem_size);
+	vpu->pool = (struct mdp_config_pool *)pool;
+	msg.work_addr = vpu->work_addr;
+	msg.work_size = vpu->work_size;
+	err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg));
+	if (err)
+		goto err_work_size;
+
+	memset(vpu->pool, 0, sizeof(*vpu->pool));
+	return 0;
+
+err_work_size:
+	switch (vpu->status) {
+	case -MDP_IPI_EBUSY:
+		err = -EBUSY;
+		break;
+	case -MDP_IPI_ENOMEM:
+		err = -ENOSPC;	/* -ENOMEM */
+		break;
+	}
+	return err;
+err_mem_size:
+err_mem_alloc:
+	return err;
+}
+
+int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu)
+{
+	struct mdp_ipi_deinit_msg msg = {
+		.drv_data = (unsigned long)vpu,
+		.work_addr = vpu->work_addr,
+	};
+
+	return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_DEINIT, &msg, sizeof(msg));
+}
+
+static struct img_config *mdp_config_get(struct mdp_vpu_dev *vpu,
+					 enum mdp_config_id id, uint32_t *addr)
+{
+	struct img_config *config;
+
+	if (id < 0 || id >= MDP_CONFIG_POOL_SIZE)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(vpu->lock);
+	vpu->pool->cfg_count[id]++;
+	config = &vpu->pool->configs[id];
+	*addr = vpu->work_addr +
+		((unsigned long)config - (phys_addr_t)vpu->work);
+	mutex_unlock(vpu->lock);
+
+	return config;
+}
+
+static int mdp_config_put(struct mdp_vpu_dev *vpu,
+			  enum mdp_config_id id,
+			  const struct img_config *config)
+{
+	int err = 0;
+
+	if (id < 0 || id >= MDP_CONFIG_POOL_SIZE)
+		return -EINVAL;
+	if (vpu->lock)
+		mutex_lock(vpu->lock);
+	if (!vpu->pool->cfg_count[id] || config != &vpu->pool->configs[id])
+		err = -EINVAL;
+	else
+		vpu->pool->cfg_count[id]--;
+	if (vpu->lock)
+		mutex_unlock(vpu->lock);
+	return err;
+}
+
+int mdp_vpu_ctx_init(struct mdp_vpu_ctx *ctx, struct mdp_vpu_dev *vpu,
+		     enum mdp_config_id id)
+{
+	ctx->config = mdp_config_get(vpu, id, &ctx->inst_addr);
+	if (IS_ERR(ctx->config)) {
+		int err = PTR_ERR(ctx->config);
+
+		ctx->config = NULL;
+		return err;
+	}
+	ctx->config_id = id;
+	ctx->vpu_dev = vpu;
+	return 0;
+}
+
+int mdp_vpu_ctx_deinit(struct mdp_vpu_ctx *ctx)
+{
+	int err = mdp_config_put(ctx->vpu_dev, ctx->config_id, ctx->config);
+
+	ctx->config_id = 0;
+	ctx->config = NULL;
+	ctx->inst_addr = 0;
+	return err;
+}
+
+int mdp_vpu_process(struct mdp_vpu_ctx *ctx, struct img_ipi_frameparam *param)
+{
+	struct mdp_vpu_dev *vpu = ctx->vpu_dev;
+	struct mdp_dev *mdp = vpu_to_mdp(vpu);
+	struct img_sw_addr addr;
+
+	if (!ctx->vpu_dev->work || !ctx->vpu_dev->work_addr) {
+		if (mdp_vpu_shared_mem_alloc(vpu)) {
+			dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
+			return -ENOMEM;
+		}
+	}
+	memset((void *)ctx->vpu_dev->work, 0, ctx->vpu_dev->work_size);
+	memset(ctx->config, 0, sizeof(*ctx->config));
+	param->config_data.va = (unsigned long)ctx->config;
+	param->config_data.pa = ctx->inst_addr;
+	param->drv_data = (unsigned long)ctx;
+
+	memcpy((void *)ctx->vpu_dev->work, param, sizeof(*param));
+	addr.pa = ctx->vpu_dev->work_addr;
+	addr.va = (phys_addr_t)ctx->vpu_dev->work;
+	return mdp_vpu_sendmsg(ctx->vpu_dev, SCP_IPI_MDP_FRAME,
+		&addr, sizeof(addr));
+}
+
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.h
new file mode 100644
index 000000000000..4be8f861a93e
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
+ */
+
+#ifndef __MTK_MDP3_VPU_H__
+#define __MTK_MDP3_VPU_H__
+
+#include <linux/platform_device.h>
+#include "mtk-img-ipi.h"
+
+enum mdp_ipi_result {
+	MDP_IPI_SUCCESS	= 0,
+	MDP_IPI_ENOMEM	= 12,
+	MDP_IPI_EBUSY	= 16,
+	MDP_IPI_EINVAL	= 22,
+	MDP_IPI_EMINST	= 24,
+	MDP_IPI_ERANGE	= 34,
+	MDP_IPI_NR_ERRNO,
+
+	MDP_IPI_EOTHER	= MDP_IPI_NR_ERRNO,
+	MDP_IPI_PATH_CANT_MERGE,
+	MDP_IPI_OP_FAIL,
+};
+
+struct mdp_ipi_init_msg {
+	u32	status;
+	u64	drv_data;
+	u32	work_addr;	/* [in] working buffer address */
+	u32	work_size;	/* [in] working buffer size */
+} __attribute__ ((__packed__));
+
+struct mdp_ipi_deinit_msg {
+	u32	status;
+	u64	drv_data;
+	u32	work_addr;
+} __attribute__ ((__packed__));
+
+enum mdp_config_id {
+	MDP_DEV_M2M = 0,
+	MDP_CONFIG_POOL_SIZE	/* ALWAYS keep at the end */
+};
+
+struct mdp_config_pool {
+	u64			cfg_count[MDP_CONFIG_POOL_SIZE];
+	struct img_config	configs[MDP_CONFIG_POOL_SIZE];
+};
+
+struct mdp_vpu_dev {
+	/* synchronization protect for accessing vpu working buffer info */
+	struct mutex		*lock;
+	struct mtk_scp		*scp;
+	struct completion	ipi_acked;
+	void			*work;
+	dma_addr_t		work_addr;
+	size_t			work_size;
+	struct mdp_config_pool	*pool;
+	u32			status;
+};
+
+struct mdp_vpu_ctx {
+	struct mdp_vpu_dev	*vpu_dev;
+	u32			config_id;
+	struct img_config	*config;
+	u32			inst_addr;
+};
+
+void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu);
+int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp,
+		     struct mutex *lock);
+int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu);
+int mdp_vpu_ctx_init(struct mdp_vpu_ctx *ctx, struct mdp_vpu_dev *vpu,
+		     enum mdp_config_id id);
+int mdp_vpu_ctx_deinit(struct mdp_vpu_ctx *ctx);
+int mdp_vpu_process(struct mdp_vpu_ctx *vpu, struct img_ipi_frameparam *param);
+
+#endif  /* __MTK_MDP3_VPU_H__ */
+
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 02/10] media: mtk-mdp3: fix redundant process done caused KE
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 03/10] media: mtk-mdp3: revise suspend strategy Moudy Ho
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

From: daoyuan huang <daoyuan.huang@mediatek.com>

In mdp_m2m_worker, there is m2m process done in error handle,
so add statement in mdp_cmdq_send for preventing redundant
process done in cmdq_pkt_flush return fail case.

Signed-off-by: daoyuan huang <daoyuan.huang@mediatek.com>
---
 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
index ee81a3387cf9..f8bf8fde599c 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -454,8 +454,10 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 			mdp_dump_info(~0, 1);
 		}
 #endif
-		if (param->mdp_ctx)
-			mdp_m2m_job_finish(param->mdp_ctx);
+		if (!ret) { /* error handle in mdp_m2m_worker */
+			if (param->mdp_ctx)
+				mdp_m2m_job_finish(param->mdp_ctx);
+		}
 		cmdq_pkt_destroy(cmd.pkt);
 		for (i = 0; i < param->config->num_components; i++)
 			mdp_comp_clock_off(&mdp->pdev->dev, path.comps[i].comp);
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 03/10] media: mtk-mdp3: revise suspend strategy
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 02/10] media: mtk-mdp3: fix redundant process done caused KE Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 04/10] media: mtk-mdp3: add error handling in error return Moudy Ho
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

From: daoyuan huang <daoyuan.huang@mediatek.com>

1.The wait queue check for incomplete running task
  should be put in mdp_suspend instead of mdp_pm_suspend;
  Due to mdp_suspend could be called while task is running;
  Add error return value in suspend fail situation.
2.modify dma modules' power control from larb device to modules'
  device self;
  For support real mdp_pm_suspend callback.

Signed-off-by: daoyuan huang <daoyuan.huang@mediatek.com>
---
 .../media/platform/mtk-mdp3/mtk-mdp3-comp.c   | 36 ++++++++-----------
 .../media/platform/mtk-mdp3/mtk-mdp3-comp.h   |  2 +-
 .../media/platform/mtk-mdp3/mtk-mdp3-core.c   | 34 +++++-------------
 3 files changed, 23 insertions(+), 49 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
index 3033cd32340c..23dd413f3423 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
@@ -1039,8 +1039,8 @@ void mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
 {
 	int i, err;
 
-	if (comp->larb_dev) {
-		err = pm_runtime_get_sync(comp->larb_dev);
+	if (comp->comp_dev) {
+		err = pm_runtime_get_sync(comp->comp_dev);
 		if (err < 0)
 			dev_err(dev,
 				"Failed to get larb, err %d. type:%d id:%d\n",
@@ -1068,8 +1068,8 @@ void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
 		clk_disable_unprepare(comp->clks[i]);
 	}
 
-	if (comp->larb_dev)
-		pm_runtime_put(comp->larb_dev);
+	if (comp->comp_dev)
+		pm_runtime_put(comp->comp_dev);
 }
 
 static int mdp_get_subsys_id(struct device *dev, struct device_node *node,
@@ -1153,8 +1153,7 @@ static int mdp_comp_init(struct device *dev, struct mdp_dev *mdp,
 			 struct device_node *node, struct mdp_comp *comp,
 			 enum mdp_comp_id id)
 {
-	struct device_node *larb_node;
-	struct platform_device *larb_pdev;
+	struct platform_device *pdev;
 	int i;
 
 	if (id < 0 || id >= MDP_MAX_COMP_COUNT) {
@@ -1176,29 +1175,22 @@ static int mdp_comp_init(struct device *dev, struct mdp_dev *mdp,
 
 	mdp_get_subsys_id(dev, node, comp);
 
-	/* Only DMA capable components need the LARB property */
-	comp->larb_dev = NULL;
+	/* Only DMA capable components need the pm control */
+	comp->comp_dev = NULL;
 	if (comp->type != MDP_COMP_TYPE_RDMA &&
 	    comp->type != MDP_COMP_TYPE_WROT &&
 		comp->type != MDP_COMP_TYPE_WDMA)
 		return 0;
 
-	larb_node = of_parse_phandle(node, "mediatek,larb", 0);
-	if (!larb_node) {
-		dev_err(dev, "Missing mediatek,larb phandle in %pOF node\n",
-			node);
-		return -EINVAL;
-	}
-
-	larb_pdev = of_find_device_by_node(larb_node);
-	if (!larb_pdev) {
-		dev_warn(dev, "Waiting for larb device %pOF\n", larb_node);
-		of_node_put(larb_node);
-		return -EPROBE_DEFER;
+	pdev = of_find_device_by_node(node);
+	if (!pdev) {
+		dev_warn(dev, "can't find platform device of node:%s\n",
+			 node->name);
+		return -ENODEV;
 	}
-	of_node_put(larb_node);
 
-	comp->larb_dev = &larb_pdev->dev;
+	comp->comp_dev = &pdev->dev;
+	pm_runtime_enable(comp->comp_dev);
 
 	return 0;
 }
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
index 77d2c3e989c4..27d58dc51dce 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
@@ -113,7 +113,7 @@ struct mdp_comp {
 	phys_addr_t			reg_base;
 	u8				subsys_id;
 	struct clk			*clks[2];
-	struct device			*larb_dev;
+	struct device			*comp_dev;
 	enum mdp_comp_type		type;
 	enum mdp_comp_id		id;
 	u32				alias_id;
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
index 4a59dec8cfd9..eaf5b07e720f 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
@@ -152,7 +152,6 @@ static int mdp_probe(struct platform_device *pdev)
 #endif
 
 	vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
-	pm_runtime_enable(dev);
 
 	ret = v4l2_device_register(dev, &mdp->v4l2_dev);
 	if (ret) {
@@ -212,7 +211,7 @@ static int mdp_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static int __maybe_unused mdp_pm_suspend(struct device *dev)
+static int __maybe_unused mdp_suspend(struct device *dev)
 {
 	struct mdp_dev *mdp = dev_get_drvdata(dev);
 	int ret;
@@ -222,19 +221,19 @@ static int __maybe_unused mdp_pm_suspend(struct device *dev)
 	if (atomic_read(&mdp->job_count)) {
 		ret = wait_event_timeout(mdp->callback_wq,
 					 !atomic_read(&mdp->job_count),
-					 HZ);
-		if (ret == 0)
+					 2 * HZ);
+		if (ret == 0) {
 			dev_err(dev,
-				"%s:flushed cmdq task incomplete\n",
-				__func__);
-		else//need to remove
-			pr_err("%s:ret=%d\n", __func__, ret);
+				"%s:flushed cmdq task incomplete, count=%d\n",
+				__func__, atomic_read(&mdp->job_count));
+			return -EBUSY;
+		}
 	}
 
 	return 0;
 }
 
-static int __maybe_unused mdp_pm_resume(struct device *dev)
+static int __maybe_unused mdp_resume(struct device *dev)
 {
 	struct mdp_dev *mdp = dev_get_drvdata(dev);
 
@@ -243,25 +242,8 @@ static int __maybe_unused mdp_pm_resume(struct device *dev)
 	return 0;
 }
 
-static int __maybe_unused mdp_suspend(struct device *dev)
-{
-	if (pm_runtime_suspended(dev))
-		return 0;
-
-	return mdp_pm_suspend(dev);
-}
-
-static int __maybe_unused mdp_resume(struct device *dev)
-{
-	if (pm_runtime_suspended(dev))
-		return 0;
-
-	return mdp_pm_resume(dev);
-}
-
 static const struct dev_pm_ops mdp_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume)
-	SET_RUNTIME_PM_OPS(mdp_pm_suspend, mdp_pm_resume, NULL)
 };
 
 static struct platform_driver mdp_driver = {
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 04/10] media: mtk-mdp3: add error handling in error return
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 02/10] media: mtk-mdp3: fix redundant process done caused KE Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 03/10] media: mtk-mdp3: revise suspend strategy Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 05/10] media: mtk-mdp3: remove unnecessary Null check Moudy Ho
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

From: daoyuan huang <daoyuan.huang@mediatek.com>

add error handling in missed places.

Signed-off-by: daoyuan huang <daoyuan.huang@mediatek.com>
---
 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c | 14 +++++++++++++-
 drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c | 16 ++++++++++++++++
 drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h |  2 ++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
index f8bf8fde599c..42a51061677a 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -398,7 +398,17 @@ static void mdp_handle_cmdq_callback(struct cmdq_cb_data data)
 
 	cmdq_pkt_destroy(cb_param->pkt);
 	INIT_WORK(&cb_param->auto_release_work, mdp_auto_release_work);
-	queue_work(mdp->clock_wq, &cb_param->auto_release_work);
+	if (!queue_work(mdp->clock_wq, &cb_param->auto_release_work)) {
+		mdp_err("%s:queue_work fail!\n", __func__);
+		mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
+				    cb_param->num_comps);
+
+		kfree(cb_param->comps);
+		kfree(cb_param);
+
+		atomic_dec(&mdp->job_count);
+		wake_up(&mdp->callback_wq);
+	}
 }
 
 int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
@@ -495,6 +505,8 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 					   (void *)cb_param);
 		if (ret) {
 			mdp_err("%s:cmdq_pkt_flush_async fail!\n", __func__);
+			mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
+					    cb_param->num_comps);
 			kfree(cb_param);
 			kfree(comps);
 		}
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
index 23dd413f3423..157ef9408ed3 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
@@ -1072,6 +1072,22 @@ void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp)
 		pm_runtime_put(comp->comp_dev);
 }
 
+void mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++)
+		mdp_comp_clock_on(dev, &comps[i]);
+}
+
+void mdp_comp_clocks_off(struct device *dev, struct mdp_comp *comps, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++)
+		mdp_comp_clock_off(dev, &comps[i]);
+}
+
 static int mdp_get_subsys_id(struct device *dev, struct device_node *node,
 			     struct mdp_comp *comp)
 {
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
index 27d58dc51dce..f201bced3c06 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
@@ -147,6 +147,8 @@ int mdp_component_init(struct mdp_dev *mdp);
 void mdp_component_deinit(struct mdp_dev *mdp);
 void mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp);
 void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp);
+void mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num);
+void mdp_comp_clocks_off(struct device *dev, struct mdp_comp *comps, int num);
 int mdp_comp_ctx_init(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx,
 		      const struct img_compparam *param,
 	const struct img_ipi_frameparam *frame);
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 05/10] media: mtk-mdp3: remove unnecessary Null check
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (2 preceding siblings ...)
  2021-06-23  7:35 ` [RFC PATCH V0 04/10] media: mtk-mdp3: add error handling in error return Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 06/10] media: mtk-mdp3: move clock on to precise place Moudy Ho
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

From: daoyuan huang <daoyuan.huang@mediatek.com>

Remove logically unnecessary NULL check in call back function.

Due to no NULL callback param should occur in normal case;
and if we use NULL check to jump over this clock off step,
the clock ref. count may go asymmetric.

Signed-off-by: daoyuan huang <daoyuan.huang@mediatek.com>
---
 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
index 42a51061677a..df956ca3685c 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -349,13 +349,8 @@ static void mdp_auto_release_work(struct work_struct *work)
 				auto_release_work);
 	mdp = cb_param->mdp;
 
-	if (cb_param->comps && cb_param->num_comps) {
-		int i;
-
-		for (i = 0; i < cb_param->num_comps; i++)
-			mdp_comp_clock_off(&mdp->pdev->dev,
-					   &cb_param->comps[i]);
-	}
+	mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
+			    cb_param->num_comps);
 
 	kfree(cb_param->comps);
 	kfree(cb_param);
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 06/10] media: mtk-mdp3: move clock on to precise place
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (3 preceding siblings ...)
  2021-06-23  7:35 ` [RFC PATCH V0 05/10] media: mtk-mdp3: remove unnecessary Null check Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 07/10] media: mtk-mdp3: Fix unpaired settings Moudy Ho
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

From: daoyuan huang <daoyuan.huang@mediatek.com>

Move clock on to the previous line of cmdq_pkt_flush.

Due to there're two ways(sync/async) to submit CMDQ task,
and for async case we need to prepare callback param struct along
with error checks and error handlings before submit,
if we move clock on after these error check steps,
we can save some clock off code in error handling.

Signed-off-by: daoyuan huang <daoyuan.huang@mediatek.com>
---
 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
index df956ca3685c..a1bdf92d45f7 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -445,11 +445,9 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 		return ret;
 	}
 
-	// TODO: engine conflict dispatch
-	for (i = 0; i < param->config->num_components; i++)
-		mdp_comp_clock_on(&mdp->pdev->dev, path.comps[i].comp);
-
 	if (param->wait) {
+		for (i = 0; i < param->config->num_components; i++)
+			mdp_comp_clock_on(&mdp->pdev->dev, path.comps[i].comp);
 		ret = cmdq_pkt_flush(cmd.pkt);
 #ifdef MDP_DEBUG
 		if (ret) {
@@ -495,6 +493,9 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 		cb_param->num_comps = param->config->num_components;
 		cb_param->mdp_ctx = param->mdp_ctx;
 
+		mdp_comp_clocks_on(&mdp->pdev->dev, cb_param->comps,
+				   cb_param->num_comps);
+
 		ret = cmdq_pkt_flush_async(cmd.pkt,
 					   mdp_handle_cmdq_callback,
 					   (void *)cb_param);
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 07/10] media: mtk-mdp3: Fix unpaired settings
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (4 preceding siblings ...)
  2021-06-23  7:35 ` [RFC PATCH V0 06/10] media: mtk-mdp3: move clock on to precise place Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 08/10] media: mtk-mdp3: remove illegal device node usage Moudy Ho
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

Fix unpaired settings about:
1. clk on/off.
2. CMDQ packet kzalloc/kfree.
3. MDP job_count increase/decrease.

Also revise the redundant log.

Signed-off-by: Moudy Ho <moudy.ho@mediatek.com>
---
 .../media/platform/mtk-mdp3/mtk-mdp3-cmdq.c   | 97 ++++++++++++-------
 .../media/platform/mtk-mdp3/mtk-mdp3-core.h   |  4 +-
 .../media/platform/mtk-mdp3/mtk-mdp3-m2m.c    |  2 +-
 3 files changed, 67 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
index a1bdf92d45f7..eac10944283a 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -5,6 +5,7 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include "mtk-mdp3-cmdq.h"
 #include "mtk-mdp3-comp.h"
 #include "mtk-mdp3-core.h"
@@ -230,6 +231,25 @@ static int mdp_path_subfrm_run(const struct mdp_path_subfrm *subfrm,
 	return 0;
 }
 
+static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
+{
+	const struct img_config *config = path->config;
+	int index, ret;
+
+	if (config->num_components < 1)
+	    return -EINVAL;
+
+	for (index = 0; index < config->num_components; index++) {
+		ret = mdp_comp_ctx_init(mdp, &path->comps[index],
+					&config->components[index],
+					path->param);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int mdp_path_config_subfrm(struct mdp_cmd *cmd, struct mdp_path *path,
 				  u32 count)
 {
@@ -297,14 +317,6 @@ static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmd *cmd,
 	struct mdp_comp_ctx *ctx;
 	int index, count, ret;
 
-	for (index = 0; index < config->num_components; index++) {
-		ret = mdp_comp_ctx_init(mdp, &path->comps[index],
-					&config->components[index],
-					path->param);
-		if (ret)
-			return ret;
-	}
-
 	/* Config path frame */
 	/* Reset components */
 	for (index = 0; index < config->num_components; index++) {
@@ -410,6 +422,8 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 {
 	struct mdp_cmd cmd;
 	struct mdp_path path;
+	struct mdp_cmdq_cb_param *cb_param = NULL;
+	struct mdp_comp *comps = NULL;
 	int i, ret;
 
 	if (atomic_read(&mdp->suspended))
@@ -438,16 +452,23 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 		path.composes[i] = param->composes[i] ?
 			param->composes[i] : &path.bounds[i];
 	}
+
+	ret = mdp_path_ctx_init(mdp, &path);
+	if (ret) {
+		pr_info("%s mdp_path_ctx_init error\n", __func__);
+		goto err_destory_pkt;
+	}
+
+	for (i = 0; i < param->config->num_components; i++)
+			mdp_comp_clock_on(&mdp->pdev->dev, path.comps[i].comp);
+
 	ret = mdp_path_config(mdp, &cmd, &path);
 	if (ret) {
-		atomic_dec(&mdp->job_count);
-		wake_up(&mdp->callback_wq);
-		return ret;
+		pr_info("%s mdp_path_config error\n", __func__);
+		goto err_destory_pkt;
 	}
 
 	if (param->wait) {
-		for (i = 0; i < param->config->num_components; i++)
-			mdp_comp_clock_on(&mdp->pdev->dev, path.comps[i].comp);
 		ret = cmdq_pkt_flush(cmd.pkt);
 #ifdef MDP_DEBUG
 		if (ret) {
@@ -461,25 +482,20 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 			if (param->mdp_ctx)
 				mdp_m2m_job_finish(param->mdp_ctx);
 		}
-		cmdq_pkt_destroy(cmd.pkt);
-		for (i = 0; i < param->config->num_components; i++)
-			mdp_comp_clock_off(&mdp->pdev->dev, path.comps[i].comp);
-
-		atomic_dec(&mdp->job_count);
-		wake_up(&mdp->callback_wq);
+		goto err_clock_off;
 	} else {
-		struct mdp_cmdq_cb_param *cb_param;
-		struct mdp_comp *comps;
-
 		cb_param = kzalloc(sizeof(*cb_param), GFP_KERNEL);
-		if (!cb_param)
-			return -ENOMEM;
+		if (!cb_param) {
+			ret = -ENOMEM;
+			goto err_destory_pkt;
+		}
+
 		comps = kcalloc(param->config->num_components, sizeof(*comps),
 				GFP_KERNEL);
 		if (!comps) {
-			kfree(cb_param);
 			mdp_err("%s:comps alloc fail!\n", __func__);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_destory_pkt;
 		}
 
 		for (i = 0; i < param->config->num_components; i++)
@@ -493,20 +509,35 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 		cb_param->num_comps = param->config->num_components;
 		cb_param->mdp_ctx = param->mdp_ctx;
 
-		mdp_comp_clocks_on(&mdp->pdev->dev, cb_param->comps,
-				   cb_param->num_comps);
-
+		cmdq_pkt_finalize(cmd.pkt);
 		ret = cmdq_pkt_flush_async(cmd.pkt,
 					   mdp_handle_cmdq_callback,
 					   (void *)cb_param);
 		if (ret) {
 			mdp_err("%s:cmdq_pkt_flush_async fail!\n", __func__);
-			mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
-					    cb_param->num_comps);
-			kfree(cb_param);
-			kfree(comps);
+			goto err_clock_off;
 		}
 	}
+	return 0;
+
+err_clock_off:
+	if (param->wait) {
+		for (i = 0; i < param->config->num_components; i++)
+			mdp_comp_clock_off(&mdp->pdev->dev, path.comps[i].comp);
+	} else {
+		mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
+					    cb_param->num_comps);
+	}
+err_destory_pkt:
+	cmdq_pkt_destroy(cmd.pkt);
+	atomic_dec(&mdp->job_count);
+	if (param->wait)
+		wake_up(&mdp->callback_wq);
+	if (comps)
+		kfree(comps);
+	if (cb_param)
+		kfree(cb_param);
+
 	return ret;
 }
 
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
index 98cf54b1d92b..19f46da487aa 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
@@ -64,12 +64,12 @@ extern int mtk_mdp_debug;
 #define mdp_dbg(level, fmt, ...)\
 	do {\
 		if (mtk_mdp_debug >= (level))\
-			pr_info("[MTK-MDP3] %d %s:%d: " fmt "\n",\
+			pr_info("[MTK-MDP3] %d %s:%d: " fmt,\
 				level, __func__, __LINE__, ##__VA_ARGS__);\
 	} while (0)
 
 #define mdp_err(fmt, ...)\
-	pr_err("[MTK-MDP3][ERR] %s:%d: " fmt "\n", __func__, __LINE__,\
+	pr_err("[MTK-MDP3][ERR] %s:%d: " fmt, __func__, __LINE__,\
 		##__VA_ARGS__)
 
 #else
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
index 1ae499f6c84b..ff80f01be82f 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
@@ -133,7 +133,7 @@ static void mdp_m2m_worker(struct work_struct *work)
 	task.config = ctx->vpu.config;
 	task.param = &param;
 	task.composes[0] = &frame->compose;
-	task.wait = 1;
+	task.wait = 0;
 	task.cmdq_cb = NULL;
 	task.cb_data = NULL;
 	task.mdp_ctx = ctx;
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 08/10] media: mtk-mdp3: remove illegal device node usage
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (5 preceding siblings ...)
  2021-06-23  7:35 ` [RFC PATCH V0 07/10] media: mtk-mdp3: Fix unpaired settings Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 09/10] media: mtk-mdp3: revise error handling about get/probe MDP3 Moudy Ho
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

This patch is used for review before send upstream patch.
From Rob Herring's review comment: device node can't use same
register address as other nodes'.
Remove illegal device nodes in device tree.
MDP's sub component init need to do corresponding modification.

Signed-off-by: Moudy Ho <moudy.ho@mediatek.com>
---
 .../media/platform/mtk-mdp3/mtk-mdp3-comp.c   | 224 +++++++++++++-----
 .../media/platform/mtk-mdp3/mtk-mdp3-comp.h   |   2 +-
 2 files changed, 163 insertions(+), 63 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
index 157ef9408ed3..e89fd02bb556 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
@@ -1016,23 +1016,15 @@ static const struct of_device_id mdp_comp_dt_ids[] = {
 	{}
 };
 
-static int mdp_comp_get_id(struct device *dev, struct device_node *node,
-			   enum mdp_comp_type type)
+static int mdp_comp_get_id(enum mdp_comp_type type, u32 alias_id)
 {
-	u32 alias_id;
-	int i, ret;
-
-	ret = of_property_read_u32(node, "mediatek,mdp-id", &alias_id);
-	if (ret)
-		return ret;
+	int i;
 
 	for (i = 0; i < ARRAY_SIZE(mdp_comp_matches); i++)
 		if (mdp_comp_matches[i].type == type &&
 		    mdp_comp_matches[i].alias_id == alias_id)
 			return i;
-
-	dev_err(dev, "Failed to get id. type: %d, alias: %d\n", type, alias_id);
-	return -EINVAL;
+	return -ENODEV;
 }
 
 void mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
@@ -1143,33 +1135,10 @@ static void __mdp_comp_init(struct mdp_dev *mdp, struct device_node *node,
 	comp->reg_base = base;
 }
 
-static int mdp_mm_init(struct mdp_dev *mdp,
-		       struct mdp_comp *comp, const char *ref_name)
+static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node,
+			 struct mdp_comp *comp, enum mdp_comp_id id)
 {
-	struct device_node *node;
 	struct device *dev = &mdp->pdev->dev;
-
-	node = of_parse_phandle(dev->of_node, ref_name, 0);
-	if (!node) {
-		dev_err(dev, "Failed to parse dt %s\n", ref_name);
-		return -EINVAL;
-	}
-
-	__mdp_comp_init(mdp, node, comp);
-	mdp_get_subsys_id(dev, node, comp);
-	of_node_put(node);
-	if (!comp->reg_base) {
-		dev_err(dev, "Failed to init %s base\n", ref_name);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int mdp_comp_init(struct device *dev, struct mdp_dev *mdp,
-			 struct device_node *node, struct mdp_comp *comp,
-			 enum mdp_comp_id id)
-{
-	struct platform_device *pdev;
 	int i;
 
 	if (id < 0 || id >= MDP_MAX_COMP_COUNT) {
@@ -1191,32 +1160,140 @@ static int mdp_comp_init(struct device *dev, struct mdp_dev *mdp,
 
 	mdp_get_subsys_id(dev, node, comp);
 
-	/* Only DMA capable components need the pm control */
-	comp->comp_dev = NULL;
-	if (comp->type != MDP_COMP_TYPE_RDMA &&
-	    comp->type != MDP_COMP_TYPE_WROT &&
-		comp->type != MDP_COMP_TYPE_WDMA)
-		return 0;
+	return 0;
+}
 
-	pdev = of_find_device_by_node(node);
-	if (!pdev) {
-		dev_warn(dev, "can't find platform device of node:%s\n",
-			 node->name);
-		return -ENODEV;
+static struct mdp_comp *mdp_comp_create(struct mdp_dev *mdp,
+					struct device_node *node,
+					enum mdp_comp_id id)
+{
+	struct device *dev = &mdp->pdev->dev;
+	struct mdp_comp *comp;
+	int ret;
+
+	if (mdp->comp[id])
+		return ERR_PTR(-EEXIST);
+
+	comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+	if (!comp)
+		return ERR_PTR(-ENOMEM);
+
+	ret = mdp_comp_init(mdp, node, comp, id);
+	if (ret) {
+		kfree(comp);
+		return ERR_PTR(ret);
 	}
+	mdp->comp[id] = comp;
+
+	dev_info(dev, "%s type:%d alias:%d id:%d base:%#x regs:%p\n",
+		dev->of_node->name, comp->type, comp->alias_id, id,
+		(u32)comp->reg_base, comp->regs);
+	return comp;
+}
 
-	comp->comp_dev = &pdev->dev;
-	pm_runtime_enable(comp->comp_dev);
+static int mdp_sub_comps_create(struct mdp_dev *mdp, struct device_node *node)
+{
+	struct device *dev = &mdp->pdev->dev;
+	struct property *prop;
+	const char *name;
+	int index = 0;
+
+	of_property_for_each_string(node, "mdp-comps", prop, name) {
+		const struct of_device_id *matches = mdp_comp_dt_ids;
+		enum mdp_comp_type type = MDP_COMP_NONE;
+		u32 alias_id;
+		int id, ret;
+		struct mdp_comp *comp;
 
+		for (; matches->compatible[0]; matches++) {
+			if (of_compat_cmp(name, matches->compatible,
+				strlen(matches->compatible)) == 0) {
+				type = (enum mdp_comp_type)matches->data;
+				break;
+			}
+		}
+
+		ret = of_property_read_u32_index(node, "mdp-comp-ids",
+			index, &alias_id);
+		if (ret) {
+			dev_warn(dev, "Skipping unknown component %s\n", name);
+			return ret;
+		}
+
+		id = mdp_comp_get_id(type, alias_id);
+		if (id < 0) {
+			dev_err(dev, "Failed to get component id: "
+				"%s type %d, alias %d\n", name, type, alias_id);
+			return -ENODEV;
+		}
+
+		comp = mdp_comp_create(mdp, node, id);
+		if (IS_ERR(comp))
+			return PTR_ERR(comp);
+
+		index++;
+	}
 	return 0;
 }
 
 static void mdp_comp_deinit(struct mdp_comp *comp)
 {
-	iounmap(comp->regs);
+	if (!comp)
+		return;
+
+	if (comp->regs)
+		iounmap(comp->regs);
 	/* of_node_put(comp->dev_node); */
 }
 
+static int mdp_imgi_init(struct mdp_dev *mdp, const char *ref_name)
+{
+	struct device_node *node;
+	struct device *dev = &mdp->pdev->dev;
+	int ret;
+
+	node = of_parse_phandle(dev->of_node, ref_name, 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse dt %s\n", ref_name);
+		return -EINVAL;
+	}
+
+	ret = mdp_sub_comps_create(mdp, node);
+	of_node_put(node);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mdp_mm_init(struct mdp_dev *mdp, struct mdp_comp *comp,
+		       const char *ref_name)
+{
+	struct device_node *node;
+	struct device *dev = &mdp->pdev->dev;
+	int ret;
+
+	node = of_parse_phandle(dev->of_node, ref_name, 0);
+	if (!node) {
+		dev_err(dev, "Failed to parse dt %s\n", ref_name);
+		return -EINVAL;
+	}
+
+	__mdp_comp_init(mdp, node, comp);
+	mdp_get_subsys_id(dev, node, comp);
+	if (!comp->reg_base) {
+		dev_err(dev, "Failed to init %s base\n", ref_name);
+		of_node_put(node);
+		return -EINVAL;
+	}
+
+	ret = mdp_sub_comps_create(mdp, node);
+	of_node_put(node);
+	if (ret)
+		return ret;
+	return 0;
+}
+
 void mdp_component_deinit(struct mdp_dev *mdp)
 {
 	int i;
@@ -1235,6 +1312,8 @@ int mdp_component_init(struct mdp_dev *mdp)
 {
 	struct device *dev = &mdp->pdev->dev;
 	struct device_node *node, *parent;
+	struct platform_device *pdev;
+	u32 alias_id;
 	int i, ret;
 
 	for (i = RDMA0_SOF; i < MDP_MAX_EVENT_COUNT; i++) {
@@ -1260,7 +1339,11 @@ int mdp_component_init(struct mdp_dev *mdp)
 
 	ret = mdp_mm_init(mdp, &mdp->mm_mutex, "mediatek,mm-mutex");
 	if (ret)
-		goto err_init_mm;
+		goto err_init_comps;
+
+	ret = mdp_imgi_init(mdp, "mediatek,imgsys");
+	if (ret)
+		goto err_init_comps;
 
 	parent = dev->of_node->parent;
 	/* Iterate over sibling MDP function blocks */
@@ -1281,27 +1364,44 @@ int mdp_component_init(struct mdp_dev *mdp)
 		}
 
 		type = (enum mdp_comp_type)of_id->data;
-		id = mdp_comp_get_id(dev, node, type);
-		if (id < 0) {
+		ret = of_property_read_u32(node, "mediatek,mdp-id", &alias_id);
+		if (ret) {
 			dev_warn(dev, "Skipping unknown component %pOF\n",
 				 node);
 			continue;
 		}
+		id = mdp_comp_get_id(type, alias_id);
+		if (id < 0) {
+			dev_err(dev,
+				"Fail to get component id: type %d alias %d\n",
+				type, alias_id);
+			continue;
+		}
 
-		comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
-		if (!comp) {
-			ret = -ENOMEM;
+		comp = mdp_comp_create(mdp, node, id);
+		if (IS_ERR(comp))
 			goto err_init_comps;
-		}
-		mdp->comp[id] = comp;
 
-		ret = mdp_comp_init(dev, mdp, node, comp, id);
+		ret = mdp_sub_comps_create(mdp, node);
 		if (ret)
 			goto err_init_comps;
 
-		dev_info(dev, "%s type:%d alias:%d id:%d base:%#x regs:%p\n",
-			 of_id->compatible, type, comp->alias_id, id,
-			(u32)comp->reg_base, comp->regs);
+		/* Only DMA capable components need the pm control */
+		comp->comp_dev = NULL;
+		if (comp->type != MDP_COMP_TYPE_RDMA &&
+		    comp->type != MDP_COMP_TYPE_WROT &&
+			comp->type != MDP_COMP_TYPE_WDMA)
+			continue;
+
+		pdev = of_find_device_by_node(node);
+		if (!pdev) {
+			dev_warn(dev, "can't find platform device of node:%s\n",
+				 node->name);
+			return -ENODEV;
+		}
+
+		comp->comp_dev = &pdev->dev;
+		pm_runtime_enable(comp->comp_dev);
 	}
 	return 0;
 
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
index f201bced3c06..f5d514a51236 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
@@ -112,7 +112,7 @@ struct mdp_comp {
 	void __iomem			*regs;
 	phys_addr_t			reg_base;
 	u8				subsys_id;
-	struct clk			*clks[2];
+	struct clk			*clks[4];
 	struct device			*comp_dev;
 	enum mdp_comp_type		type;
 	enum mdp_comp_id		id;
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 09/10] media: mtk-mdp3: revise error handling about get/probe MDP3
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (6 preceding siblings ...)
  2021-06-23  7:35 ` [RFC PATCH V0 08/10] media: mtk-mdp3: remove illegal device node usage Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23  7:35 ` [RFC PATCH V0 10/10] media: mtk-mdp3: Adjust related settings for 5.13-rc1 Moudy Ho
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

This patch is used for review before send upstream patch.
From Alexandre Courbot's review comment: Independent from the main patch.
Revise error handling about get/probe MDP3 driver to make it stable.

Signed-off-by: Moudy Ho <moudy.ho@mediatek.com>
---
 drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
index eaf5b07e720f..207b55ace97b 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
@@ -40,9 +40,9 @@ struct platform_device *mdp_get_plat_device(struct platform_device *pdev)
 	}
 
 	mdp_pdev = of_find_device_by_node(mdp_node);
+	of_node_put(mdp_node);
 	if (WARN_ON(!mdp_pdev)) {
 		dev_err(dev, "mdp pdev failed\n");
-		of_node_put(mdp_node);
 		return NULL;
 	}
 
@@ -113,7 +113,7 @@ static int mdp_probe(struct platform_device *pdev)
 	if (!mdp->job_wq) {
 		dev_err(dev, "Unable to create job workqueue\n");
 		ret = -ENOMEM;
-		goto err_destroy_job_wq;
+		goto err_deinit_comp;
 	}
 
 	mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE,
@@ -121,7 +121,7 @@ static int mdp_probe(struct platform_device *pdev)
 	if (!mdp->clock_wq) {
 		dev_err(dev, "Unable to create clock workqueue\n");
 		ret = -ENOMEM;
-		goto err_destroy_clock_wq;
+		goto err_destroy_job_wq;
 	}
 
 	mdp->scp = scp_get(pdev);
@@ -179,6 +179,8 @@ static int mdp_probe(struct platform_device *pdev)
 	destroy_workqueue(mdp->clock_wq);
 err_destroy_job_wq:
 	destroy_workqueue(mdp->job_wq);
+err_deinit_comp:
+		mdp_component_deinit(mdp);
 err_return:
 	dev_dbg(dev, "Errno %d\n", ret);
 	return ret;
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH V0 10/10] media: mtk-mdp3: Adjust related settings for 5.13-rc1
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (7 preceding siblings ...)
  2021-06-23  7:35 ` [RFC PATCH V0 09/10] media: mtk-mdp3: revise error handling about get/probe MDP3 Moudy Ho
@ 2021-06-23  7:35 ` Moudy Ho
  2021-06-23 10:41 ` [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Chun-Kuang Hu
  2021-07-02 12:00 ` Enric Balletbo Serra
  10 siblings, 0 replies; 12+ messages in thread
From: Moudy Ho @ 2021-06-23  7:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec
  Cc: Maoguang Meng, Krzysztof Kozlowski, daoyuan huang, Ping-Hsun Wu,
	Geert Uytterhoeven, Rob Landley, Laurent Pinchart, linux-media,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	tfiga, drinkcat, acourbot, pihsun, menghui.lin, sj.huang,
	ben.lok, randy.wu, moudy.ho, srv_heupstream, frederic.chen

From: mtk18742 <moudy.ho@mediatek.com>

1. remove cmdq_pkt_flush usage.
2. remove VFL_TYPE_GRABBER enum.
3. remove undefined format
4. Adjust CMDQ API param.

Signed-off-by: Moudy Ho <moudy.ho@mediatek.com>
---
 .../media/platform/mtk-mdp3/mmsys_reg_base.h  |  2 +-
 .../media/platform/mtk-mdp3/mtk-mdp3-cmdq.c   | 92 +++++++------------
 .../media/platform/mtk-mdp3/mtk-mdp3-cmdq.h   |  3 +-
 .../media/platform/mtk-mdp3/mtk-mdp3-core.c   |  2 +-
 .../media/platform/mtk-mdp3/mtk-mdp3-m2m.c    |  3 +-
 .../media/platform/mtk-mdp3/mtk-mdp3-regs.c   |  2 +-
 6 files changed, 39 insertions(+), 65 deletions(-)

diff --git a/drivers/media/platform/mtk-mdp3/mmsys_reg_base.h b/drivers/media/platform/mtk-mdp3/mmsys_reg_base.h
index d79b82eea61b..738ecd525474 100644
--- a/drivers/media/platform/mtk-mdp3/mmsys_reg_base.h
+++ b/drivers/media/platform/mtk-mdp3/mmsys_reg_base.h
@@ -16,7 +16,7 @@
 			(0xffffffff) : (mask), ##__VA_ARGS__)
 
 #define MM_REG_WAIT(cmd, evt) \
-	cmdq_pkt_wfe(cmd->pkt, cmd->event[(evt)])
+	cmdq_pkt_wfe(cmd->pkt, cmd->event[(evt)], true)
 
 #define MM_REG_WAIT_NO_CLEAR(cmd, evt) \
 	cmdq_pkt_wait_no_clear(cmd->pkt, cmd->event[(evt)])
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
index eac10944283a..151485933eae 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -468,71 +468,48 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 		goto err_destory_pkt;
 	}
 
-	if (param->wait) {
-		ret = cmdq_pkt_flush(cmd.pkt);
-#ifdef MDP_DEBUG
-		if (ret) {
-			struct mdp_func_struct *p_func = mdp_get_func();
-
-			p_func->mdp_dump_mmsys_config();
-			mdp_dump_info(~0, 1);
-		}
-#endif
-		if (!ret) { /* error handle in mdp_m2m_worker */
-			if (param->mdp_ctx)
-				mdp_m2m_job_finish(param->mdp_ctx);
-		}
-		goto err_clock_off;
-	} else {
-		cb_param = kzalloc(sizeof(*cb_param), GFP_KERNEL);
-		if (!cb_param) {
-			ret = -ENOMEM;
-			goto err_destory_pkt;
-		}
+	cb_param = kzalloc(sizeof(*cb_param), GFP_KERNEL);
+	if (!cb_param) {
+		ret = -ENOMEM;
+		goto err_destory_pkt;
+	}
 
-		comps = kcalloc(param->config->num_components, sizeof(*comps),
-				GFP_KERNEL);
-		if (!comps) {
-			mdp_err("%s:comps alloc fail!\n", __func__);
-			ret = -ENOMEM;
-			goto err_destory_pkt;
-		}
+	comps = kcalloc(param->config->num_components, sizeof(*comps),
+			GFP_KERNEL);
+	if (!comps) {
+		mdp_err("%s:comps alloc fail!\n", __func__);
+		ret = -ENOMEM;
+		goto err_destory_pkt;
+	}
 
-		for (i = 0; i < param->config->num_components; i++)
-			memcpy(&comps[i], path.comps[i].comp,
-			       sizeof(struct mdp_comp));
-		cb_param->mdp = mdp;
-		cb_param->user_cmdq_cb = param->cmdq_cb;
-		cb_param->user_cb_data = param->cb_data;
-		cb_param->pkt = cmd.pkt;
-		cb_param->comps = comps;
-		cb_param->num_comps = param->config->num_components;
-		cb_param->mdp_ctx = param->mdp_ctx;
-
-		cmdq_pkt_finalize(cmd.pkt);
-		ret = cmdq_pkt_flush_async(cmd.pkt,
-					   mdp_handle_cmdq_callback,
-					   (void *)cb_param);
-		if (ret) {
-			mdp_err("%s:cmdq_pkt_flush_async fail!\n", __func__);
-			goto err_clock_off;
-		}
+	for (i = 0; i < param->config->num_components; i++)
+		memcpy(&comps[i], path.comps[i].comp,
+		       sizeof(struct mdp_comp));
+	cb_param->mdp = mdp;
+	cb_param->user_cmdq_cb = param->cmdq_cb;
+	cb_param->user_cb_data = param->cb_data;
+	cb_param->pkt = cmd.pkt;
+	cb_param->comps = comps;
+	cb_param->num_comps = param->config->num_components;
+	cb_param->mdp_ctx = param->mdp_ctx;
+
+	cmdq_pkt_finalize(cmd.pkt);
+	ret = cmdq_pkt_flush_async(cmd.pkt,
+				   mdp_handle_cmdq_callback,
+				   (void *)cb_param);
+	if (ret) {
+		mdp_err("%s:cmdq_pkt_flush_async fail!\n", __func__);
+		goto err_clock_off;
 	}
 	return 0;
 
 err_clock_off:
-	if (param->wait) {
-		for (i = 0; i < param->config->num_components; i++)
-			mdp_comp_clock_off(&mdp->pdev->dev, path.comps[i].comp);
-	} else {
-		mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
-					    cb_param->num_comps);
-	}
+	mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
+				    cb_param->num_comps);
 err_destory_pkt:
 	cmdq_pkt_destroy(cmd.pkt);
 	atomic_dec(&mdp->job_count);
-	if (param->wait)
-		wake_up(&mdp->callback_wq);
+	wake_up(&mdp->callback_wq);
 	if (comps)
 		kfree(comps);
 	if (cb_param)
@@ -543,7 +520,7 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
 
 int mdp_cmdq_sendtask(struct platform_device *pdev, struct img_config *config,
 		      struct img_ipi_frameparam *param,
-		      struct v4l2_rect *compose, unsigned int wait,
+		      struct v4l2_rect *compose,
 		      void (*cmdq_cb)(struct cmdq_cb_data data), void *cb_data)
 {
 	struct mdp_dev *mdp = platform_get_drvdata(pdev);
@@ -551,7 +528,6 @@ int mdp_cmdq_sendtask(struct platform_device *pdev, struct img_config *config,
 		.config = config,
 		.param = param,
 		.composes[0] = compose,
-		.wait = wait,
 		.cmdq_cb = cmdq_cb,
 		.cb_data = cb_data,
 	};
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
index 6b8b0f6b4bb5..f6394d3d0358 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
@@ -16,7 +16,7 @@ struct platform_device *mdp_get_plat_device(struct platform_device *pdev);
 
 int mdp_cmdq_sendtask(struct platform_device *pdev, struct img_config *config,
 		      struct img_ipi_frameparam *param,
-		      struct v4l2_rect *compose, unsigned int wait,
+		      struct v4l2_rect *compose,
 		      void (*cmdq_cb)(struct cmdq_cb_data data), void *cb_data);
 
 struct mdp_cmd {
@@ -28,7 +28,6 @@ struct mdp_cmdq_param {
 	struct img_config *config;
 	struct img_ipi_frameparam *param;
 	const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS];
-	unsigned int wait;
 
 	void (*cmdq_cb)(struct cmdq_cb_data data);
 	void *cb_data;
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
index 207b55ace97b..a42e436d3a8c 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
@@ -137,7 +137,7 @@ static int mdp_probe(struct platform_device *pdev)
 	mutex_init(&mdp->vpu_lock);
 	mutex_init(&mdp->m2m_lock);
 
-	mdp->cmdq_clt = cmdq_mbox_create(dev, 0, 1200);
+	mdp->cmdq_clt = cmdq_mbox_create(dev, 0);
 	if (IS_ERR(mdp->cmdq_clt)) {
 		ret = PTR_ERR(mdp->cmdq_clt);
 		goto err_put_scp;
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
index ff80f01be82f..536574f6bc32 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
@@ -133,7 +133,6 @@ static void mdp_m2m_worker(struct work_struct *work)
 	task.config = ctx->vpu.config;
 	task.param = &param;
 	task.composes[0] = &frame->compose;
-	task.wait = 0;
 	task.cmdq_cb = NULL;
 	task.cb_data = NULL;
 	task.mdp_ctx = ctx;
@@ -769,7 +768,7 @@ int mdp_m2m_device_register(struct mdp_dev *mdp)
 		goto err_m2m_init;
 	}
 
-	ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_GRABBER, 2);
+	ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, 2);
 	if (ret) {
 		dev_err(dev, "Failed to register video device\n");
 		goto err_video_register;
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
index 5c48a7e75efd..0c4c942b5f9c 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
@@ -168,7 +168,7 @@ static const struct mdp_format mdp_formats[] = {
 		.halign		= 5,
 		.flags		= MDP_FMT_FLAG_OUTPUT,
 	}, {
-		.pixelformat	= V4L2_PIX_FMT_MM21,
+		.pixelformat	= V4L2_PIX_FMT_NV12MT,
 		.mdp_color	= MDP_COLOR_420_BLK,
 		.depth		= { 8, 4 },
 		.row_depth	= { 8, 8 },
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (8 preceding siblings ...)
  2021-06-23  7:35 ` [RFC PATCH V0 10/10] media: mtk-mdp3: Adjust related settings for 5.13-rc1 Moudy Ho
@ 2021-06-23 10:41 ` Chun-Kuang Hu
  2021-07-02 12:00 ` Enric Balletbo Serra
  10 siblings, 0 replies; 12+ messages in thread
From: Chun-Kuang Hu @ 2021-06-23 10:41 UTC (permalink / raw)
  To: Moudy Ho
  Cc: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec, Maoguang Meng, Krzysztof Kozlowski,
	daoyuan huang, Ping-Hsun Wu, Geert Uytterhoeven, Rob Landley,
	Laurent Pinchart, linux-media, DTML, Linux ARM,
	moderated list:ARM/Mediatek SoC support, linux-kernel,
	Tomasz Figa, Nicolas Boichat, acourbot, Pi-Hsun Shih,
	menghui.lin, Sj Huang (黃信璋),
	ben.lok, randy.wu, srv_heupstream,
	Frederic Chen (陳俊元)

Hi, Moudy:

Moudy Ho <moudy.ho@mediatek.com> 於 2021年6月23日 週三 下午3:46寫道:
>
> From: mtk18742 <moudy.ho@mediatek.com>
>
> Add MDP driver for MT8183
>
> Signed-off-by: Moudy Ho <moudy.ho@mediatek.com>
> ---

[snip]

> +
> +#endif  // __MMSYS_CONFIG_H__
> diff --git a/drivers/media/platform/mtk-mdp3/mmsys_mutex.h b/drivers/media/platform/mtk-mdp3/mmsys_mutex.h
> new file mode 100644
> index 000000000000..fb8c179f11af
> --- /dev/null
> +++ b/drivers/media/platform/mtk-mdp3/mmsys_mutex.h
> @@ -0,0 +1,35 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2019 MediaTek Inc.
> + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
> + */
> +
> +#ifndef __MMSYS_MUTEX_H__
> +#define __MMSYS_MUTEX_H__
> +
> +#include "mmsys_reg_base.h"
> +#include "mdp-platform.h"
> +
> +#define MM_MUTEX_INTEN              0x00
> +#define MM_MUTEX_INTSTA             0x04
> +#define MM_MUTEX_CFG                0x08
> +
> +#define MM_MUTEX_EN                 (0x20 + mutex_id * 0x20)
> +#define MM_MUTEX_GET                (0x24 + mutex_id * 0x20)
> +#define MM_MUTEX_RST                (0x28 + mutex_id * 0x20)
> +#define MM_MUTEX_MOD                (MM_MUTEX_MOD_OFFSET + mutex_id * 0x20)
> +#define MM_MUTEX_SOF                (MM_MUTEX_SOF_OFFSET + mutex_id * 0x20)

mtk_mutex driver is in drivers/soc/mediatek/mtk-mutex.c, so the
mtk_mutex control should be placed there.

> +
> +// MASK
> +#define MM_MUTEX_INTEN_MASK         0x0fff
> +#define MM_MUTEX_INTSTA_MASK        0x0fff
> +#define MM_MUTEX_DEBUG_OUT_SEL_MASK 0x03
> +#define MM_MUTEX_CFG_MASK           0x01
> +
> +#define MM_MUTEX_EN_MASK            0x01
> +#define MM_MUTEX_GET_MASK           0x03
> +#define MM_MUTEX_RST_MASK           0x01
> +#define MM_MUTEX_MOD_MASK           0x07ffffff
> +#define MM_MUTEX_SOF_MASK           0x0f
> +

[snip]

> +int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
> +{
> +       struct mdp_cmd cmd;
> +       struct mdp_path path;
> +       int i, ret;
> +
> +       if (atomic_read(&mdp->suspended))
> +               return -ECANCELED;
> +
> +       atomic_inc(&mdp->job_count);
> +
> +       cmd.pkt = cmdq_pkt_create(mdp->cmdq_clt, SZ_16K);
> +       if (IS_ERR(cmd.pkt)) {
> +               atomic_dec(&mdp->job_count);
> +               wake_up(&mdp->callback_wq);
> +               return PTR_ERR(cmd.pkt);
> +       }
> +       cmd.event = &mdp->event[0];
> +
> +       path.mdp_dev = mdp;
> +       path.config = param->config;
> +       path.param = param->param;
> +       for (i = 0; i < param->param->num_outputs; i++) {
> +               path.bounds[i].left = 0;
> +               path.bounds[i].top = 0;
> +               path.bounds[i].width =
> +                       param->param->outputs[i].buffer.format.width;
> +               path.bounds[i].height =
> +                       param->param->outputs[i].buffer.format.height;
> +               path.composes[i] = param->composes[i] ?
> +                       param->composes[i] : &path.bounds[i];
> +       }
> +       ret = mdp_path_config(mdp, &cmd, &path);
> +       if (ret) {
> +               atomic_dec(&mdp->job_count);
> +               wake_up(&mdp->callback_wq);
> +               return ret;
> +       }
> +
> +       // TODO: engine conflict dispatch
> +       for (i = 0; i < param->config->num_components; i++)
> +               mdp_comp_clock_on(&mdp->pdev->dev, path.comps[i].comp);
> +
> +       if (param->wait) {
> +               ret = cmdq_pkt_flush(cmd.pkt);

cmdq_pkt_flush() is removed in latest kernel, please rebase this
series onto latest kernel before you send patches.

Regards,
Chun-Kuang.

> +#ifdef MDP_DEBUG
> +               if (ret) {
> +                       struct mdp_func_struct *p_func = mdp_get_func();
> +
> +                       p_func->mdp_dump_mmsys_config();
> +                       mdp_dump_info(~0, 1);
> +               }
> +#endif
> +               if (param->mdp_ctx)
> +                       mdp_m2m_job_finish(param->mdp_ctx);
> +               cmdq_pkt_destroy(cmd.pkt);
> +               for (i = 0; i < param->config->num_components; i++)
> +                       mdp_comp_clock_off(&mdp->pdev->dev, path.comps[i].comp);
> +
> +               atomic_dec(&mdp->job_count);
> +               wake_up(&mdp->callback_wq);
> +       } else {
> +               struct mdp_cmdq_cb_param *cb_param;
> +               struct mdp_comp *comps;
> +
> +               cb_param = kzalloc(sizeof(*cb_param), GFP_KERNEL);
> +               if (!cb_param)
> +                       return -ENOMEM;
> +               comps = kcalloc(param->config->num_components, sizeof(*comps),
> +                               GFP_KERNEL);
> +               if (!comps) {
> +                       kfree(cb_param);
> +                       mdp_err("%s:comps alloc fail!\n", __func__);
> +                       return -ENOMEM;
> +               }
> +
> +               for (i = 0; i < param->config->num_components; i++)
> +                       memcpy(&comps[i], path.comps[i].comp,
> +                              sizeof(struct mdp_comp));
> +               cb_param->mdp = mdp;
> +               cb_param->user_cmdq_cb = param->cmdq_cb;
> +               cb_param->user_cb_data = param->cb_data;
> +               cb_param->pkt = cmd.pkt;
> +               cb_param->comps = comps;
> +               cb_param->num_comps = param->config->num_components;
> +               cb_param->mdp_ctx = param->mdp_ctx;
> +
> +               ret = cmdq_pkt_flush_async(cmd.pkt,
> +                                          mdp_handle_cmdq_callback,
> +                                          (void *)cb_param);
> +               if (ret) {
> +                       mdp_err("%s:cmdq_pkt_flush_async fail!\n", __func__);
> +                       kfree(cb_param);
> +                       kfree(comps);
> +               }
> +       }
> +       return ret;
> +}
> +

> --
> 2.18.0
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver
  2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
                   ` (9 preceding siblings ...)
  2021-06-23 10:41 ` [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Chun-Kuang Hu
@ 2021-07-02 12:00 ` Enric Balletbo Serra
  10 siblings, 0 replies; 12+ messages in thread
From: Enric Balletbo Serra @ 2021-07-02 12:00 UTC (permalink / raw)
  To: Moudy Ho
  Cc: Mauro Carvalho Chehab, Rob Herring, Matthias Brugger,
	Hans Verkuil, Jernej Skrabec, Maoguang Meng, Krzysztof Kozlowski,
	daoyuan huang, Ping-Hsun Wu, Geert Uytterhoeven, Rob Landley,
	Laurent Pinchart, linux-media, devicetree, linux-arm-kernel,
	linux-mediatek, linux-kernel, tfiga, drinkcat, acourbot, pihsun,
	menghui.lin, sj.huang, ben.lok, randy.wu, srv_heupstream,
	frederic.chen

Hi Mody Ho,

Thank you for your patch. Some comments below.

Missatge de Moudy Ho <moudy.ho@mediatek.com> del dia dc., 23 de juny
2021 a les 9:36:
>
> From: mtk18742 <moudy.ho@mediatek.com>
>

Please fix your git configuration, I assume this should be something
like Moudy Ho <moudy.ho@mediatek.com>. Note that the author and the
Signed-off must match.

> Add MDP driver for MT8183
>

In general please use a more verbose commit messages, you know what
MDP means (I probably also know, but not everyone knows what MDP
means) It is a good practice to when you introduce a new driver to
explain well what is and for what is used.

The first question that I have here is why current MDP driver (that
supports other Mediatek chips like the MT8173) can't be extended to
support MT8183. How different is this MDP driver and why can't share
the code.

This single patch is huge, and is unlikely that anyone spend time
reviewing it just for that. I'd recommend to split it and introduce
step-by-step, functionality by functionally. I also have the
impression that you're just reimplementing things that are actually
upstream or not taking advantage of what is already upstream. i.e the
access to the mmsys registers. Please use current kernel
drivers/interfaces API instead of reimplementing it.

I'd strongly recommend to look at current Mediatek mdp driver and see
if you can add support for MT8183 there, and if not, looks at it as
reference.

Best regards,
  Enric


> Signed-off-by: Moudy Ho <moudy.ho@mediatek.com>
> ---
>  drivers/media/platform/Kconfig                |   17 +
>  drivers/media/platform/Makefile               |    2 +
>  drivers/media/platform/mtk-mdp3/Makefile      |    9 +
>  drivers/media/platform/mtk-mdp3/isp_reg.h     |   37 +
>  .../media/platform/mtk-mdp3/mdp-platform.h    |   58 +
>  .../media/platform/mtk-mdp3/mdp_reg_ccorr.h   |   75 +
>  .../media/platform/mtk-mdp3/mdp_reg_rdma.h    |  206 +++
>  drivers/media/platform/mtk-mdp3/mdp_reg_rsz.h |  109 ++
>  .../media/platform/mtk-mdp3/mdp_reg_wdma.h    |  125 ++
>  .../media/platform/mtk-mdp3/mdp_reg_wrot.h    |  115 ++
>  .../media/platform/mtk-mdp3/mmsys_config.h    |  188 +++
>  drivers/media/platform/mtk-mdp3/mmsys_mutex.h |   35 +
>  .../media/platform/mtk-mdp3/mmsys_reg_base.h  |   38 +
>  drivers/media/platform/mtk-mdp3/mtk-img-ipi.h |  282 ++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-cmdq.c   |  521 +++++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-cmdq.h   |   54 +
>  .../media/platform/mtk-mdp3/mtk-mdp3-comp.c   | 1329 +++++++++++++++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-comp.h   |  155 ++
>  .../media/platform/mtk-mdp3/mtk-mdp3-core.c   |  282 ++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-core.h   |   86 ++
>  .../media/platform/mtk-mdp3/mtk-mdp3-debug.c  |  973 ++++++++++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-debug.h  |   39 +
>  .../media/platform/mtk-mdp3/mtk-mdp3-m2m.c    |  804 ++++++++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-m2m.h    |   42 +
>  .../media/platform/mtk-mdp3/mtk-mdp3-regs.c   |  748 ++++++++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-regs.h   |  373 +++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-vpu.c    |  313 ++++
>  .../media/platform/mtk-mdp3/mtk-mdp3-vpu.h    |   79 +
>  28 files changed, 7094 insertions(+)
>  create mode 100644 drivers/media/platform/mtk-mdp3/Makefile
>  create mode 100644 drivers/media/platform/mtk-mdp3/isp_reg.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mdp-platform.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_ccorr.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_rdma.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_rsz.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_wdma.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mdp_reg_wrot.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mmsys_config.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mmsys_mutex.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mmsys_reg_base.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-img-ipi.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.c
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-debug.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.c
>  create mode 100644 drivers/media/platform/mtk-mdp3/mtk-mdp3-vpu.h

 [snip]

> --
> 2.18.0
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-07-02 12:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-23  7:35 [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 02/10] media: mtk-mdp3: fix redundant process done caused KE Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 03/10] media: mtk-mdp3: revise suspend strategy Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 04/10] media: mtk-mdp3: add error handling in error return Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 05/10] media: mtk-mdp3: remove unnecessary Null check Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 06/10] media: mtk-mdp3: move clock on to precise place Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 07/10] media: mtk-mdp3: Fix unpaired settings Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 08/10] media: mtk-mdp3: remove illegal device node usage Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 09/10] media: mtk-mdp3: revise error handling about get/probe MDP3 Moudy Ho
2021-06-23  7:35 ` [RFC PATCH V0 10/10] media: mtk-mdp3: Adjust related settings for 5.13-rc1 Moudy Ho
2021-06-23 10:41 ` [RFC PATCH V0 01/10] media: mtk-mdp3: Add Mediatek MDP Driver Chun-Kuang Hu
2021-07-02 12:00 ` Enric Balletbo Serra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).