feat(mt8196): add topology module for power management

Add topology module to support CPU power state control.

Signed-off-by: Kai Liang <kai.liang@mediatek.com>
Change-Id: I0cc1e5a426762b1b29bff1e940e077643da02e5e
This commit is contained in:
Kai Liang 2025-01-15 20:33:26 +08:00 committed by Wenzhen Yu
parent adf73ae20a
commit da54c72436
9 changed files with 383 additions and 2 deletions

View file

@ -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 # 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} 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))) $(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))

View file

@ -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();
}

View file

@ -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)))

View file

@ -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();
}

View file

@ -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)))

View file

@ -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

View file

@ -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;
}

View file

@ -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))

View file

@ -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 # SPDX-License-Identifier: BSD-3-Clause
# #
@ -7,6 +7,15 @@
LOCAL_DIR := $(call GET_LOCAL_DIR) LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := topology 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 LOCAL_SRCS-y := $(LOCAL_DIR)/$(ARCH_VERSION)/topology.c
endif
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL))) $(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))