Merge "feat(mediatek): add vcp driver support" into integration
diff --git a/plat/mediatek/drivers/vcp/mt8196/vcp_helper.h b/plat/mediatek/drivers/vcp/mt8196/vcp_helper.h
new file mode 100644
index 0000000..3d87d40
--- /dev/null
+++ b/plat/mediatek/drivers/vcp/mt8196/vcp_helper.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VCP_HELPER_H
+#define VCP_HELPER_H
+
+#define MTK_VCP_SRAM_SIZE		(0x60000)
+
+/* Export extern API */
+uint32_t get_mmup_fw_size(void);
+uint64_t get_mmup_l2tcm_offset(void);
+
+/* SMC calls OPS */
+enum mtk_tinysys_vcp_kernel_op {
+	MTK_TINYSYS_VCP_KERNEL_OP_RESET_SET = 0,
+	MTK_TINYSYS_VCP_KERNEL_OP_RESET_RELEASE,
+	MTK_TINYSYS_VCP_KERNEL_OP_COLD_BOOT_VCP,
+	MTK_TINYSYS_MMUP_KERNEL_OP_RESET_SET,
+	MTK_TINYSYS_MMUP_KERNEL_OP_RESET_RELEASE,
+	MTK_TINYSYS_MMUP_KERNEL_OP_SET_L2TCM_OFFSET,
+	MTK_TINYSYS_MMUP_KERNEL_OP_SET_FW_SIZE,
+	MTK_TINYSYS_MMUP_KERNEL_OP_COLD_BOOT_MMUP,
+	MTK_TINYSYS_VCP_KERNEL_OP_NUM,
+};
+
+#endif /* VCP_HELPER_H */
diff --git a/plat/mediatek/drivers/vcp/mt8196/vcp_reg.h b/plat/mediatek/drivers/vcp/mt8196/vcp_reg.h
new file mode 100644
index 0000000..4aa8332
--- /dev/null
+++ b/plat/mediatek/drivers/vcp/mt8196/vcp_reg.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VCP_REG_H
+#define VCP_REG_H
+
+#include <platform_def.h>
+
+#define MTK_VCP_REG_BASE		(IO_PHYS + 0x21800000)
+#define MTK_VCP_REG_BANK_SIZE		(0x1000)
+
+/*******************************************************************************
+ * VCP power related setting
+ ******************************************************************************/
+#define VCP_POWER_STATUS		(0xE60)
+#define MMUP_PWR_STA_BIT		(30)
+#define MMUP_PWR_STA_EN			((uint32_t)(0x3))
+
+/*******************************************************************************
+ * VCP registers
+ ******************************************************************************/
+/* cfgreg */
+#define VCP_R_CFGREG			(MTK_VCP_REG_BASE + 0x3d0000)
+
+#define VCP_R_CORE0_SW_RSTN_CLR		(VCP_R_CFGREG + 0x0000)
+#define VCP_R_CORE0_SW_RSTN_SET		(VCP_R_CFGREG + 0x0004)
+#define VCP_R_CORE1_SW_RSTN_CLR		(VCP_R_CFGREG + 0x0008)
+#define VCP_R_CORE1_SW_RSTN_SET		(VCP_R_CFGREG + 0x000c)
+#define VCP_R_GIPC_IN_SET		(VCP_R_CFGREG + 0x0028)
+#define VCP_R_GIPC_IN_CLR		(VCP_R_CFGREG + 0x002c)
+#define B_GIPC3_SETCLR_1		BIT(13)
+
+/* cfgreg_core0 */
+#define VCP_R_CFGREG_CORE0		(MTK_VCP_REG_BASE + 0x20a000)
+
+#define VCP_R_CORE0_STATUS		(VCP_R_CFGREG_CORE0 + 0x0070)
+
+#define CORE0_R_GPR5			(VCP_R_CFGREG_CORE0 + 0x0054)
+#define VCP_GPR_C0_H0_REBOOT		CORE0_R_GPR5
+#define CORE0_R_GPR6			(VCP_R_CFGREG_CORE0 + 0x0058)
+#define VCP_GPR_C0_H1_REBOOT		CORE0_R_GPR6
+#define VCP_CORE_RDY_TO_REBOOT		(0x34)
+#define VCP_CORE_REBOOT_OK		BIT(0)
+
+/* cfgreg_core1 */
+#define VCP_R_CFGREG_CORE1		(MTK_VCP_REG_BASE + 0x20d000)
+
+#define VCP_R_CORE1_STATUS		(VCP_R_CFGREG_CORE1 + 0x0070)
+#define CORE1_R_GPR5			(VCP_R_CFGREG_CORE1 + 0x0054)
+#define VCP_GPR_CORE1_REBOOT		CORE1_R_GPR5
+
+/* sec */
+#define VCP_R_SEC_CTRL			(MTK_VCP_REG_BASE + 0x270000)
+#define VCP_OFFSET_ENABLE_P		BIT(13)
+#define VCP_OFFSET_ENABLE_B		BIT(12)
+#define VCP_R_SEC_CTRL_2		(VCP_R_SEC_CTRL + 0x0004)
+#define CORE0_SEC_BIT_SEL		BIT(0)
+#define CORE1_SEC_BIT_SEL		BIT(8)
+#define VCP_GPR0_CFGREG_SEC		(VCP_R_SEC_CTRL + 0x0040)
+#define VCP_GPR1_CFGREG_SEC		(VCP_R_SEC_CTRL + 0x0044)
+#define VCP_GPR2_CFGREG_SEC		(VCP_R_SEC_CTRL + 0x0048)
+#define VCP_GPR3_CFGREG_SEC		(VCP_R_SEC_CTRL + 0x004C)
+#define VCP_R_SEC_DOMAIN		(VCP_R_SEC_CTRL + 0x0080)
+#define VCP_DOMAIN_ID			U(13)
+#define VCP_DOMAIN_MASK			U(0xF)
+#define VCP_CORE0_TH0_PM_AXI_DOMAIN	(0)
+#define VCP_CORE0_TH0_DM_AXI_DOMAIN	(4)
+#define VCP_S_DMA0_DOMAIN		(12)
+#define VCP_HWCCF_DOMAIN		(16)
+#define VCP_CORE0_TH1_PM_AXI_DOMAIN	(20)
+#define VCP_CORE0_TH1_DM_AXI_DOMAIN	(24)
+#define VCP_DOMAIN_SET			((VCP_DOMAIN_ID << VCP_CORE0_TH0_PM_AXI_DOMAIN) | \
+					 (VCP_DOMAIN_ID << VCP_CORE0_TH0_DM_AXI_DOMAIN) | \
+					 (VCP_DOMAIN_ID << VCP_CORE0_TH1_PM_AXI_DOMAIN) | \
+					 (VCP_DOMAIN_ID << VCP_CORE0_TH1_DM_AXI_DOMAIN) | \
+					 (VCP_DOMAIN_ID << VCP_S_DMA0_DOMAIN))
+#define VCP_R_SEC_DOMAIN_MMPC		(VCP_R_SEC_CTRL + 0x0084)
+#define VCP_CORE_MMPC_PM_AXI_DOMAIN	(0)
+#define VCP_CORE_MMPC_DM_AXI_DOMAIN	(4)
+#define VCP_DOMAIN_SET_MMPC		((VCP_DOMAIN_ID << VCP_CORE_MMPC_PM_AXI_DOMAIN) | \
+					(VCP_DOMAIN_ID << VCP_CORE_MMPC_DM_AXI_DOMAIN))
+#define R_L2TCM_OFFSET_RANGE_0_LOW	(VCP_R_SEC_CTRL + 0x00B0)
+#define R_L2TCM_OFFSET_RANGE_0_HIGH	(VCP_R_SEC_CTRL + 0x00B4)
+#define R_L2TCM_OFFSET			(VCP_R_SEC_CTRL + 0x00D0)
+#define VCP_R_DYN_SECURE		(VCP_R_SEC_CTRL + 0x01d0)
+#define VCP_NS_I0			BIT(4)
+#define VCP_NS_D0			BIT(6)
+#define VCP_NS_SECURE_B_REGION_ENABLE	(24)
+#define RESET_NS_SECURE_B_REGION	U(0xFF)
+#define VCP_R_DYN_SECURE_TH1		(VCP_R_SEC_CTRL + 0x01d4)
+#define VCP_NS_I1			BIT(5)
+#define VCP_NS_D1			BIT(7)
+#define VCP_R_S_DOM_EN0_31		(VCP_R_SEC_CTRL + 0x0200)
+#define VCP_R_S_DOM_EN32_63		(VCP_R_SEC_CTRL + 0x0204)
+#define VCP_R_NS_DOM_EN0_31		(VCP_R_SEC_CTRL + 0x0208)
+#define VCP_R_NS_DOM_EN32_63		(VCP_R_SEC_CTRL + 0x020c)
+/* IOMMU */
+#define VCP_R_AXIOMMUEN_DEV_APC		(VCP_R_SEC_CTRL + 0x0088)
+#define VCP_R_CFG_DEVAPC_AO_BASE	(MTK_VCP_REG_BASE + 0x2d0000)
+
+#endif /* VCP_REG_H */
diff --git a/plat/mediatek/drivers/vcp/rules.mk b/plat/mediatek/drivers/vcp/rules.mk
new file mode 100644
index 0000000..9e342de
--- /dev/null
+++ b/plat/mediatek/drivers/vcp/rules.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2024, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := vcp
+
+SUB_RULES-y := $(LOCAL_DIR)/rv
+
+$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
diff --git a/plat/mediatek/drivers/vcp/rv/mmup_common.c b/plat/mediatek/drivers/vcp/rv/mmup_common.c
new file mode 100644
index 0000000..a6d0819
--- /dev/null
+++ b/plat/mediatek/drivers/vcp/rv/mmup_common.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "mmup_common.h"
+#include "vcp_helper.h"
+#include "vcp_reg.h"
+
+#define MODULE_TAG "[MMUP]"
+
+bool mmup_smc_rstn_set(bool boot_ok)
+{
+	if (mmio_read_32(VCP_GPR_CORE1_REBOOT) != 0 &&
+	    mmio_read_32(VCP_R_CORE1_STATUS) != 0 &&
+	    (mmio_read_32(VCP_R_GIPC_IN_SET) & B_GIPC3_SETCLR_1) == 0 &&
+	    (mmio_read_32(VCP_R_GIPC_IN_CLR) & B_GIPC3_SETCLR_1) == 0 &&
+	    mmio_read_32(VCP_GPR_CORE1_REBOOT) != VCP_CORE_RDY_TO_REBOOT) {
+		ERROR("%s: [%s] mmup reset set fail!GIPC 0x%x 0x%x REBOOT 0x%x\n",
+		      MODULE_TAG, __func__, mmio_read_32(VCP_R_GIPC_IN_SET),
+		      mmio_read_32(VCP_R_GIPC_IN_CLR),
+		      mmio_read_32(VCP_GPR_CORE1_REBOOT));
+		return false;
+	}
+
+	mmio_write_32(VCP_R_CORE1_SW_RSTN_SET, BIT(0));
+
+	/* reset sec control */
+	mmio_write_32(VCP_R_SEC_CTRL_2, 0);
+
+	/* reset domain setting */
+	mmio_write_32(VCP_R_S_DOM_EN0_31, 0x0);
+	mmio_write_32(VCP_R_S_DOM_EN32_63, 0x0);
+	mmio_write_32(VCP_R_NS_DOM_EN0_31, 0x0);
+	mmio_write_32(VCP_R_NS_DOM_EN32_63, 0x0);
+
+	/* reset sec setting */
+	mmio_clrbits_32(VCP_R_DYN_SECURE,
+			RESET_NS_SECURE_B_REGION << VCP_NS_SECURE_B_REGION_ENABLE);
+
+	if (boot_ok)
+		mmio_write_32(VCP_GPR_CORE1_REBOOT, VCP_CORE_REBOOT_OK);
+
+	dsbsy();
+	return true;
+}
+
+bool mmup_smc_rstn_clr(void)
+{
+	if ((mmio_read_32(VCP_R_CORE1_SW_RSTN_SET) & BIT(0)) == 1) {
+		ERROR("%s: [%s] mmup not reset set !\n", MODULE_TAG, __func__);
+		return false;
+	}
+
+	if ((get_mmup_fw_size() == 0) || get_mmup_l2tcm_offset() == 0) {
+		ERROR("%s: [%s] mmup no enough l2tcm to run !\n", MODULE_TAG, __func__);
+		return false;
+	}
+
+	mmio_write_32(VCP_R_SEC_DOMAIN_MMPC, VCP_DOMAIN_SET_MMPC);
+
+	/* enable IOVA Mode */
+	mmio_write_32(VCP_R_AXIOMMUEN_DEV_APC, BIT(0));
+
+	/* reset secure setting */
+	mmio_setbits_32(VCP_R_SEC_CTRL_2, CORE1_SEC_BIT_SEL);
+
+	/* l2tcm offset*/
+	mmio_setbits_32(VCP_R_SEC_CTRL, VCP_OFFSET_ENABLE_P | VCP_OFFSET_ENABLE_B);
+	mmio_write_32(R_L2TCM_OFFSET_RANGE_0_LOW, 0x0);
+	mmio_write_32(R_L2TCM_OFFSET_RANGE_0_HIGH, round_up(get_mmup_fw_size(), PAGE_SIZE));
+	mmio_write_32(R_L2TCM_OFFSET, get_mmup_l2tcm_offset());
+
+	/* start vcp-mmup */
+	mmio_write_32(VCP_R_CORE1_SW_RSTN_CLR, BIT(0));
+	dsbsy();
+	return true;
+}
diff --git a/plat/mediatek/drivers/vcp/rv/mmup_common.h b/plat/mediatek/drivers/vcp/rv/mmup_common.h
new file mode 100644
index 0000000..e70d25f
--- /dev/null
+++ b/plat/mediatek/drivers/vcp/rv/mmup_common.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MMUP_COMMON_H
+#define MMUP_COMMON_H
+
+bool mmup_smc_rstn_set(bool boot_ok);
+bool mmup_smc_rstn_clr(void);
+
+#endif /* MMUP_COMMON_H */
diff --git a/plat/mediatek/drivers/vcp/rv/rules.mk b/plat/mediatek/drivers/vcp/rv/rules.mk
new file mode 100644
index 0000000..e637067
--- /dev/null
+++ b/plat/mediatek/drivers/vcp/rv/rules.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2024, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := vcp_rv_${MTK_SOC}
+
+PLAT_INCLUDES += -I${MTK_PLAT}/drivers/vcp/${MTK_SOC}
+
+LOCAL_SRCS-${CONFIG_MTK_TINYSYS_VCP} := ${LOCAL_DIR}/vcp_common.c
+LOCAL_SRCS-${CONFIG_MTK_TINYSYS_VCP} += ${LOCAL_DIR}/mmup_common.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/vcp/rv/vcp_common.c b/plat/mediatek/drivers/vcp/rv/vcp_common.c
new file mode 100644
index 0000000..9dfb133
--- /dev/null
+++ b/plat/mediatek/drivers/vcp/rv/vcp_common.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2024, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <smccc_helpers.h>
+
+#include "mmup_common.h"
+#include <mtk_mmap_pool.h>
+#include <mtk_sip_svc.h>
+#include "vcp_helper.h"
+#include "vcp_reg.h"
+
+#define MODULE_TAG "[VCP]"
+
+static const mmap_region_t vcp_mmap[] MTK_MMAP_SECTION = {
+	MAP_REGION_FLAT(VCP_R_CFGREG, MTK_VCP_REG_BANK_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(VCP_R_CFGREG_CORE0, MTK_VCP_REG_BANK_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(VCP_R_CFGREG_CORE1, MTK_VCP_REG_BANK_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(VCP_R_SEC_CTRL, MTK_VCP_REG_BANK_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	{0}
+};
+DECLARE_MTK_MMAP_REGIONS(vcp_mmap);
+
+/* vcp-mmup l2tcm memory offset */
+static uint64_t g_l2tcm_offset;
+static uint32_t g_mmup_fw_size;
+
+static bool get_vcp_pwr_status(void)
+{
+#if defined(SPM_BASE)
+	uint32_t spm_pwr_sta = mmio_read_32(SPM_BASE + VCP_POWER_STATUS);
+
+	if (!(spm_pwr_sta & (MMUP_PWR_STA_EN << MMUP_PWR_STA_BIT))) {
+		ERROR("%s: pwr_sta:%x, bit:%d disable\n", MODULE_TAG,
+		      spm_pwr_sta, MMUP_PWR_STA_BIT);
+		return false;
+	}
+#endif
+	return true;
+}
+
+uint32_t get_mmup_fw_size(void)
+{
+	return g_mmup_fw_size;
+}
+
+uint64_t get_mmup_l2tcm_offset(void)
+{
+	return g_l2tcm_offset;
+}
+
+static bool vcp_cold_boot_reset(void)
+{
+	mmio_write_32(VCP_GPR2_CFGREG_SEC, 0);
+	mmio_write_32(VCP_GPR3_CFGREG_SEC, 0);
+
+	return true;
+}
+
+static bool mmup_cold_boot_reset(void)
+{
+	mmio_write_32(VCP_GPR0_CFGREG_SEC, 0);
+	mmio_write_32(VCP_GPR1_CFGREG_SEC, 0);
+
+	return true;
+}
+
+static bool vcp_set_mmup_l2tcm_offset(uint64_t l2tcm_offset)
+{
+	g_l2tcm_offset = l2tcm_offset;
+
+	if (g_l2tcm_offset > MTK_VCP_SRAM_SIZE) {
+		g_l2tcm_offset = 0;
+		return false;
+	}
+
+	return true;
+}
+
+static bool vcp_set_mmup_fw_size(uint64_t fw_size)
+{
+	g_mmup_fw_size = fw_size;
+
+	if (g_mmup_fw_size > MTK_VCP_SRAM_SIZE - g_l2tcm_offset) {
+		g_mmup_fw_size = 0;
+		return false;
+	}
+
+	return true;
+}
+
+static bool vcp_smc_rstn_set(bool boot_ok)
+{
+	if (mmio_read_32(VCP_GPR_C0_H0_REBOOT) != 0 &&
+	    mmio_read_32(VCP_R_CORE0_STATUS) != 0 &&
+	    (mmio_read_32(VCP_R_GIPC_IN_SET) & B_GIPC3_SETCLR_1) == 0 &&
+	    (mmio_read_32(VCP_R_GIPC_IN_CLR) & B_GIPC3_SETCLR_1) == 0 &&
+	    mmio_read_32(VCP_GPR_C0_H0_REBOOT) != VCP_CORE_RDY_TO_REBOOT &&
+	    mmio_read_32(VCP_GPR_C0_H1_REBOOT) != VCP_CORE_RDY_TO_REBOOT) {
+		ERROR("%s: [%s] mmup reset set fail!GIPC 0x%x 0x%x REBOOT 0x%x 0x%x\n",
+		      MODULE_TAG, __func__, mmio_read_32(VCP_R_GIPC_IN_SET),
+		      mmio_read_32(VCP_R_GIPC_IN_CLR),
+		      mmio_read_32(VCP_GPR_C0_H0_REBOOT),
+		      mmio_read_32(VCP_GPR_C0_H1_REBOOT));
+		return false;
+	}
+
+	mmio_write_32(VCP_R_CORE0_SW_RSTN_SET, BIT(0));
+
+	/* reset sec control */
+	mmio_write_32(VCP_R_SEC_CTRL_2, 0);
+
+	/* reset domain setting */
+	mmio_write_32(VCP_R_S_DOM_EN0_31, 0x0);
+	mmio_write_32(VCP_R_S_DOM_EN32_63, 0x0);
+	mmio_write_32(VCP_R_NS_DOM_EN0_31, 0x0);
+	mmio_write_32(VCP_R_NS_DOM_EN32_63, 0x0);
+
+	/* reset sec setting */
+	mmio_clrbits_32(VCP_R_DYN_SECURE,
+			RESET_NS_SECURE_B_REGION << VCP_NS_SECURE_B_REGION_ENABLE);
+
+	if (boot_ok) {
+		mmio_write_32(VCP_GPR_C0_H0_REBOOT, VCP_CORE_REBOOT_OK);
+		mmio_write_32(VCP_GPR_C0_H1_REBOOT, VCP_CORE_REBOOT_OK);
+	}
+
+	dsbsy();
+	return true;
+}
+
+static bool vcp_smc_rstn_clr(void)
+{
+	if ((mmio_read_32(VCP_R_CORE0_SW_RSTN_SET) & BIT(0)) == 1) {
+		ERROR("%s: [%s] mmup not reset set !\n", MODULE_TAG, __func__);
+		return false;
+	}
+
+	mmio_clrsetbits_32(VCP_R_SEC_DOMAIN,
+			   ~(VCP_DOMAIN_MASK << VCP_HWCCF_DOMAIN), VCP_DOMAIN_SET);
+
+	/* enable IOVA Mode */
+	mmio_write_32(VCP_R_AXIOMMUEN_DEV_APC, BIT(0));
+
+	/* reset secure setting */
+	mmio_setbits_32(VCP_R_SEC_CTRL_2, CORE0_SEC_BIT_SEL);
+	mmio_clrbits_32(VCP_R_DYN_SECURE, VCP_NS_I0 | VCP_NS_D0);
+	mmio_clrbits_32(VCP_R_DYN_SECURE_TH1, VCP_NS_I1 | VCP_NS_D1);
+
+	/* start vcp */
+	mmio_write_32(VCP_R_CORE0_SW_RSTN_CLR, BIT(0));
+	dsbsy();
+	return true;
+}
+
+static u_register_t tinysys_vcp_kernel_control(u_register_t arg0,
+					       u_register_t arg1,
+					       u_register_t arg2,
+					       u_register_t arg3,
+					       void *handle,
+					       struct smccc_res *smccc_ret)
+{
+	uint32_t request_ops;
+	uint64_t ret = MTK_SIP_E_SUCCESS;
+
+	if (!get_vcp_pwr_status())
+		return MTK_SIP_E_NOT_SUPPORTED;
+
+	request_ops = (uint32_t)arg0;
+
+	switch (request_ops) {
+	case MTK_TINYSYS_VCP_KERNEL_OP_RESET_SET:
+		ret = vcp_smc_rstn_set((bool)!!arg1);
+		break;
+	case MTK_TINYSYS_VCP_KERNEL_OP_RESET_RELEASE:
+		ret = vcp_smc_rstn_clr();
+		break;
+	case MTK_TINYSYS_VCP_KERNEL_OP_COLD_BOOT_VCP:
+		ret = vcp_cold_boot_reset();
+		break;
+	case MTK_TINYSYS_MMUP_KERNEL_OP_RESET_SET:
+		ret = mmup_smc_rstn_set((bool)!!arg1);
+		break;
+	case MTK_TINYSYS_MMUP_KERNEL_OP_RESET_RELEASE:
+		ret = mmup_smc_rstn_clr();
+		break;
+	case MTK_TINYSYS_MMUP_KERNEL_OP_SET_L2TCM_OFFSET:
+		ret = vcp_set_mmup_l2tcm_offset(arg1);
+		break;
+	case MTK_TINYSYS_MMUP_KERNEL_OP_SET_FW_SIZE:
+		ret = vcp_set_mmup_fw_size(arg1);
+		break;
+	case MTK_TINYSYS_MMUP_KERNEL_OP_COLD_BOOT_MMUP:
+		ret = mmup_cold_boot_reset();
+		break;
+	default:
+		ERROR("%s: %s, unknown request_ops = %x\n", MODULE_TAG, __func__, request_ops);
+		ret = MTK_SIP_E_INVALID_PARAM;
+		break;
+	}
+
+	return ret;
+}
+
+/* Register SiP SMC service */
+DECLARE_SMC_HANDLER(MTK_SIP_KERNEL_VCP_CONTROL, tinysys_vcp_kernel_control);
diff --git a/plat/mediatek/include/mtk_sip_def.h b/plat/mediatek/include/mtk_sip_def.h
index a86a46c..ff12408 100644
--- a/plat/mediatek/include/mtk_sip_def.h
+++ b/plat/mediatek/include/mtk_sip_def.h
@@ -17,7 +17,8 @@
 	_func(MTK_SIP_AUDIO_CONTROL, 0x517) \
 	_func(MTK_SIP_APUSYS_CONTROL, 0x51E) \
 	_func(MTK_SIP_DP_CONTROL, 0x523) \
-	_func(MTK_SIP_KERNEL_GIC_OP, 0x526)
+	_func(MTK_SIP_KERNEL_GIC_OP, 0x526) \
+	_func(MTK_SIP_KERNEL_VCP_CONTROL, 0x52C)
 
 #define MTK_SIP_SMC_FROM_S_EL1_TABLE(_func) \
 	_func(MTK_SIP_TEE_MPU_PERM_SET, 0x031)
diff --git a/plat/mediatek/mt8196/plat_config.mk b/plat/mediatek/mt8196/plat_config.mk
index dd83b9a..dc78701 100644
--- a/plat/mediatek/mt8196/plat_config.mk
+++ b/plat/mediatek/mt8196/plat_config.mk
@@ -36,6 +36,7 @@
 CONFIG_MTK_CPU_SUSPEND_EN := y
 CONFIG_MTK_SPM_VERSION := mt8196
 CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND := y
+CONFIG_MTK_TINYSYS_VCP := y
 CPU_PM_TINYSYS_SUPPORT := y
 MTK_PUBEVENT_ENABLE := y
 
diff --git a/plat/mediatek/mt8196/platform.mk b/plat/mediatek/mt8196/platform.mk
index 062735b..0d6ca24 100644
--- a/plat/mediatek/mt8196/platform.mk
+++ b/plat/mediatek/mt8196/platform.mk
@@ -28,6 +28,7 @@
 MODULES-y += $(MTK_PLAT)/drivers/dp
 MODULES-y += $(MTK_PLAT)/drivers/mcusys
 MODULES-y += $(MTK_PLAT)/drivers/timer
+MODULES-y += $(MTK_PLAT)/drivers/vcp
 MODULES-y += $(MTK_PLAT)/helpers
 MODULES-y += $(MTK_PLAT)/topology