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 000000000..6b30ff7f7 --- /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 + +#include + +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; +} diff --git a/plat/mediatek/common/lpm/rules.mk b/plat/mediatek/common/lpm/rules.mk index eb68e03f5..d24f4d823 100644 --- a/plat/mediatek/common/lpm/rules.mk +++ b/plat/mediatek/common/lpm/rules.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2023, MediaTek Inc. All rights reserved. +# Copyright (c) 2023-2025, MediaTek Inc. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -11,6 +11,7 @@ MODULE := lpm LOCAL_SRCS-y := $(LOCAL_DIR)/mt_lp_api.c LOCAL_SRCS-y += $(LOCAL_DIR)/mt_lp_rm.c LOCAL_SRCS-y += $(LOCAL_DIR)/mt_lp_rq.c +LOCAL_SRCS-y += ${LOCAL_DIR}/mt_lpm_dispatch.c PLAT_INCLUDES += -I${LOCAL_DIR} diff --git a/plat/mediatek/drivers/cpu_pm/cpcv5_4/mt_cpu_pm.c b/plat/mediatek/drivers/cpu_pm/cpcv5_4/mt_cpu_pm.c index 4537c8800..f105b882b 100644 --- a/plat/mediatek/drivers/cpu_pm/cpcv5_4/mt_cpu_pm.c +++ b/plat/mediatek/drivers/cpu_pm/cpcv5_4/mt_cpu_pm.c @@ -394,6 +394,17 @@ mt_pwr_mcusysoff_reflect: mt_pwr_mcusysoff_break: plat_mt_lp_cpu_rc = -1; + if (IS_PLAT_ALL_ONLINE_CORES_S2IDLE(state)) { + /* set SPM pending if s2idle fail to turn mcusys off */ + if (suspend_abort_reason == MTK_PM_SUSPEND_ABORT_PWR_REQ) + NOTICE("[LPM] PWR_REQ is held\n"); + else if (suspend_abort_reason == MTK_PM_SUSPEND_ABORT_LAST_CORE) + NOTICE("[LPM] suspend last core prot fail\n"); + else if (suspend_abort_reason == + MTK_PM_SUSPEND_ABORT_RC_INVALID) + NOTICE("[LPM] no available RC\n"); + } + return MTK_CPUPM_E_FAIL; } diff --git a/plat/mediatek/include/lpm/mt_lpm_dispatch.h b/plat/mediatek/include/lpm/mt_lpm_dispatch.h new file mode 100644 index 000000000..9b30dbe93 --- /dev/null +++ b/plat/mediatek/include/lpm/mt_lpm_dispatch.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MT_LPM_DISPATCH_H +#define MT_LPM_DISPATCH_H + +#include + +#include "mt_lpm_smc.h" +#include + +#define MTK_DISPATCH_ID_MAX 32 + +typedef uint64_t (*mt_lpm_dispatch_fn)(u_register_t x1, u_register_t x2, + u_register_t x3, u_register_t x4, + void *handle, + struct smccc_res *smccc_ret); + +struct mt_dispatch_ctrl { + unsigned int enable; + mt_lpm_dispatch_fn fn[MT_LPM_SMC_USER_MAX]; +}; + +void mt_lpm_dispatcher_registry(unsigned int id, mt_lpm_dispatch_fn fn); + +void mt_secure_lpm_dispatcher_registry(unsigned int id, mt_lpm_dispatch_fn fn); + +extern struct mt_dispatch_ctrl mt_dispatcher; +extern struct mt_dispatch_ctrl mt_secure_dispatcher; +#endif diff --git a/plat/mediatek/include/mtk_sip_def.h b/plat/mediatek/include/mtk_sip_def.h index 6f496d259..85b723086 100644 --- a/plat/mediatek/include/mtk_sip_def.h +++ b/plat/mediatek/include/mtk_sip_def.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023, MediaTek Inc. All rights reserved. + * Copyright (c) 2024, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -13,6 +13,7 @@ _func(MTK_SIP_KERNEL_DFD, 0x205) \ _func(MTK_SIP_KERNEL_MSDC, 0x273) \ _func(MTK_SIP_VCORE_CONTROL, 0x506) \ + _func(MTK_SIP_MTK_LPM_CONTROL, 0x507) \ _func(MTK_SIP_EMIDBG_CONTROL, 0x50B) \ _func(MTK_SIP_IOMMU_CONTROL, 0x514) \ _func(MTK_SIP_AUDIO_CONTROL, 0x517) \ @@ -27,6 +28,7 @@ #define MTK_SIP_SMC_FROM_BL33_TABLE(_func) \ _func(MTK_SIP_KERNEL_BOOT, 0x115) \ + _func(MTK_SIP_BL_LPM_CONTROL, 0x410) \ _func(MTK_SIP_BL_EMIMPU_CONTROL, 0x415) #endif /* MTK_SIP_DEF_H */ diff --git a/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c b/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c index a0171bf1b..73b1f6855 100644 --- a/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c +++ b/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c @@ -371,6 +371,19 @@ static void get_sys_suspend_power_state(psci_power_state_t *req_state) } #endif +static void __dead2 pwr_domain_pwr_down_wfi(const psci_power_state_t *req_state) +{ + unsigned int cpu = plat_my_core_pos(); + int ret = MTK_CPUPM_E_NOT_SUPPORT; + + if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_PWR_DOMAIN_POWER_DOWN_WFI)) + ret = imtk_cpu_pwr.ops->pwr_domain_pwr_down_wfi(cpu); + if (ret == MTK_CPUPM_E_OK) + plat_panic_handler(); + else + psci_power_down_wfi(); +} + static void pm_smp_init(unsigned int cpu_id, uintptr_t entry_point) { if (entry_point == 0) { @@ -382,6 +395,16 @@ static void pm_smp_init(unsigned int cpu_id, uintptr_t entry_point) INFO("[%s:%d] - Initialize finished\n", __func__, __LINE__); } +static struct plat_pm_pwr_ctrl armv9_0_pwr_ops = { + .pwr_domain_suspend = power_domain_suspend, + .pwr_domain_suspend_finish = power_domain_suspend_finish, + .validate_power_state = validate_power_state, +#if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND + .get_sys_suspend_power_state = get_sys_suspend_power_state, +#endif + .pwr_domain_pwr_down_wfi = pwr_domain_pwr_down_wfi, +}; + struct plat_pm_smp_ctrl armv9_0_smp_ops = { .init = pm_smp_init, .pwr_domain_on = power_domain_on, @@ -416,6 +439,50 @@ int plat_pm_invoke_func(enum mtk_cpu_pm_mode mode, unsigned int id, void *priv) return ret; } +int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops) +{ + int success = 1; + unsigned int fns = 0; + + if (!ops || imtk_cpu_pwr.ops) { + ERROR("[%s:%d] register cpu_pm fail !!\n", __FILE__, __LINE__); + return MTK_CPUPM_E_ERR; + } + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CORE, + cpu_resume, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CORE, + cpu_suspend, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CLUSTER, + cluster_resume, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CLUSTER, + cluster_suspend, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_MCUSYS, + mcusys_resume, 1, + success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_MCUSYS, + mcusys_suspend, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_CPUPM_GET_PWR_STATE, + get_pstate, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_STATE_VALID, + pwr_state_valid, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_INIT, + init, 1, success, fns); + CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_DOMAIN_POWER_DOWN_WFI, + pwr_domain_pwr_down_wfi, 1, success, fns); + if (success) { + imtk_cpu_pwr.ops = ops; + imtk_cpu_pwr.fn_mask |= fns; + plat_pm_ops_setup_pwr(&armv9_0_pwr_ops); + INFO("[%s:%d] CPU pwr ops register success, support:0x%x\n", + __func__, __LINE__, fns); + } else { + ERROR("[%s:%d] register cpu_pm ops fail !, fn:0x%x\n", + __func__, __LINE__, fn_flags); + assert(0); + } + return MTK_CPUPM_E_OK; +} + int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops) { int success = 1; diff --git a/plat/mediatek/lib/pm/mtk_pm.c b/plat/mediatek/lib/pm/mtk_pm.c index 3dbeb511e..772c2d721 100644 --- a/plat/mediatek/lib/pm/mtk_pm.c +++ b/plat/mediatek/lib/pm/mtk_pm.c @@ -45,6 +45,9 @@ int plat_pm_ops_setup_pwr(struct plat_pm_pwr_ctrl *ops) mtk_pm_ops.get_sys_suspend_power_state = ops->get_sys_suspend_power_state; } + if (!mtk_pm_ops.pwr_domain_pwr_down_wfi) + mtk_pm_ops.pwr_domain_pwr_down_wfi = ops->pwr_domain_pwr_down_wfi; + mtk_pm_status |= MTK_PM_ST_PWR_READY; #endif return MTK_CPUPM_E_OK; diff --git a/plat/mediatek/mt8196/include/platform_def.h b/plat/mediatek/mt8196/include/platform_def.h index 362f93fa7..1c01483da 100644 --- a/plat/mediatek/mt8196/include/platform_def.h +++ b/plat/mediatek/mt8196/include/platform_def.h @@ -258,7 +258,6 @@ ******************************************************************************/ #define CPU_EB_TCM_BASE 0x0C2CF000 #define CPU_EB_TCM_SIZE 0x1000 -#define CPU_EB_MBOX3_OFFSET 0xFCE0 #define CPU_EB_TCM_CNT_BASE 0x0C2CC000 /******************************************************************************* diff --git a/plat/mediatek/mt8196/plat_config.mk b/plat/mediatek/mt8196/plat_config.mk index e4a56c848..7d4309757 100644 --- a/plat/mediatek/mt8196/plat_config.mk +++ b/plat/mediatek/mt8196/plat_config.mk @@ -36,17 +36,20 @@ CONFIG_MTK_APUSYS_SEC_CTRL := y CONFIG_MTK_APUSYS_SETUP_CE := y CONFIG_MTK_MCUSYS := y MCUSYS_VERSION := v4 +MCUPM_VERSION := v3 CONFIG_MTK_PM_SUPPORT := y CONFIG_MTK_PM_ARCH := 9_0 CONFIG_MTK_CPU_PM_SUPPORT := y CONFIG_MTK_CPU_PM_ARCH := 5_4 CONFIG_MTK_SMP_EN := y -CONFIG_MTK_CPU_SUSPEND_EN := n +CONFIG_MTK_CPU_SUSPEND_EN := y CONFIG_MTK_SPM_VERSION := mt8196 CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND := n CONFIG_MTK_TINYSYS_VCP := y CPU_PWR_TOPOLOGY := group_4_3_1 CPU_PM_CORE_ARCH64_ONLY := y +CPU_PM_DOMAIN_CORE_ONLY := n +CPU_PM_SUSPEND_NOTIFY := y CPU_PM_TINYSYS_SUPPORT := y MTK_PUBEVENT_ENABLE := y CONFIG_MTK_PMIC := y diff --git a/plat/mediatek/mt8196/platform.mk b/plat/mediatek/mt8196/platform.mk index c8bfb47fd..068fe5ef4 100644 --- a/plat/mediatek/mt8196/platform.mk +++ b/plat/mediatek/mt8196/platform.mk @@ -24,6 +24,7 @@ PLAT_INCLUDES := -I${MTK_PLAT}/common \ -Idrivers/arm/gic \ MODULES-y += $(MTK_PLAT)/common +MODULES-y += $(MTK_PLAT)/common/lpm MODULES-y += $(MTK_PLAT)/lib/mtk_init MODULES-y += $(MTK_PLAT)/lib/pm MODULES-y += $(MTK_PLAT)/drivers/apusys