feat(mt8196): add mcdi driver

Add MCDI driver to manage CPU idle states and optimize power consumption.

Signed-off-by: Kai Liang <kai.liang@mediatek.com>
Change-Id: I3a2e163730dd997dd72f2ebc1375dea38d728cb7
diff --git a/plat/mediatek/common/lpm/mt_lpm_dispatch.c b/plat/mediatek/common/lpm/mt_lpm_dispatch.c
new file mode 100644
index 0000000..6b30ff7
--- /dev/null
+++ b/plat/mediatek/common/lpm/mt_lpm_dispatch.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2025, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+
+#include <lpm/mt_lpm_dispatch.h>
+
+struct mt_dispatch_ctrl mt_dispatcher __section("mt_lpm_s") = {
+	.enable = 0,
+};
+
+struct mt_dispatch_ctrl mt_secure_dispatcher __section("mt_secure_lpm_s") = {
+	.enable = 0,
+};
+
+u_register_t invoke_mt_lpm_dispatch(u_register_t x1,
+				    u_register_t x2,
+				    u_register_t x3,
+				    u_register_t x4,
+				    void *handle,
+				    struct smccc_res *smccc_ret)
+{
+	uint64_t res = 0;
+	uint32_t user;
+
+	if (!IS_MT_LPM_SMC(x1))
+		return 0;
+
+	user = MT_LPM_SMC_USER(x1);
+	if ((user < MT_LPM_SMC_USER_MAX) &&
+	    (mt_dispatcher.enable & (BIT(user)))) {
+		res = mt_dispatcher.fn[user](MT_LPM_SMC_USER_ID(x1),
+					     x2,
+					     x3,
+					     x4,
+					     handle,
+					     smccc_ret);
+	}
+
+	return res;
+}
+DECLARE_SMC_HANDLER(MTK_SIP_MTK_LPM_CONTROL, invoke_mt_lpm_dispatch);
+
+u_register_t invoke_mt_secure_lpm_dispatch(u_register_t x1,
+					   u_register_t x2,
+					   u_register_t x3,
+					   u_register_t x4,
+					   void *handle,
+					   struct smccc_res *smccc_ret)
+{
+	uint64_t res = 0;
+	uint32_t user;
+
+	if (!IS_MT_LPM_SMC(x1))
+		return 0;
+
+	user = MT_LPM_SMC_USER(x1);
+	if (mt_secure_dispatcher.enable & (BIT(user))) {
+		res = mt_secure_dispatcher.fn[user](MT_LPM_SMC_USER_ID(x1),
+						    x2,
+						    x3,
+						    x4,
+						    handle,
+						    smccc_ret);
+	}
+
+	return res;
+}
+DECLARE_SMC_HANDLER(MTK_SIP_BL_LPM_CONTROL, invoke_mt_secure_lpm_dispatch);
+
+/* Check lpm smc user number at compile time */
+CASSERT(MT_LPM_SMC_USER_MAX <= MTK_DISPATCH_ID_MAX,
+	lpm_smc_user_declare_too_large);
+
+void mt_lpm_dispatcher_registry(unsigned int id, mt_lpm_dispatch_fn fn)
+{
+	if (id >= MT_LPM_SMC_USER_MAX)
+		return;
+
+	mt_dispatcher.enable |= BIT(id);
+	mt_dispatcher.fn[id] = fn;
+}
+
+void mt_secure_lpm_dispatcher_registry(unsigned int id, mt_lpm_dispatch_fn fn)
+{
+	if (id >= MT_LPM_SMC_USER_MAX)
+		return;
+
+	mt_secure_dispatcher.enable |= BIT(id);
+	mt_secure_dispatcher.fn[id] = fn;
+}