diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/Makefile b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/Makefile
index 571d0ae000eb..26c8c1d39750 100644
--- a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/Makefile
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/Makefile
@@ -2,10 +2,18 @@
 #
 
 mtk_imgsys_util-objs := \
+mtk_imgsys-module_main.o \
 mtk_imgsys-of.o \
 mtk_imgsys-formats.o \
 mtk_imgsys-dev.o \
 mtk_imgsys-sys.o \
 mtk_imgsys-v4l2.o
 
+mtk_imgsys_hw_isp-objs := \
+modules/mtk_imgsys-dip.o \
+modules/mtk_imgsys-traw.o \
+modules/mtk_imgsys-pqdip.o \
+modules/mtk_imgsys-wpe.o
+
 obj-$(CONFIG_VIDEO_MTK_ISP_71_IMGSYS) += mtk_imgsys_util.o
+obj-$(CONFIG_VIDEO_MTK_ISP_71_IMGSYS) += mtk_imgsys_hw_isp.o
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-dip.c b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-dip.c
new file mode 100644
index 000000000000..1cc1f3e87e8b
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-dip.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Frederic Chen <frederic.chen@mediatek.com>
+ *         Holmes Chiou <holmes.chiou@mediatek.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include "../mtk_imgsys-module_common.h"
+#include "mtk_imgsys-dip.h"
+
+/********************************************************************
+ * Global Define
+ ********************************************************************/
+#define DIPCTL_D1A_DIPCTL_INT1_EN    0x094
+#define DIPCTL_D1A_DIPCTL_INT2_EN    0x0A0
+#define DIPCTL_D1A_DIPCTL_INT3_EN    0x0AC
+#define DIPCTL_D1A_DIPCTL_CQ_INT1_EN 0x0C4
+#define DIPCTL_D1A_DIPCTL_CQ_INT2_EN 0x0D0
+#define DIPCTL_D1A_DIPCTL_CQ_INT3_EN 0x0DC
+
+#define DIPCQ_D1A_DIPCQ_CQ_THR0_CTL  0x208
+#define DIPCQ_D1A_DIPCQ_CQ_THR1_CTL  0x218
+#define DIPCQ_D1A_DIPCQ_CQ_THR2_CTL  0x228
+#define DIPCQ_D1A_DIPCQ_CQ_THR3_CTL  0x238
+#define DIPCQ_D1A_DIPCQ_CQ_THR4_CTL  0x248
+#define DIPCQ_D1A_DIPCQ_CQ_THR5_CTL  0x258
+#define DIPCQ_D1A_DIPCQ_CQ_THR6_CTL  0x268
+#define DIPCQ_D1A_DIPCQ_CQ_THR7_CTL  0x278
+#define DIPCQ_D1A_DIPCQ_CQ_THR8_CTL  0x288
+#define DIPCQ_D1A_DIPCQ_CQ_THR9_CTL  0x298
+#define DIPCQ_D1A_DIPCQ_CQ_THR10_CTL 0x2A8
+#define DIPCQ_D1A_DIPCQ_CQ_THR11_CTL 0x2B8
+#define DIPCQ_D1A_DIPCQ_CQ_THR12_CTL 0x2C8
+#define DIPCQ_D1A_DIPCQ_CQ_THR13_CTL 0x2D8
+#define DIPCQ_D1A_DIPCQ_CQ_THR14_CTL 0x2E8
+#define DIPCQ_D1A_DIPCQ_CQ_THR15_CTL 0x2F8
+#define DIPCQ_D1A_DIPCQ_CQ_THR16_CTL 0x308
+#define DIPCQ_D1A_DIPCQ_CQ_THR17_CTL 0x318
+#define DIPCQ_D1A_DIPCQ_CQ_THR18_CTL 0x328
+
+#define DIP_INIT_ARRAY_COUNT	ARRAY_SIZE(mtk_imgsys_dip_init_ary)
+
+/********************************************************************
+ * Global Variable
+ ********************************************************************/
+static const struct mtk_imgsys_init_array mtk_imgsys_dip_init_ary[] = {
+	{ DIPCTL_D1A_DIPCTL_INT1_EN, 0x80000000 },
+	{ DIPCTL_D1A_DIPCTL_INT2_EN, 0x0 },
+	{ DIPCTL_D1A_DIPCTL_INT3_EN, 0x0 },
+	{ DIPCTL_D1A_DIPCTL_CQ_INT1_EN, 0x0 },
+	{ DIPCTL_D1A_DIPCTL_CQ_INT2_EN, 0x0 },
+	{ DIPCTL_D1A_DIPCTL_CQ_INT3_EN, 0x0 },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR0_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR1_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR2_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR3_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR4_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR5_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR6_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR7_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR8_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR9_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR10_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR11_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR12_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR13_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR14_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR15_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR16_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR17_CTL, CQ_THRX_CTL },
+	{ DIPCQ_D1A_DIPCQ_CQ_THR18_CTL, CQ_THRX_CTL },
+};
+
+static void __iomem *dip_reg_base[MTK_IMGSYS_DIP_HW_SET];
+
+/********************************************************************
+ * Functions
+ ********************************************************************/
+void imgsys_dip_init(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int i, hw_id, hw_idx;
+	void __iomem *offset = NULL;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_DIP_HW_SET; hw_idx++) {
+		hw_id = IMGSYS_REG_DIP1 + hw_idx;
+		dip_reg_base[hw_idx] = of_iomap(imgsys_dev->dev->of_node, hw_id);
+		if (!dip_reg_base[hw_idx]) {
+			dev_info(imgsys_dev->dev,
+				 "%s: error: unable to iomap dip_%d registers, devnode(%s).\n",
+				 __func__, hw_id, imgsys_dev->dev->of_node->name);
+			continue;
+		}
+
+		for (i = 0 ; i < DIP_INIT_ARRAY_COUNT; i++) {
+			offset = dip_reg_base[hw_idx] + mtk_imgsys_dip_init_ary[i].offset;
+			writel(mtk_imgsys_dip_init_ary[i].value, offset);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_dip_init);
+
+void imgsys_dip_uninit(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int hw_idx;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_DIP_HW_SET; hw_idx++) {
+		iounmap(dip_reg_base[hw_idx]);
+		dip_reg_base[hw_idx] = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_dip_uninit);
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-dip.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-dip.h
new file mode 100644
index 000000000000..22b4a7c3616d
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-dip.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Frederic Chen <frederic.chen@mediatek.com>
+ *
+ */
+
+#ifndef _MTK_DIP_DIP_H_
+#define _MTK_DIP_DIP_H_
+
+#include "../mtk_imgsys-dev.h"
+
+void imgsys_dip_init(struct mtk_imgsys_dev *imgsys_dev);
+void imgsys_dip_uninit(struct mtk_imgsys_dev *imgsys_dev);
+
+#endif /* _MTK_DIP_DIP_H_ */
+
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-pqdip.c b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-pqdip.c
new file mode 100644
index 000000000000..d1d3507555d9
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-pqdip.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Author: Daniel Huang <daniel.huang@mediatek.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include "../mtk_imgsys-module_common.h"
+#include "mtk_imgsys-pqdip.h"
+
+/********************************************************************
+ * Global Define
+ ********************************************************************/
+#define PQDIPCTL_P1A_REG_PQDIPCTL_INT1_EN		0x0050
+#define PQDIPCTL_P1A_REG_PQDIPCTL_INT2_EN		0x0060
+#define PQDIPCTL_P1A_REG_PQDIPCTL_CQ_INT1_EN	0x0070
+#define PQDIPCTL_P1A_REG_PQDIPCTL_CQ_INT2_EN	0x0080
+#define PQDIPCTL_P1A_REG_PQDIPCTL_CQ_INT3_EN	0x0090
+
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR0_CTL			0x0208
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR1_CTL			0x0218
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR2_CTL			0x0228
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR3_CTL			0x0238
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR4_CTL			0x0248
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR5_CTL			0x0258
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR6_CTL			0x0268
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR7_CTL			0x0278
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR8_CTL			0x0288
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR9_CTL			0x0298
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR10_CTL		0x02A8
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR11_CTL		0x02B8
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR12_CTL		0x02C8
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR13_CTL		0x02D8
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR14_CTL		0x02E8
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR15_CTL		0x02F8
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR16_CTL		0x0308
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR17_CTL		0x0318
+#define DIPCQ_P1A_REG_DIPCQ_CQ_THR18_CTL		0x0328
+
+#define PQDIP_INIT_ARRAY_COUNT	ARRAY_SIZE(mtk_imgsys_pqdip_init_ary)
+
+/********************************************************************
+ * Global Variable
+ ********************************************************************/
+static const struct mtk_imgsys_init_array mtk_imgsys_pqdip_init_ary[] = {
+	{ PQDIPCTL_P1A_REG_PQDIPCTL_INT1_EN, 0x80000000 },
+	{ PQDIPCTL_P1A_REG_PQDIPCTL_INT2_EN, 0x0 },
+	{ PQDIPCTL_P1A_REG_PQDIPCTL_CQ_INT1_EN, 0x0 },
+	{ PQDIPCTL_P1A_REG_PQDIPCTL_CQ_INT2_EN, 0x0 },
+	{ PQDIPCTL_P1A_REG_PQDIPCTL_CQ_INT3_EN, 0x0 },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR0_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR1_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR2_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR3_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR4_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR5_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR6_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR7_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR8_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR9_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR10_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR11_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR12_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR13_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR14_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR15_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR16_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR17_CTL, CQ_THRX_CTL },
+	{ DIPCQ_P1A_REG_DIPCQ_CQ_THR18_CTL, CQ_THRX_CTL },
+};
+
+static void __iomem *pqdip_reg_base[MTK_IMGSYS_PQDIP_HW_SET];
+
+/********************************************************************
+ * Functions
+ ********************************************************************/
+void imgsys_pqdip_init(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int i, hw_id, hw_idx;
+	void __iomem *offset = NULL;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_PQDIP_HW_SET; hw_idx++) {
+		hw_id = IMGSYS_REG_PQDIP1 + hw_idx;
+		pqdip_reg_base[hw_idx] = of_iomap(imgsys_dev->dev->of_node, hw_id);
+		if (!pqdip_reg_base[hw_idx]) {
+			dev_info(imgsys_dev->dev,
+				 "%s: error: unable to iomap pqdip_%d registers, devnode(%s).\n",
+				 __func__, hw_id, imgsys_dev->dev->of_node->name);
+			continue;
+		}
+
+		for (i = 0 ; i < PQDIP_INIT_ARRAY_COUNT; i++) {
+			offset = pqdip_reg_base[hw_idx] + mtk_imgsys_pqdip_init_ary[i].offset;
+			writel(mtk_imgsys_pqdip_init_ary[i].value, offset);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_pqdip_init);
+
+void imgsys_pqdip_uninit(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int hw_idx;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_PQDIP_HW_SET; hw_idx++) {
+		iounmap(pqdip_reg_base[hw_idx]);
+		pqdip_reg_base[hw_idx] = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_pqdip_uninit);
+
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-pqdip.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-pqdip.h
new file mode 100644
index 000000000000..00f93d536181
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-pqdip.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Author: Daniel Huang <daniel.huang@mediatek.com>
+ *
+ */
+
+#ifndef _MTK_IMGSYS_PQDIP_H_
+#define _MTK_IMGSYS_PQDIP_H_
+
+#include "../mtk_imgsys-dev.h"
+
+void imgsys_pqdip_init(struct mtk_imgsys_dev *imgsys_dev);
+void imgsys_pqdip_uninit(struct mtk_imgsys_dev *imgsys_dev);
+
+#endif /* _MTK_IMGSYS_PQDIP_H_ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-traw.c b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-traw.c
new file mode 100644
index 000000000000..292f0ad09c46
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-traw.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Author: Shih-Fang Chuang <shih-fang.chuang@mediatek.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include "../mtk_imgsys-module_common.h"
+#include "mtk_imgsys-traw.h"
+
+/********************************************************************
+ * Global Define
+ ********************************************************************/
+#define TRAWCTL_INT1_EN 0x00A0
+
+#define TRAW_INIT_ARRAY_COUNT	ARRAY_SIZE(mtk_imgsys_traw_init_ary)
+
+/********************************************************************
+ * Global Variable
+ ********************************************************************/
+static const struct mtk_imgsys_init_array mtk_imgsys_traw_init_ary[] = {
+	{ TRAWCTL_INT1_EN, 0x80000000 },
+};
+
+static void __iomem *traw_reg_base[MTK_IMGSYS_TRAW_HW_SET];
+
+/********************************************************************
+ * Functions
+ ********************************************************************/
+void imgsys_traw_init(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int i, hw_id, hw_idx;
+	void __iomem *offset = NULL;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_TRAW_HW_SET; hw_idx++) {
+		hw_id = IMGSYS_REG_TRAW1 + hw_idx;
+		traw_reg_base[hw_idx] = of_iomap(imgsys_dev->dev->of_node, hw_id);
+		if (!traw_reg_base[hw_idx]) {
+			dev_info(imgsys_dev->dev,
+				 "%s: error: unable to iomap traw_%d registers, devnode(%s).\n",
+				 __func__, hw_id, imgsys_dev->dev->of_node->name);
+			continue;
+		}
+
+		for (i = 0 ; i < TRAW_INIT_ARRAY_COUNT; i++) {
+			offset = traw_reg_base[hw_idx] + mtk_imgsys_traw_init_ary[i].offset;
+			writel(mtk_imgsys_traw_init_ary[i].value, offset);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_traw_init);
+
+void imgsys_traw_uninit(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int hw_idx;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_TRAW_HW_SET; hw_idx++) {
+		iounmap(traw_reg_base[hw_idx]);
+		traw_reg_base[hw_idx] = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_traw_uninit);
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-traw.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-traw.h
new file mode 100644
index 000000000000..f3727216b58c
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-traw.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Author: Shih-fang Chuang <shih-fang.chuang@mediatek.com>
+ *
+ */
+
+#ifndef _MTK_IMGSYS_TRAW_H_
+#define _MTK_IMGSYS_TRAW_H_
+
+#include "../mtk_imgsys-dev.h"
+
+void imgsys_traw_init(struct mtk_imgsys_dev *imgsys_dev);
+void imgsys_traw_uninit(struct mtk_imgsys_dev *imgsys_dev);
+
+#endif /* _MTK_IMGSYS_TRAW_H_ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-wpe.c b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-wpe.c
new file mode 100644
index 000000000000..b19d61529b80
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-wpe.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Author: Floria Huang <floria.huang@mediatek.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include "../mtk_imgsys-module_common.h"
+#include "mtk_imgsys-wpe.h"
+
+/********************************************************************
+ * Global Define
+ ********************************************************************/
+/* Define register offsets */
+#define WPE_TOP_CTL_INT_EN_OFFSET       0x0018
+#define WPE_TOP_CTL_INT_STATUSX_OFFSET  0x0024
+#define WPE_TOP_CQ_IRQ_EN_OFFSET        0x00D4
+#define WPE_TOP_CQ_IRQ_STX_OFFSET       0x00DC
+#define WPE_TOP_CQ_IRQ_EN2_OFFSET       0x00E0
+#define WPE_TOP_CQ_IRQ_STX2_OFFSET      0x00E8
+#define WPE_TOP_CQ_IRQ_EN3_OFFSET       0x00EC
+#define WPE_TOP_CQ_IRQ_STX3_OFFSET      0x00F4
+#define WPE_CACHE_RWCTL_CTL_OFFSET      0x0204
+#define WPE_DMA_DMA_ERR_CTRL_OFFSET     0x03D4
+#define DIPCQ_W1A_DIPCQ_CQ_THR0_CTL_OFFSET 0x0B08
+#define DIPCQ_W1A_DIPCQ_CQ_THR1_CTL_OFFSET 0x0B18
+#define DIPCQ_W1A_DIPCQ_CQ_THR2_CTL_OFFSET 0x0B28
+#define DIPCQ_W1A_DIPCQ_CQ_THR3_CTL_OFFSET 0x0B38
+#define DIPCQ_W1A_DIPCQ_CQ_THR4_CTL_OFFSET 0x0B48
+#define DIPCQ_W1A_DIPCQ_CQ_THR5_CTL_OFFSET 0x0B58
+#define DIPCQ_W1A_DIPCQ_CQ_THR6_CTL_OFFSET 0x0B68
+#define DIPCQ_W1A_DIPCQ_CQ_THR7_CTL_OFFSET 0x0B78
+#define DIPCQ_W1A_DIPCQ_CQ_THR8_CTL_OFFSET 0x0B88
+#define DIPCQ_W1A_DIPCQ_CQ_THR9_CTL_OFFSET 0x0B98
+#define DIPCQ_W1A_DIPCQ_CQ_THR10_CTL_OFFSET 0x0BA8
+#define DIPCQ_W1A_DIPCQ_CQ_THR11_CTL_OFFSET 0x0BB8
+#define DIPCQ_W1A_DIPCQ_CQ_THR12_CTL_OFFSET 0x0BC8
+#define DIPCQ_W1A_DIPCQ_CQ_THR13_CTL_OFFSET 0x0BD8
+#define DIPCQ_W1A_DIPCQ_CQ_THR14_CTL_OFFSET 0x0BE8
+
+#define WPE_INIT_ARRAY_COUNT	ARRAY_SIZE(mtk_imgsys_wpe_init_ary)
+/********************************************************************
+ * Global Variable
+ ********************************************************************/
+static const struct mtk_imgsys_init_array mtk_imgsys_wpe_init_ary[] = {
+	{ WPE_TOP_CTL_INT_EN_OFFSET, 0x80000000 },
+	{ WPE_TOP_CTL_INT_STATUSX_OFFSET, 0xFFFFFFFF },
+	{ WPE_TOP_CQ_IRQ_EN_OFFSET, 0x80000000 },
+	{ WPE_TOP_CQ_IRQ_STX_OFFSET, 0xFFFFFFFF },
+	{ WPE_TOP_CQ_IRQ_EN2_OFFSET, 0x80000000 },
+	{ WPE_TOP_CQ_IRQ_STX2_OFFSET, 0xFFFFFFFF },
+	{ WPE_TOP_CQ_IRQ_EN3_OFFSET, 0x80000000 },
+	{ WPE_TOP_CQ_IRQ_STX3_OFFSET, 0xFFFFFFFF },
+	{ WPE_CACHE_RWCTL_CTL_OFFSET, 0x00000002 },
+	{ WPE_DMA_DMA_ERR_CTRL_OFFSET, 0x80000000 },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR0_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR1_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR2_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR3_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR4_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR5_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR6_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR7_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR8_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR9_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR10_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR11_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR12_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR13_CTL_OFFSET, CQ_THRX_CTL },
+	{ DIPCQ_W1A_DIPCQ_CQ_THR14_CTL_OFFSET, CQ_THRX_CTL },
+};
+
+static void __iomem *wpe_reg_base[MTK_IMGSYS_WPE_HW_SET];
+
+/********************************************************************
+ * Functions
+ ********************************************************************/
+void imgsys_wpe_init(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int i, hw_id, hw_idx;
+	void __iomem *offset = NULL;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_WPE_HW_SET; hw_idx++) {
+		hw_id = IMGSYS_REG_WPE1 + hw_idx;
+		wpe_reg_base[hw_idx] = of_iomap(imgsys_dev->dev->of_node, hw_id);
+		if (!wpe_reg_base[hw_idx]) {
+			dev_info(imgsys_dev->dev,
+				 "%s: error: unable to iomap wpe_%d registers, devnode(%s).\n",
+				 __func__, hw_id, imgsys_dev->dev->of_node->name);
+			continue;
+		}
+
+		for (i = 0 ; i < WPE_INIT_ARRAY_COUNT; i++) {
+			offset = wpe_reg_base[hw_idx] + mtk_imgsys_wpe_init_ary[i].offset;
+			writel(mtk_imgsys_wpe_init_ary[i].value, offset);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_wpe_init);
+
+void imgsys_wpe_uninit(struct mtk_imgsys_dev *imgsys_dev)
+{
+	unsigned int hw_idx;
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_WPE_HW_SET; hw_idx++) {
+		iounmap(wpe_reg_base[hw_idx]);
+		wpe_reg_base[hw_idx] = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(imgsys_wpe_uninit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek IMGSYS Modules");
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-wpe.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-wpe.h
new file mode 100644
index 000000000000..6001575265e6
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/modules/mtk_imgsys-wpe.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Author: Floria Huang <floria.huang@mediatek.com>
+ *
+ */
+
+#ifndef _MTK_IMGSYS_WPE_H_
+#define _MTK_IMGSYS_WPE_H_
+
+#include "../mtk_imgsys-dev.h"
+
+void imgsys_wpe_init(struct mtk_imgsys_dev *imgsys_dev);
+void imgsys_wpe_uninit(struct mtk_imgsys_dev *imgsys_dev);
+
+#endif /* _MTK_IMGSYS_WPE_H_ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-dev.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-dev.h
index b69cfd0043d3..b8c30cb32b97 100644
--- a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-dev.h
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-dev.h
@@ -23,7 +23,7 @@
 #include <linux/videodev2.h>
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-v4l2.h>
-
+#include "mtk_imgsys-module_ops.h"
 #include "mtk_header_desc.h"
 
 #define MTK_IMGSYS_MEDIA_MODEL_NAME	"MTK-ISP-DIP-V4L2"
@@ -273,6 +273,7 @@ struct mtk_imgsys_pipe {
  * @v4l2_dev: V4L2 device structure for video device operations.
  * @imgsys_pipe: Image system pipeline configuration structure.
  * @cust_pipes: Pointer to custom pipeline descriptors.
+ * @modules: Pointer to image system module operations.
  * @clks: Array of clock bulk data for managing multiple clocks.
  * @num_clks: Number of clocks in the clock array.
  * @larbs: Array of device pointers for managing LARB (local arbiter).
@@ -281,6 +282,9 @@ struct mtk_imgsys_pipe {
  * @rproc_handle: Handle for remote processor interface.
  * @smem_dev: Device structure for shared memory operations.
  * @num_mods: Number of modules in the image system.
+ * @init_kref: Reference counter for initialization tracking.
+ * @hw_op_lock: Mutex for serializing hardware operations.
+ * @stream_cnt: Counter for active streams, increased on stream on.
  */
 struct mtk_imgsys_dev {
 	/* Device and Resource Information */
@@ -292,6 +296,8 @@ struct mtk_imgsys_dev {
 	struct mtk_imgsys_pipe imgsys_pipe;
 	/* Imgsys Pipeline Information */
 	const struct mtk_imgsys_pipe_desc *cust_pipes;
+	/* Imgsys Moudles Information */
+	const struct module_ops *modules;
 	/* Clock Information */
 	struct clk_bulk_data *clks;
 	int num_clks;
@@ -304,6 +310,10 @@ struct mtk_imgsys_dev {
 	struct device *smem_dev;
 	/* Number of modules */
 	int num_mods;
+	/* Synchronization and Flow Control */
+	struct kref init_kref;
+	struct mutex hw_op_lock; /* Protect HW operations */
+	int stream_cnt;
 };
 
 /**
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_common.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_common.h
new file mode 100644
index 000000000000..dd02a8fa28d4
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_common.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Christopher Chen <christopher.chen@mediatek.com>
+ *
+ */
+
+#ifndef _MTK_IMGSYS_CORE_REG_H_
+#define _MTK_IMGSYS_CORE_REG_H_
+
+/**
+ * Define the minimum and maximum hardware IDs
+ * for different MediaTek Image System components
+ */
+#define WPE_HW_MIN_ID	IMGSYS_REG_WPE1
+#define WPE_HW_MAX_ID	IMGSYS_REG_WPE3
+#define TRAW_HW_MIN_ID	IMGSYS_REG_TRAW1
+#define TRAW_HW_MAX_ID	IMGSYS_REG_TRAW3
+#define DIP_HW_MIN_ID	IMGSYS_REG_DIP1
+#define DIP_HW_MAX_ID	IMGSYS_REG_DIP2
+#define PQDIP_HW_MIN_ID	IMGSYS_REG_PQDIP1
+#define PQDIP_HW_MAX_ID	IMGSYS_REG_PQDIP2
+#define ME_HW_MIN_ID	IMGSYS_REG_ME
+#define ME_HW_MAX_ID	IMGSYS_REG_ME
+
+/* Macro to calculate the size of a hardware set */
+#define HW_SET_SIZE(min_id, max_id) ((max_id) - (min_id) + 1)
+
+/* Define the hardware set sizes */
+#define MTK_IMGSYS_WPE_HW_SET	HW_SET_SIZE(WPE_HW_MIN_ID, WPE_HW_MAX_ID)
+#define MTK_IMGSYS_TRAW_HW_SET	HW_SET_SIZE(TRAW_HW_MIN_ID, TRAW_HW_MAX_ID)
+#define MTK_IMGSYS_DIP_HW_SET	HW_SET_SIZE(DIP_HW_MIN_ID, DIP_HW_MAX_ID)
+#define MTK_IMGSYS_PQDIP_HW_SET	HW_SET_SIZE(PQDIP_HW_MIN_ID, PQDIP_HW_MAX_ID)
+#define MTK_IMGSYS_ME_HW_SET	HW_SET_SIZE(ME_HW_MIN_ID, ME_HW_MAX_ID)
+
+/* Define the CQ's control register bits */
+#define CQ_THRX_CTL_EN		BIT(0)
+#define CQ_THRX_CTL_MODE	BIT(4)
+#define CQ_THRX_CTL			(CQ_THRX_CTL_EN | CQ_THRX_CTL_MODE)
+
+/**
+ * enum mtk_imgsys_reg_id
+ *
+ * Definition about hw register map id
+ * The engine order should be the same as register order in dts
+ */
+enum mtk_imgsys_reg_id {
+	IMGSYS_REG_TOP = 0,
+	IMGSYS_REG_TRAW1,
+	IMGSYS_REG_TRAW2,
+	IMGSYS_REG_TRAW3,
+	IMGSYS_REG_DIP1,
+	IMGSYS_REG_DIP2,
+	IMGSYS_REG_PQDIP1,
+	IMGSYS_REG_PQDIP2,
+	IMGSYS_REG_WPE1,
+	IMGSYS_REG_WPE2,
+	IMGSYS_REG_WPE3,
+	IMGSYS_REG_WPE1_DIP1,
+	IMGSYS_REG_ME,
+	IMGSYS_REG_WPE2_DIP1,
+	IMGSYS_REG_WPE3_DIP1,
+	IMGSYS_REG_DIP1_TOP,
+	IMGSYS_REG_DIP2_TOP
+};
+
+/**
+ * struct mtk_imgsys_init_array - Array structure for initializing registers
+ * @offset: Offset of the register
+ * @val: Value to be written to the register
+ *
+ * This structure represents an array element used for initializing registers
+ * in the MediaTek Image System. Each element contains the offset of the register
+ * and the value to be written to that register.
+ */
+struct mtk_imgsys_init_array {
+	unsigned int    offset;
+	unsigned int    value;
+};
+#endif /* _MTK_IMGSYS_CORE_REG_H_ */
+
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_main.c b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_main.c
new file mode 100644
index 000000000000..5daa8f863bd2
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_main.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Christopher Chen <christopher.chen@mediatek.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include "mtk_imgsys-module_common.h"
+#include "mtk_imgsys-module_main.h"
+
+/********************************************************************
+ * Global Define
+ ********************************************************************/
+/* Define the reset register bits */
+#define SW_RST				(0x000C)
+
+/********************************************************************
+ * Global Variable
+ ********************************************************************/
+static void __iomem *imgsys_main_reg_base;
+static void __iomem *wpe_dip1_reg_base;
+static void __iomem *wpe_dip2_reg_base;
+static void __iomem *wpe_dip3_reg_base;
+static void __iomem *dip1_reg_base;
+static void __iomem *dip2_reg_base;
+
+/********************************************************************
+ * Functions
+ ********************************************************************/
+static void imgsys_main_hw_init(struct mtk_imgsys_dev *imgsys_dev)
+{
+	void __iomem *wpe_reg_base = NULL;
+	void __iomem *wpe_ctrl = NULL;
+	unsigned int hw_idx = 0;
+
+	/* Enable all LARBs of ImgSys */
+	/**
+	 * The flow will be updated based on the patch series 958467 from
+	 * the Linux MediaTek project. For more details, refer to the following link:
+	 * https://patchwork.kernel.org/project/linux-mediatek/list/?series=958467
+	 */
+
+	/* Reset ImgSys hardware */
+	iowrite32(0xFFFFFFFF, dip1_reg_base + SW_RST);
+	iowrite32(0xFFFFFFFF, dip2_reg_base + SW_RST);
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_WPE_HW_SET; hw_idx++) {
+		if (hw_idx == 0)
+			wpe_reg_base = wpe_dip1_reg_base;
+		else if (hw_idx == 1)
+			wpe_reg_base = wpe_dip2_reg_base;
+		else
+			wpe_reg_base = wpe_dip3_reg_base;
+
+		wpe_ctrl = wpe_reg_base + SW_RST;
+		iowrite32(0xFFFFFFFF, wpe_ctrl);
+		iowrite32(0x0, wpe_ctrl);
+	}
+
+	iowrite32(0x00CF00FF, imgsys_main_reg_base + SW_RST);
+	iowrite32(0x0, imgsys_main_reg_base + SW_RST);
+
+	iowrite32(0x0, dip1_reg_base + SW_RST);
+	iowrite32(0x0, dip2_reg_base + SW_RST);
+
+	for (hw_idx = 0; hw_idx < MTK_IMGSYS_WPE_HW_SET; hw_idx++) {
+		if (hw_idx == 0)
+			wpe_reg_base = wpe_dip1_reg_base;
+		else if (hw_idx == 1)
+			wpe_reg_base = wpe_dip2_reg_base;
+		else
+			wpe_reg_base = wpe_dip3_reg_base;
+
+		wpe_ctrl = wpe_reg_base + SW_RST;
+		iowrite32(0xFFFFFFFF, wpe_ctrl);
+		iowrite32(0x0, wpe_ctrl);
+	}
+
+	iowrite32(0x00CF00FF, imgsys_main_reg_base + SW_RST);
+	iowrite32(0x0, imgsys_main_reg_base + SW_RST);
+
+	/* Disable all LARBs of ImgSys*/
+	/**
+	 * The flow will be updated based on the patch series 958467 from
+	 * the Linux MediaTek project. For more details, refer to the following link:
+	 * https://patchwork.kernel.org/project/linux-mediatek/list/?series=958467
+	 */
+}
+
+void imgsys_main_init(struct mtk_imgsys_dev *imgsys_dev)
+{
+	imgsys_main_reg_base = of_iomap(imgsys_dev->dev->of_node, IMGSYS_REG_TOP);
+	if (!imgsys_main_reg_base) {
+		dev_info(imgsys_dev->dev, "%s Unable to ioremap imgsys_top registers\n",
+			 __func__);
+		dev_info(imgsys_dev->dev, "%s of_iomap fail, devnode(%s).\n",
+			 __func__, imgsys_dev->dev->of_node->name);
+		return;
+	}
+
+	wpe_dip1_reg_base = of_iomap(imgsys_dev->dev->of_node, IMGSYS_REG_WPE1_DIP1);
+	if (!wpe_dip1_reg_base) {
+		dev_info(imgsys_dev->dev, "%s Unable to ioremap wpe_dip1 registers\n",
+			 __func__);
+		dev_info(imgsys_dev->dev, "%s of_iomap fail, devnode(%s).\n",
+			 __func__, imgsys_dev->dev->of_node->name);
+		return;
+	}
+
+	wpe_dip2_reg_base = of_iomap(imgsys_dev->dev->of_node, IMGSYS_REG_WPE2_DIP1);
+	if (!wpe_dip2_reg_base) {
+		dev_info(imgsys_dev->dev, "%s Unable to ioremap wpe_dip2 registers\n",
+			 __func__);
+		dev_info(imgsys_dev->dev, "%s of_iomap fail, devnode(%s).\n",
+			 __func__, imgsys_dev->dev->of_node->name);
+		return;
+	}
+
+	wpe_dip3_reg_base = of_iomap(imgsys_dev->dev->of_node, IMGSYS_REG_WPE3_DIP1);
+	if (!wpe_dip3_reg_base) {
+		dev_info(imgsys_dev->dev, "%s Unable to ioremap wpe_dip3 registers\n",
+			 __func__);
+		dev_info(imgsys_dev->dev, "%s of_iomap fail, devnode(%s).\n",
+			 __func__, imgsys_dev->dev->of_node->name);
+		return;
+	}
+
+	dip1_reg_base = of_iomap(imgsys_dev->dev->of_node, IMGSYS_REG_DIP1_TOP);
+	if (!dip1_reg_base) {
+		dev_info(imgsys_dev->dev, "%s Unable to ioremap dip_top registers\n",
+			 __func__);
+		dev_info(imgsys_dev->dev, "%s of_iomap fail, devnode(%s).\n",
+			 __func__, imgsys_dev->dev->of_node->name);
+		return;
+	}
+
+	dip2_reg_base = of_iomap(imgsys_dev->dev->of_node, IMGSYS_REG_DIP2_TOP);
+	if (!dip2_reg_base) {
+		dev_info(imgsys_dev->dev, "%s Unable to ioremap dip_top_nr registers\n",
+			 __func__);
+		dev_info(imgsys_dev->dev, "%s of_iomap fail, devnode(%s).\n",
+			 __func__, imgsys_dev->dev->of_node->name);
+		return;
+	}
+
+	imgsys_main_hw_init(imgsys_dev);
+}
+
+void imgsys_main_uninit(struct mtk_imgsys_dev *imgsys_dev)
+{
+	if (imgsys_main_reg_base) {
+		iounmap(imgsys_main_reg_base);
+		imgsys_main_reg_base = NULL;
+	}
+
+	if (wpe_dip1_reg_base) {
+		iounmap(wpe_dip1_reg_base);
+		wpe_dip1_reg_base = NULL;
+	}
+
+	if (wpe_dip2_reg_base) {
+		iounmap(wpe_dip2_reg_base);
+		wpe_dip2_reg_base = NULL;
+	}
+
+	if (wpe_dip3_reg_base) {
+		iounmap(wpe_dip3_reg_base);
+		wpe_dip3_reg_base = NULL;
+	}
+
+	if (dip1_reg_base) {
+		iounmap(dip1_reg_base);
+		dip1_reg_base = NULL;
+	}
+
+	if (dip2_reg_base) {
+		iounmap(dip2_reg_base);
+		dip2_reg_base = NULL;
+	}
+}
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_main.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_main.h
new file mode 100644
index 000000000000..2a3fbd08d128
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_main.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Christopher Chen <christopher.chen@mediatek.com>
+ *
+ */
+
+#ifndef _MTK_IMGSYS_DEBUG_H_
+#define _MTK_IMGSYS_DEBUG_H_
+
+#include "mtk_imgsys-dev.h"
+
+void imgsys_main_init(struct mtk_imgsys_dev *imgsys_dev);
+void imgsys_main_uninit(struct mtk_imgsys_dev *imgsys_dev);
+
+#endif /* _MTK_IMGSYS_DEBUG_H_ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_ops.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_ops.h
index 6dc4b7b60832..a2eea8f4fb3c 100644
--- a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_ops.h
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-module_ops.h
@@ -24,4 +24,30 @@ enum mtk_imgsys_module {
 	IMGSYS_MOD_MAX,
 };
 
+struct mtk_imgsys_dev;
+
+/**
+ * struct module_ops - Operations for a specific module in the MediaTek Image System
+ * @module_id: Identifier for the module.
+ * @init: Function pointer to initialize the module.
+ *        This function sets the default values for various software-related
+ *        parameters and ensures that the module is ready for operation.
+ *        Example function: imgsys_dip_init
+ * @uninit: Function pointer to uninitialize the module.
+ *          This function resets various software-related parameters to ensure
+ *          the module is properly cleaned up and ready for shutdown.
+ *          Example function: imgsys_dip_uninit
+ *
+ * This structure defines a set of operations for specific modules within the
+ * MediaTek Image System, such as WPE (Warping Engine), TRAW (Tile-Raw),
+ * DIP (Digital Image Processing), PQDIP (Picture Quality Digital Image
+ * Processing), and ME (Motion Estimation). Each module is identified by
+ * a unique identifier and includes function pointers for operations like
+ * initialization and deinitialization.
+ */
+struct module_ops {
+	int module_id;
+	void (*init)(struct mtk_imgsys_dev *imgsys_dev);
+	void (*uninit)(struct mtk_imgsys_dev *imgsys_dev);
+};
 #endif /* _MTK_IMGSYS_MODULES_H_ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-of.h b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-of.h
index 5088c9df704c..f34ea9465745 100644
--- a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-of.h
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-of.h
@@ -12,6 +12,7 @@
 
 #include <linux/clk.h>
 #include "mtk_imgsys-dev.h"
+#include "mtk_imgsys-module_ops.h"
 
 /**
  * struct mtk_imgsys_mod_pipe_desc - Description of a module's pipeline
@@ -31,6 +32,7 @@ struct mtk_imgsys_mod_pipe_desc {
  * @mod_num: Number of modules in the pipeline.
  * @pipe_settings: Pointer to pipeline settings for the module.
  * @pipe_num: Number of pipeline settings.
+ * @imgsys_modules: Pointer to module operations for image system modules.
  */
 struct cust_data {
 	struct clk_bulk_data *clks;
@@ -39,6 +41,7 @@ struct cust_data {
 	unsigned int mod_num;
 	const struct mtk_imgsys_pipe_desc *pipe_settings;
 	unsigned int pipe_num;
+	const struct module_ops *imgsys_modules;
 };
 
 /**
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-sys.c b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-sys.c
index 9cdcdb0a0200..9f118491b37d 100644
--- a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-sys.c
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-sys.c
@@ -6,7 +6,45 @@
  *
  */
 
+#include <linux/pm_runtime.h>
 #include "mtk_imgsys-sys.h"
+#include "mtk_imgsys-dev.h"
+
+static int mtk_imgsys_hw_connect(struct mtk_imgsys_dev *imgsys_dev)
+{
+	int ret, i;
+
+	ret = pm_runtime_get_sync(imgsys_dev->dev);
+	if (ret < 0) {
+		dev_err(imgsys_dev->dev, "Failed to sync runtime PM: %d\n", ret);
+		return ret;
+	}
+
+	/* Set default value for hardware modules */
+	for (i = 0; i < (imgsys_dev->num_mods); i++)
+		imgsys_dev->modules[i].init(imgsys_dev);
+
+	kref_init(&imgsys_dev->init_kref);
+
+	return 0;
+}
+
+static void module_uninit(struct kref *kref)
+{
+	struct mtk_imgsys_dev *imgsys_dev;
+	int i;
+
+	imgsys_dev = container_of(kref, struct mtk_imgsys_dev, init_kref);
+
+	for (i = 0; i < (imgsys_dev->num_mods); i++)
+		if (imgsys_dev->modules[i].uninit)
+			imgsys_dev->modules[i].uninit(imgsys_dev);
+}
+
+static void mtk_imgsys_hw_disconnect(struct mtk_imgsys_dev *imgsys_dev)
+{
+	kref_put(&imgsys_dev->init_kref, module_uninit);
+}
 
 void mtk_imgsys_hw_enqueue(struct mtk_imgsys_dev *imgsys_dev,
 			   struct mtk_imgsys_request *req)
@@ -16,12 +54,43 @@ void mtk_imgsys_hw_enqueue(struct mtk_imgsys_dev *imgsys_dev,
 
 int mtk_imgsys_hw_streamon(struct mtk_imgsys_pipe *pipe)
 {
-	/* Function implementation will be provided in subsequent patches */
+	struct mtk_imgsys_dev *imgsys_dev = pipe->imgsys_dev;
+	int ret;
+
+	mutex_lock(&imgsys_dev->hw_op_lock);
+	if (!imgsys_dev->stream_cnt) {
+		ret = mtk_imgsys_hw_connect(pipe->imgsys_dev);
+		if (ret) {
+			dev_info(pipe->imgsys_dev->dev,
+				 "%s:%s: pipe(%d) connect to dip_hw failed\n",
+				 __func__, pipe->desc->name, pipe->desc->id);
+			mutex_unlock(&imgsys_dev->hw_op_lock);
+			return ret;
+		}
+	}
+	imgsys_dev->stream_cnt++;
+	mutex_unlock(&imgsys_dev->hw_op_lock);
+
+	dev_dbg(pipe->imgsys_dev->dev,
+		"%s:%s: stream on, id(%d), stream cnt(%d)\n",
+		__func__, pipe->desc->name, pipe->desc->id, imgsys_dev->stream_cnt);
+
 	return 0;
 }
 
 int mtk_imgsys_hw_streamoff(struct mtk_imgsys_pipe *pipe)
 {
-	/* Function implementation will be provided in subsequent patches */
+	struct mtk_imgsys_dev *imgsys_dev = pipe->imgsys_dev;
+
+	dev_dbg(pipe->imgsys_dev->dev,
+		"%s:%s: stream off, id(%d), stream cnt(%d)\n",
+		__func__, pipe->desc->name, pipe->desc->id, imgsys_dev->stream_cnt);
+
+	mutex_lock(&imgsys_dev->hw_op_lock);
+	imgsys_dev->stream_cnt--;
+	if (!imgsys_dev->stream_cnt)
+		mtk_imgsys_hw_disconnect(imgsys_dev);
+	mutex_unlock(&imgsys_dev->hw_op_lock);
+
 	return 0;
 }
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-v4l2.c b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-v4l2.c
index 919c69493bbc..e25f17b98649 100644
--- a/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-v4l2.c
+++ b/drivers/media/platform/mediatek/isp/isp_7x/imgsys/mtk_imgsys-v4l2.c
@@ -18,8 +18,13 @@
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-event.h>
 #include "linux/mtkisp_imgsys.h"
-#include "mtk_imgsys-of.h"
 #include "mtk_imgsys-module_ops.h"
+#include "mtk_imgsys-module_main.h"
+#include "modules/mtk_imgsys-dip.h"
+#include "modules/mtk_imgsys-traw.h"
+#include "modules/mtk_imgsys-pqdip.h"
+#include "modules/mtk_imgsys-wpe.h"
+#include "mtk_imgsys-of.h"
 #include "mtk_imgsys-vnode_id.h"
 #include "mtk_imgsys_v4l2_vnode.h"
 #include "mtk_imgsys-dev.h"
@@ -1499,6 +1504,7 @@ static int mtk_imgsys_probe(struct platform_device *pdev)
 	init_imgsys_pipeline(data);
 
 	imgsys_dev->cust_pipes = data->pipe_settings;
+	imgsys_dev->modules = data->imgsys_modules;
 	imgsys_dev->dev = &pdev->dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1511,6 +1517,8 @@ static int mtk_imgsys_probe(struct platform_device *pdev)
 	dev_set_drvdata(&pdev->dev, imgsys_dev);
 
 	imgsys_dev->num_mods = data->mod_num;
+	imgsys_dev->stream_cnt = 0;
+	mutex_init(&imgsys_dev->hw_op_lock);
 
 	/* Get Clocks */
 	imgsys_dev->clks = data->clks;
@@ -1613,6 +1621,7 @@ static void mtk_imgsys_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 	platform_driver_unregister(&mtk_imgsys_larb_driver);
 	mtk_imgsys_dev_v4l2_release(imgsys_dev);
+	mutex_destroy(&imgsys_dev->hw_op_lock);
 	devm_kfree(&pdev->dev, imgsys_dev->larbs);
 	devm_kfree(&pdev->dev, imgsys_dev);
 }
@@ -1709,6 +1718,39 @@ static struct clk_bulk_data imgsys_isp7_clks[] = {
 	{ .id = "ME_CG_LARB12" },
 };
 
+static const struct module_ops imgsys_isp7_modules[] = {
+	[IMGSYS_MOD_IMGMAIN] = {
+		.module_id = IMGSYS_MOD_IMGMAIN,
+		.init = imgsys_main_init,
+		.uninit = imgsys_main_uninit,
+	},
+	[IMGSYS_MOD_WPE] = {
+		.module_id = IMGSYS_MOD_WPE,
+		.init = imgsys_wpe_init,
+		.uninit = imgsys_wpe_uninit,
+	},
+	[IMGSYS_MOD_TRAW] = {
+		.module_id = IMGSYS_MOD_TRAW,
+		.init = imgsys_traw_init,
+		.uninit = imgsys_traw_uninit,
+	},
+	[IMGSYS_MOD_DIP] = {
+		.module_id = IMGSYS_MOD_DIP,
+		.init = imgsys_dip_init,
+		.uninit = imgsys_dip_uninit,
+	},
+	[IMGSYS_MOD_PQDIP] = {
+		.module_id = IMGSYS_MOD_PQDIP,
+		.init = imgsys_pqdip_init,
+		.uninit = imgsys_pqdip_uninit,
+	},
+	[IMGSYS_MOD_ME] = {
+		.module_id = IMGSYS_MOD_ME,
+		.init = NULL,
+		.uninit = NULL,
+	},
+};
+
 static const struct cust_data imgsys_data[] = {
 	[0] = {
 		.clks = imgsys_isp7_clks,
@@ -1717,6 +1759,7 @@ static const struct cust_data imgsys_data[] = {
 		.mod_num = ARRAY_SIZE(module_pipe_isp7),
 		.pipe_settings = pipe_settings_isp7,
 		.pipe_num = ARRAY_SIZE(pipe_settings_isp7),
+		.imgsys_modules = imgsys_isp7_modules,
 	},
 };
 
