diff --git a/plat/mediatek/drivers/cpu_pm/rules.mk b/plat/mediatek/drivers/cpu_pm/rules.mk index 8df4f2189..d43b5a7ea 100644 --- a/plat/mediatek/drivers/cpu_pm/rules.mk +++ b/plat/mediatek/drivers/cpu_pm/rules.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, MediaTek Inc. All rights reserved. +# Copyright (c) 2025, MediaTek Inc. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -10,4 +10,10 @@ MODULE := cpu_pm SUB_RULES-${CONFIG_MTK_CPU_PM_SUPPORT} := $(LOCAL_DIR)/cpcv${CONFIG_MTK_CPU_PM_ARCH} +ifneq ($(CPU_PWR_TOPOLOGY),) +SUB_RULES-${CONFIG_MTK_CPU_PM_SUPPORT} += $(LOCAL_DIR)/topology/$(CPU_PWR_TOPOLOGY) +else +SUB_RULES-${CONFIG_MTK_CPU_PM_SUPPORT} += $(LOCAL_DIR)/topology/default +endif + $(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y))) diff --git a/plat/mediatek/drivers/cpu_pm/topology/default/pwr.c b/plat/mediatek/drivers/cpu_pm/topology/default/pwr.c new file mode 100644 index 000000000..ce1793b6d --- /dev/null +++ b/plat/mediatek/drivers/cpu_pm/topology/default/pwr.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <stdint.h> + +#include <lib/spinlock.h> +#include <platform_def.h> + +#include "../inc/pwr_topology.h" +#include <lib/pm/mtk_pm.h> +#include <lpm/mt_lp_rm.h> + +#ifdef MT_CPU_PM_USING_BAKERY_LOCK +DEFINE_BAKERY_LOCK(mt_pwr_lock); + +#define plat_pwr_lock_init() bakery_lock_init(&mt_pwr_lock) + +#define plat_pwr_lock() bakery_lock_get(&mt_pwr_lock) + +#define plat_pwr_unlock() bakery_lock_release(&mt_pwr_lock) +#else +spinlock_t mt_pwr_lock; + +#define plat_pwr_lock_init() +#define plat_pwr_lock() spin_lock(&mt_pwr_lock) + +#define plat_pwr_unlock() spin_unlock(&mt_pwr_lock) +#endif + +enum mt_pwr_domain_node { + MT_PWR_NONMCUSYS = 0, + MT_PWR_MCUSYS_PDN, + MT_PWR_MAX +}; + +#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN && \ +!CPU_PM_DOMAIN_CORE_ONLY +static int mt_pwr_domain_st[MT_PWR_MAX]; +#endif + +#define ALL_IN_ONE_GROUP 0xFF +unsigned int pwr_domain_coordination(enum pwr_domain_status pwr, + const mtk_pstate_type psci_state, + const struct mtk_cpupm_pwrstate *state, + afflv_prepare fn) +{ + unsigned int pstate = 0; + +#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN && \ +!CPU_PM_DOMAIN_CORE_ONLY + unsigned int is_flush = 0; + struct pwr_toplogy tp = { + .cur_group_bit = ALL_IN_ONE_GROUP, + .group = ALL_IN_ONE_GROUP, + }; + + /* Skip to process smp */ + if (pwr > PWR_DOMAIN_OFF) + return pstate; + + if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id)) { + plat_pwr_lock(); + if (pwr == PWR_DOMAIN_OFF) + mt_pwr_domain_st[MT_PWR_NONMCUSYS] += 1; + else + mt_pwr_domain_st[MT_PWR_NONMCUSYS] -= 1; + flush_dcache_range( + (uintptr_t)&mt_pwr_domain_st[MT_PWR_NONMCUSYS], + sizeof(mt_pwr_domain_st[MT_PWR_NONMCUSYS])); + plat_pwr_unlock(); + } + + plat_pwr_lock(); + if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) + pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER; + + if (psci_get_pstate_pwrlvl(psci_state) >= PLAT_MT_CPU_SUSPEND_CLUSTER) + pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU; + + if (pwr == PWR_DOMAIN_OFF) { + if (IS_PLAT_MCUSYSOFF_AFFLV(state->pwr.afflv) && + (mt_pwr_domain_st[MT_PWR_NONMCUSYS] == 0)) { + int ret = MTK_CPUPM_E_OK; + + tp.group = ALL_IN_ONE_GROUP; + if (fn) + ret = fn(1, state, &tp); + + if (ret == MTK_CPUPM_E_OK) { + pstate |= MT_CPUPM_PWR_DOMAIN_MCUSYS; + mt_pwr_domain_st[MT_PWR_MCUSYS_PDN] += 1; + is_flush = 1; + } + } + } else { + if (mt_pwr_domain_st[MT_PWR_MCUSYS_PDN]) { + tp.group = 0x0; + if (fn) + fn(1, state, &tp); + pstate |= MT_CPUPM_PWR_DOMAIN_MCUSYS; + mt_pwr_domain_st[MT_PWR_MCUSYS_PDN] -= 1; + is_flush = 1; + } + if (mt_pwr_domain_st[MT_PWR_NONMCUSYS] < 0) + assert(0); + } + + if (is_flush) + flush_dcache_range( + (uintptr_t)&mt_pwr_domain_st[MT_PWR_MCUSYS_PDN], + sizeof(mt_pwr_domain_st[MT_PWR_MCUSYS_PDN])); + + plat_pwr_unlock(); +#endif + return pstate; +} + +void pwr_topology_init(void) +{ + plat_pwr_lock_init(); +} diff --git a/plat/mediatek/drivers/cpu_pm/topology/default/rules.mk b/plat/mediatek/drivers/cpu_pm/topology/default/rules.mk new file mode 100644 index 000000000..4fb2f56c9 --- /dev/null +++ b/plat/mediatek/drivers/cpu_pm/topology/default/rules.mk @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025, MediaTek Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +LOCAL_DIR := $(call GET_LOCAL_DIR) + +MODULE := pwr_topology_default + +LOCAL_SRCS-y := ${LOCAL_DIR}/pwr.c + +$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL))) diff --git a/plat/mediatek/drivers/cpu_pm/topology/group_4_3_1/pwr.c b/plat/mediatek/drivers/cpu_pm/topology/group_4_3_1/pwr.c new file mode 100644 index 000000000..2eb518a35 --- /dev/null +++ b/plat/mediatek/drivers/cpu_pm/topology/group_4_3_1/pwr.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <stdint.h> + +#include <lib/spinlock.h> +#include <plat/common/platform.h> +#include <platform_def.h> + +#include "../inc/pwr_topology.h" +#include <lib/pm/mtk_pm.h> +#include <lpm/mt_lp_rm.h> + +#define GROUP_CPU_ALL 0x7 +#define GROUP_0_CPUID_MAX 3 +#define GROUP_1_CPUID_MAX 6 +#define GROUP_2_CPUID_MAX 7 + +#define IS_ALL_GROUP_OFF(_mask) ((_mask & GROUP_CPU_ALL) == GROUP_CPU_ALL) + +#define GET_GROUPID(_cpuid, _gid) ({ \ + if (_cpuid <= GROUP_0_CPUID_MAX) \ + _gid = 0; \ + else if (_cpuid <= GROUP_1_CPUID_MAX) \ + _gid = 1; \ + else \ + _gid = 2; }) + +#define GET_GROUPMASK(_cpuid, _gmask) ({ \ + if (_cpuid <= GROUP_0_CPUID_MAX) \ + _gmask = BIT(0); \ + else if (_cpuid <= GROUP_1_CPUID_MAX) \ + _gmask = BIT(1);\ + else if (_cpuid <= GROUP_2_CPUID_MAX) \ + _gmask = BIT(2); \ + else \ + _gmask = 0; }) + +#ifdef MT_CPU_PM_USING_BAKERY_LOCK +DEFINE_BAKERY_LOCK(mt_pwr_lock); +#define plat_pwr_lock_init() bakery_lock_init(&mt_pwr_lock) +#define plat_pwr_lock() bakery_lock_get(&mt_pwr_lock) +#define plat_pwr_unlock() bakery_lock_release(&mt_pwr_lock) +#else +spinlock_t mt_pwr_lock; +#define plat_pwr_lock_init() +#define plat_pwr_lock() spin_lock(&mt_pwr_lock) +#define plat_pwr_unlock() spin_unlock(&mt_pwr_lock) +#endif /* MT_CPU_PM_USING_BAKERY_LOCK */ + +#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN && \ +!CPU_PM_DOMAIN_CORE_ONLY +static unsigned int cpu_groupmask; +#endif + +unsigned int pwr_domain_coordination(enum pwr_domain_status pwr, + const mtk_pstate_type psci_state, + const struct mtk_cpupm_pwrstate *state, + afflv_prepare fn) +{ + unsigned int pstate = MT_CPUPM_PWR_DOMAIN_CORE; + +#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN && \ +!CPU_PM_DOMAIN_CORE_ONLY + struct pwr_toplogy tp; + + if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) { + unsigned int fgmask; + + if (state->info.cpuid >= PLATFORM_CORE_COUNT) + assert(0); + + GET_GROUPMASK(state->info.cpuid, tp.cur_group_bit); + + plat_pwr_lock(); + if ((pwr == PWR_DOMAIN_OFF) || (pwr == PWR_DOMAIN_SMP_OFF)) { + tp.group = (cpu_groupmask | tp.cur_group_bit); + fgmask = tp.group; + } else { + tp.group = (cpu_groupmask & ~tp.cur_group_bit); + fgmask = cpu_groupmask; + } + fn(1, state, &tp); + cpu_groupmask = tp.group; + + plat_pwr_unlock(); + if (IS_ALL_GROUP_OFF(fgmask)) + pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER; + } + + /* Skip to process smp */ + if (pwr > PWR_DOMAIN_OFF) + return pstate; + + if (psci_get_pstate_pwrlvl(psci_state) >= PLAT_MT_CPU_SUSPEND_CLUSTER) + pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU; + + if (IS_PLAT_MCUSYSOFF_AFFLV(state->pwr.afflv)) { + int ret = MTK_CPUPM_E_OK; + + if (fn) + ret = fn(state->pwr.afflv, state, &tp); + + if (ret == MTK_CPUPM_E_OK) + pstate |= MT_CPUPM_PWR_DOMAIN_MCUSYS; + } +#endif + return pstate; +} + +void pwr_topology_init(void) +{ +#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN && \ +!CPU_PM_DOMAIN_CORE_ONLY + cpu_groupmask = GROUP_CPU_ALL; +#endif + + plat_pwr_lock_init(); +} diff --git a/plat/mediatek/drivers/cpu_pm/topology/group_4_3_1/rules.mk b/plat/mediatek/drivers/cpu_pm/topology/group_4_3_1/rules.mk new file mode 100644 index 000000000..0d5473bda --- /dev/null +++ b/plat/mediatek/drivers/cpu_pm/topology/group_4_3_1/rules.mk @@ -0,0 +1,17 @@ +# +# Copyright (c) 2025, MediaTek Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +#Prologue, init variable +LOCAL_DIR := $(call GET_LOCAL_DIR) + +#Define your module name +MODULE := pwr_topology_default + +#Add your source code here +LOCAL_SRCS-y := ${LOCAL_DIR}/pwr.c + +#Epilogue, build as module +$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL))) diff --git a/plat/mediatek/drivers/cpu_pm/topology/inc/pwr_topology.h b/plat/mediatek/drivers/cpu_pm/topology/inc/pwr_topology.h new file mode 100644 index 000000000..24dd86dd2 --- /dev/null +++ b/plat/mediatek/drivers/cpu_pm/topology/inc/pwr_topology.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PWR_TOPOLOGY_H +#define PWR_TOPOLOGY_H + +#include <lib/pm/mtk_pm.h> + +enum pwr_domain_status { + PWR_DOMAIN_ON, + PWR_DOMAIN_OFF, + PWR_DOMAIN_SMP_ON, + PWR_DOMAIN_SMP_OFF, +}; + +struct pwr_toplogy { + unsigned int cur_group_bit; + unsigned int group; +}; + +typedef int (*afflv_prepare)(unsigned int, + const struct mtk_cpupm_pwrstate *, + const struct pwr_toplogy *); + +void pwr_topology_init(void); + +unsigned int pwr_domain_coordination(enum pwr_domain_status pwr, + const mtk_pstate_type psci_state, + const struct mtk_cpupm_pwrstate *state, + afflv_prepare fn); + +#endif diff --git a/plat/mediatek/topology/group_4_3_1/topology.c b/plat/mediatek/topology/group_4_3_1/topology.c new file mode 100644 index 000000000..5ccdfd257 --- /dev/null +++ b/plat/mediatek/topology/group_4_3_1/topology.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> + +#include <lib/psci/psci.h> +#include <platform_def.h> + +#pragma weak plat_get_power_domain_tree_desc + +#define PWR_DOMAIN_GROUP_COUNT U(3) +#define PWR_DOMAIN_GROUP_NODE_0 U(4) +#define PWR_DOMAIN_GROUP_NODE_1 U(3) +#define PWR_DOMAIN_GROUP_NODE_2 U(1) + +static const unsigned char mtk_power_domain_tree_desc[] = { + PLATFORM_SYSTEM_COUNT, + PWR_DOMAIN_GROUP_COUNT, + PWR_DOMAIN_GROUP_NODE_0, + PWR_DOMAIN_GROUP_NODE_1, + PWR_DOMAIN_GROUP_NODE_2 +}; + +/******************************************************************************* + * This function returns the default topology tree information. + ******************************************************************************/ +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return mtk_power_domain_tree_desc; +} diff --git a/plat/mediatek/topology/group_4_3_1/topology_conf.mk b/plat/mediatek/topology/group_4_3_1/topology_conf.mk new file mode 100644 index 000000000..6b0bb27ec --- /dev/null +++ b/plat/mediatek/topology/group_4_3_1/topology_conf.mk @@ -0,0 +1,20 @@ +# +# Copyright (c) 2025, MediaTek Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_MAX_PWR_LVL := 2 +$(eval $(call add_defined_option,PLAT_MAX_PWR_LVL)) + +PLAT_MAX_OFF_STATE := 2 +$(eval $(call add_defined_option,PLAT_MAX_OFF_STATE)) + +PLAT_AFFLV_SYSTEM := 2 +$(eval $(call add_defined_option,PLAT_AFFLV_SYSTEM)) + +PLAT_AFFLV_CLUSTER := 1 +$(eval $(call add_defined_option,PLAT_AFFLV_CLUSTER)) + +PLAT_AFFLV_MCUSYS := 2 +$(eval $(call add_defined_option,PLAT_AFFLV_MCUSYS)) diff --git a/plat/mediatek/topology/rules.mk b/plat/mediatek/topology/rules.mk index 29f15bbb5..687654153 100644 --- a/plat/mediatek/topology/rules.mk +++ b/plat/mediatek/topology/rules.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, MediaTek Inc. All rights reserved. +# Copyright (c) 2025, MediaTek Inc. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -7,6 +7,15 @@ LOCAL_DIR := $(call GET_LOCAL_DIR) MODULE := topology + +ifneq (,$(wildcard $(LOCAL_DIR)/$(CPU_PWR_TOPOLOGY)/topology_conf.mk)) +include $(LOCAL_DIR)/$(CPU_PWR_TOPOLOGY)/topology_conf.mk +endif + +ifneq ($(CPU_PWR_TOPOLOGY),) +LOCAL_SRCS-y := $(LOCAL_DIR)/$(CPU_PWR_TOPOLOGY)/topology.c +else LOCAL_SRCS-y := $(LOCAL_DIR)/$(ARCH_VERSION)/topology.c +endif $(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))