[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1605839346-10648-5-git-send-email-daoyuan.huang@mediatek.com>
Date: Fri, 20 Nov 2020 10:29:06 +0800
From: Daoyuan Huang <daoyuan.huang@...iatek.com>
To: Mauro Carvalho Chehab <mchehab@...nel.org>,
Rob Herring <robh+dt@...nel.org>,
Matthias Brugger <matthias.bgg@...il.com>,
Hans Verkuil <hverkuil-cisco@...all.nl>,
Jernej Skrabec <jernej.skrabec@...l.net>
CC: Maoguang Meng <maoguang.meng@...iatek.com>,
Krzysztof Kozlowski <krzk@...nel.org>,
daoyuan huang <daoyuan.huang@...iatek.com>,
Ping-Hsun Wu <ping-hsun.wu@...iatek.com>,
Geert Uytterhoeven <geert+renesas@...der.be>,
Rob Landley <rob@...dley.net>,
Laurent Pinchart <laurent.pinchart@...asonboard.com>,
<linux-media@...r.kernel.org>, <devicetree@...r.kernel.org>,
<linux-arm-kernel@...ts.infradead.org>,
<linux-mediatek@...ts.infradead.org>,
<linux-kernel@...r.kernel.org>, <tfiga@...omium.org>,
<drinkcat@...omium.org>, <acourbot@...omium.org>,
<pihsun@...omium.org>, <menghui.lin@...iatek.com>,
<sj.huang@...iatek.com>, <ben.lok@...iatek.com>,
<randy.wu@...iatek.com>, <moudy.ho@...iatek.com>,
<srv_heupstream@...iatek.com>
Subject: [PATCH v4 4/4] media: platform: mtk-mdp3: Add Mediatek MDP3 driver
From: daoyuan huang <daoyuan.huang@...iatek.com>
This patch adds driver for Media Data Path 3 (MDP3).
Each modules' related operation control is sited in mtk-mdp3-comp.c
Each modules' register table is defined in file with "mdp_reg_"
and "mmsys_" prefix
GCE related API, operation control sited in mtk-mdp3-cmdq.c
V4L2 m2m device functions are implemented in mtk-mdp3-m2m.c
Probe, power, suspend/resume, system level functions are defined in
mtk-mdp3-core.c
Signed-off-by: Ping-Hsun Wu <ping-hsun.wu@...iatek.com>
Signed-off-by: daoyuan huang <daoyuan.huang@...iatek.com>
---
Depend on:
[1] https://patchwork.kernel.org/project/linux-mediatek/patch/20190906115513.159705-9-acourbot@chromium.org/
[2] https://patchwork.kernel.org/project/linux-mediatek/patch/20190906115513.159705-10-acourbot@chromium.org/
---
drivers/media/platform/mtk-mdp3/Makefile | 7 +
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 | 281 ++++
.../media/platform/mtk-mdp3/mtk-mdp3-cmdq.c | 504 ++++++
.../media/platform/mtk-mdp3/mtk-mdp3-cmdq.h | 54 +
.../media/platform/mtk-mdp3/mtk-mdp3-comp.c | 1420 +++++++++++++++++
.../media/platform/mtk-mdp3/mtk-mdp3-comp.h | 155 ++
.../media/platform/mtk-mdp3/mtk-mdp3-core.c | 269 ++++
.../media/platform/mtk-mdp3/mtk-mdp3-core.h | 86 +
.../media/platform/mtk-mdp3/mtk-mdp3-m2m.c | 795 +++++++++
.../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 +
24 files changed, 6112 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-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/mtk-mdp3/Makefile b/drivers/media/platform/mtk-mdp3/Makefile
new file mode 100644
index 000000000000..dd7b1ca1633e
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/Makefile
@@ -0,0 +1,7 @@
+# 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
+
+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..89ba8dc484de
--- /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@...iatek.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@...iatek.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@...iatek.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@...iatek.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@...iatek.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@...iatek.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@...iatek.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@...iatek.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@...iatek.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@...iatek.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..79c3919f52e1
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-img-ipi.h
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Holmes Chiou <holmes.chiou@...iatek.com>
+ * Ping-Hsun Wu <ping-hsun.wu@...iatek.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 for Linux OS access */
+ u32 pa; /* Used for CM4 access */
+ u32 iova; /* Used for IOMMU HW access */
+} __attribute__ ((__packed__));
+
+struct tuning_addr {
+ u64 present;
+ u32 pa; /* Used for CM4 access */
+ u32 iova; /* Used for IOMMU HW access */
+} __attribute__ ((__packed__));
+
+struct img_sw_addr {
+ u64 va; /* Used for APMCU access */
+ u32 pa; /* Used for 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 for APMCU access */
+ u32 scp_addr; /* Used for 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..bd8f274fcaa9
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@...iatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include "mtk-mdp3-cmdq.h"
+#include "mtk-mdp3-comp.h"
+#include "mtk-mdp3-core.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);
+
+ 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);
+ 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@...iatek.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..3aa27a63531b
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-comp.c
@@ -0,0 +1,1420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@...iatek.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_of_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(enum mdp_comp_type type, u32 alias_id)
+{
+ 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;
+ return -ENODEV;
+}
+
+void mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp)
+{
+ int i, err;
+
+ if (comp->comp_dev) {
+ err = pm_runtime_get_sync(comp->comp_dev);
+ if (err < 0)
+ dev_err(dev,
+ "Failed to get power, 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->comp_dev)
+ pm_runtime_put(comp->comp_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_info(&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_comp_init(struct mdp_dev *mdp, struct device_node *node,
+ struct mdp_comp *comp, enum mdp_comp_id id)
+{
+ struct device *dev = &mdp->pdev->dev;
+ 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);
+
+ return 0;
+}
+
+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;
+}
+
+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_of_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)
+{
+ 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;
+
+ 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;
+ struct platform_device *pdev;
+ u32 alias_id;
+ 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_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 */
+ 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_of_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;
+ 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 = mdp_comp_create(mdp, node, id);
+ if (IS_ERR(comp))
+ goto err_init_comps;
+
+ ret = mdp_sub_comps_create(mdp, node);
+ if (ret)
+ goto err_init_comps;
+
+ /* 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;
+
+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..36b2b29df7ed
--- /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@...iatek.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[4];
+ struct device *comp_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..52138c300a71
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@...iatek.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-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);
+ of_node_put(mdp_node);
+ if (WARN_ON(!mdp_pdev)) {
+ dev_err(dev, "mdp pdev failed\n");
+ 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_deinit_comp;
+ }
+
+ 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_job_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);
+
+ 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_deinit_comp:
+ mdp_component_deinit(mdp);
+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);
+
+ 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)
+{
+ return 0;
+}
+
+static int __maybe_unused mdp_pm_resume(struct device *dev)
+{
+ return 0;
+}
+
+static int __maybe_unused mdp_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_resume(struct device *dev)
+{
+ struct mdp_dev *mdp = dev_get_drvdata(dev);
+
+ atomic_set(&mdp->suspended, 0);
+
+ return 0;
+}
+
+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@...iatek.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@...iatek.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-m2m.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
new file mode 100644
index 000000000000..b832cb4cd710
--- /dev/null
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
@@ -0,0 +1,795 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ping-Hsun Wu <ping-hsun.wu@...iatek.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(¶m.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(¶m.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, ¶m);
+ 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 = ¶m;
+ 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);
+
+ 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);
+ }
+}
+
+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->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_VIDEO, 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@...iatek.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@...iatek.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) ? ¶m->limit->out_limit :
+ ¶m->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(¶m->list);
+ mutex_init(¶m->state_lock);
+ param->limit = &mdp_def_limit;
+ param->type = MDP_STREAM_TYPE_BITBLT;
+
+ frame = ¶m->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 = ¶m->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@...iatek.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@...iatek.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@...iatek.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
Powered by blists - more mailing lists