Merge changes I1126311e,I6ae5b5b4,I1b907256,I9facb6bf,Ie51cffeb, ... into integration

* changes:
  feat(mt8196): add vcore dvfs drivers
  feat(mt8196): add LPM v2 support
  feat(mt8196): add SPM common version support
  feat(mt8196): add SPM common driver support
  feat(mt8196): add SPM basic features support
  feat(mt8196): add SPM features support
  feat(mt8196): enable PMIC low power setting
  feat(mt8196): add mcdi driver
  feat(mt8196): add pwr_ctrl module for CPU power management
  feat(mt8196): add mcusys moudles for power management
  feat(mt8196): add CPC module for power management
  feat(mt8196): add topology module for power management
  feat(mt8196): add SPMI driver
  feat(mt8196): add PMIC driver
This commit is contained in:
Govindraj Raja 2025-01-28 22:07:51 +01:00 committed by TrustedFirmware Code Review
commit cf2df874cd
139 changed files with 25525 additions and 26 deletions

View file

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

View file

@ -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 # 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_api.c
LOCAL_SRCS-y += $(LOCAL_DIR)/mt_lp_rm.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_lp_rq.c
LOCAL_SRCS-y += ${LOCAL_DIR}/mt_lpm_dispatch.c
PLAT_INCLUDES += -I${LOCAL_DIR} PLAT_INCLUDES += -I${LOCAL_DIR}

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lpm_v2/mt_lp_api.h>
#define UPDATE_STATUS(val, status, bit) \
((val) ? ((status) | (1 << (bit))) : ((status) & ~(1 << (bit))))
static uint64_t lp_status;
int mt_audio_update(int type)
{
int ret, val;
switch (type) {
case AUDIO_AFE_ENTER:
case AUDIO_AFE_LEAVE:
val = (type == AUDIO_AFE_ENTER) ? 1 : 0;
lp_status = UPDATE_STATUS(val, lp_status, AUDIO_AFE);
ret = mt_lp_rm_do_update(-1, PLAT_RC_IS_FMAUDIO, &val);
break;
case AUDIO_DSP_ENTER:
case AUDIO_DSP_LEAVE:
val = (type == AUDIO_DSP_ENTER) ? 1 : 0;
lp_status = UPDATE_STATUS(val, lp_status, AUDIO_DSP);
ret = mt_lp_rm_do_update(-1, PLAT_RC_IS_ADSP, &val);
break;
default:
ret = -1;
break;
}
return ret;
}
int mt_usb_update(int type)
{
int ret, val;
switch (type) {
case LPM_USB_ENTER:
case LPM_USB_LEAVE:
val = (type == LPM_USB_ENTER) ? 1 : 0;
ret = mt_lp_rm_do_update(-1, PLAT_RC_IS_USB_INFRA, &val);
break;
case USB_HEADSET_ENTER:
case USB_HEADSET_LEAVE:
val = (type == USB_HEADSET_ENTER) ? 1 : 0;
lp_status = UPDATE_STATUS(val, lp_status, USB_HEADSET);
ret = mt_lp_rm_do_update(-1, PLAT_RC_IS_USB_HEADSET, &val);
break;
default:
ret = -1;
break;
}
return ret;
}
uint64_t mt_get_lp_scenario_status(void)
{
return lp_status;
}
int mt_gpueb_hwctrl(int type, void *priv)
{
int ret, val;
switch (type) {
case GPUEB_PLL_EN:
case GPUEB_PLL_DIS:
val = (type == GPUEB_PLL_EN) ? 1 : 0;
ret = mt_lp_rm_do_hwctrl(PLAT_AP_GPUEB_PLL_CONTROL, val, priv);
break;
case GPUEB_GET_PWR_STATUS:
ret = mt_lp_rm_do_hwctrl(PLAT_AP_GPUEB_PWR_STATUS, 0, priv);
break;
case GPUEB_GET_MFG0_PWR_CON:
ret = mt_lp_rm_do_hwctrl(PLAT_AP_GPUEB_MFG0_PWR_CON, 0, priv);
break;
default:
ret = -1;
break;
}
return ret;
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <mtk_mmap_pool.h>
static const mmap_region_t lpm_sram_mmap[] MTK_MMAP_SECTION = {
#if (MTK_LPM_SRAM_BASE && MTK_LPM_SRAM_MAP_SIZE)
/* LPM used syssram */
MAP_REGION_FLAT(MTK_LPM_SRAM_BASE, MTK_LPM_SRAM_MAP_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
#endif
{0}
};
DECLARE_MTK_MMAP_REGIONS(lpm_sram_mmap);

View file

@ -0,0 +1,164 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
#include <lpm_v2/mt_lp_rm.h>
struct platform_mt_resource_manager {
unsigned int count;
struct mt_resource_manager *plat_rm;
};
static struct platform_mt_resource_manager plat_mt_rm;
int mt_lp_rm_register(struct mt_resource_manager *rm)
{
unsigned int i;
struct mt_resource_constraint *const *rc;
if ((rm == NULL) || (rm->consts == NULL) ||
(plat_mt_rm.plat_rm != NULL)) {
return MT_RM_STATUS_BAD;
}
for (i = 0U, rc = rm->consts; *rc != NULL; i++, rc++) {
if ((*rc)->init != NULL)
(*rc)->init();
}
plat_mt_rm.plat_rm = rm;
plat_mt_rm.count = i;
return MT_RM_STATUS_OK;
}
int mt_lp_rm_reset_constraint(unsigned int idx, unsigned int cpuid, int stateid)
{
struct mt_resource_constraint const *rc = NULL;
if ((plat_mt_rm.plat_rm == NULL) || (idx >= plat_mt_rm.count))
return MT_RM_STATUS_BAD;
rc = plat_mt_rm.plat_rm->consts[idx];
if ((rc == NULL) || (rc->reset == NULL))
return MT_RM_STATUS_BAD;
return rc->reset(cpuid, stateid);
}
int mt_lp_rm_get_status(unsigned int type, void *priv)
{
int res = 0;
struct mt_resource_constraint *const *con;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if ((rm == NULL) || (type >= PLAT_RC_MAX))
return -1;
for (con = rm->consts; *con != NULL; con++) {
if ((*con)->get_status == NULL)
continue;
res = (*con)->get_status(type, priv);
if (res == MT_RM_STATUS_STOP)
break;
}
return res;
}
int mt_lp_rm_do_constraint(unsigned int constraint_id, unsigned int cpuid, int stateid)
{
int res = MT_RM_STATUS_BAD;
struct mt_resource_constraint const *rc;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if ((rm == NULL) || (constraint_id >= plat_mt_rm.count))
return res;
rc = rm->consts[constraint_id];
if ((rc != NULL) && (rc->run != NULL))
res = rc->run(cpuid, stateid);
return res;
}
int mt_lp_rm_find_constraint(unsigned int idx, unsigned int cpuid,
int stateid, void *priv)
{
unsigned int i;
int res = MT_RM_STATUS_BAD;
struct mt_resource_constraint *const *rc;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if ((rm == NULL) || (idx >= plat_mt_rm.count))
return res;
/* If subsys clk/mtcmos is on, add block-resource-off flag */
if (rm->update != NULL) {
res = rm->update(rm->consts, plat_mt_rm.count, stateid, priv);
if (res != 0)
return MT_RM_STATUS_BAD;
}
res = MT_RM_STATUS_BAD;
for (i = idx, rc = (rm->consts + idx); *rc != NULL; i++, rc++) {
if (((*rc)->is_valid != NULL) &&
((*rc)->is_valid(cpuid, stateid))) {
res = i;
break;
}
}
return res;
}
int mt_lp_rm_find_and_run_constraint(unsigned int idx, unsigned int cpuid,
int stateid, void *priv)
{
int res = MT_RM_STATUS_BAD;
res = mt_lp_rm_find_constraint(idx, cpuid, stateid, priv);
if (res != MT_RM_STATUS_BAD)
mt_lp_rm_do_constraint(res, cpuid, stateid);
return res;
}
int mt_lp_rm_do_update(int stateid, int type, void const *p)
{
int res = MT_RM_STATUS_BAD;
struct mt_resource_constraint *const *rc;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if (rm == NULL)
return res;
for (rc = rm->consts; *rc != NULL; rc++) {
if ((*rc)->update != NULL) {
res = (*rc)->update(stateid, type, p);
if (res != MT_RM_STATUS_OK)
break;
}
}
return res;
}
int mt_lp_rm_do_hwctrl(unsigned int type, int set, void *priv)
{
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
int res = 0;
if (!rm || !rm->hwctrl || (type >= PLAT_AP_HW_CTRL_MAX))
return -1;
res = rm->hwctrl(type, set, priv);
return res;
}

View file

@ -0,0 +1,239 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <string.h>
#include <common/debug.h>
#include <drivers/console.h>
#include <lib/spinlock.h>
#include <lpm_v2/mt_lp_rm.h>
#include <lpm_v2/mt_lp_rqm.h>
struct _mt_lp_res_req_m_ {
unsigned int uname[MT_LP_RQ_USER_MAX];
unsigned int user_num;
unsigned int user_valid;
unsigned int resource_num;
unsigned int generic_resource_req;
unsigned int flag;
struct mt_resource_req_manager *plat_rqm;
};
static struct _mt_lp_res_req_m_ plat_mt_rqm;
static spinlock_t mt_lp_rq_lock;
static int mt_lp_resource_update_and_set(struct mt_lp_resource_user *this);
static int mt_lp_resource_request(struct mt_lp_resource_user *this,
unsigned int resource)
{
int i;
struct mt_lp_res_req *const *rs;
int ret;
if ((this == NULL) || (resource == 0) || (resource > MT_LP_RQ_ALL)) {
ERROR("invalid request(%x)\n", resource);
return MT_LP_RQ_STA_BAD;
}
spin_lock(&mt_lp_rq_lock);
rs = (plat_mt_rqm.plat_rqm)->res;
for (i = 0; i < plat_mt_rqm.resource_num; i++) {
if ((resource & rs[i]->res_id) != 0)
rs[i]->res_usage |= this->umask;
}
plat_mt_rqm.flag = MT_LP_RQ_FLAG_NEED_UPDATE;
spin_unlock(&mt_lp_rq_lock);
ret = mt_lp_resource_update_and_set(this);
return ret;
}
static int mt_lp_resource_release(struct mt_lp_resource_user *this)
{
int i;
struct mt_lp_res_req *const *rs;
int ret;
if (this == NULL)
return MT_LP_RQ_STA_BAD;
spin_lock(&mt_lp_rq_lock);
rs = (plat_mt_rqm.plat_rqm)->res;
for (i = 0; i < plat_mt_rqm.resource_num; i++)
rs[i]->res_usage &= ~(this->umask);
plat_mt_rqm.flag = MT_LP_RQ_FLAG_NEED_UPDATE;
spin_unlock(&mt_lp_rq_lock);
ret = mt_lp_resource_update_and_set(this);
return ret;
}
int mt_lp_resource_request_manager_register(struct mt_resource_req_manager *rm)
{
unsigned int count;
struct mt_lp_res_req *const *rs;
if (!rm || !(rm->res) || (plat_mt_rqm.plat_rqm != NULL))
return MT_LP_RQ_STA_BAD;
rs = rm->res;
count = 0;
while (*rs != NULL) {
count++;
rs++;
}
plat_mt_rqm.plat_rqm = rm;
plat_mt_rqm.resource_num = count;
return MT_LP_RQ_STA_OK;
}
int mt_lp_resource_user_register(char *user, struct mt_lp_resource_user *ru)
{
int i, len;
unsigned int uname;
if ((plat_mt_rqm.plat_rqm == NULL) || (user == NULL))
goto invalid;
len = strnlen(user, MT_LP_RQ_USER_NAME_LEN);
uname = 0;
for (i = 0; i < len; i++)
uname |= (user[i] << (MT_LP_RQ_USER_CHAR_U * i));
spin_lock(&mt_lp_rq_lock);
if (plat_mt_rqm.user_num >= MT_LP_RQ_USER_MAX) {
spin_unlock(&mt_lp_rq_lock);
goto invalid;
}
i = plat_mt_rqm.user_num;
plat_mt_rqm.user_num += 1;
plat_mt_rqm.uname[i] = uname;
plat_mt_rqm.user_valid |= BIT(i);
spin_unlock(&mt_lp_rq_lock);
ru->umask = BIT(i);
ru->uid = i;
ru->request = mt_lp_resource_request;
ru->release = mt_lp_resource_release;
INFO("%s register by %s, uid = %d\n", __func__, user, ru->uid);
return MT_LP_RQ_STA_OK;
invalid:
ru->uid = MT_LP_RQ_USER_INVALID;
ru->umask = 0;
ru->request = NULL;
ru->release = NULL;
return MT_LP_RQ_STA_BAD;
}
int mt_lp_rq_get_status(int type, void *p)
{
int i;
unsigned int update_sta = 0;
struct mt_lp_res_req *const *rs;
struct resource_req_status *rq_sta = (struct resource_req_status *)p;
spin_lock(&mt_lp_rq_lock);
if (plat_mt_rqm.flag) {
rs = (plat_mt_rqm.plat_rqm)->res;
for (i = 0; i < plat_mt_rqm.resource_num; i++) {
if ((rs[i]->res_usage & plat_mt_rqm.user_valid) != 0)
update_sta |= rs[i]->res_rq;
}
plat_mt_rqm.generic_resource_req = update_sta;
plat_mt_rqm.flag = MT_LP_RQ_FLAG_DONE;
}
switch (type) {
case PLAT_RQ_REQ_USAGE:
rs = (plat_mt_rqm.plat_rqm)->res;
rq_sta->val = plat_mt_rqm.generic_resource_req;
if (rq_sta->id < plat_mt_rqm.resource_num)
rq_sta->val = rs[rq_sta->id]->res_usage;
break;
case PLAT_RQ_USER_NUM:
rq_sta->val = plat_mt_rqm.user_num;
break;
case PLAT_RQ_USER_VALID:
rq_sta->val = plat_mt_rqm.user_valid;
break;
case PLAT_RQ_PER_USER_NAME:
rq_sta->val = (rq_sta->id < plat_mt_rqm.user_num) ?
plat_mt_rqm.uname[rq_sta->id] : 0;
break;
case PLAT_RQ_REQ_NUM:
rq_sta->val = plat_mt_rqm.resource_num;
break;
default:
break;
}
spin_unlock(&mt_lp_rq_lock);
return MT_LP_RQ_STA_OK;
}
int mt_lp_rq_update_status(int type, void *p)
{
unsigned int user;
struct resource_req_status *rq_sta = (struct resource_req_status *)p;
spin_lock(&mt_lp_rq_lock);
switch (type) {
case PLAT_RQ_USER_VALID:
if (rq_sta->id >= plat_mt_rqm.user_num)
break;
user = BIT(rq_sta->id);
plat_mt_rqm.user_valid = (rq_sta->val == 0) ?
(plat_mt_rqm.user_valid & ~(user)) :
(plat_mt_rqm.user_valid | user);
plat_mt_rqm.flag = MT_LP_RQ_FLAG_NEED_UPDATE;
break;
default:
break;
}
spin_unlock(&mt_lp_rq_lock);
return MT_LP_RQ_STA_OK;
}
static int mt_lp_resource_update_and_set(struct mt_lp_resource_user *this)
{
unsigned int ret = MT_LP_RQ_STA_OK;
struct resource_req_status generic_spm_resource_req = {
.id = MT_LP_RQ_ID_ALL_USAGE,
.val = 0,
};
mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE, &generic_spm_resource_req);
ret = mt_lp_rm_do_hwctrl(PLAT_AP_SPM_RESOURCE_REQUEST_UPDATE, 1,
&generic_spm_resource_req.val);
if (ret)
ret = MT_LP_RQ_STA_BAD;
return ret;
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <cdefs.h>
#include <lpm_v2/mt_lpm_dispatch.h>
/*
* Notice, this data don't link to bss section.
* It means data structure won't be set as zero.
* Please make sure the member will be initialized.
*/
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 res;
user = MT_LPM_SMC_USER(x1);
if ((user < MT_LPM_SMC_USER_MAX) &&
(mt_dispatcher.enable & (1 << 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;
unsigned int user;
if (!IS_MT_LPM_SMC(x1))
return res;
user = MT_LPM_SMC_USER(x1);
if (mt_secure_dispatcher.enable & (1 << 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;
}

View file

@ -0,0 +1,19 @@
#
# Copyright (c) 2025, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := lpm_v2
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_lp_mmap.c
LOCAL_SRCS-y += ${LOCAL_DIR}/mt_lpm_dispatch.c
PLAT_INCLUDES += -I${LOCAL_DIR}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,314 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_CPU_PM_H
#define MT_CPU_PM_H
#include <assert.h>
#include <platform_def.h>
#include <lib/pm/mtk_pm.h>
#if !HW_ASSISTED_COHERENCY
#define MT_CPU_PM_USING_BAKERY_LOCK
#endif /* !HW_ASSISTED_COHERENCY */
/*
* Enable bit of CPU_PM callbacks
*/
static inline unsigned int CPU_PM_FN(void)
{
return (MTK_CPUPM_FN_CPUPM_GET_PWR_STATE |
MTK_CPUPM_FN_PWR_STATE_VALID |
MTK_CPUPM_FN_PWR_ON_CORE_PREPARE |
MTK_CPUPM_FN_RESUME_CORE |
#ifdef CPU_PM_PWR_REQ
MTK_CPUPM_FN_SUSPEND_CLUSTER |
#endif /* CPU_PM_PWR_REQ */
MTK_CPUPM_FN_RESUME_CLUSTER |
MTK_CPUPM_FN_SUSPEND_MCUSYS |
MTK_CPUPM_FN_RESUME_MCUSYS |
MTK_CPUPM_FN_SMP_INIT |
MTK_CPUPM_FN_SMP_CORE_ON |
MTK_CPUPM_FN_SMP_CORE_OFF);
}
#define CPU_PM_ASSERT(_cond) ({ \
if (!(_cond)) { \
INFO("[%s:%d] - %s\n", __func__, __LINE__, #_cond); \
panic(); \
} })
/* related registers */
#define SPM_POWERON_CONFIG_EN (SPM_BASE + 0x000)
#define SPM_CPU_PWR_STATUS (SPM_BASE + 0x174)
/* bit-fields of SPM_POWERON_CONFIG_EN */
#define PROJECT_CODE (0xB16U << 16)
#define BCLK_CG_EN BIT(0)
#define CPC_PWR_MASK_MCUSYS_MP0 (0xC001)
#define PER_CLUSTER_PWR_DATA(_p, _cl) ({ \
_p.pwr.ppu_pwpr = CLUSTER_PPU_PWPR_##_cl; \
_p.pwr.ppu_pwsr = CLUSTER_PPU_PWSR_##_cl; \
_p.pwr.ppu_dcdr0 = CLUSTER_PPU_DCDR0_##_cl; \
_p.pwr.ppu_dcdr1 = CLUSTER_PPU_DCDR1_##_cl; \
})
#define PER_CLUSTER_PWR_CTRL(_val, _cl) ({ \
switch (_cl) { \
case 0: \
PER_CLUSTER_PWR_DATA(_val, 0); \
break; \
default: \
assert(0); \
break; \
} })
#define PER_CPU_PWR_DATA(_p, _cl, _c) ({ \
_p.rvbaraddr_l = CORE_RVBRADDR_##_cl##_##_c##_L; \
_p.rvbaraddr_h = CORE_RVBRADDR_##_cl##_##_c##_H; \
_p.pwr.ppu_pwpr = CORE_PPU_PWPR_##_cl##_##_c; \
_p.pwr.ppu_pwsr = CORE_PPU_PWSR_##_cl##_##_c; \
_p.pwr.ppu_dcdr0 = CORE_PPU_DCDR0_##_cl##_##_c; \
_p.pwr.ppu_dcdr1 = CORE_PPU_DCDR1_##_cl##_##_c; })
#define PER_CPU_PWR_CTRL(_val, _cpu) ({ \
switch (_cpu) { \
case 0: \
PER_CPU_PWR_DATA(_val, 0, 0); \
break; \
case 1: \
PER_CPU_PWR_DATA(_val, 0, 1); \
break; \
case 2: \
PER_CPU_PWR_DATA(_val, 0, 2); \
break; \
case 3: \
PER_CPU_PWR_DATA(_val, 0, 3); \
break; \
case 4: \
PER_CPU_PWR_DATA(_val, 0, 4); \
break; \
case 5: \
PER_CPU_PWR_DATA(_val, 0, 5); \
break; \
case 6: \
PER_CPU_PWR_DATA(_val, 0, 6); \
break; \
case 7: \
PER_CPU_PWR_DATA(_val, 0, 7); \
break; \
default: \
assert(0); \
break; \
} })
/*
* Definition about bootup address for each core
* CORE_RVBRADDR_clusterid_cpuid
*/
#define CORE_RVBRADDR_0_0_L (MCUCFG_BASE + 0x00)
#define CORE_RVBRADDR_0_1_L (MCUCFG_BASE + 0x08)
#define CORE_RVBRADDR_0_2_L (MCUCFG_BASE + 0x10)
#define CORE_RVBRADDR_0_3_L (MCUCFG_BASE + 0x18)
#define CORE_RVBRADDR_0_4_L (MCUCFG_BASE + 0x20)
#define CORE_RVBRADDR_0_5_L (MCUCFG_BASE + 0x28)
#define CORE_RVBRADDR_0_6_L (MCUCFG_BASE + 0x30)
#define CORE_RVBRADDR_0_7_L (MCUCFG_BASE + 0x38)
#define CORE_RVBRADDR_0_0_H (MCUCFG_BASE + 0x04)
#define CORE_RVBRADDR_0_1_H (MCUCFG_BASE + 0x0C)
#define CORE_RVBRADDR_0_2_H (MCUCFG_BASE + 0x14)
#define CORE_RVBRADDR_0_3_H (MCUCFG_BASE + 0x1C)
#define CORE_RVBRADDR_0_4_H (MCUCFG_BASE + 0x24)
#define CORE_RVBRADDR_0_5_H (MCUCFG_BASE + 0x2C)
#define CORE_RVBRADDR_0_6_H (MCUCFG_BASE + 0x34)
#define CORE_RVBRADDR_0_7_H (MCUCFG_BASE + 0x3C)
/*
* Definition about PPU PWPR for each core
* PPU_PWPR_clusterid_cpuid
*/
#define CORE_PPU_PWPR_0_0 (MT_UTILITYBUS_BASE + 0x080000)
#define CORE_PPU_PWPR_0_1 (MT_UTILITYBUS_BASE + 0x180000)
#define CORE_PPU_PWPR_0_2 (MT_UTILITYBUS_BASE + 0x280000)
#define CORE_PPU_PWPR_0_3 (MT_UTILITYBUS_BASE + 0x380000)
#define CORE_PPU_PWPR_0_4 (MT_UTILITYBUS_BASE + 0x480000)
#define CORE_PPU_PWPR_0_5 (MT_UTILITYBUS_BASE + 0x580000)
#define CORE_PPU_PWPR_0_6 (MT_UTILITYBUS_BASE + 0x680000)
#define CORE_PPU_PWPR_0_7 (MT_UTILITYBUS_BASE + 0x780000)
/*
* Definition about PPU PWSR for each core
* PPU_PWSR_clusterid_cpuid
*/
#define CORE_PPU_PWSR_0_0 (MT_UTILITYBUS_BASE + 0x080008)
#define CORE_PPU_PWSR_0_1 (MT_UTILITYBUS_BASE + 0x180008)
#define CORE_PPU_PWSR_0_2 (MT_UTILITYBUS_BASE + 0x280008)
#define CORE_PPU_PWSR_0_3 (MT_UTILITYBUS_BASE + 0x380008)
#define CORE_PPU_PWSR_0_4 (MT_UTILITYBUS_BASE + 0x480008)
#define CORE_PPU_PWSR_0_5 (MT_UTILITYBUS_BASE + 0x580008)
#define CORE_PPU_PWSR_0_6 (MT_UTILITYBUS_BASE + 0x680008)
#define CORE_PPU_PWSR_0_7 (MT_UTILITYBUS_BASE + 0x780008)
/*
* Definition about device delay control 0
* PPU_DCDR0_clusterid_cpuid
*/
#define CORE_PPU_DCDR0_0_0 (MT_UTILITYBUS_BASE + 0x080170)
#define CORE_PPU_DCDR0_0_1 (MT_UTILITYBUS_BASE + 0x180170)
#define CORE_PPU_DCDR0_0_2 (MT_UTILITYBUS_BASE + 0x280170)
#define CORE_PPU_DCDR0_0_3 (MT_UTILITYBUS_BASE + 0x380170)
#define CORE_PPU_DCDR0_0_4 (MT_UTILITYBUS_BASE + 0x480170)
#define CORE_PPU_DCDR0_0_5 (MT_UTILITYBUS_BASE + 0x580170)
#define CORE_PPU_DCDR0_0_6 (MT_UTILITYBUS_BASE + 0x680170)
#define CORE_PPU_DCDR0_0_7 (MT_UTILITYBUS_BASE + 0x780170)
/*
* Definition about device delay control 1
* PPU_DCDR0_clusterid_cpuid
*/
#define CORE_PPU_DCDR1_0_0 (MT_UTILITYBUS_BASE + 0x080174)
#define CORE_PPU_DCDR1_0_1 (MT_UTILITYBUS_BASE + 0x180174)
#define CORE_PPU_DCDR1_0_2 (MT_UTILITYBUS_BASE + 0x280174)
#define CORE_PPU_DCDR1_0_3 (MT_UTILITYBUS_BASE + 0x380174)
#define CORE_PPU_DCDR1_0_4 (MT_UTILITYBUS_BASE + 0x480174)
#define CORE_PPU_DCDR1_0_5 (MT_UTILITYBUS_BASE + 0x580174)
#define CORE_PPU_DCDR1_0_6 (MT_UTILITYBUS_BASE + 0x680174)
#define CORE_PPU_DCDR1_0_7 (MT_UTILITYBUS_BASE + 0x780174)
/*
* Definition about PPU PWPR for cluster
* PPU_PWPR_clusterid
*/
#define CLUSTER_PPU_PWPR_0 (MT_UTILITYBUS_BASE + 0x030000)
#define CLUSTER_PPU_PWSR_0 (MT_UTILITYBUS_BASE + 0x030008)
#define CLUSTER_PPU_DCDR0_0 (MT_UTILITYBUS_BASE + 0x030170)
#define CLUSTER_PPU_DCDR1_0 (MT_UTILITYBUS_BASE + 0x030174)
struct ppu_pwr_ctrl {
unsigned int ppu_pwpr;
unsigned int ppu_pwsr;
unsigned int ppu_dcdr0;
unsigned int ppu_dcdr1;
};
struct cpu_pwr_ctrl {
unsigned int rvbaraddr_l;
unsigned int rvbaraddr_h;
#ifndef CPU_PM_CORE_ARCH64_ONLY
unsigned int arch_addr;
#endif /* CPU_PM_CORE_ARCH64_ONLY */
struct ppu_pwr_ctrl pwr;
unsigned int pwr_ctrl;
};
struct cluster_pwr_ctrl {
struct ppu_pwr_ctrl pwr;
};
#define MT_CPUPM_PWR_ON BIT(0)
#define MT_CPUPM_PWR_OFF BIT(1)
#ifdef CPU_PM_SUSPEND_NOTIFY
#define PER_CPU_STATUS_S2IDLE BIT(0)
#define PER_CPU_STATUS_PDN BIT(1)
#define PER_CPU_STATUS_HOTPLUG BIT(2)
#define PER_CPU_STATUS_S2IDLE_PDN \
(PER_CPU_STATUS_S2IDLE | PER_CPU_STATUS_PDN)
#define CPUPM_PWR_STATUS(_state, _tar) ((_state & _tar) == _tar)
#define IS_CPUPM_SAVE_PWR_STATUS(_state) ( \
CPUPM_PWR_STATUS(_state, PER_CPU_STATUS_S2IDLE_PDN) || \
(_state & PER_CPU_STATUS_HOTPLUG))
#ifdef CONFIG_MTK_CPU_ILDO
#define CPU_PM_CPU_RET_IS_ENABLED CPU_PM_CPU_RET_MASK
enum {
CPU_PM_RET_SET_SUCCESS = 0,
CPU_PM_RET_SET_FAIL
};
#define CPU_EB_RET_STA_REG (CPU_EB_TCM_BASE + CPU_EB_RET_STA_OFFSET)
#define CPU_RET_TIMEOUT 100
#endif /* CONFIG_MTK_CPU_ILDO */
struct per_cpu_stage {
unsigned int cpu_status;
};
#endif /* CPU_PM_SUSPEND_NOTIFY */
#define MCUSYS_STATUS_PDN BIT(0)
#define MCUSYS_STATUS_CPUSYS_PROTECT BIT(8)
#define MCUSYS_STATUS_MCUSYS_PROTECT BIT(9)
#ifdef CPU_PM_ACP_FSM
#define ACP_FSM_TIMEOUT_MAX (500)
#define ACP_FSM_AWARE_TIME (100)
#define DO_ACP_FSM_WAIT_TIMEOUT(k_cnt) ({ \
if (k_cnt >= ACP_FSM_TIMEOUT_MAX) { \
INFO("[%s:%d] - ACP FSM TIMEOUT %u us (> %u)\n", \
__func__, __LINE__, k_cnt, ACP_FSM_TIMEOUT_MAX); \
panic(); \
} else if (k_cnt == ACP_FSM_AWARE_TIME) { \
INFO("[%s:%d] - ACP FSM latency exceed %u us\n", \
__func__, __LINE__, ACP_FSM_AWARE_TIME); \
} \
k_cnt++; udelay(1); })
#endif /* CPU_PM_ACP_FSM */
/* cpu_pm function ID */
enum mt_cpu_pm_user_id {
MCUSYS_STATUS = 0,
CPC_COMMAND,
};
/* cpu_pm lp function ID */
enum mt_cpu_pm_lp_smc_id {
LP_CPC_COMMAND = 0,
IRQS_REMAIN_ALLOC,
IRQS_REMAIN_CTRL,
IRQS_REMAIN_IRQ,
IRQS_REMAIN_WAKEUP_CAT,
IRQS_REMAIN_WAKEUP_SRC,
SUSPEND_SRC,
CPU_PM_COUNTER_CTRL,
CPU_PM_RECORD_CTRL,
SUSPEND_ABORT_REASON,
CPU_PM_RET_CTRL
};
enum mt_suspend_abort_reason {
MTK_PM_SUSPEND_OK = 0,
MTK_PM_SUSPEND_ABORT_PWR_REQ,
MTK_PM_SUSPEND_ABORT_LAST_CORE,
MTK_PM_SUSPEND_ABORT_RC_INVALID,
};
struct mtk_plat_dev_config {
int auto_off;
unsigned int auto_thres_us;
};
struct mt_cpu_pm_record {
unsigned int cnt;
uint64_t name[2];
};
unsigned int cpupm_cpu_retention_control(unsigned int enable);
unsigned int cpupu_get_cpu_retention_control(void);
void mt_plat_cpu_pm_dev_update(struct mtk_plat_dev_config *config);
int mt_plat_cpu_pm_dev_config(struct mtk_plat_dev_config **config);
int cpupm_set_suspend_state(unsigned int act, unsigned int cpuid);
uint64_t mtk_mcusys_off_record_cnt_get(void);
uint64_t mtk_mcusys_off_record_name_get(void);
uint64_t mtk_suspend_abort_reason_get(void);
#endif /* MT_CPU_PM_H */

View file

@ -0,0 +1,701 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <drivers/delay_timer.h>
#include <lib/spinlock.h>
#include <lib/pm/mtk_pm.h>
#include <mcucfg.h>
#include "mt_cpu_pm.h"
#include "mt_cpu_pm_cpc.h"
#include "mt_smp.h"
#include <mt_timer.h>
#define CHECK_GIC_SGI_PENDING (0)
#define MTK_SYS_TIMER_SYNC_SUPPORT (1)
#define MCUSYS_CLUSTER_DORMANT_MASK 0xFFFF
struct mtk_cpc_lat_data {
unsigned int on_sum;
unsigned int on_min;
unsigned int on_max;
unsigned int off_sum;
unsigned int off_min;
unsigned int off_max;
unsigned int on_cnt;
unsigned int off_cnt;
};
struct mtk_cpc_device {
union {
struct mtk_cpc_lat_data p[DEV_TYPE_NUM];
struct {
struct mtk_cpc_lat_data cpu[PLATFORM_CORE_COUNT];
struct mtk_cpc_lat_data cluster;
struct mtk_cpc_lat_data mcusys;
};
};
};
static struct mtk_cpc_device cpc_dev;
static bool cpu_pm_counter_enabled;
static bool cpu_cpc_prof_enabled;
static void mtk_cpc_auto_dormant_en(unsigned int en)
{
struct mtk_plat_dev_config *cfg = NULL;
if (en)
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_AUTO_OFF_EN);
else
mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_AUTO_OFF_EN);
mt_plat_cpu_pm_dev_config(&cfg);
if (cfg) {
cfg->auto_off = !!en;
mt_plat_cpu_pm_dev_update(cfg);
}
}
static void mtk_cpc_auto_dormant_tick(unsigned int us)
{
struct mtk_plat_dev_config *cfg = NULL;
mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, US_TO_TICKS(us));
mt_plat_cpu_pm_dev_config(&cfg);
if (cfg) {
cfg->auto_thres_us = us;
mt_plat_cpu_pm_dev_update(cfg);
}
}
static void mtk_cpu_pm_mcusys_prot_release(void)
{
mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
}
static int mtk_cpc_last_core_prot(int prot_req, int resp_reg, int resp_ofs)
{
unsigned int sta, retry;
retry = 0;
while (retry < RETRY_CNT_MAX) {
mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
udelay(1);
sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
if (sta == PROT_GIVEUP)
return CPC_ERR_FAIL;
if (sta == PROT_SUCCESS) {
if (mmio_read_32(CPC_WAKEUP_REQ) ==
CPC_WAKEUP_STAT_NONE)
return CPC_SUCCESS;
mtk_cpu_pm_mcusys_prot_release();
}
retry++;
}
return CPC_ERR_TIMEOUT;
}
static int mtk_cpu_pm_mcusys_prot_aquire(void)
{
return mtk_cpc_last_core_prot(MCUSYS_PROT_SET,
CPC_MCUSYS_LAST_CORE_RESP,
MCUSYS_RESP_OFS);
}
int mtk_cpu_pm_cluster_prot_aquire(int cluster)
{
return mtk_cpc_last_core_prot(CPUSYS_PROT_SET,
CPC_MCUSYS_MP_LAST_CORE_RESP,
CPUSYS_RESP_OFS);
}
void mtk_cpu_pm_cluster_prot_release(int cluster)
{
mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
}
static bool is_cpu_pm_counter_enabled(void)
{
return cpu_pm_counter_enabled;
}
static void mtk_cpc_cluster_cnt_backup(void)
{
int backup_cnt;
int curr_cnt;
if (is_cpu_pm_counter_enabled() == false)
return;
/* Single Cluster */
backup_cnt = mmio_read_32(SYSRAM_CLUSTER_CNT_BACKUP);
curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
/* Get off count if dormant count is 0 */
if ((curr_cnt & MCUSYS_CLUSTER_DORMANT_MASK) == 0)
curr_cnt = (curr_cnt >> 16) & MCUSYS_CLUSTER_DORMANT_MASK;
else
curr_cnt = curr_cnt & MCUSYS_CLUSTER_DORMANT_MASK;
mmio_write_32(SYSRAM_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, 0x3);
}
static inline void mtk_cpc_mcusys_off_en(void)
{
mmio_setbits_32(CPC_MCUSYS_PWR_CTRL, CPC_MCUSYS_OFF_EN);
}
static inline void mtk_cpc_mcusys_off_dis(void)
{
mmio_clrbits_32(CPC_MCUSYS_PWR_CTRL, CPC_MCUSYS_OFF_EN);
}
void mtk_cpc_mcusys_off_reflect(void)
{
mtk_cpc_mcusys_off_dis();
mtk_cpu_pm_mcusys_prot_release();
}
int mtk_cpc_mcusys_off_prepare(void)
{
if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS)
return CPC_ERR_FAIL;
#if CHECK_GIC_SGI_PENDING
if (!!(gicr_get_sgi_pending())) {
mtk_cpu_pm_mcusys_prot_release();
return CPC_ERR_FAIL;
}
#endif /* CHECK_GIC_SGI_PENDING */
mtk_cpc_cluster_cnt_backup();
mtk_cpc_mcusys_off_en();
return CPC_SUCCESS;
}
void mtk_cpc_core_on_hint_set(int cpu)
{
mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
}
void mtk_cpc_core_on_hint_clr(int cpu)
{
mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
}
static void mtk_cpc_dump_timestamp(void)
{
unsigned int id;
for (id = 0; id < CPC_TRACE_ID_NUM; id++) {
mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
(const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
CPC_TRACE_SIZE);
}
}
void mtk_cpc_time_sync(void)
{
#if MTK_SYS_TIMER_SYNC_SUPPORT
uint64_t kt;
uint32_t systime_l, systime_h;
kt = sched_clock();
systime_l = mmio_read_32(CNTSYS_L_REG);
systime_h = mmio_read_32(CNTSYS_H_REG);
/* sync kernel timer to cpc */
mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
/* sync system timer to cpc */
mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
#endif /* MTK_SYS_TIMER_SYNC_SUPPORT */
}
static void mtk_cpc_time_freeze(bool is_freeze)
{
#if MTK_SYS_TIMER_SYNC_SUPPORT
mtk_cpc_time_sync();
if (is_freeze)
mmio_setbits_32(CPC_MCUSYS_CPC_DBG_SETTING, CPC_FREEZE);
else
mmio_clrbits_32(CPC_MCUSYS_CPC_DBG_SETTING, CPC_FREEZE);
#endif /* MTK_SYS_TIMER_SYNC_SUPPORT */
}
static void *mtk_cpc_el3_timesync_handler(const void *arg)
{
if (arg) {
unsigned int *is_time_sync = (unsigned int *)arg;
if (*is_time_sync)
mtk_cpc_time_freeze(false);
else
mtk_cpc_time_freeze(true);
}
return (void *)arg;
}
MT_CPUPM_SUBCRIBE_EL3_UPTIME_SYNC_WITH_KERNEL(mtk_cpc_el3_timesync_handler);
static void mtk_cpc_config(unsigned int cfg, unsigned int data)
{
unsigned int reg = 0;
switch (cfg) {
case CPC_SMC_CONFIG_PROF:
reg = CPC_MCUSYS_CPC_DBG_SETTING;
if (data)
mmio_setbits_32(reg, CPC_PROF_EN);
else
mmio_clrbits_32(reg, CPC_PROF_EN);
break;
case CPC_SMC_CONFIG_CNT_CLR:
reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR;
mmio_write_32(reg, 0x3);
break;
case CPC_SMC_CONFIG_TIME_SYNC:
mtk_cpc_time_sync();
break;
default:
break;
}
}
static unsigned int mtk_cpc_read_config(unsigned int cfg)
{
unsigned int res = 0;
switch (cfg) {
case CPC_SMC_CONFIG_PROF:
res = mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN
? 1 : 0;
break;
default:
break;
}
return res;
}
#define PROF_DEV_NAME_LEN 8
uint64_t mtk_cpc_prof_dev_name(unsigned int dev_id)
{
uint64_t ret = 0, tran = 0;
unsigned int i = 0;
static const char *prof_dev_name[DEV_TYPE_NUM] = {
"CPU0",
"CPU1",
"CPU2",
"CPU3",
"CPU4",
"CPU5",
"CPU6",
"CPU7",
"CPUSYS",
"MCUSYS"
};
while ((prof_dev_name[dev_id][i] != '\0') && (i < PROF_DEV_NAME_LEN)) {
tran = (uint64_t)(prof_dev_name[dev_id][i] & 0xFF);
ret |= (tran << (i << 3));
i++;
}
return ret;
}
static void mtk_cpc_prof_clr(void)
{
int i;
for (i = 0; i < DEV_TYPE_NUM; i++)
memset((char *)&cpc_dev.p[i], 0,
sizeof(struct mtk_cpc_lat_data));
}
void mtk_cpc_prof_enable(bool enable)
{
unsigned int reg = 0;
reg = CPC_MCUSYS_CPC_DBG_SETTING;
if (enable)
mmio_setbits_32(reg, CPC_PROF_EN);
else
mmio_clrbits_32(reg, CPC_PROF_EN);
if ((cpu_cpc_prof_enabled == false) && (enable == true))
mtk_cpc_prof_clr();
cpu_cpc_prof_enabled = enable;
}
bool mtk_cpc_prof_is_enabled(void)
{
return cpu_cpc_prof_enabled;
}
uint64_t mtk_cpc_prof_dev_num(void)
{
return DEV_TYPE_NUM;
}
#define cpc_tick_to_us(val) ((val) / 13)
uint64_t mtk_cpc_prof_read(unsigned int prof_act, unsigned int dev_type)
{
uint64_t ret = 0;
struct mtk_cpc_lat_data *lat_data;
if (dev_type >= DEV_TYPE_NUM)
return CPC_ERR_FAIL;
lat_data = &cpc_dev.p[dev_type];
switch (prof_act) {
case CPC_PROF_OFF_CNT:
ret = lat_data->off_cnt;
break;
case CPC_PROF_OFF_AVG:
ret = cpc_tick_to_us(lat_data->off_sum / lat_data->off_cnt);
break;
case CPC_PROF_OFF_MAX:
ret = cpc_tick_to_us(lat_data->off_max);
break;
case CPC_PROF_OFF_MIN:
ret = cpc_tick_to_us(lat_data->off_min);
break;
case CPC_PROF_ON_CNT:
ret = lat_data->on_cnt;
break;
case CPC_PROF_ON_AVG:
ret = cpc_tick_to_us(lat_data->on_sum / lat_data->on_cnt);
break;
case CPC_PROF_ON_MAX:
ret = cpc_tick_to_us(lat_data->on_max);
break;
case CPC_PROF_ON_MIN:
ret = cpc_tick_to_us(lat_data->on_min);
break;
default:
break;
}
return ret;
}
uint64_t mtk_cpc_prof_latency(unsigned int prof_act, unsigned int arg)
{
uint64_t res = 0;
switch (prof_act) {
case CPC_PROF_ENABLE:
mtk_cpc_prof_enable((bool)arg);
break;
case CPC_PROF_ENABLED:
res = (uint64_t)mtk_cpc_prof_is_enabled();
break;
case CPC_PROF_DEV_NUM:
res = mtk_cpc_prof_dev_num();
break;
case CPC_PROF_DEV_NAME:
res = mtk_cpc_prof_dev_name(arg);
break;
case CPC_PROF_OFF_CNT:
case CPC_PROF_OFF_AVG:
case CPC_PROF_OFF_MAX:
case CPC_PROF_OFF_MIN:
case CPC_PROF_ON_CNT:
case CPC_PROF_ON_AVG:
case CPC_PROF_ON_MAX:
case CPC_PROF_ON_MIN:
res = (uint64_t)mtk_cpc_prof_read(prof_act, arg);
break;
default:
break;
}
return res;
}
uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
{
uint64_t res = 0;
switch (act) {
case CPC_SMC_EVENT_GIC_DPG_SET:
/* isolated_status = x2; */
break;
case CPC_SMC_EVENT_CPC_CONFIG:
mtk_cpc_config((unsigned int)arg1, (unsigned int)arg2);
break;
case CPC_SMC_EVENT_READ_CONFIG:
res = mtk_cpc_read_config((unsigned int)arg1);
break;
case CPC_SMC_EVENT_PROF_LATENCY:
res = mtk_cpc_prof_latency((unsigned int)arg1,
(unsigned int)arg2);
break;
default:
break;
}
return res;
}
uint64_t mtk_cpc_trace_dump(uint64_t act, uint64_t arg1, uint64_t arg2)
{
uint64_t res = 0;
switch (act) {
case CPC_SMC_EVENT_DUMP_TRACE_DATA:
mtk_cpc_dump_timestamp();
break;
default:
break;
}
return res;
}
void mtk_cpu_pm_counter_clear(void)
{
unsigned int cpu = 0;
for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
mmio_write_32(SYSRAM_RECENT_CPU_CNT(cpu), 0);
mmio_write_32(SYSRAM_RECENT_CLUSTER_CNT, 0);
mmio_write_32(SYSRAM_RECENT_MCUSYS_CNT, 0);
mmio_write_32(SYSRAM_CPUSYS_CNT, 0);
mmio_write_32(SYSRAM_MCUSYS_CNT, 0);
mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, 0x3);
mmio_write_32(SYSRAM_CLUSTER_CNT_BACKUP, 0x0);
mmio_write_32(SYSRAM_RECENT_CNT_TS_H, 0x0);
mmio_write_32(SYSRAM_RECENT_CNT_TS_L, 0x0);
}
void mtk_cpu_pm_counter_enable(bool enable)
{
cpu_pm_counter_enabled = enable;
if (cpu_pm_counter_enabled == false)
mtk_cpu_pm_counter_clear();
}
bool mtk_cpu_pm_counter_enabled(void)
{
return cpu_pm_counter_enabled;
}
#define sec_to_us(v) ((v) * 1000 * 1000ULL)
#define DUMP_INTERVAL sec_to_us(5)
void mtk_cpu_pm_counter_update(unsigned int cpu)
{
#ifdef CONFIG_MTK_CPU_SUSPEND_EN
unsigned int cnt = 0, curr_mcusys_cnt = 0, mcusys_cnt = 0;
static unsigned int prev_mcusys_cnt = 0,
cpu_cnt[PLATFORM_CORE_COUNT] = {0};
uint64_t curr_us = 0;
static uint64_t last_dump_us;
static bool reset;
if (is_cpu_pm_counter_enabled() == false) {
reset = true;
return;
}
if (reset == true) {
last_dump_us = sched_clock() / 1000;
prev_mcusys_cnt = mmio_read_32(MCUPM_TCM_MCUSYS_COUNTER);
mtk_cpu_pm_counter_clear();
cpu_cnt[cpu] = 0;
reset = false;
}
cpu_cnt[cpu]++;
curr_us = sched_clock() / 1000;
if (curr_us - last_dump_us > DUMP_INTERVAL) {
last_dump_us = curr_us;
/* CPU off count */
for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
mmio_write_32(SYSRAM_RECENT_CPU_CNT(cpu),
cpu_cnt[cpu]);
cpu_cnt[cpu] = 0;
}
/* Cluster off count */
curr_mcusys_cnt = mmio_read_32(MCUPM_TCM_MCUSYS_COUNTER);
if (curr_mcusys_cnt >= prev_mcusys_cnt)
mcusys_cnt = curr_mcusys_cnt - prev_mcusys_cnt;
else
mcusys_cnt = curr_mcusys_cnt;
prev_mcusys_cnt = mmio_read_32(MCUPM_TCM_MCUSYS_COUNTER);
cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
/**
* bit[0:15] : memory retention
* bit[16:31] : memory off
*/
if ((cnt & MCUSYS_CLUSTER_DORMANT_MASK) == 0)
cnt = ((cnt >> 16) & MCUSYS_CLUSTER_DORMANT_MASK);
else
cnt = cnt & MCUSYS_CLUSTER_DORMANT_MASK;
cnt += mmio_read_32(SYSRAM_CLUSTER_CNT_BACKUP);
cnt += mcusys_cnt;
mmio_write_32(SYSRAM_RECENT_CLUSTER_CNT, cnt);
mmio_write_32(SYSRAM_CPUSYS_CNT,
cnt + mmio_read_32(SYSRAM_CPUSYS_CNT));
mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, 0x3);
mmio_write_32(SYSRAM_CLUSTER_CNT_BACKUP, 0x0);
/* MCUSYS off count */
mmio_write_32(SYSRAM_RECENT_MCUSYS_CNT,
mcusys_cnt);
mmio_write_32(SYSRAM_MCUSYS_CNT,
mmio_read_32(SYSRAM_MCUSYS_CNT) + mcusys_cnt);
mmio_write_32(SYSRAM_RECENT_CNT_TS_H,
(unsigned int)((last_dump_us >> 32) & 0xFFFFFFFF));
mmio_write_32(SYSRAM_RECENT_CNT_TS_L,
(unsigned int)(last_dump_us & 0xFFFFFFFF));
}
#endif /* CONFIG_MTK_CPU_SUSPEND_EN */
}
#define __mtk_cpc_record_lat(sum, min, max, lat)\
do { \
if (lat > max) \
max = lat; \
if ((lat < min) || (min == 0)) \
min = lat; \
(sum) += (lat); \
} while (0)
#ifdef MT_CPU_PM_USING_BAKERY_LOCK
DEFINE_BAKERY_LOCK(mt_cpu_pm_cpc_lock);
#define plat_cpu_pm_cpc_lock_init() bakery_lock_init(&mt_cpu_pm_cpc_lock)
#define plat_cpu_pm_cpc_lock() bakery_lock_get(&mt_cpu_pm_cpc_lock)
#define plat_cpu_pm_cpc_unlock() bakery_lock_release(&mt_cpu_pm_cpc_lock)
#else
spinlock_t mt_cpu_pm_cpc_lock;
#define plat_cpu_pm_cpc_lock_init()
#define plat_cpu_pm_cpc_lock() spin_lock(&mt_cpu_pm_cpc_lock)
#define plat_cpu_pm_cpc_unlock() spin_unlock(&mt_cpu_pm_cpc_lock)
#endif /* MT_CPU_PM_USING_BAKERY_LOCK */
static void mtk_cpc_record_lat(struct mtk_cpc_lat_data *lat,
unsigned int on_ticks, unsigned int off_ticks)
{
if ((on_ticks == 0) || (off_ticks == 0))
return;
__mtk_cpc_record_lat(lat->on_sum, lat->on_min, lat->on_max, on_ticks);
lat->on_cnt++;
__mtk_cpc_record_lat(lat->off_sum, lat->off_min,
lat->off_max, off_ticks);
lat->off_cnt++;
}
#define CPC_CPU_LATENCY_MASK 0xFFFF
void mtk_cpu_pm_save_cpc_latency(enum dev_type dev_type)
{
unsigned int lat = 0, lat_on = 0, lat_off = 0;
struct mtk_cpc_lat_data *lat_data = NULL;
if (mtk_cpc_prof_is_enabled() == false)
return;
plat_cpu_pm_cpc_lock();
if (dev_type < DEV_TYPE_CPUSYS) {
lat = mmio_read_32(CPC_CPU_ON_LATENCY(dev_type));
lat_on = lat & CPC_CPU_LATENCY_MASK;
lat = mmio_read_32(CPC_CPU_OFF_LATENCY(dev_type));
lat_off = lat & CPC_CPU_LATENCY_MASK;
lat_data = &cpc_dev.cpu[dev_type];
} else if (dev_type == DEV_TYPE_CPUSYS) {
lat_on = mmio_read_32(CPC_CLUSTER_ON_LATENCY);
lat_on = lat_on & CPC_CPU_LATENCY_MASK;
lat_off = mmio_read_32(CPC_CLUSTER_OFF_LATENCY);
lat_off = lat_off & CPC_CPU_LATENCY_MASK;
lat_data = &cpc_dev.cluster;
} else if (dev_type == DEV_TYPE_MCUSYS) {
lat = mmio_read_32(CPC_MCUSYS_ON_LATENCY);
lat_on = lat & CPC_CPU_LATENCY_MASK;
lat = mmio_read_32(CPC_MCUSYS_OFF_LATENCY);
lat_off = lat & CPC_CPU_LATENCY_MASK;
lat_data = &cpc_dev.mcusys;
}
if (lat_data)
mtk_cpc_record_lat(lat_data, lat_on, lat_off);
plat_cpu_pm_cpc_unlock();
}
#define RVBARADDR_ONKEEPON_SEL (MCUCFG_BASE + 0x388)
void mtk_cpc_init(void)
{
struct mtk_plat_dev_config cfg = {
#ifndef CPU_PM_ACP_FSM
.auto_off = 1,
#else
.auto_off = 0,
#endif /* CPU_PM_ACP_FSM */
.auto_thres_us = MTK_CPC_AUTO_DORMANT_THR_US,
};
if (mmio_read_32(RVBARADDR_ONKEEPON_SEL) == 0x1) {
ERROR("ONKEEPON_SEL=%x, CPC_FLOW_CTRL_CFG=%x\n",
mmio_read_32(RVBARADDR_ONKEEPON_SEL),
mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG));
mmio_write_32(RVBARADDR_ONKEEPON_SEL, 0x1);
}
#if CONFIG_MTK_SMP_EN
mt_smp_init();
#endif /* CONFIG_MTK_SMP_EN */
#if CONFIG_MTK_CPU_SUSPEND_EN
mtk_cpu_pm_counter_clear();
#endif /* CONFIG_MTK_CPU_SUSPEND_EN */
mtk_cpc_auto_dormant_en(cfg.auto_off);
mtk_cpc_auto_dormant_tick(cfg.auto_thres_us);
mmio_setbits_32(CPC_MCUSYS_CPC_DBG_SETTING,
CPC_DBG_EN | CPC_CALC_EN);
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
CPC_OFF_PRE_EN);
/* enable CPC */
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
plat_cpu_pm_cpc_lock_init();
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_CPU_PM_CPC_H
#define MT_CPU_PM_CPC_H
#include <lib/mmio.h>
#include <platform_def.h>
#include <mcucfg.h>
#include <mcupm_cfg.h>
#define NEED_CPUSYS_PROT_WORKAROUND 1
/* system sram registers */
#define CPUIDLE_SRAM_REG(r) (0x11B000 + (r))
/* db dump */
#define CPC_TRACE_SIZE 0x20
#define CPC_TRACE_ID_NUM 13
#define CPC_TRACE_SRAM(id) (CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
/* backup off count */
#define SYSRAM_RECENT_CPU_CNT(i) CPUIDLE_SRAM_REG(4 * (i) + 0x1B0)
#define SYSRAM_RECENT_CLUSTER_CNT CPUIDLE_SRAM_REG(0x1D0)
#define SYSRAM_RECENT_MCUSYS_CNT CPUIDLE_SRAM_REG(0x1D4)
#define SYSRAM_RECENT_CNT_TS_L CPUIDLE_SRAM_REG(0x1D8)
#define SYSRAM_RECENT_CNT_TS_H CPUIDLE_SRAM_REG(0x1DC)
#define SYSRAM_CPUSYS_CNT CPUIDLE_SRAM_REG(0x1E8)
#define SYSRAM_MCUSYS_CNT CPUIDLE_SRAM_REG(0x1EC)
#define SYSRAM_CLUSTER_CNT_BACKUP CPUIDLE_SRAM_REG(0x1F0)
#define MCUPM_TCM_MCUSYS_COUNTER \
(CPU_EB_TCM_CNT_BASE + CPU_EB_MCUSYS_CNT_OFST)
/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG(0x114): debug setting */
#define CPC_PWR_ON_SEQ_DIS BIT(1)
#define CPC_PWR_ON_PRIORITY BIT(2)
#define CPC_AUTO_OFF_EN BIT(5)
#define CPC_DORMANT_WAIT_EN BIT(14)
#define CPC_CTRL_EN BIT(16)
#define CPC_OFF_PRE_EN BIT(29)
/* CPC_MCUSYS_LAST_CORE_REQ(0x118) : last core protection */
#define CPUSYS_PROT_SET BIT(0)
#define MCUSYS_PROT_SET BIT(8)
/* CPC_PWR_ON_MASK(0x128) : last core protection */
#define CPUSYS_PROT_CLR BIT(8)
#define MCUSYS_PROT_CLR BIT(9)
#define CPC_PROT_RESP_MASK (0x3)
/* CPC_CPUSYS_LAST_CORE_RESP(0x11C) : last core protection */
#define CPUSYS_RESP_OFS (16)
/* CPC_MCUSYS_LAST_CORE_RESP(0x124) : last core protection */
#define MCUSYS_RESP_OFS (30)
#define RETRY_CNT_MAX (1000)
#define PROT_RETRY (0)
#define PROT_SUCCESS (1)
#define PROT_GIVEUP (2)
/* CPC_MCUSYS_CPC_DBG_SETTING(0x200): debug setting */
#define CPC_PROF_EN BIT(0)
#define CPC_DBG_EN BIT(1)
#define CPC_FREEZE BIT(2)
#define CPC_CALC_EN BIT(3)
enum mcusys_cpc_lastcore_prot_status {
CPC_SUCCESS = 0,
CPC_ERR_FAIL,
CPC_ERR_TIMEOUT,
NF_CPC_ERR
};
enum mcusys_cpc_smc_events {
CPC_SMC_EVENT_DUMP_TRACE_DATA,
CPC_SMC_EVENT_GIC_DPG_SET,
CPC_SMC_EVENT_CPC_CONFIG,
CPC_SMC_EVENT_READ_CONFIG,
CPC_SMC_EVENT_PROF_LATENCY,
NF_CPC_SMC_EVENT
};
enum mcusys_cpc_smc_config {
CPC_SMC_CONFIG_PROF,
CPC_SMC_CONFIG_CNT_CLR,
CPC_SMC_CONFIG_TIME_SYNC,
NF_CPC_SMC_CONFIG,
};
enum dev_type {
DEV_TYPE_CPU_0 = 0,
DEV_TYPE_CPUSYS = PLATFORM_CORE_COUNT,
DEV_TYPE_MCUSYS,
DEV_TYPE_NUM
};
enum {
CPC_PROF_ENABLE,
CPC_PROF_ENABLED,
CPC_PROF_DEV_NUM,
CPC_PROF_DEV_NAME,
CPC_PROF_OFF_CNT,
CPC_PROF_OFF_AVG,
CPC_PROF_OFF_MAX,
CPC_PROF_OFF_MIN,
CPC_PROF_ON_CNT,
CPC_PROF_ON_AVG,
CPC_PROF_ON_MAX,
CPC_PROF_ON_MIN,
CPC_PROF_NUM
};
#define MTK_CPC_AUTO_DORMANT_THR_US (8000)
#define US_TO_TICKS(us) ((us) * 26)
#define TICKS_TO_US(tick) ((tick) / 26)
int mtk_cpu_pm_cluster_prot_aquire(int cluster);
void mtk_cpu_pm_cluster_prot_release(int cluster);
void mtk_cpc_mcusys_off_reflect(void);
int mtk_cpc_mcusys_off_prepare(void);
void mtk_cpc_core_on_hint_set(int cpu);
void mtk_cpc_core_on_hint_clr(int cpu);
void mtk_cpc_time_sync(void);
uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
uint64_t mtk_cpc_trace_dump(uint64_t act, uint64_t arg1, uint64_t arg2);
void mtk_cpu_pm_counter_enable(bool enable);
bool mtk_cpu_pm_counter_enabled(void);
void mtk_cpu_pm_counter_update(unsigned int cpu);
void mtk_cpc_prof_enable(bool enable);
bool mtk_cpc_prof_is_enabled(void);
void mtk_cpu_pm_save_cpc_latency(enum dev_type dev_type);
void mtk_cpc_init(void);
#endif /* MT_CPU_PM_CPC_H */

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <mcupm_cfg.h>
#include "mt_cpu_pm_mbox.h"
#ifdef __GNUC__
#define mcdi_likely(x) __builtin_expect(!!(x), 1)
#define mcdi_unlikely(x) __builtin_expect(!!(x), 0)
#else
#define mcdi_likely(x) (x)
#define mcdi_unlikely(x) (x)
#endif /* __GNUC__ */
#define MCUPM_MBOX_3_BASE (CPU_EB_TCM_BASE + CPU_EB_MBOX3_OFFSET)
#define _mcupm_mbox_write(id, val) \
mmio_write_32(MCUPM_MBOX_3_BASE + 4 * (id), val)
#define _mcupm_mbox_read(id) \
mmio_read_32(MCUPM_MBOX_3_BASE + 4 * (id))
void mtk_set_mcupm_pll_mode(unsigned int mode)
{
if (mode < NF_MCUPM_ARMPLL_MODE)
_mcupm_mbox_write(MCUPM_MBOX_ARMPLL_MODE, mode);
}
int mtk_get_mcupm_pll_mode(void)
{
return _mcupm_mbox_read(MCUPM_MBOX_ARMPLL_MODE);
}
void mtk_set_mcupm_buck_mode(unsigned int mode)
{
if (mode < NF_MCUPM_BUCK_MODE)
_mcupm_mbox_write(MCUPM_MBOX_BUCK_MODE, mode);
}
int mtk_get_mcupm_buck_mode(void)
{
return _mcupm_mbox_read(MCUPM_MBOX_BUCK_MODE);
}
void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid)
{
return _mcupm_mbox_write(MCUPM_MBOX_WAKEUP_CPU, cpuid);
}
unsigned int mtk_get_cpu_pm_preffered_cpu(void)
{
return _mcupm_mbox_read(MCUPM_MBOX_WAKEUP_CPU);
}
static int mtk_wait_mbox_init_done(void)
{
int sta = _mcupm_mbox_read(MCUPM_MBOX_TASK_STA);
if (sta != MCUPM_TASK_INIT)
return sta;
mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
_mcupm_mbox_write(MCUPM_MBOX_PWR_CTRL_EN,
MCUPM_MCUSYS_CTRL |
MCUPM_CM_CTRL |
MCUPM_BUCK_CTRL |
MCUPM_ARMPLL_CTRL);
return sta;
}
int mtk_lp_depd_condition(enum cpupm_mbox_depd_type type)
{
int ret = 0, status = 0;
if (type == CPUPM_MBOX_WAIT_DEV_INIT) {
status = mtk_wait_mbox_init_done();
if (mcdi_unlikely(status != MCUPM_TASK_INIT))
ret = -ENXIO;
else
_mcupm_mbox_write(MCUPM_MBOX_AP_READY, 1);
} else if (type == CPUPM_MBOX_WAIT_TASK_READY) {
status = _mcupm_mbox_read(MCUPM_MBOX_TASK_STA);
if (mcdi_unlikely((status != MCUPM_TASK_WAIT) &&
(status != MCUPM_TASK_INIT_FINISH)))
ret = -ENXIO;
}
return ret;
}
void mtk_set_mcupm_group_hint(unsigned int gmask)
{
_mcupm_mbox_write(MCUPM_MBOX_GROUP, gmask);
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_CPU_PM_MBOX_H
#define MT_CPU_PM_MBOX_H
#define MCUPM_MBOX_AP_READY 0
#define MCUPM_MBOX_GROUP 1
#define MCUPM_MBOX_RESERVED_2 2
#define MCUPM_MBOX_RESERVED_3 3
#define MCUPM_MBOX_PWR_CTRL_EN 4
#define MCUPM_MBOX_L3_CACHE_MODE 5
#define MCUPM_MBOX_BUCK_MODE 6
#define MCUPM_MBOX_ARMPLL_MODE 7
#define MCUPM_MBOX_TASK_STA 8
#define MCUPM_MBOX_RESERVED_9 9
#define MCUPM_MBOX_RESERVED_10 10
#define MCUPM_MBOX_RESERVED_11 11
#define MCUPM_MBOX_WAKEUP_CPU 12
#define MCUPM_MCUSYS_CTRL BIT(0)
#define MCUPM_BUCK_CTRL BIT(1)
#define MCUPM_ARMPLL_CTRL BIT(2)
#define MCUPM_CM_CTRL BIT(3)
#define MCUPM_L3_OFF_MODE 0
#define MCUPM_L3_DORMANT_MODE 1
#define NF_MCUPM_L3_MODE 2U
#define MCUPM_BUCK_NORMAL_MODE 0
#define MCUPM_BUCK_LP_MODE 1
#define MCUPM_BUCK_OFF_MODE 2
#define NF_MCUPM_BUCK_MODE 3U
#define MCUPM_ARMPLL_ON 0
#define MCUPM_ARMPLL_GATING 1
#define MCUPM_ARMPLL_OFF 2
#define NF_MCUPM_ARMPLL_MODE 3U
#define MCUPM_TASK_UNINIT 0
#define MCUPM_TASK_INIT 1
#define MCUPM_TASK_INIT_FINISH 2
#define MCUPM_TASK_WAIT 3
#define MCUPM_TASK_RUN 4
#define MCUPM_TASK_PAUSE 5
void mtk_set_mcupm_pll_mode(unsigned int mode);
int mtk_get_mcupm_pll_mode(void);
void mtk_set_mcupm_buck_mode(unsigned int mode);
int mtk_get_mcupm_buck_mode(void);
void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid);
unsigned int mtk_get_cpu_pm_preffered_cpu(void);
void mtk_set_mcupm_group_hint(unsigned int gmask);
enum cpupm_mbox_depd_type {
CPUPM_MBOX_WAIT_DEV_INIT,
CPUPM_MBOX_WAIT_TASK_READY,
};
int mtk_lp_depd_condition(enum cpupm_mbox_depd_type type);
#endif /* MT_CPU_PM_MBOX_H */

View file

@ -0,0 +1,187 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <lib/spinlock.h>
#include "mt_cpu_pm.h"
#include "mt_cpu_pm_cpc.h"
#include "mt_cpu_pm_smc.h"
#include "mt_lp_irqremain.h"
/*
* The locker must use the bakery locker when cache turn off.
* Using spin_lock will has better performance.
*/
#ifdef MT_CPU_PM_USING_BAKERY_LOCK
DEFINE_BAKERY_LOCK(mt_cpu_pm_smc_lock);
#define plat_cpu_pm_smc_lock_init() bakery_lock_init(&mt_cpu_pm_smc_lock)
#define plat_cpu_pm_smc_lock() bakery_lock_get(&mt_cpu_pm_smc_lock)
#define plat_cpu_pm_smc_unlock() bakery_lock_release(&mt_cpu_pm_smc_lock)
#else
spinlock_t mt_cpu_pm_smc_lock;
#define plat_cpu_pm_smc_lock_init()
#define plat_cpu_pm_smc_lock() spin_lock(&mt_cpu_pm_smc_lock)
#define plat_cpu_pm_smc_unlock() spin_unlock(&mt_cpu_pm_smc_lock)
#endif /* MT_CPU_PM_USING_BAKERY_LOCK */
static uint64_t cpupm_dispatcher(u_register_t lp_id,
u_register_t act,
u_register_t arg1,
u_register_t arg2,
void *handle,
struct smccc_res *smccc_ret)
{
uint64_t res = 0;
switch (lp_id) {
case CPC_COMMAND:
res = mtk_cpc_handler(act, arg1, arg2);
break;
default:
break;
}
return res;
}
static uint64_t cpupm_lp_dispatcher(u_register_t lp_id,
u_register_t act,
u_register_t arg1,
u_register_t arg2,
void *handle,
struct smccc_res *smccc_ret)
{
uint64_t res = 0;
#ifdef CPU_PM_IRQ_REMAIN_ENABLE
int ret;
#endif
switch (lp_id) {
case LP_CPC_COMMAND:
res = mtk_cpc_handler(act, arg1, arg2);
break;
#ifdef CPU_PM_IRQ_REMAIN_ENABLE
case IRQS_REMAIN_ALLOC:
if (act & MT_LPM_SMC_ACT_GET)
res = (uint64_t)mt_lp_irqremain_count();
break;
case IRQS_REMAIN_CTRL:
plat_cpu_pm_smc_lock();
if (act & MT_LPM_SMC_ACT_SUBMIT)
ret = mt_lp_irqremain_submit();
else if (act & MT_LPM_SMC_ACT_PUSH) {
ret = mt_lp_irqremain_push();
if (ret)
INFO("Irqs remain push fail\n");
} else
INFO("Irqs remain control not support! (0x%lx)\n", act);
plat_cpu_pm_smc_unlock();
break;
case IRQS_REMAIN_IRQ:
case IRQS_REMAIN_WAKEUP_CAT:
case IRQS_REMAIN_WAKEUP_SRC:
plat_cpu_pm_smc_lock();
if (act & MT_LPM_SMC_ACT_SET) {
const struct mt_lp_irqinfo info = {
.val = (unsigned int)arg1,
};
ret = mt_lp_irqremain_set((unsigned int)lp_id, &info);
if (ret)
INFO("Irqs remain command: %lu, set fail\n",
lp_id);
} else if (act & MT_LPM_SMC_ACT_GET) {
struct mt_lp_irqinfo info;
ret = mt_lp_irqremain_get((unsigned int)arg1,
(unsigned int)lp_id, &info);
if (ret) {
INFO("Irqs remain command: %lu, get fail\n",
lp_id);
res = 0;
} else
res = (uint64_t)info.val;
} else
INFO("Irqs remain command not support! (0x%lx)\n", act);
plat_cpu_pm_smc_unlock();
break;
#ifdef CPU_PM_SUSPEND_NOTIFY
case SUSPEND_SRC:
ret = cpupm_set_suspend_state((unsigned int)act,
(unsigned int)arg1);
if (ret)
INFO("cpu_pm lp command: %lu, set fail\n", lp_id);
break;
#endif
case CPU_PM_COUNTER_CTRL:
if (act & MT_LPM_SMC_ACT_SET)
mtk_cpu_pm_counter_enable((bool)arg1);
else if (act & MT_LPM_SMC_ACT_GET)
res = (uint64_t)mtk_cpu_pm_counter_enabled();
break;
case CPU_PM_RECORD_CTRL:
if (act & MT_LPM_SMC_ACT_GET) {
if (arg1 == 0)
res = mtk_mcusys_off_record_cnt_get();
else if (arg1 == 1)
res = mtk_mcusys_off_record_name_get();
}
break;
#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN
case SUSPEND_ABORT_REASON:
if (act & MT_LPM_SMC_ACT_GET)
res = mtk_suspend_abort_reason_get();
break;
#endif
#ifdef CONFIG_MTK_CPU_ILDO
case CPU_PM_RET_CTRL:
if (act & MT_LPM_SMC_ACT_SET)
res = cpupm_cpu_retention_control((unsigned int) arg1);
else if (act & MT_LPM_SMC_ACT_GET)
res = cpupu_get_cpu_retention_control();
else if (act & MT_LPM_SMC_ACT_COMPAT)
res = CPU_PM_CPU_RET_IS_ENABLED;
break;
#endif
#endif
default:
break;
}
return res;
}
static uint64_t secure_cpupm_dispatcher(u_register_t lp_id,
u_register_t act,
u_register_t arg1,
u_register_t arg2,
void *handle,
struct smccc_res *smccc_ret)
{
uint64_t res = 0;
switch (lp_id) {
case CPC_COMMAND:
res = mtk_cpc_trace_dump(act, arg1, arg2);
break;
default:
break;
}
return res;
}
void cpupm_smc_init(void)
{
plat_cpu_pm_smc_lock_init();
mt_lpm_dispatcher_registry(MT_LPM_SMC_USER_CPU_PM,
cpupm_dispatcher);
mt_lpm_dispatcher_registry(MT_LPM_SMC_USER_CPU_PM_LP,
cpupm_lp_dispatcher);
mt_secure_lpm_dispatcher_registry(MT_LPM_SMC_USER_SECURE_CPU_PM,
secure_cpupm_dispatcher);
}

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_CPU_PM_SMC_H
#define MT_CPU_PM_SMC_H
#include <lpm/mt_lp_rm.h>
#include <lpm/mt_lpm_dispatch.h>
#include <lpm/mt_lpm_smc.h>
void cpupm_smc_init(void);
#endif /* MT_CPU_PM_SMC_H */

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <stdio.h>
#include <drivers/cirq.h>
#include <platform_def.h>
#include <lib/pm/mtk_pm.h>
#include <lpm/mt_lp_rm.h>
#include "mt_cpu_pm.h"
#include "mt_lp_irqremain.h"
static struct mt_irqremain remain_irqs;
static struct mt_irqremain *p_irqs;
int mt_lp_irqremain_push(void)
{
if (remain_irqs.count >= MT_IRQ_REMAIN_MAX)
return -1;
remain_irqs.count += 1;
return 0;
}
int mt_lp_irqremain_pop(void)
{
if (remain_irqs.count == 0)
return -1;
remain_irqs.count -= 1;
return 0;
}
int mt_lp_irqremain_set(unsigned int type,
const struct mt_lp_irqinfo *info)
{
unsigned int idx;
if (p_irqs || !info)
return -1;
idx = remain_irqs.count;
switch (type) {
case IRQS_REMAIN_IRQ:
remain_irqs.irqs[idx] = info->val;
break;
case IRQS_REMAIN_WAKEUP_CAT:
remain_irqs.wakeupsrc_cat[idx] = info->val;
break;
case IRQS_REMAIN_WAKEUP_SRC:
remain_irqs.wakeupsrc[idx] = info->val;
break;
}
return 0;
}
int mt_lp_irqremain_get(unsigned int idx, unsigned int type,
struct mt_lp_irqinfo *info)
{
if (!p_irqs || !info || (idx > remain_irqs.count))
return -1;
switch (type) {
case IRQS_REMAIN_IRQ:
info->val = remain_irqs.irqs[idx];
break;
case IRQS_REMAIN_WAKEUP_CAT:
info->val = remain_irqs.wakeupsrc_cat[idx];
break;
case IRQS_REMAIN_WAKEUP_SRC:
info->val = remain_irqs.wakeupsrc[idx];
break;
}
return 0;
}
unsigned int mt_lp_irqremain_count(void)
{
return remain_irqs.count;
}
int mt_lp_irqremain_submit(void)
{
if (remain_irqs.count == 0)
return -1;
set_wakeup_sources(remain_irqs.irqs, remain_irqs.count);
mt_lp_rm_do_update(-1, PLAT_RC_UPDATE_REMAIN_IRQS, &remain_irqs);
p_irqs = &remain_irqs;
return 0;
}
int mt_lp_irqremain_aquire(void)
{
if (!p_irqs)
return -1;
mt_cirq_sw_reset();
mt_cirq_clone_gic();
mt_cirq_enable();
return 0;
}
int mt_lp_irqremain_release(void)
{
if (!p_irqs)
return -1;
mt_cirq_flush();
mt_cirq_disable();
return 0;
}
void mt_lp_irqremain_init(void)
{
p_irqs = NULL;
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_LP_IRQREMAIN_H
#define MT_LP_IRQREMAIN_H
struct mt_lp_irqinfo {
unsigned int val;
};
enum mt_lp_irqremain_type {
MT_LP_IRQREMAIN_IRQ,
MT_LP_IRQREMAIN_WAKEUP_CAT,
MT_LP_IRQREMAIN_WAKEUP_SRC,
};
int mt_lp_irqremain_set(unsigned int type,
const struct mt_lp_irqinfo *value);
int mt_lp_irqremain_get(unsigned int idx, unsigned int type,
struct mt_lp_irqinfo *value);
unsigned int mt_lp_irqremain_count(void);
int mt_lp_irqremain_push(void);
int mt_lp_irqremain_pop(void);
int mt_lp_irqremain_submit(void);
int mt_lp_irqremain_aquire(void);
int mt_lp_irqremain_release(void);
void mt_lp_irqremain_init(void);
#endif /* MT_LP_IRQREMAIN_H */

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "mt_ppu.h"
#define MTK_PPU_PWR_DYNAMIC_POLICY_SET(_ctrl, _policy) \
mmio_clrsetbits_32(_ctrl->ppu_pwpr, \
PPU_PWPR_MASK, \
PPU_PWPR_DYNAMIC_MODE | ((_policy) & PPU_PWPR_MASK))
#define MTK_PPU_PWR_STATIC_POLICY_SET(_ctrl, _policy) \
mmio_clrsetbits_32(_ctrl->ppu_pwpr, \
PPU_PWPR_MASK | PPU_PWPR_DYNAMIC_MODE, \
((_policy) & PPU_PWPR_MASK))
void mt_smp_ppu_pwr_dynamic_set(struct ppu_pwr_ctrl *ctrl,
unsigned int policy)
{
CPU_PM_ASSERT(ctrl);
MTK_PPU_PWR_DYNAMIC_POLICY_SET(ctrl, policy);
dmbsy();
}
void mt_smp_ppu_pwr_static_set(struct ppu_pwr_ctrl *ctrl,
unsigned int policy)
{
CPU_PM_ASSERT(ctrl);
MTK_PPU_PWR_STATIC_POLICY_SET(ctrl, policy);
dmbsy();
}
void mt_smp_ppu_pwr_set(struct ppu_pwr_ctrl *ctrl,
unsigned int mode,
unsigned int policy)
{
CPU_PM_ASSERT(ctrl);
if (mode & PPU_PWPR_DYNAMIC_MODE)
MTK_PPU_PWR_DYNAMIC_POLICY_SET(ctrl, policy);
else
MTK_PPU_PWR_STATIC_POLICY_SET(ctrl, policy);
mmio_write_32(ctrl->ppu_dcdr0, MT_PPU_DCDR0);
mmio_write_32(ctrl->ppu_dcdr1, MT_PPU_DCDR1);
dsbsy();
}
void mt_smp_ppu_op_set(struct ppu_pwr_ctrl *ctrl,
unsigned int mode,
unsigned int policy)
{
unsigned int val;
CPU_PM_ASSERT(ctrl);
val = mmio_read_32(ctrl->ppu_pwpr);
val &= ~(PPU_PWPR_OP_MASK | PPU_PWPR_OP_DYNAMIC_MODE);
val |= PPU_PWPR_OP_MODE(policy);
if (mode & PPU_PWPR_OP_DYNAMIC_MODE)
val |= PPU_PWPR_OP_DYNAMIC_MODE;
mmio_write_32(ctrl->ppu_pwpr, val);
dsbsy();
}
void mt_smp_ppu_set(struct ppu_pwr_ctrl *ctrl,
unsigned int op_mode,
unsigned int policy,
unsigned int pwr_mode,
unsigned int pwr_policy)
{
unsigned int val;
CPU_PM_ASSERT(ctrl);
val = mmio_read_32(ctrl->ppu_pwpr);
if (op_mode & PPU_PWPR_OP_DYNAMIC_MODE)
val |= (PPU_PWPR_OP_DYNAMIC_MODE |
PPU_PWPR_OP_MODE(policy));
else
val |= PPU_PWPR_OP_MODE(policy);
if (pwr_mode & PPU_PWPR_DYNAMIC_MODE) {
val &= ~(PPU_PWPR_MASK);
val |= (PPU_PWPR_DYNAMIC_MODE | (pwr_policy & PPU_PWPR_MASK));
} else {
val &= ~(PPU_PWPR_MASK | PPU_PWPR_DYNAMIC_MODE);
val |= (pwr_policy & PPU_PWPR_MASK);
}
mmio_write_32(ctrl->ppu_pwpr, val);
dsbsy();
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_PPU_H
#define MT_PPU_H
#include <lib/mmio.h>
#include "mt_cpu_pm.h"
/* PPU PWPR definition */
#define PPU_PWPR_MASK 0xF
#define PPU_PWPR_MODE_MASK 0x1
#define PPU_PWPR_OFF 0
#define PPU_PWPR_MEM_RET 2
#define PPU_PWPR_FULL_RET 5
#define PPU_PWPR_MEM_OFF 6
#define PPU_PWPR_FUN_RET 7
#define PPU_PWPR_ON 8
#define PPU_PWPR_WARM_RESET 10
#define PPU_PWPR_DYNAMIC_MODE BIT(8)
#define PPU_PWPR_OP_MASK 0xF0000
#define PPU_PWPR_OP_DYNAMIC_MODE BIT(24)
#define PPU_PWPR_OP_MODE(_policy) (((_policy) << 16) & PPU_PWPR_OP_MASK)
#define PPU_PWPR_OP_ONE_SLICE_SF_ONLY 0
#define PPU_PWPR_OP_ONE_SLICE_HALF_DRAM 1
#define PPU_PWPR_OP_ONE_SLICE_FULL_DRAM 3
#define PPU_PWPR_OP_ALL_SLICE_SF_ONLY 4
#define PPU_PWPR_OP_ALL_SLICE_HALF_DRAM 5
#define PPU_PWPR_OP_ALL_SLICE_FULL_DRAM 7
#define DSU_PPU_PWPR_OP_MODE_DEF (PPU_PWPR_OP_ONE_SLICE_HALF_DRAM)
/* PPU PWSR definition */
#define PPU_PWSR_STATE_ON BIT(3)
#ifdef CPU_PM_ACP_FSM
#define PPU_PWSR_OP_STATUS 0x30000
#define PPU_OP_ST_SF_ONLY 0x0
#endif /* CPU_PM_ACP_FSM */
#define MT_PPU_DCDR0 0x00606060
#define MT_PPU_DCDR1 0x00006060
void mt_smp_ppu_pwr_set(struct ppu_pwr_ctrl *ctrl,
unsigned int mode,
unsigned int policy);
void mt_smp_ppu_op_set(struct ppu_pwr_ctrl *ctrl,
unsigned int mode,
unsigned int policy);
void mt_smp_ppu_pwr_dynamic_set(struct ppu_pwr_ctrl *ctrl,
unsigned int policy);
void mt_smp_ppu_pwr_static_set(struct ppu_pwr_ctrl *ctrl,
unsigned int policy);
void mt_smp_ppu_set(struct ppu_pwr_ctrl *ctrl,
unsigned int op_mode,
unsigned int policy,
unsigned int pwr_mode,
unsigned int pwr_policy);
#endif /* MT_PPU_H */

View file

@ -0,0 +1,108 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <plat/common/platform.h>
#include <lib/pm/mtk_pm.h>
#include <mcucfg.h>
#include "mt_cpu_pm.h"
#include "mt_ppu.h"
#include "mt_smp.h"
#define is_core_power_status_on(_pwr_ctrl)\
(!!((mmio_read_32(_pwr_ctrl->pwr.ppu_pwsr)) & (PPU_PWSR_STATE_ON)))
#ifndef CPU_PM_CORE_ARCH64_ONLY
void mt_smp_core_init_arch(int cluster,
int cpu,
int arm64,
struct cpu_pwr_ctrl *pwr_ctrl)
{
CPU_PM_ASSERT(cluster == 0);
CPU_PM_ASSERT(pwr_ctrl);
/* aa64naa32 in bits[16:23] */
if (arm64)
mmio_setbits_32(pwr_ctrl->arch_addr,
BIT(AA64NAA32_FLAG_START_BIT + cpu));
else
mmio_clrbits_32(pwr_ctrl->arch_addr,
BIT(AA64NAA32_FLAG_START_BIT + cpu));
}
#endif /* CPU_PM_CORE_ARCH64_ONLY */
void mt_smp_core_bootup_address_set(int cluster,
int cpu,
struct cpu_pwr_ctrl *pwr_ctrl,
uintptr_t entry)
{
CPU_PM_ASSERT(pwr_ctrl);
/* Set bootup address */
mmio_write_32(pwr_ctrl->rvbaraddr_l, entry);
mmio_write_32(pwr_ctrl->rvbaraddr_h, 0);
}
int mt_smp_power_core_on(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl)
{
unsigned int val = 0;
CPU_PM_ASSERT(pwr_ctrl);
mt_smp_ppu_pwr_set(&pwr_ctrl->pwr, PPU_PWPR_DYNAMIC_MODE, PPU_PWPR_OFF);
val = is_core_power_status_on(pwr_ctrl);
if (!val) {
mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
GIC_WAKEUP_IGNORE(cpu_id));
mmio_setbits_32(SPM_EXT_INT_WAKEUP_REQ_SET, BIT(cpu_id));
mmio_clrbits_32(SPMC_CONTROL_CONFIG,
SPMC_CPU_RESET_PWRON_CONFIG << (cpu_id));
dsbsy();
isb();
while (!is_core_power_status_on(pwr_ctrl))
DO_SMP_CORE_ON_WAIT_TIMEOUT(cpu_id, val);
mmio_setbits_32(SPM_EXT_INT_WAKEUP_REQ_CLR, BIT(cpu_id));
} else {
mmio_clrbits_32(SPMC_CONTROL_CONFIG,
SPMC_CPU_RESET_PWRON_CONFIG << (cpu_id));
INFO("[%s:%d] - core_%u have been power on\n",
__func__, __LINE__, cpu_id);
}
return MTK_CPUPM_E_OK;
}
int mt_smp_power_core_off(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl)
{
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
GIC_WAKEUP_IGNORE(cpu_id));
return MTK_CPUPM_E_OK;
}
void mt_smp_init(void)
{
mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN);
/* INFO=SPMC_INIT: clear resetpwron of mcusys/cluster/core0 */
mmio_clrbits_32(SPMC_CONTROL_CONFIG, SPMC_MCUSYS_RESET_PWRON_CONFIG);
mmio_clrbits_32(SPMC_CONTROL_CONFIG, SPMC_CPUTOP_RESET_PWRON_CONFIG);
/* Switch DSU ISO/CKDIS control from PCSM to PPU */
mmio_setbits_32(CPC_FCM_SPMC_SW_CFG2,
(CPUSYS_PPU_CLK_EN_CTRL | CPUSYS_PPU_ISO_CTRL));
#ifdef SPM_CPU_BUCK_ISO_CON
/* Make sure that buck iso have been released before power on */
mmio_write_32(SPM_CPU_BUCK_ISO_CON, SPM_CPU_BUCK_ISO_DEFAUT);
#endif /* SPM_CPU_BUCK_ISO_CON */
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SMP_H
#define MT_SMP_H
#include <lib/mmio.h>
#include <platform_def.h>
#include "mt_cpu_pm.h"
#define CPUSYS_PPU_CLK_EN_CTRL BIT(12)
#define CPUSYS_PPU_ISO_CTRL BIT(13)
#define AA64NAA32_FLAG_START_BIT 16
#define SMP_CORE_TIMEOUT_MAX (50000)
#define DO_SMP_CORE_ON_WAIT_TIMEOUT(cpu_id, k_cnt) ({ \
if (k_cnt >= SMP_CORE_TIMEOUT_MAX) { \
INFO("[%s:%d] - CORE%d ON WAIT TIMEOUT %u us (> %u)\n", \
__func__, __LINE__, cpu_id, k_cnt, SMP_CORE_TIMEOUT_MAX); \
panic(); \
} \
k_cnt++; udelay(1); })
#ifdef CPU_PM_CORE_ARCH64_ONLY
#define mt_smp_core_init_arch(_a, _b, _c, _d)
#else
void mt_smp_core_init_arch(int cluster, int cpu, int arm64,
struct cpu_pwr_ctrl *pwr_ctrl);
#endif /* CPU_PM_CORE_ARCH64_ONLY */
void mt_smp_core_bootup_address_set(int cluster,
int cpu,
struct cpu_pwr_ctrl *pwr_ctrl,
uintptr_t entry);
int mt_smp_power_core_on(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl);
int mt_smp_power_core_off(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl);
void mt_smp_init(void);
int mt_smp_cluster_pwpr_init(struct cluster_pwr_ctrl *pwr_ctrl);
int mt_smp_cluster_pwpr_op_init(struct cluster_pwr_ctrl *pwr_ctrl);
#endif /* MT_SMP_H */

View file

@ -0,0 +1,43 @@
#
# Copyright (c) 2025, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#Prologue, init variable
LOCAL_DIR := $(call GET_LOCAL_DIR)
CPU_PM_PWR_REQ := y
CPU_PM_PWR_REQ_DEBUG := n
#Define your module name
MODULE := cpcv${CONFIG_MTK_CPU_PM_ARCH}
#Add your source code here
LOCAL_SRCS-y := ${LOCAL_DIR}/mt_cpu_pm.c \
${LOCAL_DIR}/mt_cpu_pm_cpc.c \
${LOCAL_DIR}/mt_cpu_pm_smc.c \
${LOCAL_DIR}/mt_ppu.c
LOCAL_SRCS-$(CPU_PM_TINYSYS_SUPPORT) += ${LOCAL_DIR}/mt_cpu_pm_mbox.c
LOCAL_SRCS-$(CONFIG_MTK_SMP_EN) += ${LOCAL_DIR}/mt_smp.c
LOCAL_SRCS-${CPU_PM_IRQ_REMAIN_ENABLE} += ${LOCAL_DIR}/mt_lp_irqremain.c
$(eval $(call add_defined_option,CPU_PM_IRQ_REMAIN_ENABLE))
$(eval $(call add_defined_option,CPU_PM_DOMAIN_CORE_ONLY))
$(eval $(call add_defined_option,CPU_PM_CORE_ARCH64_ONLY))
$(eval $(call add_defined_option,CPU_PM_TINYSYS_SUPPORT))
$(eval $(call add_defined_option,CPU_PM_SUSPEND_NOTIFY))
$(eval $(call add_defined_option,CPU_PM_PWR_REQ))
$(eval $(call add_defined_option,CPU_PM_PWR_REQ_DEBUG))
$(eval $(call add_defined_option,CONFIG_MTK_CPU_ILDO))
$(eval $(call add_defined_option,CPU_PM_CPU_RET_MASK))
#Epilogue, build as module
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
$(eval $(call add_defined_option,CPU_PM_ACP_FSM))

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

@ -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
# #
@ -8,7 +8,15 @@ LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := mcusys MODULE := mcusys
ifeq ($(MTK_SOC), mt8196)
PLAT_INCLUDES += -I${MTK_PLAT}/include/drivers/mcusys/$(MCUSYS_VERSION)
ifneq ($(MCUPM_VERSION),)
PLAT_INCLUDES += -I${MTK_PLAT}/include/drivers/mcusys/mcupm
CFLAGS += -DMCUPM_VERSION_${MCUPM_VERSION}
endif
else
PLAT_INCLUDES += -I$(LOCAL_DIR)/$(MCUSYS_VERSION) PLAT_INCLUDES += -I$(LOCAL_DIR)/$(MCUSYS_VERSION)
endif
LOCAL_SRCS-y := $(LOCAL_DIR)/mcusys.c LOCAL_SRCS-y := $(LOCAL_DIR)/mcusys.c

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <drivers/pmic/pmic_psc.h>
#include <drivers/spmi_api.h>
#include <lib/mtk_init/mtk_init.h>
#include "registers.h"
static struct spmi_device *sdev;
static const struct pmic_psc_reg mt6363_psc_regs[] = {
PMIC_PSC_REG(RG_PWRHOLD, MT6363_PPCCTL0, 0),
PMIC_PSC_REG(RG_CRST, MT6363_PPCCTL1, 0),
PMIC_PSC_REG(RG_SMART_RST_SDN_EN, MT6363_STRUP_CON12, 1),
PMIC_PSC_REG(RG_SMART_RST_MODE, MT6363_STRUP_CON12, 2),
};
static int mt6363_psc_read_field(uint32_t reg, uint32_t *val, uint32_t mask, uint32_t shift)
{
uint8_t rdata = 0;
int ret = 0;
if (!val)
return -EINVAL;
if (!sdev)
return -ENODEV;
ret = spmi_ext_register_readl(sdev, reg, &rdata, 1);
if (ret < 0)
return ret;
rdata &= (mask << shift);
*val = (rdata >> shift);
return 0;
}
static int mt6363_psc_write_field(uint32_t reg, uint32_t val, uint32_t mask, uint32_t shift)
{
uint8_t org = 0;
int ret = 0;
if (!sdev)
return -ENODEV;
ret = spmi_ext_register_readl(sdev, reg, &org, 1);
if (ret < 0)
return ret;
org &= ~(mask << shift);
org |= (val << shift);
ret = spmi_ext_register_writel(sdev, reg, &org, 1);
return ret;
}
static const struct pmic_psc_config mt6363_psc_config = {
.read_field = mt6363_psc_read_field,
.write_field = mt6363_psc_write_field,
.regs = mt6363_psc_regs,
.reg_size = ARRAY_SIZE(mt6363_psc_regs),
};
static int mt6363_psc_init(void)
{
sdev = get_spmi_device(SPMI_MASTER_1, SPMI_SLAVE_4);
if (!sdev)
ERROR("%s: get spmi device fail\n", __func__);
return pmic_psc_register(&mt6363_psc_config);
}
MTK_PLAT_SETUP_0_INIT(mt6363_psc_init);
#ifdef CONFIG_MTK_PMIC_SPT_SUPPORT
static int mt6363_spt_enable(void)
{
/* Enable PMIC Self-Protection Timer(SPT) */
return mt6363_psc_write_field(MT6363_RG_SELFWDT_EN_ADDR, MT6363_RG_SELFWDT_EN_MASK,
MT6363_RG_SELFWDT_EN_MASK, 0);
}
MTK_PLAT_RUNTIME_INIT(mt6363_spt_enable);
#endif

View file

@ -0,0 +1,17 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT6363_REGISTER_H
#define MT6363_REGISTER_H
/* PMIC Registers for PSC */
#define MT6363_PPCCTL0 0xA08
#define MT6363_PPCCTL1 0xA09
#define MT6363_STRUP_CON12 0xA0F
#define MT6363_RG_SELFWDT_EN_ADDR 0xA14
#define MT6363_RG_SELFWDT_EN_MASK 0x1
#endif /* MT6363_REGISTER_H */

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 := mt6363
#Add your source code here
LOCAL_SRCS-y := $(LOCAL_DIR)/${PMIC_CHIP}_psc.c
#Epilogue, build as module
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <drivers/pmic/pmic_set_lowpower.h>
#include <drivers/pmic/pmic_swap_api.h>
#include <drivers/spmi/spmi_common.h>
#include <lib/mtk_init/mtk_init.h>
#define MASTER_ID SPMI_MASTER_1
struct spmi_device *lowpower_sdev[SPMI_MAX_SLAVE_ID];
static const uint8_t lowpower_slvid_arr[] = {
MT6363_SLAVE,
MT6373_SLAVE,
MT6316_S6_SLAVE,
MT6316_S7_SLAVE,
MT6316_S8_SLAVE,
MT6316_S15_SLAVE,
};
static int pmic_lowpower_init(void)
{
uint8_t i, slvid;
for (i = 0; i < ARRAY_SIZE(lowpower_slvid_arr); i++) {
slvid = lowpower_slvid_arr[i];
lowpower_sdev[slvid] = get_spmi_device(MASTER_ID, slvid);
if (!lowpower_sdev[slvid])
return -ENODEV;
}
/* MT6363 Deep idle, SODI3 */
/* VREQ config by SCP owner in LK2 */
PMIC_BUCK_SET_LP(MT6363, VBUCK4, HW2, true, OP_MODE_LP, HW_LP);
PMIC_BUCK_SET_LP(MT6363, VBUCK4, RC9, true, OP_MODE_MU, HW_ON);
PMIC_BUCK_SET_LP(MT6363, VS2, HW2, true, OP_MODE_LP, HW_LP);
PMIC_BUCK_SET_LP(MT6363, VS2, RC9, true, OP_MODE_MU, HW_ON);
PMIC_BUCK_SET_LP(MT6363, VS3, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VSRAM_CPUB, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VSRAM_CPUB, RC9, true, OP_MODE_MU, HW_ON);
PMIC_LDO_SET_LP(MT6363, VSRAM_CPUL, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VSRAM_CPUL, RC9, true, OP_MODE_MU, HW_ON);
PMIC_LDO_SET_LP(MT6363, VSRAM_APU, RC2, true, OP_MODE_MU, HW_OFF);
PMIC_LDO_SET_LP(MT6363, VSRAM_MODEM, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VSRAM_MODEM, RC9, true, OP_MODE_MU, HW_ON);
PMIC_LDO_SET_LP(MT6363, VA12_1, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VA12_1, RC9, true, OP_MODE_MU, HW_ON);
PMIC_LDO_SET_LP(MT6363, VA12_2, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VA12_2, RC9, true, OP_MODE_MU, HW_ON);
PMIC_LDO_SET_LP(MT6363, VUFS18, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VUFS18, RC9, true, OP_MODE_MU, HW_ON);
PMIC_LDO_SET_LP(MT6363, VUFS12, HW2, true, OP_MODE_LP, HW_LP);
/* MT6373 Deep idle, SODI3 */
PMIC_BUCK_SET_LP(MT6373, VBUCK4, HW2, true, OP_MODE_LP, HW_OFF);
PMIC_BUCK_SET_LP(MT6373, VBUCK5, HW2, true, OP_MODE_LP, HW_OFF);
PMIC_BUCK_SET_LP(MT6373, VBUCK6, HW2, true, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6373, VUSB, HW2, true, OP_MODE_LP, HW_LP);
/* MT6316 Deep idle, SODI3 */
PMIC_SLVID_BUCK_SET_LP(MT6316, S8, VBUCK1, HW2, true, OP_MODE_LP, HW_LP);
PMIC_SLVID_BUCK_SET_LP(MT6316, S6, VBUCK3, HW2, true, OP_MODE_LP, HW_ONLV);
return 0;
}
MTK_PLAT_SETUP_0_INIT(pmic_lowpower_init);

View file

@ -0,0 +1,291 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <drivers/pmic/pmic_shutdown_cfg.h>
#include <drivers/spmi/spmi_common.h>
#include <drivers/spmi_api.h>
#include <lib/mtk_init/mtk_init.h>
#define MASTER_ID SPMI_MASTER_1
#ifndef MT8678_PMIC_SUPPORT
/* MT6316 will automatically disable wdt in poffs */
#define MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR 0x408
#define MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_MASK 0x1
#define MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT 1
#else
/* MT6319 will automatically disable wdt in poffs */
#define MT6319_TOP_RST_MISC_CLR 0x128
#define MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR 0x138
#define MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_MASK 0x1
#define MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT 2
#endif
#define MT6373_TOP_RST_MISC1_CLR 0x13B
#define MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR 0x408
#define MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_MASK 0x1
#define MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT 1
#define MT6685_TOP_RST_MISC_CLR 0x129
#define MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR 0x408
#define MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_MASK 0x1
#define MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT 1
struct spmi_device *sdev_arr[SPMI_MAX_SLAVE_ID];
struct cfg_t {
uint8_t slvid;
uint32_t addr;
uint32_t shutdown_src_addr;
uint32_t shutdown_src_mask;
uint32_t shutdown_src_shift;
uint8_t val;
};
#ifndef MT8678_PMIC_SUPPORT
static const struct cfg_t cfg_arr[] = {
{
.slvid = SPMI_SLAVE_6,
.addr = 0,
.shutdown_src_addr = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_7,
.addr = 0,
.shutdown_src_addr = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_8,
.addr = 0,
.shutdown_src_addr = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_15,
.addr = 0,
.shutdown_src_addr = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6316_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_5,
.addr = MT6373_TOP_RST_MISC1_CLR,
.shutdown_src_addr = MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_9,
.addr = MT6685_TOP_RST_MISC_CLR,
.shutdown_src_addr = MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}
};
#else /* MT8678_PMIC_SUPPORT */
static const struct cfg_t cfg_arr[] = {
{
.slvid = SPMI_SLAVE_6,
.addr = MT6319_TOP_RST_MISC_CLR,
.shutdown_src_addr = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_7,
.addr = MT6319_TOP_RST_MISC_CLR,
.shutdown_src_addr = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_8,
.addr = MT6319_TOP_RST_MISC_CLR,
.shutdown_src_addr = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_15,
.addr = MT6319_TOP_RST_MISC_CLR,
.shutdown_src_addr = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6319_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_5,
.addr = MT6373_TOP_RST_MISC1_CLR,
.shutdown_src_addr = MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6373_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}, {
.slvid = SPMI_SLAVE_9,
.addr = MT6685_TOP_RST_MISC_CLR,
.shutdown_src_addr = MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_ADDR,
.shutdown_src_mask = MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_MASK,
.shutdown_src_shift = MT6685_PMIC_RG_SHUTDOWN_SRC_SEL_SHIFT,
.val = 0x1
}
};
#endif /* MT8678_PMIC_SUPPORT */
#define MT6316_TOP_ANA_KEY 0x3AA
#define MT6316_PMIC_RG_VI075_SINK_CUR_ADDR 0x994
#define MT6316_PMIC_RG_VI075_SINK_CUR_MASK 0xF
#define MT6316_PMIC_RG_VI075_SINK_CUR_SHIFT 4
#define MT6316_PMIC_RG_PSEQ_ELR_RSV2_ADDR 0xA2C
#define MT6316_PMIC_RG_PSEQ_ELR_RSV2_MASK 0x7
#define MT6316_PMIC_RG_PSEQ_ELR_RSV2_SHIFT 5
#define PSEQ_ELR_RSV2_VAL_MASK_1 0x3
#define PSEQ_ELR_RSV2_VAL_MASK_2 0x1
#define VI075_SINK_CUR_SOURCE_1 0x5
#define VI075_SINK_CUR_SOURCE_2 0
#define VI075_SINK_CUR_SOURCE_3 0xB
#define ARRAY_LENGTH_MAX 2
#ifndef MT8678_PMIC_SUPPORT
static void mt6316_key_lock_check(struct spmi_device *mt6316_dev, uint16_t key)
{
int i, ret;
uint16_t rdata;
uint8_t work_val[ARRAY_LENGTH_MAX];
uint8_t wdata[ARRAY_LENGTH_MAX];
for (i = 0; i < 2; i++) {
ret = spmi_ext_register_readl(mt6316_dev, key, &work_val[0], 2);
if (ret < 0) {
INFO("[%s]: read fail, addr = 0x%x, ret = %d\n"
, __func__, key, ret);
i = 0;
continue;
}
rdata = work_val[0] | (work_val[1] << 8);
if (rdata != 0) {
INFO("[%s] lock fail, addr = 0x%x, rdata = 0x%x.\n"
, __func__, key, rdata);
wdata[0] = 0;
wdata[1] = 0;
spmi_ext_register_writel(mt6316_dev, key, &wdata[0], 2);
i = 0;
}
}
}
static void wk_vio075_sink_cur(struct spmi_device *mt6316_dev, unsigned char en_seq_off)
{
uint8_t rval, wval;
int ret;
uint8_t buf[ARRAY_LENGTH_MAX];
ret = spmi_ext_register_readl(mt6316_dev, MT6316_PMIC_RG_PSEQ_ELR_RSV2_ADDR, &rval, 1);
if (ret < 0)
return;
rval = (rval >> MT6316_PMIC_RG_PSEQ_ELR_RSV2_SHIFT) & MT6316_PMIC_RG_PSEQ_ELR_RSV2_MASK;
if (!(rval & PSEQ_ELR_RSV2_VAL_MASK_1)) {
wval = VI075_SINK_CUR_SOURCE_1;
} else if (rval & PSEQ_ELR_RSV2_VAL_MASK_2) {
if (en_seq_off)
wval = VI075_SINK_CUR_SOURCE_2;
else
wval = VI075_SINK_CUR_SOURCE_3;
} else {
wval = VI075_SINK_CUR_SOURCE_2;
}
buf[0] = 0xDC;
buf[1] = 0xF1;
spmi_ext_register_writel(mt6316_dev,
MT6316_TOP_ANA_KEY,
&buf[0], 2); /* unlock TOP_ANA key */
spmi_ext_register_writel_field(mt6316_dev,
MT6316_PMIC_RG_VI075_SINK_CUR_ADDR, wval,
MT6316_PMIC_RG_VI075_SINK_CUR_MASK,
MT6316_PMIC_RG_VI075_SINK_CUR_SHIFT);
buf[0] = 0;
buf[1] = 0;
spmi_ext_register_writel(mt6316_dev,
MT6316_TOP_ANA_KEY,
&buf[0], 2); /* lock TOP_ANA key */
mt6316_key_lock_check(mt6316_dev, MT6316_TOP_ANA_KEY);
}
#endif
static int pmic_shutdown_cfg_init(void)
{
uint8_t i, slvid;
for (i = 0; i < ARRAY_SIZE(cfg_arr); i++) {
slvid = cfg_arr[i].slvid;
if (sdev_arr[slvid] != NULL)
continue;
sdev_arr[slvid] = get_spmi_device(MASTER_ID, slvid);
if (!sdev_arr[slvid])
return -ENODEV;
}
return 0;
}
MTK_PLAT_SETUP_0_INIT(pmic_shutdown_cfg_init);
int pmic_shutdown_cfg(void)
{
int ret;
uint8_t i, slvid;
uint32_t addr;
uint8_t val;
for (i = 0; i < ARRAY_SIZE(cfg_arr); i++) {
slvid = cfg_arr[i].slvid;
if (!sdev_arr[slvid])
return -ENODEV;
/* mt6316 vio075 sink current adjustment */
if ((slvid >= SPMI_SLAVE_6 && slvid <= SPMI_SLAVE_8) || slvid == SPMI_SLAVE_15)
wk_vio075_sink_cur(sdev_arr[slvid], 1);
addr = cfg_arr[i].addr;
val = cfg_arr[i].val;
/* Disable WDTRSTB_EN */
if (addr) {
ret = spmi_ext_register_writel(sdev_arr[slvid], addr, &val, 1);
if (ret < 0)
return ret;
}
/* set RG_SHUTDOWN_SRC_SEL to 1, shutdown PMIC by SPMI command */
spmi_ext_register_writel_field(sdev_arr[slvid],
cfg_arr[i].shutdown_src_addr, 1,
cfg_arr[i].shutdown_src_mask,
cfg_arr[i].shutdown_src_shift);
}
return 1; /* 1: use spmi_command_shutdown API */
}
/* shutdown PMIC by SPMI command */
int spmi_shutdown(void)
{
struct spmi_device *mt6363_sdev = get_spmi_device(SPMI_MASTER_1, SPMI_SLAVE_4);
if (!mt6363_sdev)
return -ENODEV;
/* set RG_SHUTDOWN_SRC_SEL to 1 */
spmi_ext_register_writel_field(mt6363_sdev, 0x408, 1, 0x1, 1);
spmi_command_shutdown(SPMI_MASTER_P_1, mt6363_sdev, 0x800);
spmi_command_shutdown(SPMI_MASTER_1, mt6363_sdev, 0x800);
return 0;
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdbool.h>
#include <drivers/pmic/pmic_swap_api.h>
/* No need to check second pmic mt6373 */
bool is_second_pmic_pp_swap(void)
{
return false;
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdbool.h>
#include <drivers/pmic/pmic_swap_api.h>
#pragma weak is_second_pmic_pp_swap
bool is_second_pmic_pp_swap(void)
{
return false;
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <drivers/pmic/pmic_psc.h>
#ifdef CONFIG_MTK_PMIC_SHUTDOWN_CFG
#include <drivers/pmic/pmic_shutdown_cfg.h>
#endif
#define ERR_INVALID_ARGS -EINVAL
#define ERR_NOT_CONFIGURED -ENODEV
static const struct pmic_psc_config *pmic_psc;
static uint32_t read_pmic_psc_reg(enum pmic_psc_reg_name reg_name)
{
uint32_t val = 0;
const struct pmic_psc_reg *reg;
if (reg_name >= pmic_psc->reg_size)
return 0;
reg = &pmic_psc->regs[reg_name];
pmic_psc->read_field(reg->reg_addr, &val, reg->reg_mask, reg->reg_shift);
return val;
}
static int set_pmic_psc_reg(enum pmic_psc_reg_name reg_name)
{
const struct pmic_psc_reg *reg;
if (reg_name >= pmic_psc->reg_size)
return ERR_INVALID_ARGS;
reg = &pmic_psc->regs[reg_name];
pmic_psc->write_field(reg->reg_addr, 1, reg->reg_mask, reg->reg_shift);
return 0;
}
static int clr_pmic_psc_reg(enum pmic_psc_reg_name reg_name)
{
const struct pmic_psc_reg *reg;
if (reg_name >= pmic_psc->reg_size)
return ERR_INVALID_ARGS;
reg = &pmic_psc->regs[reg_name];
pmic_psc->write_field(reg->reg_addr, 0, reg->reg_mask, reg->reg_shift);
return 0;
}
int enable_pmic_smart_reset(bool enable)
{
if (!pmic_psc)
return ERR_NOT_CONFIGURED;
if (enable)
set_pmic_psc_reg(RG_SMART_RST_MODE);
else
clr_pmic_psc_reg(RG_SMART_RST_MODE);
return 0;
}
int enable_pmic_smart_reset_shutdown(bool enable)
{
if (!pmic_psc)
return ERR_NOT_CONFIGURED;
if (enable)
set_pmic_psc_reg(RG_SMART_RST_SDN_EN);
else
clr_pmic_psc_reg(RG_SMART_RST_SDN_EN);
return 0;
}
int platform_cold_reset(void)
{
if (!pmic_psc)
return ERR_NOT_CONFIGURED;
/* Some PMICs may not support cold reset */
if (!pmic_psc->regs[RG_CRST].reg_addr)
return ERR_NOT_CONFIGURED;
set_pmic_psc_reg(RG_CRST);
return 0;
}
int platform_power_hold(bool hold)
{
int use_spmi_cmd_sdn = 0;
if (!pmic_psc)
return ERR_NOT_CONFIGURED;
if (hold)
set_pmic_psc_reg(RG_PWRHOLD);
else {
#ifdef CONFIG_MTK_PMIC_SHUTDOWN_CFG
use_spmi_cmd_sdn = pmic_shutdown_cfg();
#endif
if (use_spmi_cmd_sdn == 1)
spmi_shutdown();
else
clr_pmic_psc_reg(RG_PWRHOLD);
}
return 0;
}
int pmic_psc_register(const struct pmic_psc_config *psc)
{
if (!psc || !psc->regs || !psc->read_field || !psc->write_field)
return ERR_INVALID_ARGS;
pmic_psc = psc;
INFO("POWER_HOLD=0x%x\n", read_pmic_psc_reg(RG_PWRHOLD));
return 0;
}

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2022, MediaTek Inc. All rights reserved. # Copyright (c) 2022-2025, MediaTek Inc. All rights reserved.
# #
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# #
@ -8,8 +8,24 @@ LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := pmic MODULE := pmic
ifneq (${PMIC_CHIP}, mt6363)
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic.c LOCAL_SRCS-y += ${LOCAL_DIR}/pmic.c
PLAT_INCLUDES += -I${LOCAL_DIR}/ PLAT_INCLUDES += -I${LOCAL_DIR}/
else
LOCAL_SRCS-y := ${LOCAL_DIR}/pmic_psc.c
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_common_swap_api.c
LOCAL_SRCS-${CONFIG_MTK_PMIC_LOWPOWER} += ${LOCAL_DIR}/${MTK_SOC}/pmic_lowpower_init.c
LOCAL_SRCS-${CONFIG_MTK_PMIC_LOWPOWER} += ${LOCAL_DIR}/${MTK_SOC}/pmic_swap_api.c
LOCAL_SRCS-${CONFIG_MTK_PMIC_SHUTDOWN_CFG} += ${LOCAL_DIR}/${MTK_SOC}/pmic_shutdown_cfg.c
endif
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL))) $(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
$(eval $(call add_defined_option,CONFIG_MTK_PMIC_SPT_SUPPORT))
$(eval $(call add_defined_option,CONFIG_MTK_PMIC_SHUTDOWN_CFG))
#Include sub rules.mk
ifneq (${PMIC_CHIP},)
SUB_RULES-y := $(LOCAL_DIR)/$(PMIC_CHIP)
#Expand sub rules.mk
$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
endif

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DBG_CTRL_H
#define DBG_CTRL_H
/* SPM_WAKEUP_MISC */
#define WAKE_MISC_TWAM BIT(18)
#define WAKE_MISC_PCM_TIMER BIT(19)
#define WAKE_MISC_CPU_WAKE BIT(20)
struct dbg_ctrl {
uint32_t count;
uint32_t duration;
void *ext;
};
enum dbg_ctrl_enum {
DBG_CTRL_COUNT,
DBG_CTRL_DURATION,
DBG_CTRL_MAX,
};
#endif /* DBG_CTRL_H */

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights resrved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_COMMON_H
#define MT_SPM_COMMON_H
#include <lib/bakery_lock.h>
#include <lib/spinlock.h>
/*
* ARM v8.2, the cache will turn off automatically when cpu
* power down. So, there is no doubt to use the spin_lock here
*/
#if !HW_ASSISTED_COHERENCY
#define MT_SPM_USING_BAKERY_LOCK
#endif
#ifdef MT_SPM_USING_BAKERY_LOCK
DECLARE_BAKERY_LOCK(spm_lock);
#define plat_spm_lock() \
bakery_lock_get(&spm_lock)
#define plat_spm_unlock() \
bakery_lock_release(&spm_lock)
#else
extern spinlock_t spm_lock;
#define plat_spm_lock() \
spin_lock(&spm_lock)
#define plat_spm_unlock() \
spin_unlock(&spm_lock)
#endif
#define MT_SPM_ERR_NO_FW_LOAD -1
#define MT_SPM_ERR_KICKED -2
#define MT_SPM_ERR_RUNNING -3
#define MT_SPM_ERR_FW_NOT_FOUND -4
#define MT_SPM_ERR_INVALID -5
#define MT_SPM_ERR_OVERFLOW -6
static inline void spm_lock_get(void)
{
plat_spm_lock();
}
static inline void spm_lock_release(void)
{
plat_spm_unlock();
}
#endif /* MT_SPM_COMMON_H */

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_CONSTRAINT_H
#define MT_SPM_CONSTRAINT_H
#include <lpm_v2/mt_lp_rm.h>
#define MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF BIT(0)
#define MT_RM_CONSTRAINT_ALLOW_DRAM_S0 BIT(1)
#define MT_RM_CONSTRAINT_ALLOW_DRAM_S1 BIT(2)
#define MT_RM_CONSTRAINT_ALLOW_VCORE_LP BIT(3)
#define MT_RM_CONSTRAINT_ALLOW_INFRA_PDN BIT(4)
#define MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF BIT(5)
#define MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND BIT(6) /* System suspend */
#define MT_RM_CONSTRAINT_ALLOW_BBLPM BIT(7)
#define MT_RM_CONSTRAINT_ALLOW_XO_UFS BIT(8)
#define MT_RM_CONSTRAINT_ALLOW_GPS_STATE BIT(9)
#define MT_RM_CONSTRAINT_ALLOW_LVTS_STATE BIT(10)
#define MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND BIT(11) /* Kernel suspend */
#define MT_RM_CONSTRAINT_ALLOW_VCORE_OFF BIT(12)
#define MT_SPM_RC_INVALID 0x0
#define MT_SPM_RC_VALID_SW BIT(0)
#define MT_SPM_RC_VALID_FW BIT(1)
#define MT_SPM_RC_VALID_RESIDNECY BIT(2)
#define MT_SPM_RC_VALID_COND_CHECK BIT(3)
#define MT_SPM_RC_VALID_COND_LATCH BIT(4)
#define MT_SPM_RC_VALID_UFS_H8 BIT(5)
#define MT_SPM_RC_VALID_FLIGHTMODE BIT(6)
#define MT_SPM_RC_VALID_XSOC_BBLPM BIT(7)
#define MT_SPM_RC_VALID_TRACE_EVENT BIT(8)
#define MT_SPM_RC_VALID_TRACE_TIME BIT(9)
#define MT_SPM_RC_VALID_NOTIFY BIT(10)
#define MT_SPM_RC_VALID (MT_SPM_RC_VALID_SW | MT_SPM_RC_VALID_FW)
#define IS_MT_RM_RC_READY(status) \
((status & MT_SPM_RC_VALID) == MT_SPM_RC_VALID)
struct constraint_status {
uint16_t id;
uint16_t is_valid;
uint64_t is_cond_block;
uint32_t enter_cnt;
uint64_t all_pll_dump;
unsigned long long residency;
struct mt_spm_cond_tables *cond_res;
};
enum constraint_status_update_type {
CONSTRAINT_UPDATE_VALID,
CONSTRAINT_UPDATE_COND_CHECK,
CONSTRAINT_RESIDNECY,
};
enum constraint_status_get_type {
CONSTRAINT_GET_VALID = 0xD0000000,
CONSTRAINT_GET_ENTER_CNT,
CONSTRAINT_GET_RESIDENCY,
CONSTRAINT_GET_COND_EN,
CONSTRAINT_COND_BLOCK,
CONSTRAINT_GET_COND_BLOCK_LATCH,
CONSTRAINT_GET_COND_BLOCK_DETAIL,
CONSTRAINT_GET_RESIDNECY,
};
struct rc_common_state {
unsigned int id;
unsigned int act;
unsigned int type;
void *value;
};
#define MT_SPM_RC_BBLPM_MODE (MT_SPM_RC_VALID_UFS_H8 | \
MT_SPM_RC_VALID_FLIGHTMODE | \
MT_SPM_RC_VALID_XSOC_BBLPM)
#define IS_MT_SPM_RC_BBLPM_MODE(st) \
((st & (MT_SPM_RC_BBLPM_MODE)) == MT_SPM_RC_BBLPM_MODE)
#define IS_MT_SPM_RC_NOTIFY_ENABLE(st) \
((st & (MT_SPM_RC_VALID_NOTIFY)))
#define MT_SPM_RC_EXTERN_STATUS_SET(v, st) ({v |= (st & 0xffff); })
#define MT_SPM_RC_EXTERN_STATUS_CLR(v, st) ({v &= ~(st & 0xffff); })
#endif /* MT_SPM_CONSTRAINT_H */

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_SMC_H
#define MT_SPM_SMC_H
/*
* SPM dispatcher's smc id definition
* Please adding custom smc id here for spm dispatcher
*/
#define MT_SPM_STATUS_SUSPEND_SLEEP BIT(27)
enum mt_spm_smc_uid {
MT_SPM_SMC_UID_STATUS,
MT_SPM_SMC_UID_PCM_WDT,
MT_SPM_SMC_UID_PCM_TIMER,
MT_SPM_SMC_UID_FW_TYPE,
MT_SPM_SMC_UID_PHYPLL_MODE,
MT_SPM_SMC_UID_SET_PENDING_IRQ_INIT,
MT_SPM_SMC_UID_FW_INIT = 0x5731,
};
/*
* SPM dbg dispatcher's smc id definition
* Please adding custom smc id here for spm dbg dispatcher
*/
enum mt_spm_dbg_smc_uid {
MT_SPM_DBG_SMC_UID_IDLE_PWR_CTRL,
MT_SPM_DBG_SMC_UID_IDLE_CNT,
MT_SPM_DBG_SMC_UID_SUSPEND_PWR_CTRL,
MT_SPM_DBG_SMC_UID_SUSPEND_DBG_CTRL,
MT_SPM_DBG_SMC_UID_FS,
MT_SPM_DBG_SMC_UID_RC_SWITCH,
MT_SPM_DBG_SMC_UID_RC_CNT,
MT_SPM_DBG_SMC_UID_COND_CHECK,
MT_SPM_DBG_SMC_UID_COND_BLOCK,
MT_SPM_DBG_SMC_UID_BLOCK_LATCH,
MT_SPM_DBG_SMC_UID_BLOCK_DETAIL,
MT_SPM_DBG_SMC_UID_RES_NUM,
MT_SPM_DBG_SMC_UID_RES_REQ,
MT_SPM_DBG_SMC_UID_RES_USAGE,
MT_SPM_DBG_SMC_UID_RES_USER_NUM,
MT_SPM_DBG_SMC_UID_RES_USER_VALID,
MT_SPM_DBG_SMC_UID_RES_USER_NAME,
MT_SPM_DBG_SMC_UID_DOE_RESOURCE_CTRL,
MT_SPM_DBG_SMC_UID_DOE_RC,
MT_SPM_DBG_SMC_UID_RC_COND_CTRL,
MT_SPM_DBG_SMC_UID_RC_RES_CTRL,
MT_SPM_DBG_SMC_UID_RC_RES_INFO,
MT_SPM_DBG_SMC_UID_RC_BBLPM,
MT_SPM_DBG_SMC_UID_RC_TRACE,
MT_SPM_DBG_SMC_UID_RC_TRACE_TIME,
MT_SPM_DBG_SMC_UID_DUMP_PLL,
MT_SPM_DBG_SMC_HWCG_NUM,
MT_SPM_DBG_SMC_HWCG_STATUS,
MT_SPM_DBG_SMC_HWCG_SETTING,
MT_SPM_DBG_SMC_HWCG_DEF_SETTING,
MT_SPM_DBG_SMC_HWCG_RES_NAME,
MT_SPM_DBG_SMC_UID_RC_NOTIFY_CTRL,
MT_SPM_DBG_SMC_VCORE_LP_ENABLE,
MT_SPM_DBG_SMC_VCORE_LP_VOLT,
MT_SPM_DBG_SMC_VSRAM_LP_ENABLE,
MT_SPM_DBG_SMC_VSRAM_LP_VOLT,
MT_SPM_DBG_SMC_PERI_REQ_NUM,
MT_SPM_DBG_SMC_PERI_REQ_STATUS,
MT_SPM_DBG_SMC_PERI_REQ_SETTING,
MT_SPM_DBG_SMC_PERI_REQ_DEF_SETTING,
MT_SPM_DBG_SMC_PERI_REQ_RES_NAME,
MT_SPM_DBG_SMC_PERI_REQ_STATUS_RAW,
MT_SPM_DBG_SMC_IDLE_PWR_STAT,
MT_SPM_DBG_SMC_SUSPEND_PWR_STAT,
MT_SPM_DBG_SMC_LP_REQ_STAT,
MT_SPM_DBG_SMC_COMMON_SODI_CTRL,
MT_SPM_DBG_SMC_SPM_TIMESTAMP,
MT_SPM_DBG_SMC_SPM_TIMESTAMP_SIZE,
MT_SPM_DBG_SMC_UID_COMMON_SODI_PWR_CTRL,
};
enum wake_status_enum {
WAKE_STA_ASSERT_PC,
WAKE_STA_R12,
WAKE_STA_R12_EXT,
WAKE_STA_RAW_STA,
WAKE_STA_RAW_EXT_STA,
WAKE_STA_WAKE_MISC,
WAKE_STA_TIMER_OUT,
WAKE_STA_R13,
WAKE_STA_IDLE_STA,
WAKE_STA_REQ_STA,
WAKE_STA_DEBUG_FLAG,
WAKE_STA_DEBUG_FLAG1,
WAKE_STA_EVENT_REG,
WAKE_STA_ISR,
WAKE_STA_MAX_COUNT,
};
#endif /* MT_SPM_SMC_H */

View file

@ -0,0 +1,18 @@
#
# 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 := spm_common
#Add your source code here
LOCAL_SRCS-y :=
#Epilogue, build as module
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
$(eval $(call add_defined_option,CONFIG_MTK_VCOREDVFS_SUPPORT))

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <constraints/mt_spm_rc_api.h>
#include <constraints/mt_spm_rc_internal.h>
#include <lpm_v2/mt_lpm_smc.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_common.h>
#define SPM_RC_VALID_SET(dest, src) ({ (dest) |= (src); })
#define SPM_RC_VALID_CLR(dest, src) ({ (dest) &= ~(src); })
int spm_rc_constraint_status_get(uint32_t id, uint32_t type,
uint32_t act,
enum mt_spm_rm_rc_type dest_rc_id,
struct constraint_status * const src,
struct constraint_status * const dest)
{
if (((id != MT_RM_CONSTRAINT_ID_ALL) &&
(id != dest_rc_id)) || !dest || !src)
return -1;
spm_lock_get();
switch (type) {
case CONSTRAINT_GET_ENTER_CNT:
if (id == MT_RM_CONSTRAINT_ID_ALL)
dest->enter_cnt += src->enter_cnt;
else
dest->enter_cnt = src->enter_cnt;
break;
case CONSTRAINT_GET_VALID:
dest->is_valid = src->is_valid;
break;
case CONSTRAINT_COND_BLOCK:
dest->is_cond_block = src->is_cond_block;
dest->all_pll_dump = src->all_pll_dump;
break;
case CONSTRAINT_GET_COND_BLOCK_DETAIL:
dest->cond_res = src->cond_res;
break;
case CONSTRAINT_GET_RESIDNECY:
dest->residency = src->residency;
if (act & MT_LPM_SMC_ACT_CLR)
src->residency = 0;
break;
default:
break;
}
spm_lock_release();
return 0;
}
int spm_rc_constraint_status_set(uint32_t id, uint32_t type,
uint32_t act,
enum mt_spm_rm_rc_type dest_rc_id,
struct constraint_status * const src,
struct constraint_status * const dest)
{
if (((id != MT_RM_CONSTRAINT_ID_ALL) &&
(id != dest_rc_id)) || !dest)
return -1;
spm_lock_get();
switch (type) {
case CONSTRAINT_UPDATE_VALID:
if (src) {
if (act & MT_LPM_SMC_ACT_SET)
SPM_RC_VALID_SET(dest->is_valid, src->is_valid);
else if (act & MT_LPM_SMC_ACT_CLR)
SPM_RC_VALID_CLR(dest->is_valid, src->is_valid);
}
break;
case CONSTRAINT_RESIDNECY:
if (act & MT_LPM_SMC_ACT_CLR)
dest->residency = 0;
break;
default:
break;
}
spm_lock_release();
return 0;
}
int spm_rc_constraint_valid_set(enum mt_spm_rm_rc_type id,
enum mt_spm_rm_rc_type dest_rc_id,
uint32_t valid,
struct constraint_status * const dest)
{
if (((id != MT_RM_CONSTRAINT_ID_ALL) &&
(id != dest_rc_id)) || !dest)
return -1;
spm_lock_get();
SPM_RC_VALID_SET(dest->is_valid, valid);
spm_lock_release();
return 0;
}
int spm_rc_constraint_valid_clr(enum mt_spm_rm_rc_type id,
enum mt_spm_rm_rc_type dest_rc_id,
uint32_t valid,
struct constraint_status * const dest)
{
if (((id != MT_RM_CONSTRAINT_ID_ALL) &&
(id != dest_rc_id)) || !dest)
return -1;
spm_lock_get();
SPM_RC_VALID_CLR(dest->is_valid, valid);
spm_lock_release();
return 0;
}
/*
* CIRQ will respresent interrupt which type is edge
* when gic mask. But if the 26 clk have turned off before
* then cirq won't work normally.
* So we need to set irq pending for specific wakeup source.
*/
#ifndef MTK_PLAT_CIRQ_UNSUPPORT
static void mt_spm_irq_remain_dump(struct mt_irqremain *irqs,
uint32_t irq_index,
struct wake_status *wakeup)
{
INFO("[SPM] r12=0x%08x(0x%08x), irq:%u(0x%08x) set pending\n",
wakeup->tr.comm.r12,
wakeup->md32pcm_wakeup_sta,
irqs->wakeupsrc[irq_index],
irqs->irqs[irq_index]);
}
void do_irqs_delivery(struct mt_irqremain *irqs,
struct wake_status *wakeup)
{
uint32_t idx;
if (!irqs || !wakeup)
return;
for (idx = 0; idx < irqs->count; idx++) {
if ((wakeup->tr.comm.raw_sta & irqs->wakeupsrc[idx]) ||
(wakeup->tr.comm.r12 & irqs->wakeupsrc[idx])) {
if ((irqs->wakeupsrc_cat[idx] & MT_IRQ_REMAIN_CAT_LOG))
mt_spm_irq_remain_dump(irqs, idx, wakeup);
}
}
}
#endif

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_RC_API_H
#define MT_SPM_RC_API_H
#include <constraints/mt_spm_trace.h>
#include <mt_spm.h>
#include <mt_spm_constraint.h>
#include <mt_spm_internal.h>
enum mt_spm_rm_rc_type {
MT_RM_CONSTRAINT_ID_VCORE,
MT_RM_CONSTRAINT_ID_BUS26,
MT_RM_CONSTRAINT_ID_SYSPL,
MT_RM_CONSTRAINT_ID_ALL = 0xff,
};
enum mt_spm_rc_fp_type {
MT_SPM_RC_FP_INIT = 0,
MT_SPM_RC_FP_ENTER_START,
MT_SPM_RC_FP_ENTER_NOTIFY,
MT_SPM_RC_FP_ENTER_WAKE_SPM_BEFORE,
MT_SPM_RC_FP_ENTER_WAKE_SPM_AFTER,
MT_SPM_RC_FP_RESUME_START,
MT_SPM_RC_FP_RESUME_NOTIFY,
MT_SPM_RC_FP_RESUME_RESET_SPM_BEFORE,
MT_SPM_RC_FP_RESUME_BACKUP_EDGE_INT,
};
#define MT_SPM_RC_INFO(_cpu, _stateid, _rc_id) ({ \
MT_SPM_TRACE_COMMON_U32_WR(MT_SPM_TRACE_COMM_RC_INFO, \
((_cpu) << 28) | \
(((_stateid) & 0xffff) << 12) | \
((_rc_id) & 0xfff)); })
#define MT_SPM_RC_LAST_TIME(_time) ({ \
MT_SPM_TRACE_COMMON_U32_WR(MT_SPM_TRACE_COMM_RC_LAST_TIME_H, \
(uint32_t)((_time) >> 32)); \
MT_SPM_TRACE_COMMON_U32_WR(MT_SPM_TRACE_COMM_RC_LAST_TIME_L, \
(uint32_t)((_time) & 0xffffffff)); })
#define MT_SPM_RC_TAG(_cpu, _stateid, _rc_id) \
MT_SPM_RC_INFO(_cpu, _stateid, _rc_id)
#define MT_SPM_RC_FP(fp) ({ \
MT_SPM_TRACE_COMMON_U32_WR(MT_SPM_TRACE_COMM_RC_FP, fp); })
#define MT_SPM_RC_TAG_VALID(_valid) ({ \
MT_SPM_TRACE_COMMON_U32_WR(MT_SPM_TRACE_COMM_RC_VALID, _valid); })
int spm_rc_constraint_status_get(uint32_t id, uint32_t type,
uint32_t act,
enum mt_spm_rm_rc_type dest_rc_id,
struct constraint_status * const src,
struct constraint_status * const dest);
int spm_rc_constraint_status_set(uint32_t id, uint32_t type,
uint32_t act,
enum mt_spm_rm_rc_type dest_rc_id,
struct constraint_status * const src,
struct constraint_status * const dest);
int spm_rc_constraint_valid_set(enum mt_spm_rm_rc_type id,
enum mt_spm_rm_rc_type dest_rc_id,
uint32_t valid,
struct constraint_status * const dest);
int spm_rc_constraint_valid_clr(enum mt_spm_rm_rc_type id,
enum mt_spm_rm_rc_type dest_rc_id,
uint32_t valid,
struct constraint_status * const dest);
#ifdef MTK_PLAT_CIRQ_UNSUPPORT
#define do_irqs_delivery(_x, _w)
#else
void do_irqs_delivery(struct mt_irqremain *irqs,
struct wake_status *wakeup);
#endif /* MTK_PLAT_CIRQ_UNSUPPORT */
#endif /* MT_SPM_RC_API_H */

View file

@ -0,0 +1,255 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <common/debug.h>
#include <constraints/mt_spm_rc_api.h>
#include <constraints/mt_spm_rc_internal.h>
#include <drivers/spm/mt_spm_resource_req.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_rm.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_conservation.h>
#include <mt_spm_constraint.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_pmic_lp.h>
#include <mt_spm_reg.h>
#include <mt_spm_suspend.h>
#include <notifier/inc/mt_spm_notifier.h>
#define CONSTRAINT_BUS26M_ALLOW (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
MT_RM_CONSTRAINT_ALLOW_LVTS_STATE | \
MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF)
#define CONSTRAINT_BUS26M_PCM_FLAG (SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_DDR_DFS | \
SPM_FLAG_DISABLE_EMI_DFS | \
SPM_FLAG_DISABLE_BUS_DFS | \
SPM_FLAG_ENABLE_AOV | \
SPM_FLAG_DISABLE_VLP_PDN | \
SPM_FLAG_SRAM_SLEEP_CTRL | \
SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
#define CONSTRAINT_BUS26M_PCM_FLAG1 (SPM_FLAG1_ENABLE_ALCO_TRACE)
/*
* If sspm sram won't enter sleep voltage
* then vcore couldn't enter low power mode
*/
#if defined(MTK_PLAT_SPM_SRAM_SLP_UNSUPPORT) && SPM_SRAM_SLEEP_RC_RES_RESTRICT
#define CONSTRAINT_BUS26M_RESOURCE_REQ (MT_SPM_26M | MT_SPM_VCORE)
#else
#define CONSTRAINT_BUS26M_RESOURCE_REQ (MT_SPM_VCORE)
#endif
static uint32_t bus26m_ext_opand;
static struct mt_irqremain *refer2remain_irq;
static uint32_t cmd;
static struct constraint_status status = {
.id = MT_RM_CONSTRAINT_ID_BUS26,
.is_valid = (MT_SPM_RC_VALID_SW |
MT_SPM_RC_VALID_FW |
MT_SPM_RC_VALID_TRACE_TIME |
MT_SPM_RC_VALID_NOTIFY),
.enter_cnt = 0,
.all_pll_dump = 0,
.residency = 0,
};
int spm_bus26m_conduct(int state_id, struct spm_lp_scen *spm_lp,
uint32_t *resource_req)
{
if ((spm_lp == NULL) || (resource_req == NULL))
return -1;
struct pwr_ctrl *pwrctrl = spm_lp->pwrctrl;
pwrctrl->pcm_flags = CONSTRAINT_BUS26M_PCM_FLAG;
pwrctrl->pcm_flags1 = CONSTRAINT_BUS26M_PCM_FLAG1;
*resource_req |= CONSTRAINT_BUS26M_RESOURCE_REQ;
return 0;
}
bool spm_is_valid_rc_bus26m(uint32_t cpu, int state_id)
{
return (IS_MT_RM_RC_READY(status.is_valid) &&
!(bus26m_ext_opand & (MT_BUS26M_EXT_LP_26M_ON_MODE)));
}
int spm_update_rc_bus26m(int state_id, int type, const void *val)
{
int res = MT_RM_STATUS_OK;
uint32_t flag = *(uint32_t *)val;
if (type == PLAT_RC_UPDATE_REMAIN_IRQS) {
refer2remain_irq = (struct mt_irqremain *)val;
} else if (type == PLAT_RC_IS_FMAUDIO) {
if (flag)
bus26m_ext_opand |= MT_SPM_EX_OP_SET_IS_FM_AUDIO;
else
bus26m_ext_opand &= ~MT_SPM_EX_OP_SET_IS_FM_AUDIO;
} else if (type == PLAT_RC_IS_ADSP) {
if (flag)
bus26m_ext_opand |= MT_SPM_EX_OP_SET_IS_ADSP;
else
bus26m_ext_opand &= ~MT_SPM_EX_OP_SET_IS_ADSP;
} else if (type == PLAT_RC_IS_USB_HEADSET) {
if (flag)
bus26m_ext_opand |= MT_SPM_EX_OP_SET_IS_USB_HEADSET;
else
bus26m_ext_opand &= ~MT_SPM_EX_OP_SET_IS_USB_HEADSET;
} else if (type == PLAT_RC_STATUS) {
const struct rc_common_state *st;
st = (const struct rc_common_state *)val;
if (!st)
return 0;
if ((st->type == CONSTRAINT_UPDATE_VALID) ||
(st->type == CONSTRAINT_RESIDNECY))
spm_rc_constraint_status_set(st->id,
st->type, st->act,
MT_RM_CONSTRAINT_ID_BUS26,
st->value,
&status);
else
INFO("[%s:%d] - Unknown type: 0x%x\n",
__func__, __LINE__, st->type);
}
return res;
}
uint32_t spm_allow_rc_bus26m(int state_id)
{
return CONSTRAINT_BUS26M_ALLOW;
}
int spm_run_rc_bus26m(uint32_t cpu, int state_id)
{
uint32_t ext_op = MT_SPM_EX_OP_HW_S1_DETECT |
MT_SPM_EX_OP_NOTIFY_INFRA_OFF;
uint32_t nb_type = MT_SPM_NOTIFY_IDLE_ENTER;
MT_SPM_RC_TAG(cpu, state_id, MT_RM_CONSTRAINT_ID_BUS26);
MT_SPM_RC_TAG_VALID(status.is_valid);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_START);
cmd = CONSTRAINT_BUS26M_ALLOW;
if (IS_PLAT_SUSPEND_ID(state_id)) {
cmd |= (MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND |
MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND);
ext_op |= (MT_SPM_EX_OP_CLR_26M_RECORD |
MT_SPM_EX_OP_SET_WDT);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_SUSPEND_VCORE, 0);
} else {
if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME)
ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
}
#ifdef MTK_SPM_PMIC_LP_SUPPORT
do_spm_low_power(SPM_LP_ENTER, cmd);
#endif
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_NOTIFY);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(nb_type, cmd);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_BEFORE);
if (IS_PLAT_SUSPEND_ID(state_id))
mt_spm_suspend_enter(state_id, ext_op,
CONSTRAINT_BUS26M_RESOURCE_REQ);
else
mt_spm_idle_generic_enter(state_id, ext_op,
spm_bus26m_conduct);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_AFTER);
return 0;
}
int spm_reset_rc_bus26m(uint32_t cpu, int state_id)
{
struct wake_status *waken = NULL;
uint32_t ext_op = MT_SPM_EX_OP_HW_S1_DETECT |
MT_SPM_EX_OP_NOTIFY_INFRA_OFF;
uint32_t nb_type = MT_SPM_NOTIFY_IDLE_LEAVE;
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_START);
if (IS_PLAT_SUSPEND_ID(state_id)) {
ext_op |= MT_SPM_EX_OP_SET_WDT;
} else {
if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME)
ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
if (spm_unlikely(status.is_valid &
MT_SPM_RC_VALID_TRACE_EVENT))
ext_op |= MT_SPM_EX_OP_TRACE_LP;
}
#ifdef MTK_SPM_PMIC_LP_SUPPORT
do_spm_low_power(SPM_LP_RESUME, cmd);
#endif
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_NOTIFY);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(nb_type, 0);
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_RESET_SPM_BEFORE);
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_resume(state_id, ext_op, &waken);
bus26m_ext_opand = 0;
} else {
mt_spm_idle_generic_resume(state_id, ext_op, &waken, NULL);
status.enter_cnt++;
if (spm_unlikely(status.is_valid & MT_SPM_RC_VALID_RESIDNECY))
status.residency += waken ?
waken->tr.comm.timer_out : 0;
}
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_BACKUP_EDGE_INT);
do_irqs_delivery(refer2remain_irq, waken);
MT_SPM_RC_FP(MT_SPM_RC_FP_INIT);
return 0;
}
int spm_get_status_rc_bus26m(uint32_t type, void *priv)
{
int ret = MT_RM_STATUS_OK;
if (type == PLAT_RC_STATUS) {
struct rc_common_state *st = (struct rc_common_state *)priv;
if (!st)
return MT_RM_STATUS_BAD;
ret = spm_rc_constraint_status_get(st->id, st->type,
st->act,
MT_RM_CONSTRAINT_ID_BUS26,
&status,
st->value);
if (!ret && (st->id != MT_RM_CONSTRAINT_ID_ALL))
ret = MT_RM_STATUS_STOP;
}
return ret;
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_RC_INTERNAL_H
#define MT_SPM_RC_INTERNAL_H
#include <sleep_def.h>
#define SPM_SRAM_SLEEP_DEFAULT_FLAG (SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP)
#ifdef MTK_PLAT_SPM_SRAM_SLP_UNSUPPORT
#define SPM_FLAG_SRAM_SLEEP_CTRL (SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP)
#else
#define SPM_FLAG_SRAM_SLEEP_CTRL (SPM_SRAM_SLEEP_DEFAULT_FLAG)
#endif
#define SPM_SRAM_SLEEP_RC_RES_RESTRICT 0
#define SPM_RC_UPDATE_COND_ID_MASK 0xffff
#define SPM_RC_UPDATE_COND_RC_ID_MASK 0xffff
#define SPM_RC_UPDATE_COND_RC_ID_SHIFT 16
#define SPM_RC_UPDATE_COND_RC_ID_GET(val) \
(((val) >> SPM_RC_UPDATE_COND_RC_ID_SHIFT) & \
SPM_RC_UPDATE_COND_RC_ID_MASK)
#define SPM_RC_UPDATE_COND_ID_GET(val) \
((val) & SPM_RC_UPDATE_COND_ID_MASK)
/* CPU buck/ldo constraint function */
int spm_is_valid_rc_cpu_buck_ldo(int cpu, int state_id);
int spm_update_rc_cpu_buck_ldo(int state_id, int type,
const void *val);
uint32_t spm_allow_rc_cpu_buck_ldo(int state_id);
int spm_run_rc_cpu_buck_ldo(int cpu, int state_id);
int spm_reset_rc_cpu_buck_ldo(int cpu, int state_id);
int spm_get_status_rc_cpu_buck_ldo(uint32_t type, void *priv);
/* SPM resource syspll constraint function */
bool spm_is_valid_rc_syspll(uint32_t cpu, int state_id);
int spm_update_rc_syspll(int state_id, int type, const void *val);
uint32_t spm_allow_rc_syspll(int state_id);
int spm_run_rc_syspll(uint32_t cpu, int state_id);
int spm_reset_rc_syspll(uint32_t cpu, int state_id);
int spm_get_status_rc_syspll(uint32_t type, void *priv);
/* SPM resource bus26m constraint function */
bool spm_is_valid_rc_bus26m(uint32_t cpu, int state_id);
int spm_update_rc_bus26m(int state_id, int type, const void *val);
uint32_t spm_allow_rc_bus26m(int state_id);
int spm_run_rc_bus26m(uint32_t cpu, int state_id);
int spm_reset_rc_bus26m(uint32_t cpu, int state_id);
int spm_get_status_rc_bus26m(uint32_t type, void *priv);
/* SPM resource vcore constraint function */
bool spm_is_valid_rc_vcore(uint32_t cpu, int state_id);
int spm_update_rc_vcore(int state_id, int type, const void *val);
uint32_t spm_allow_rc_vcore(int state_id);
int spm_run_rc_vcore(uint32_t cpu, int state_id);
int spm_reset_rc_vcore(uint32_t cpu, int state_id);
int spm_get_status_rc_vcore(uint32_t type, void *priv);
#endif /* MT_SPM_RC_INTERNAL_H */

View file

@ -0,0 +1,260 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <common/debug.h>
#include <constraints/mt_spm_rc_api.h>
#include <constraints/mt_spm_rc_internal.h>
#include <drivers/spm/mt_spm_resource_req.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_api.h>
#include <lpm_v2/mt_lp_rm.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_conservation.h>
#include <mt_spm_constraint.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_pmic_lp.h>
#include <mt_spm_reg.h>
#include <mt_spm_suspend.h>
#include <notifier/inc/mt_spm_notifier.h>
#define CONSTRAINT_SYSPLL_ALLOW (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
MT_RM_CONSTRAINT_ALLOW_LVTS_STATE)
#define CONSTRAINT_SYSPLL_PCM_FLAG (SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_DDR_DFS | \
SPM_FLAG_DISABLE_EMI_DFS | \
SPM_FLAG_DISABLE_BUS_DFS | \
SPM_FLAG_ENABLE_AOV | \
SPM_FLAG_DISABLE_VLP_PDN | \
SPM_FLAG_SRAM_SLEEP_CTRL | \
SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
#define CONSTRAINT_SYSPLL_PCM_FLAG1 (SPM_FLAG1_ENABLE_ALCO_TRACE)
#define CONSTRAINT_SYSPLL_RESOURCE_REQ (MT_SPM_26M | \
MT_SPM_VCORE | MT_SPM_INFRA)
#define CHECK_VAL(val, sys_state) \
((val) ? !!(*((uint32_t *)(val)) == (sys_state)) : 0)
static uint32_t cmd;
static struct constraint_status status = {
.id = MT_RM_CONSTRAINT_ID_SYSPL,
.is_valid = (MT_SPM_RC_VALID_SW |
MT_SPM_RC_VALID_FW |
MT_SPM_RC_VALID_NOTIFY),
.enter_cnt = 0,
.residency = 0,
};
int spm_syspll_conduct(int state_id, struct spm_lp_scen *spm_lp,
uint32_t *resource_req)
{
if ((spm_lp == NULL) || (resource_req == NULL))
return -1;
struct pwr_ctrl *pwrctrl = spm_lp->pwrctrl;
pwrctrl->pcm_flags = CONSTRAINT_SYSPLL_PCM_FLAG;
pwrctrl->pcm_flags1 = CONSTRAINT_SYSPLL_PCM_FLAG1;
*resource_req |= CONSTRAINT_SYSPLL_RESOURCE_REQ;
return 0;
}
bool spm_is_valid_rc_syspll(uint32_t cpu, int state_id)
{
return IS_MT_RM_RC_READY(status.is_valid);
}
int spm_update_rc_syspll(int state_id, int type, const void *val)
{
int res = MT_RM_STATUS_OK;
if (type == PLAT_RC_CLKBUF_STATUS) {
bool is_flight = CHECK_VAL(val, FLIGHT_MODE_ON);
if (is_flight)
spm_rc_constraint_valid_set(MT_RM_CONSTRAINT_ID_SYSPL,
MT_RM_CONSTRAINT_ID_SYSPL,
MT_SPM_RC_VALID_FLIGHTMODE,
&status);
else
spm_rc_constraint_valid_clr(MT_RM_CONSTRAINT_ID_SYSPL,
MT_RM_CONSTRAINT_ID_SYSPL,
MT_SPM_RC_VALID_FLIGHTMODE,
&status);
} else if (type == PLAT_RC_UFS_STATUS) {
uint32_t is_ufs_h8 = CHECK_VAL(val, UFS_REF_CLK_OFF);
if (is_ufs_h8)
spm_rc_constraint_valid_set(MT_RM_CONSTRAINT_ID_SYSPL,
MT_RM_CONSTRAINT_ID_SYSPL,
MT_SPM_RC_VALID_UFS_H8,
&status);
else
spm_rc_constraint_valid_clr(MT_RM_CONSTRAINT_ID_SYSPL,
MT_RM_CONSTRAINT_ID_SYSPL,
MT_SPM_RC_VALID_UFS_H8,
&status);
} else if (type == PLAT_RC_STATUS) {
const struct rc_common_state *st;
st = (const struct rc_common_state *)val;
if (!st)
return 0;
if ((st->type == CONSTRAINT_UPDATE_VALID) ||
(st->type == CONSTRAINT_RESIDNECY))
spm_rc_constraint_status_set(st->id, st->type,
st->act,
MT_RM_CONSTRAINT_ID_SYSPL,
st->value,
&status);
else
INFO("[%s:%d] - Unknown type: 0x%x\n",
__func__, __LINE__, st->type);
}
return res;
}
uint32_t spm_allow_rc_syspll(int state_id)
{
return CONSTRAINT_SYSPLL_ALLOW;
}
int spm_run_rc_syspll(uint32_t cpu, int state_id)
{
uint32_t ext_op = MT_SPM_EX_OP_HW_S1_DETECT |
MT_SPM_EX_OP_NOTIFY_INFRA_OFF;
uint32_t nb_type = MT_SPM_NOTIFY_IDLE_ENTER;
MT_SPM_RC_TAG(cpu, state_id, MT_RM_CONSTRAINT_ID_SYSPL);
MT_SPM_RC_TAG_VALID(status.is_valid);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_START);
cmd = CONSTRAINT_SYSPLL_ALLOW;
if (IS_PLAT_SUSPEND_ID(state_id)) {
cmd |= MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND;
ext_op |= (MT_SPM_EX_OP_CLR_26M_RECORD |
MT_SPM_EX_OP_SET_WDT);
} else {
if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME)
ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
if (!IS_MT_PLAT_PWR_STATE(state_id,
MT_PLAT_PWR_STATE_SYSTEM_PLL)) {
nb_type = MT_SPM_NOTIFY_IDLE_ENTER;
ext_op &= ~MT_SPM_EX_OP_NOTIFY_INFRA_OFF;
}
}
#ifdef MTK_SPM_PMIC_LP_SUPPORT
do_spm_low_power(SPM_LP_ENTER, cmd);
#endif
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_NOTIFY);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(nb_type, cmd);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_BEFORE);
if (IS_PLAT_SUSPEND_ID(state_id))
mt_spm_suspend_enter(state_id, ext_op,
CONSTRAINT_SYSPLL_RESOURCE_REQ);
else
mt_spm_idle_generic_enter(state_id, ext_op, spm_syspll_conduct);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_AFTER);
return 0;
}
int spm_reset_rc_syspll(uint32_t cpu, int state_id)
{
uint32_t ext_op = MT_SPM_EX_OP_HW_S1_DETECT |
MT_SPM_EX_OP_NOTIFY_INFRA_OFF;
uint32_t nb_type = MT_SPM_NOTIFY_IDLE_LEAVE;
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_START);
if (IS_PLAT_SUSPEND_ID(state_id)) {
ext_op |= (MT_SPM_EX_OP_SET_WDT);
} else {
if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME)
ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
if (spm_unlikely(status.is_valid &
MT_SPM_RC_VALID_TRACE_EVENT))
ext_op |= MT_SPM_EX_OP_TRACE_LP;
if (!IS_MT_PLAT_PWR_STATE(state_id,
MT_PLAT_PWR_STATE_SYSTEM_PLL)) {
nb_type = MT_SPM_NOTIFY_IDLE_LEAVE;
ext_op &= ~MT_SPM_EX_OP_NOTIFY_INFRA_OFF;
}
}
#ifdef MTK_SPM_PMIC_LP_SUPPORT
do_spm_low_power(SPM_LP_RESUME, cmd);
#endif
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_NOTIFY);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(nb_type, cmd);
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_RESET_SPM_BEFORE);
if (IS_PLAT_SUSPEND_ID(state_id))
mt_spm_suspend_resume(state_id, ext_op, NULL);
else {
struct wake_status *waken = NULL;
mt_spm_idle_generic_resume(state_id, ext_op, &waken, NULL);
status.enter_cnt++;
if (spm_unlikely(status.is_valid & MT_SPM_RC_VALID_RESIDNECY))
status.residency += waken ?
waken->tr.comm.timer_out : 0;
}
MT_SPM_RC_FP(MT_SPM_RC_FP_INIT);
return 0;
}
int spm_get_status_rc_syspll(uint32_t type, void *priv)
{
int ret = MT_RM_STATUS_OK;
if (type == PLAT_RC_STATUS) {
int res = 0;
struct rc_common_state *st = (struct rc_common_state *)priv;
if (!st)
return MT_RM_STATUS_BAD;
res = spm_rc_constraint_status_get(st->id, st->type,
st->act,
MT_RM_CONSTRAINT_ID_SYSPL,
&status,
st->value);
if (!res && (st->id != MT_RM_CONSTRAINT_ID_ALL))
ret = MT_RM_STATUS_STOP;
}
return ret;
}

View file

@ -0,0 +1,266 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <common/debug.h>
#include <constraints/mt_spm_rc_api.h>
#include <constraints/mt_spm_rc_internal.h>
#include <drivers/spm/mt_spm_resource_req.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_rm.h>
#include <lpm_v2/mt_lp_rqm.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_conservation.h>
#include <mt_spm_constraint.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_pmic_lp.h>
#include <mt_spm_reg.h>
#include <mt_spm_suspend.h>
#include <notifier/inc/mt_spm_notifier.h>
#define ERROW_TEST
#define CONSTRAINT_VCORE_ALLOW (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
MT_RM_CONSTRAINT_ALLOW_LVTS_STATE | \
MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF | \
MT_RM_CONSTRAINT_ALLOW_VCORE_OFF)
#define CONSTRAINT_VCORE_PCM_FLAG (SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_DDR_DFS | \
SPM_FLAG_DISABLE_EMI_DFS | \
SPM_FLAG_DISABLE_BUS_DFS | \
SPM_FLAG_DISABLE_VLP_PDN | \
SPM_FLAG_DISABLE_BUS_DFS | \
SPM_FLAG_ENABLE_AOV | \
SPM_FLAG_SRAM_SLEEP_CTRL)
#define CONSTRAINT_VCORE_PCM_FLAG1 (SPM_FLAG1_ENABLE_ALCO_TRACE)
#if defined(MTK_PLAT_SPM_SRAM_SLP_UNSUPPORT) && SPM_SRAM_SLEEP_RC_RES_RESTRICT
#define CONSTRAINT_VCORE_RESOURCE_REQ (MT_SPM_26M | MT_SPM_VCORE)
#else
#define CONSTRAINT_VCORE_RESOURCE_REQ 0
#endif
static uint32_t vcore_ext_opand;
static struct mt_irqremain *refer2remain_irq;
static uint32_t cmd;
static struct constraint_status status = {
.id = MT_RM_CONSTRAINT_ID_VCORE,
.is_valid = (MT_SPM_RC_VALID_SW |
MT_SPM_RC_VALID_FW |
MT_SPM_RC_VALID_TRACE_TIME |
MT_SPM_RC_VALID_NOTIFY),
.enter_cnt = 0,
.all_pll_dump = 0,
.residency = 0,
};
int spm_vcore_conduct(int state_id, struct spm_lp_scen *spm_lp,
uint32_t *resource_req)
{
if ((spm_lp == NULL) || (resource_req == NULL))
return -1;
struct pwr_ctrl *pwrctrl = spm_lp->pwrctrl;
pwrctrl->pcm_flags = CONSTRAINT_VCORE_PCM_FLAG;
pwrctrl->pcm_flags1 = CONSTRAINT_VCORE_PCM_FLAG1;
*resource_req |= CONSTRAINT_VCORE_RESOURCE_REQ;
return 0;
}
bool spm_is_valid_rc_vcore(uint32_t cpu, int state_id)
{
uint32_t vcore_ext = vcore_ext_opand &
(MT_VCORE_EXT_LP_VCORE_ON_MODE);
return (IS_MT_RM_RC_READY(status.is_valid) &&
IS_MT_PLAT_PWR_STATE(state_id,
MT_PLAT_PWR_STATE_SYSTEM_VCORE) &&
!vcore_ext);
}
int spm_update_rc_vcore(int state_id, int type, const void *val)
{
int res = MT_RM_STATUS_OK;
uint32_t flag = *(uint32_t *)val;
if (type == PLAT_RC_UPDATE_REMAIN_IRQS) {
refer2remain_irq = (struct mt_irqremain *)val;
} else if (type == PLAT_RC_IS_FMAUDIO) {
if (flag)
vcore_ext_opand |= MT_SPM_EX_OP_SET_IS_FM_AUDIO;
else
vcore_ext_opand &= ~MT_SPM_EX_OP_SET_IS_FM_AUDIO;
} else if (type == PLAT_RC_IS_ADSP) {
if (flag)
vcore_ext_opand |= MT_SPM_EX_OP_SET_IS_ADSP;
else
vcore_ext_opand &= ~MT_SPM_EX_OP_SET_IS_ADSP;
} else if (type == PLAT_RC_IS_USB_HEADSET) {
if (flag)
vcore_ext_opand |= MT_SPM_EX_OP_SET_IS_USB_HEADSET;
else
vcore_ext_opand &= ~MT_SPM_EX_OP_SET_IS_USB_HEADSET;
} else if (type == PLAT_RC_STATUS) {
const struct rc_common_state *st;
st = (const struct rc_common_state *)val;
if (!st)
return -1;
if ((st->type == CONSTRAINT_UPDATE_VALID) ||
(st->type == CONSTRAINT_RESIDNECY))
spm_rc_constraint_status_set(st->id,
st->type, st->act,
MT_RM_CONSTRAINT_ID_VCORE,
st->value,
&status);
else
INFO("[%s:%d] - Unknown type: 0x%x\n",
__func__, __LINE__, st->type);
}
return res;
}
uint32_t spm_allow_rc_vcore(int state_id)
{
return CONSTRAINT_VCORE_ALLOW;
}
int spm_run_rc_vcore(uint32_t cpu, int state_id)
{
uint32_t ext_op = (MT_SPM_EX_OP_HW_S1_DETECT |
MT_SPM_EX_OP_DEVICES_SAVE |
MT_SPM_EX_OP_TRACE_TIMESTAMP_EN |
MT_SPM_EX_OP_NOTIFY_INFRA_OFF);
uint32_t spm_lp_notify_mode;
MT_SPM_RC_TAG(cpu, state_id, MT_RM_CONSTRAINT_ID_VCORE);
MT_SPM_RC_TAG_VALID(status.is_valid);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_START);
cmd = CONSTRAINT_VCORE_ALLOW | MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND;
spm_lp_notify_mode = MT_SPM_NOTIFY_LP_ENTER;
if (IS_PLAT_SUSPEND_ID(state_id)) {
cmd |= (MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND);
ext_op |= (MT_SPM_EX_OP_CLR_26M_RECORD |
MT_SPM_EX_OP_SET_WDT);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_SUSPEND_VCORE, 0);
} else {
if (!(status.is_valid & MT_SPM_RC_VALID_TRACE_TIME))
ext_op &= ~MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
}
#ifdef MTK_SPM_PMIC_LP_SUPPORT
do_spm_low_power(SPM_LP_ENTER, cmd);
#endif
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_NOTIFY);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(spm_lp_notify_mode, cmd);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_BEFORE);
if (IS_PLAT_SUSPEND_ID(state_id))
mt_spm_suspend_enter(state_id, ext_op, 0);
else
mt_spm_idle_generic_enter(state_id, ext_op,
spm_vcore_conduct);
MT_SPM_RC_FP(MT_SPM_RC_FP_ENTER_WAKE_SPM_AFTER);
return 0;
}
int spm_reset_rc_vcore(uint32_t cpu, int state_id)
{
struct wake_status *waken = NULL;
uint32_t ext_op = (MT_SPM_EX_OP_HW_S1_DETECT |
MT_SPM_EX_OP_DEVICES_SAVE |
MT_SPM_EX_OP_TRACE_LP |
MT_SPM_EX_OP_NOTIFY_INFRA_OFF);
uint32_t spm_lp_notify_mode;
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_START);
spm_lp_notify_mode = MT_SPM_NOTIFY_LP_LEAVE;
if (IS_PLAT_SUSPEND_ID(state_id)) {
ext_op |= MT_SPM_EX_OP_SET_WDT;
} else {
if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME)
ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
if (spm_unlikely(!(status.is_valid &
MT_SPM_RC_VALID_TRACE_EVENT)))
ext_op &= ~MT_SPM_EX_OP_TRACE_LP;
}
#ifdef MTK_SPM_PMIC_LP_SUPPORT
do_spm_low_power(SPM_LP_RESUME, cmd);
#endif
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_NOTIFY);
if (IS_MT_SPM_RC_NOTIFY_ENABLE(status.is_valid))
mt_spm_sspm_notify_u32(spm_lp_notify_mode, 0);
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_RESET_SPM_BEFORE);
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_resume(state_id, ext_op, &waken);
vcore_ext_opand = 0;
} else {
mt_spm_idle_generic_resume(state_id, ext_op, &waken, NULL);
status.enter_cnt++;
if (spm_unlikely(status.is_valid & MT_SPM_RC_VALID_RESIDNECY))
status.residency += waken ?
waken->tr.comm.timer_out : 0;
}
MT_SPM_RC_FP(MT_SPM_RC_FP_RESUME_BACKUP_EDGE_INT);
do_irqs_delivery(refer2remain_irq, waken);
MT_SPM_RC_FP(MT_SPM_RC_FP_INIT);
return 0;
}
int spm_get_status_rc_vcore(uint32_t type, void *priv)
{
int ret = MT_RM_STATUS_OK;
if (type == PLAT_RC_STATUS) {
struct rc_common_state *st = (struct rc_common_state *)priv;
if (!st)
return MT_RM_STATUS_BAD;
ret = spm_rc_constraint_status_get(st->id, st->type,
st->act,
MT_RM_CONSTRAINT_ID_VCORE,
&status,
st->value);
if (!ret && (st->id != MT_RM_CONSTRAINT_ID_ALL))
ret = MT_RM_STATUS_STOP;
}
return ret;
}

View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_TRACE_H
#define MT_SPM_TRACE_H
#include <lib/mmio.h>
#include <platform_def.h>
enum mt_spm_sysram_type {
MT_SPM_SYSRAM_COMMON,
MT_SPM_SYSRAM_SUSPEND,
MT_SPM_SYSRAM_LP,
};
/* SPM trace common type */
enum mt_spm_trace_common_type {
MT_SPM_TRACE_COMM_HAED,
MT_SPM_TRACE_COMM_FP,
MT_SPM_TRACE_COMM_RC_LAST_TIME_H,
MT_SPM_TRACE_COMM_RC_LAST_TIME_L,
MT_SPM_TRACE_COMM_RC_INFO,
MT_SPM_TRACE_COMM_RC_FP,
MT_SPM_TRACE_COMM_RC_VALID,
};
/* SPM trace suspend type */
enum mt_spm_trace_suspend_type {
MT_SPM_TRACE_SUSPEND_WAKE_SRC,
};
/*
* SPM sram usage with mcdi sram
* start offset : 0x500
*/
#define MT_SPM_SYSRAM_BASE (MTK_LPM_SRAM_BASE + 0x500)
#define MT_SPM_SYSRAM_COMM_BASE MT_SPM_SYSRAM_BASE
#define MT_SPM_SYSRAM_COMM_SZ 0x20
#define MT_SPM_SYSRAM_SUSPEND_BASE \
(MT_SPM_SYSRAM_BASE + MT_SPM_SYSRAM_COMM_SZ)
#define MT_SPM_SYSRAM_SUSPEND_SZ 0xe0
#define MT_SPM_SYSRAM_LP_BASE \
(MT_SPM_SYSRAM_SUSPEND_BASE + MT_SPM_SYSRAM_SUSPEND_SZ)
#define MT_SPM_SYSRAM_SLOT(slot) ((slot) << 2u)
#ifndef MTK_PLAT_SPM_TRACE_UNSUPPORT
#define MT_SPM_SYSRAM_W(_s, type, val, _sz) \
mt_spm_sysram_write(_s, type, val, _sz)
#define MT_SPM_SYSRAM_R_U32(addr, val) ({ \
unsigned int *r_val = (unsigned int *)val; \
if (r_val) \
*r_val = mmio_read_32(addr); })
#define MT_SPM_SYSRAM_R(_s, type, val) \
mt_spm_sysram_read(_s, type, val)
/* SPM trace common */
#define MT_SPM_TRACE_INIT(_magic) ({ \
mt_spm_sysram_init(_magic); })
#define MT_SPM_TRACE_COMMON_U32_WR(_type, _val) ({ \
mmio_write_32((MT_SPM_SYSRAM_COMM_BASE + \
MT_SPM_SYSRAM_SLOT(_type)), _val); })
#define MT_SPM_TRACE_COMMON_WR(_type, val, _sz) ({ \
int ret = MT_SPM_SYSRAM_W(MT_SPM_SYSRAM_COMMON, \
_type, val, _sz); ret; })
#define MT_SPM_TRACE_COMMON_U32_RD(_type, _val) ({ \
MT_SPM_SYSRAM_R_U32((MT_SPM_SYSRAM_COMM_BASE + \
MT_SPM_SYSRAM_SLOT(_type)), _val); })
#define MT_SPM_TRACE_COMMON_RD(_type, _val) ({ \
int ret = MT_SPM_SYSRAM_R(MT_SPM_SYSRAM_COMMON, \
_type, _val); ret; })
/* SPM trace suspend */
#define MT_SPM_TRACE_SUSPEND_U32_WR(_type, _val) ({ \
mmio_write_32((MT_SPM_SYSRAM_SUSPEND_BASE + \
MT_SPM_SYSRAM_SLOT(_type)), _val); })
#define MT_SPM_TRACE_SUSPEND_WR(_type, _val, _sz) ({ \
int ret = MT_SPM_SYSRAM_W(MT_SPM_SYSRAM_SUSPEND, \
_type, _val, _sz); ret; })
#define MT_SPM_TRACE_SUSPEND_U32_RD(_type, _val) ({\
MT_SPM_SYSRAM_R_U32((MT_SPM_SYSRAM_SUSPEND_BASE + \
MT_SPM_SYSRAM_SLOT(_type)), _val); })
#define MT_SPM_TRACE_SUSPEND_RD(_type, _val) ({ \
int ret = MT_SPM_SYSRAM_R(MT_SPM_SYSRAM_SUSPEND, \
_type, _val); ret; })
/* SPM trace low power */
#define MT_SPM_TRACE_LP_U32_WR(_type, _val) ({ \
mmio_write_32((MT_SPM_SYSRAM_LP_BASE + \
MT_SPM_SYSRAM_SLOT(_type)), _val); })
#define MT_SPM_TRACE_LP_WR(_type, _val, _sz) ({ \
int ret = MT_SPM_SYSRAM_W(MT_SPM_SYSRAM_LP, \
_type, _val, _sz); ret; })
#define MT_SPM_TRACE_LP_U32_RD(_type, _val) ({ \
MT_SPM_SYSRAM_R_U32((MT_SPM_SYSRAM_LP_BASE + \
MT_SPM_SYSRAM_SLOT(_type)), _val); })
#define MT_SPM_TRACE_LP_RD(_type, _val) ({ \
int ret = MT_SPM_SYSRAM_R(MT_SPM_SYSRAM_LP, \
_type, _val); ret; })
#define MT_SPM_TRACE_LP_RINGBUF(_pval, _sz) ({ \
int ret = mt_spm_sysram_lp_ringbuf_add(_pval, _sz); ret; })
int mt_spm_sysram_lp_ringbuf_add(const void *val, unsigned int sz);
int mt_spm_sysram_write(int section, int type, const void *val,
unsigned int sz);
int mt_spm_sysram_read(int section, int type, void *val);
int mt_spm_sysram_init(unsigned int magic);
#else
/* SPM trace common */
#define MT_SPM_TRACE_INIT(_magic)
#define MT_SPM_TRACE_COMMON_U32_WR(type, val)
#define MT_SPM_TRACE_COMMON_WR(val)
#define MT_SPM_TRACE_COMMON_U32_RD(type, val)
#define MT_SPM_TRACE_COMMON_RD(val)
/* SPM trace suspend */
#define MT_SPM_TRACE_SUSPEND_U32_WR(type, val)
#define MT_SPM_TRACE_SUSPEND_WR(val)
#define MT_SPM_TRACE_SUSPEND_U32_RD(type, val)
#define MT_SPM_TRACE_SUSPEND_RD(val)
/* SPM trace low power */
#define MT_SPM_TRACE_LP_U32_WR(type, val)
#define MT_SPM_TRACE_LP_WR(val)
#define MT_SPM_TRACE_LP_U32_RD(type, val)
#define MT_SPM_TRACE_LP_RD(val)
#define MT_SPM_TRACE_LP_RINGBUF(pval, sz)
#define mt_spm_sysram_lp_ringbuf_add(_val, _sz)
#define mt_spm_sysram_write(_s, _type, _val, _sz)
#define mt_spm_sysram_read(_s, _type, _val)
#define mt_spm_sysram_init(_magic)
#endif
#endif /* MT_SPM_TRACE_H */

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdbool.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <pmic_wrap/inc/mt_spm_pmic_wrap.h>
/*
* BIT Operation
*/
#define CMD_DATA(h, l, v) ((GENMASK(h, l) & ((v) << (l))))
#define VOLT_DATA(v) CMD_DATA(7, 0, VOLT_TO_PMIC_VAL(v))
/*
* PMIC_WRAP
*/
#define VCORE_BASE_UV 0 /* PMIC MT6316 */
#define VOLT_TO_PMIC_VAL(volt) (((volt) - VCORE_BASE_UV + 500 - 1) / 500)
#define PMIC_VAL_TO_VOLT(pmic) (((pmic) * 500) + VCORE_BASE_UV)
#define NR_PMIC_WRAP_CMD NR_IDX_ALL
#define MAX_RETRY_COUNT 100
#define SPM_DATA_SHIFT 16
/* MT6316 */
#define MT6316_TOP_VRCTL_VOSEL_VBUCK1 0x1448
#define MT6316_VCORE_VBUCK1_ON 0x1441
#define MT6316_VCORE_VBUCK1_OFF 0x1442
static struct pmic_wrap_cmd_setting cmd_table[NR_PMIC_WRAP_CMD] = {
{SPM_PWRAP_CMD0, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(57500)},
{SPM_PWRAP_CMD1, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(57500)},
{SPM_PWRAP_CMD2, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(60000)},
{SPM_PWRAP_CMD3, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(65000)},
{SPM_PWRAP_CMD4, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(72500)},
{SPM_PWRAP_CMD5, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(72500)},
{SPM_PWRAP_CMD6, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(82500)},
{SPM_PWRAP_CMD7, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(87500)},
{SPM_PWRAP_CMD8, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(87500)},
{SPM_PWRAP_CMD9, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(57500)},
{SPM_PWRAP_CMD10, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(60000)},
{SPM_PWRAP_CMD11, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(65000)},
{SPM_PWRAP_CMD12, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(72500)},
{SPM_PWRAP_CMD13, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(82500)},
{SPM_PWRAP_CMD14, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(87500)},
{SPM_PWRAP_CMD15, MT6316_VCORE_VBUCK1_ON, 1},
{SPM_PWRAP_CMD16, MT6316_VCORE_VBUCK1_OFF, 1},
{SPM_PWRAP_CMD17, MT6316_TOP_VRCTL_VOSEL_VBUCK1, VOLT_DATA(75000)},
{SPM_PWRAP_CMD18, 0, 0},
{SPM_PWRAP_CMD19, 0, 0},
{SPM_PWRAP_CMD20, 0, 0},
{SPM_PWRAP_CMD21, 0, 0},
{SPM_PWRAP_CMD22, 0, 0},
{SPM_PWRAP_CMD23, 0, 0},
{SPM_PWRAP_CMD24, 0, 0},
{SPM_PWRAP_CMD25, 0, 0},
{SPM_PWRAP_CMD26, 0, 0},
{SPM_PWRAP_CMD27, 0, 0},
{SPM_PWRAP_CMD28, 0, 0},
{SPM_PWRAP_CMD29, 0, 0},
{SPM_PWRAP_CMD30, 0, 0},
{SPM_PWRAP_CMD31, 0, 0},
};
static struct pmic_wrap_phase_setting phase_table[NR_PMIC_WRAP_PHASE] = {
{
.cmd = cmd_table,
.nr_idx = NR_IDX_ALL,
},
};
static struct pmic_wrap_setting pmic_wrap_table = {
.phase = phase_table,
.phase_nr_idx = NR_PMIC_WRAP_PHASE,
};
void plat_spm_pmic_wrap_init(void)
{
mt_spm_pmic_wrap_set_table(&pmic_wrap_table);
mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_ALLINONE);
}
#define PMIC_WRAP_REG_1 0x3E8
#define PMIC_WRAP_REG_STEP 0x4
#define PMIC_WRAP_REG_2 0xC28
#define PMIC_WRAP_REG_3 0xF54
#ifndef MTK_PLAT_SPM_PMIC_WRAP_DUMP_UNSUPPORT
void mt_spm_dump_pmic_warp_reg(void)
{
uint32_t temp;
uint32_t i;
for (i = 0; i <= PMIC_WRAP_REG_1; i += PMIC_WRAP_REG_STEP) {
temp = mmio_read_32(PMIC_WRAP_BASE + i);
}
for (i = 0xC00; i <= PMIC_WRAP_REG_2; i += PMIC_WRAP_REG_STEP) {
temp = mmio_read_32(PMIC_WRAP_BASE + i);
}
for (i = 0xF00; i <= PMIC_WRAP_REG_3; i += PMIC_WRAP_REG_STEP) {
temp = mmio_read_32(PMIC_WRAP_BASE + i);
}
}
#endif

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_PLAT_SPM_SETTING_H
#define MT_PLAT_SPM_SETTING_H
#include <sleep_def.h>
enum plat_spm_cond {
PLAT_SPM_COND_MAX = 0,
};
enum pmic_wrap_phase_id {
PMIC_WRAP_PHASE_ALLINONE,
NR_PMIC_WRAP_PHASE,
};
/* IDX mapping */
enum {
CMD_0,
CMD_1,
CMD_2,
CMD_3,
CMD_4,
CMD_5,
CMD_6,
CMD_7,
CMD_8,
CMD_9,
CMD_10,
CMD_11,
CMD_12,
CMD_13,
CMD_14,
CMD_15,
CMD_16,
CMD_17,
CMD_18,
CMD_19,
CMD_20,
CMD_21,
CMD_22,
CMD_23,
CMD_24,
CMD_25,
CMD_26,
CMD_27,
CMD_28,
CMD_29,
CMD_30,
CMD_31,
NR_IDX_ALL,
};
/* APIs */
void mt_spm_dump_pmic_warp_reg(void);
void plat_spm_pmic_wrap_init(void);
#endif /* MT_PLAT_SPM_SETTING_H */

View file

@ -0,0 +1,464 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <arch.h>
#include <common/debug.h>
#include <drivers/console.h>
#include <drivers/delay_timer.h>
#include <drivers/gpio.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <platform_def.h>
#include <constraints/mt_spm_rc_api.h>
#include <constraints/mt_spm_rc_internal.h>
#include <drivers/spm/mt_spm_resource_req.h>
#include <lib/mtk_init/mtk_init.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_rm.h>
#include <lpm_v2/mt_lp_rqm.h>
#include <lpm_v2/mt_lpm_smc.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_common.h>
#include <mt_spm_conservation.h>
#include <mt_spm_constraint.h>
#include <mt_spm_dispatcher.h>
#include <mt_spm_hwreq.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <mt_spm_suspend.h>
#include <mtk_mmap_pool.h>
#include <sleep_def.h>
#ifdef MT_SPM_USING_BAKERY_LOCK
DEFINE_BAKERY_LOCK(spm_lock);
#define plat_spm_lock_init() \
bakery_lock_init(&spm_lock)
#else
spinlock_t spm_lock;
#define plat_spm_lock_init()
#endif
uint32_t mt_spm_version;
static uint32_t spm_irq_num;
void spm_set_sysclk_settle(void)
{
uint32_t settle;
mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE);
settle = mmio_read_32(SPM_CLK_SETTLE);
INFO("md_settle = %u, settle = %u\n", SPM_SYSCLK_SETTLE, settle);
}
void spm_set_irq_num(uint32_t num)
{
spm_irq_num = num;
}
void spm_irq0_handler(uint64_t x1, uint64_t x2)
{
if (x2 == 0) {
mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM);
mmio_write_32(SPM_IRQ_STA, x1);
mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT0);
}
}
static int spm_ap_mdsrc_ack(void)
{
int ack, md_state = 0;
/* Check ap_mdsrc_ack = 1'b1, for md internal resource on ack */
ack = !!(mmio_read_32(AP_MDSRC_REQ) & AP_MDSMSRC_ACK_LSB);
if (!ack) {
/* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */
md_state = !!(mmio_read_32(SPM_REQ_STA_10)
& MD_APSRC_REQ_LSB);
ERROR("[SPM] error: md_sleep = %d\n", md_state);
ERROR("%s can not get AP_MDSRC_ACK\n", __func__);
return -1;
}
return 0;
}
static void spm_ap_mdsrc_req(int set)
{
spm_lock_get();
if (set)
mmio_setbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB);
else
mmio_clrbits_32(AP_MDSRC_REQ, AP_MDSMSRC_REQ_LSB);
spm_lock_release();
}
static int spm_is_md_sleep(void *priv)
{
int md_state = 0;
int *sleep = (int *)priv;
if (!priv)
return -1;
/* Check md_apsrc_req = 1'b0, for md state 0:sleep, 1:wakeup */
md_state = !!(mmio_read_32(SPM_REQ_STA_10)
& MD_APSRC_REQ_LSB);
if (md_state == 0)
*sleep = 1;
else
*sleep = 0;
return 0;
}
static void spm_ap_gpueb_pll_control(int set)
{
spm_lock_get();
if (set)
mmio_setbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB);
else
mmio_clrbits_32(SPM2GPUPM_CON, SC_MFG_PLL_EN_LSB);
spm_lock_release();
}
static uint32_t spm_ap_gpueb_get_pwr_status(void)
{
uint32_t ret;
ret = mmio_read_32(XPU_PWR_STATUS);
return ret;
}
static uint32_t spm_ap_gpueb_get_mfg0_pwr_con(void)
{
uint32_t ret;
ret = mmio_read_32(MFG0_PWR_CON);
return ret;
}
#ifndef MTK_PLAT_SPM_UNSUPPORT
struct mt_lp_res_req rq_xo_fpm = {
.res_id = MT_LP_RQ_XO_FPM,
.res_rq = MT_SPM_XO_FPM,
.res_usage = 0,
};
struct mt_lp_res_req rq_26m = {
.res_id = MT_LP_RQ_26M,
.res_rq = MT_SPM_26M,
.res_usage = 0,
};
struct mt_lp_res_req rq_infra = {
.res_id = MT_LP_RQ_INFRA,
.res_rq = MT_SPM_INFRA,
.res_usage = 0,
};
struct mt_lp_res_req rq_syspll = {
.res_id = MT_LP_RQ_SYSPLL,
.res_rq = MT_SPM_SYSPLL,
.res_usage = 0,
};
struct mt_lp_res_req rq_dram_s0 = {
.res_id = MT_LP_RQ_DRAM,
.res_rq = MT_SPM_DRAM_S0,
.res_usage = 0,
};
struct mt_lp_res_req rq_dram_s1 = {
.res_id = MT_LP_RQ_DRAM,
.res_rq = MT_SPM_DRAM_S1,
.res_usage = 0,
};
struct mt_lp_res_req rq_vcore = {
.res_id = MT_LP_RQ_VCORE,
.res_rq = MT_SPM_VCORE,
.res_usage = 0,
};
struct mt_lp_res_req rq_emi = {
.res_id = MT_LP_RQ_EMI,
.res_rq = MT_SPM_EMI,
.res_usage = 0,
};
struct mt_lp_res_req rq_pmic = {
.res_id = MT_LP_RQ_PMIC,
.res_rq = MT_SPM_PMIC,
.res_usage = 0,
};
struct mt_lp_res_req *spm_resources[] = {
&rq_xo_fpm,
&rq_26m,
&rq_infra,
&rq_syspll,
&rq_dram_s0,
&rq_dram_s1,
&rq_vcore,
&rq_emi,
&rq_pmic,
NULL,
};
struct mt_resource_req_manager plat_mt8196_rq = {
.res = spm_resources,
};
struct mt_resource_constraint plat_constraint_vcore = {
.is_valid = spm_is_valid_rc_vcore,
.update = spm_update_rc_vcore,
.allow = spm_allow_rc_vcore,
.run = spm_run_rc_vcore,
.reset = spm_reset_rc_vcore,
.get_status = spm_get_status_rc_vcore,
};
struct mt_resource_constraint plat_constraint_bus26m = {
.is_valid = spm_is_valid_rc_bus26m,
.update = spm_update_rc_bus26m,
.allow = spm_allow_rc_bus26m,
.run = spm_run_rc_bus26m,
.reset = spm_reset_rc_bus26m,
.get_status = spm_get_status_rc_bus26m,
};
struct mt_resource_constraint plat_constraint_syspll = {
.is_valid = spm_is_valid_rc_syspll,
.update = spm_update_rc_syspll,
.allow = spm_allow_rc_syspll,
.run = spm_run_rc_syspll,
.reset = spm_reset_rc_syspll,
.get_status = spm_get_status_rc_syspll,
};
struct mt_resource_constraint *plat_constraints[] = {
&plat_constraint_vcore,
&plat_constraint_bus26m,
&plat_constraint_syspll,
NULL,
};
#endif
int mt_spm_hwctrl(uint32_t type, int set, void *priv)
{
int ret = 0;
if (type == PLAT_AP_MDSRC_REQ) {
spm_ap_mdsrc_req(set);
} else if (type == PLAT_AP_MDSRC_ACK) {
ret = spm_ap_mdsrc_ack();
} else if (type == PLAT_AP_IS_MD_SLEEP) {
ret = spm_is_md_sleep(priv);
} else if (type == PLAT_AP_MDSRC_SETTLE) {
if (!priv)
return -1;
*(int *)priv = AP_MDSRC_REQ_MD_26M_SETTLE;
} else if (type == PLAT_AP_GPUEB_PLL_CONTROL) {
spm_ap_gpueb_pll_control(set);
} else if (type == PLAT_AP_GPUEB_PWR_STATUS) {
if (!priv)
return -1;
*(uint32_t *)priv = spm_ap_gpueb_get_pwr_status();
} else if (type == PLAT_AP_GPUEB_MFG0_PWR_CON) {
if (!priv)
return -1;
*(uint32_t *)priv = spm_ap_gpueb_get_mfg0_pwr_con();
} else if (type == PLAT_AP_SPM_RESOURCE_REQUEST_UPDATE) {
struct spm_lp_scen *spmlp = NULL;
#ifdef MT_SPM_COMMON_SODI_SUPPORT
mt_spm_common_sodi_get_spm_lp(&spmlp);
#else
#if defined(MT_SPM_FEATURE_SUPPORT)
mt_spm_idle_generic_get_spm_lp(&spmlp);
#endif
#endif
if (!spmlp)
return -1;
__spm_set_power_control(spmlp->pwrctrl, *(uint32_t *)priv);
ret = __spm_wait_spm_request_ack(*(uint32_t *)priv,
SPM_ACK_TIMEOUT_US);
} else if (type == PLAT_AP_SPM_WDT_TRIGGER) {
mmio_write_32(PCM_WDT_VAL, 0x1);
mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY |
REG_PCM_WDT_EN_LSB | REG_PCM_WDT_WAKE_LSB);
} else {
/* Not supported type */
return -1;
}
return ret;
}
#ifndef MTK_PLAT_SPM_UNSUPPORT
struct mt_resource_manager plat_mt8196_rm = {
.update = NULL,
.hwctrl = mt_spm_hwctrl,
.consts = plat_constraints,
};
#else
struct mt_resource_manager plat_mt8196_rm = {
.hwctrl = mt_spm_hwctrl,
};
#endif
/* Determine for spm sw resource user */
static struct mt_lp_resource_user spm_res_user;
struct mt_lp_resource_user *get_spm_res_user(void)
{
return &spm_res_user;
}
#ifdef MT_SPM_COMMON_SODI_SUPPORT
int mt_spm_common_sodi_get_spm_pcm_flag(uint32_t *lp, uint32_t idx)
{
struct spm_lp_scen *spmlp;
struct pwr_ctrl *pwrctrl;
mt_spm_common_sodi_get_spm_lp(&spmlp);
pwrctrl = spmlp->pwrctrl;
if (!lp || idx > 1)
return -1;
switch (idx) {
case 0:
*lp = pwrctrl->pcm_flags;
break;
case 1:
*lp = pwrctrl->pcm_flags;
break;
default:
return -1;
}
return 0;
}
void mt_spm_common_sodi_en(bool en)
{
struct spm_lp_scen *spmlp;
struct pwr_ctrl *pwrctrl;
mt_spm_common_sodi_get_spm_lp(&spmlp);
pwrctrl = spmlp->pwrctrl;
#if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
__spm_sync_vcore_dvfs_pcm_flags(&pwrctrl->pcm_flags,
&__spm_vcorefs.pwrctrl->pcm_flags);
#endif
if (en)
pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_COMMON_SODI5;
else
pwrctrl->pcm_flags &= (~SPM_FLAG_ENABLE_COMMON_SODI5);
/* Set PCM flags */
__spm_set_pcm_flags(pwrctrl);
__spm_send_cpu_wakeup_event();
}
int mt_spm_common_sodi_get_spm_lp(struct spm_lp_scen **lp)
{
if (!lp)
return -1;
*lp = &__spm_common_sodi;
return 0;
}
void mt_spm_set_common_sodi_pwrctr(void)
{
struct resource_req_status common_sodi_spm_resource_req = {
.id = MT_LP_RQ_ID_ALL_USAGE,
.val = 0,
};
struct spm_lp_scen *spmlp;
mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE,
&common_sodi_spm_resource_req);
mt_spm_common_sodi_get_spm_lp(&spmlp);
__spm_set_power_control(spmlp->pwrctrl,
common_sodi_spm_resource_req.val);
}
void mt_spm_set_common_sodi_pcm_flags(void)
{
struct spm_lp_scen *spmlp;
struct pwr_ctrl *pwrctrl;
mt_spm_common_sodi_get_spm_lp(&spmlp);
pwrctrl = spmlp->pwrctrl;
#if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
/* Set PCM flags */
__spm_sync_vcore_dvfs_pcm_flags(&pwrctrl->pcm_flags,
&__spm_vcorefs.pwrctrl->pcm_flags);
#endif
__spm_set_pcm_flags(pwrctrl);
__spm_send_cpu_wakeup_event();
}
#endif
static void spm_gpio_init(void)
{
gpio_set_direction(EC_SUSPEND_PIN, GPIO_DIR_OUT);
gpio_set_value(EC_SUSPEND_PIN, GPIO_LEVEL_HIGH);
}
int spm_boot_init(void)
{
plat_spm_lock_init();
#if defined(MT_SPM_FEATURE_SUPPORT)
plat_spm_pmic_wrap_init();
#endif
mt_lp_rm_register(&plat_mt8196_rm);
#ifndef MTK_PLAT_SPM_UNSUPPORT
mt_lp_resource_request_manager_register(&plat_mt8196_rq);
mt_lp_resource_user_register("SPM", &spm_res_user);
mt_spm_dispatcher_init();
#endif
#if defined(MT_SPM_FEATURE_SUPPORT)
spm_hwreq_init();
#endif
spm_gpio_init();
spm_irq_num = 0xFFFFFFFF;
INFO("[%s:%d] - spm finished, version = %u, PC = 0x%x\n",
__func__, __LINE__,
mt_spm_version, mmio_read_32(MD32PCM_PC));
return 0;
}
MTK_PLAT_SETUP_1_INIT(spm_boot_init);

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_H
#define MT_SPM_H
#include <stdint.h>
#include <stdio.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_rq.h>
#ifdef __GNUC__
#define spm_likely(x) __builtin_expect(!!(x), 1)
#define spm_unlikely(x) __builtin_expect(!!(x), 0)
#else
#define spm_likely(x) (x)
#define spm_unlikely(x) (x)
#endif
#define CLK_SCP_CFG_0 (CKSYS_BASE + 0x1A0)
#define INFRA_BUS_DCM_CTRL (INFRACFG_AO_BASE + 0x070)
#define RG_AXI_DCM_DIS_EN BIT(21)
#define RG_PLLCK_SEL_NO_SPM BIT(22)
#define MT_SPM_TIME_GET(tm) ({ (tm) = el3_uptime(); })
#define MT_SPM_VERSION_ES 0x0
#define MT_SPM_VERSION_CS 0x1
#define SPM_FW_NO_RESUME 1
#define MCUSYS_MTCMOS_ON 0
#define WAKEUP_LOG_ON 0
#define MT_SPM_USING_SRCLKEN_RC
/* SPM extern operand definition */
#define MT_SPM_EX_OP_CLR_26M_RECORD BIT(0)
#define MT_SPM_EX_OP_SET_WDT BIT(1)
#define MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ BIT(2)
#define MT_SPM_EX_OP_SET_SUSPEND_MODE BIT(3)
#define MT_SPM_EX_OP_SET_IS_ADSP BIT(4)
#define MT_SPM_EX_OP_SRCLKEN_RC_BBLPM BIT(5)
#define MT_SPM_EX_OP_HW_S1_DETECT BIT(6)
#define MT_SPM_EX_OP_TRACE_LP BIT(7)
#define MT_SPM_EX_OP_TRACE_SUSPEND BIT(8)
#define MT_SPM_EX_OP_TRACE_TIMESTAMP_EN BIT(9)
#define MT_SPM_EX_OP_TIME_CHECK BIT(10)
#define MT_SPM_EX_OP_TIME_OBS BIT(11)
#define MT_SPM_EX_OP_SET_IS_USB_HEADSET BIT(12)
#define MT_SPM_EX_OP_SET_IS_FM_AUDIO BIT(13)
#define MT_SPM_EX_OP_DEVICES_SAVE BIT(14)
#define MT_SPM_EX_OP_NOTIFY_INFRA_OFF BIT(15)
#define MT_BUS26M_EXT_LP_26M_ON_MODE (MT_SPM_EX_OP_SET_IS_ADSP | \
MT_SPM_EX_OP_SET_IS_FM_AUDIO)
#define MT_VCORE_EXT_LP_VCORE_ON_MODE (MT_SPM_EX_OP_SET_IS_ADSP | \
MT_SPM_EX_OP_SET_IS_FM_AUDIO)
/* EN SPM INFRA DEBUG OUT */
#define DEBUGSYS_DEBUG_EN_REG (DBGSYS_DEM_BASE + 0x94)
/* INFRA_AO_DEBUG_CON */
#define INFRA_AO_DBG_CON0 (INFRACFG_AO_BASE + 0x500)
#define INFRA_AO_DBG_CON1 (INFRACFG_AO_BASE + 0x504)
#define INFRA_AO_DBG_CON2 (INFRACFG_AO_BASE + 0x508)
#define INFRA_AO_DBG_CON3 (INFRACFG_AO_BASE + 0x50C)
/* SPM init. related registers */
#define VLP_AO_APC_CON (VLP_AO_DEVAPC_APB_BASE + 0xF00)
#define VLP_AO_MAS_SEC_0 (VLP_AO_DEVAPC_APB_BASE + 0xA00)
#define SCP_CFGREG_PERI_BUS_CTRL0 (SCP_CFGREG_BASE + 0x24)
#define MODULE_SW_CG_0_MASK (INFRACFG_AO_BASE + 0x060)
#define VLP_DBG_MON_SEL0_ADDR (VLPCFG_BUS_BASE + 0x108)
#define VLP_DBG_MON_SEL1_ADDR (VLPCFG_BUS_BASE + 0x10C)
#define VLP_CLKSQ_CON1 (VLP_CKSYS_BASE + 0x224)
#define VLP_AP_PLL_CON3 (VLP_CKSYS_BASE + 0x264)
/* SPM SRAM Data */
#define SPM_SRAM_TIMESTAMP_START (SPM_SRAM_BASE + 0xF80)
#define SPM_SRAM_TIMESTAMP_END (SPM_SRAM_BASE + 0xFFC)
#define SPM_SRAM_TIMESTAMP_SIZE \
(((SPM_SRAM_TIMESTAMP_END - SPM_SRAM_TIMESTAMP_START) >> 2) + 1)
/* AP_MDSRC_REQ MD 26M ON settle time (3ms) */
#define AP_MDSRC_REQ_MD_26M_SETTLE 3
/* Setting the SPM settle time*/
#define SPM_SYSCLK_SETTLE 0x60FE /* 1685us */
/* Setting the SPM req/ack time*/
#define SPM_ACK_TIMEOUT_US 1000
/* Settine the firmware status check for SPM PC */
#define SPM_PC_CHECKABLE
enum {
SPM_ARGS_SPMFW_IDX_KICK = 0,
SPM_ARGS_SPMFW_INIT,
SPM_ARGS_SUSPEND,
SPM_ARGS_SUSPEND_FINISH,
SPM_ARGS_SODI,
SPM_ARGS_SODI_FINISH,
SPM_ARGS_DPIDLE,
SPM_ARGS_DPIDLE_FINISH,
SPM_ARGS_PCM_WDT,
SPM_ARGS_SUSPEND_CALLBACK,
SPM_ARGS_HARDWARE_CG_CHECK,
SPM_ARGS_NUM,
};
typedef enum {
WR_NONE = 0,
WR_UART_BUSY,
WR_ABORT,
WR_PCM_TIMER,
WR_WAKE_SRC,
WR_DVFSRC,
WR_TWAM,
WR_PMSR,
WR_SPM_ACK_CHK,
WR_UNKNOWN,
} wake_reason_t;
struct pwr_ctrl;
struct spm_lp_scen;
void spm_set_irq_num(uint32_t num);
void spm_irq0_handler(uint64_t x1, uint64_t x2);
struct mt_lp_resource_user *get_spm_res_user(void);
int mt_spm_common_sodi_get_spm_pcm_flag(uint32_t *lp, uint32_t idx);
void mt_spm_common_sodi_en(bool en);
int mt_spm_common_sodi_get_spm_lp(struct spm_lp_scen **lp);
void mt_spm_set_common_sodi_pwrctr(void);
void mt_spm_set_common_sodi_pcm_flags(void);
int spm_boot_init(void);
void spm_dvfsfw_init(uint64_t boot_up_opp, uint64_t dram_issue);
extern uint32_t mt_spm_version;
extern struct pwr_ctrl spm_init_ctrl;
/* Support by bl31_plat_setup.c */
uint32_t is_abnormal_boot(void);
#endif /* MT_SPM_H */

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_rqm.h>
#include <mt_spm.h>
#include <mt_spm_common.h>
#include <mt_spm_conservation.h>
#include <mt_spm_reg.h>
#include <mt_spm_vcorefs.h>
#define MT_RESUMETIME_THRESHOLD_MAX 5
#define IS_RESUME_OVERTIME(delta) \
(delta > MT_RESUMETIME_THRESHOLD_MAX)
static struct wake_status spm_wakesta; /* Record last wakesta */
static wake_reason_t spm_wake_reason = WR_NONE;
static struct resource_req_status generic_spm_resource_req = {
.id = MT_LP_RQ_ID_ALL_USAGE,
.val = 0,
};
#define do_spm_init(pwrctrl) ({ int local_ret = 0; local_ret; })
#define do_spm_run(pwrctrl) __spm_send_cpu_wakeup_event()
static int go_to_spm_before_wfi(int state_id, uint32_t ext_opand,
struct spm_lp_scen *spm_lp,
uint32_t resource_req)
{
int ret = 0;
struct pwr_ctrl *pwrctrl;
pwrctrl = spm_lp->pwrctrl;
#if SPM_FW_NO_RESUME == 0
ret = do_spm_init(pwrctrl);
if (ret)
return ret;
#endif
__spm_set_power_control(pwrctrl, resource_req);
__spm_set_wakeup_event(pwrctrl);
#if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
__spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
#endif
if (mt_spm_version == MT_SPM_VERSION_ES)
pwrctrl->pcm_flags |= (SPM_FLAG_ENABLE_MT8196_E1_WA |
SPM_FLAG_ENABLE_MT8196_EMI_E1_WA);
#ifdef MTK_SPM_IVI_SUPPORT
pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_MT8196_IVI;
#endif
__spm_set_pcm_flags(pwrctrl);
#ifdef HW_S1_DETECT
if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT)
spm_hw_s1_state_monitor_resume();
#endif
do_spm_run(pwrctrl);
return ret;
}
static void go_to_spm_after_wfi(int state_id, uint32_t ext_opand,
struct spm_lp_scen *spm_lp,
struct wake_status **status)
{
uint32_t ext_status = 0;
spm_wakesta.tr.comm.resumetime = 0;
spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0;
if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT)
spm_hw_s1_state_monitor_pause(&ext_status);
__spm_ext_int_wakeup_req_clr();
__spm_get_wakeup_status(&spm_wakesta, ext_status);
if (status)
*status = &spm_wakesta;
#ifndef MT_SPM_COMMON_SODI_SUPPORT
__spm_clean_after_wakeup();
#endif
spm_wake_reason = __spm_output_wake_reason(&spm_wakesta);
}
int spm_conservation(int state_id, uint32_t ext_opand,
struct spm_lp_scen *spm_lp, uint32_t resource_req)
{
uint32_t rc_state = resource_req;
if (!spm_lp)
return -1;
spm_lock_get();
/* Uart bk/rs is needed if infra off for legacy project
* leave code here for reference.
*/
if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) {
#ifndef MTK_PLAT_SPM_UART_UNSUPPORT
/* Notify UART to sleep */
mt_uart_save();
#endif
}
if (!(ext_opand & MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ)) {
/* Resource request */
mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE,
&generic_spm_resource_req);
rc_state |= generic_spm_resource_req.val;
}
go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state);
spm_lock_release();
return 0;
}
void spm_conservation_finish(int state_id, uint32_t ext_opand,
struct spm_lp_scen *spm_lp,
struct wake_status **status)
{
/* Uart bk/rs is needed if infra off for legacy project
* leave code here for reference.
*/
if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) {
#ifndef MTK_PLAT_SPM_UART_UNSUPPORT
/* Notify UART to wakeup */
mt_uart_restore();
#endif
}
spm_lock_get();
go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
#ifdef MT_SPM_COMMON_SODI_SUPPORT
/* Restore common sodi mask and resource req setting */
mt_spm_set_common_sodi_pwrctr();
mt_spm_set_common_sodi_pcm_flags();
#endif
spm_lock_release();
}
int spm_conservation_get_result(struct wake_status **res)
{
if (!res)
return -1;
*res = &spm_wakesta;
return 0;
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_CONSERVATION_H
#define MT_SPM_CONSERVATION_H
#include <mt_spm.h>
#include <mt_spm_internal.h>
int spm_conservation(int state_id, uint32_t ext_opand,
struct spm_lp_scen *spm_lp,
uint32_t resource_req);
void spm_conservation_finish(int state_id, uint32_t ext_opand,
struct spm_lp_scen *spm_lp,
struct wake_status **status);
int spm_conservation_get_result(struct wake_status **res);
int spm_conservation_fw_run(uint32_t first, void *pwrctrl);
int spm_conservation_wakeup_obs(int IsSet, int cat,
uint32_t wake_src_bits);
void mt_uart_save(void);
void mt_uart_restore(void);
#endif /* MT_SPM_CONSERVATION_H */

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
#include <platform_def.h>
#include <lpm_v2/mt_lpm_dispatch.h>
#include <lpm_v2/mt_lpm_smc.h>
#include <mt_spm_conservation.h>
#include <mt_spm_dispatcher.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <mt_spm_smc.h>
#include <mt_spm_suspend.h>
#include <pcm_def.h>
#define SPM_FW_BASE_SIZE 0x100000
static void mt_spm_pcm_wdt(int enable, uint64_t time)
{
mmio_write_32(PCM_TIMER_VAL, time);
__spm_set_pcm_wdt(enable);
}
static uint32_t mt_spm_phypll_mode_check(void)
{
uint32_t val = mmio_read_32(SPM_POWER_ON_VAL0);
return val;
}
static uint64_t mt_spm_compatible_smc_id(uint64_t lp_id)
{
switch (lp_id) {
case MT_LPM_SPMC_COMPAT_LK_FW_INIT:
lp_id = MT_SPM_SMC_UID_FW_INIT;
break;
default:
break;
}
return lp_id;
}
uint64_t mt_spm_dispatcher(u_register_t lp_id, u_register_t act,
u_register_t arg1, u_register_t arg2,
void *handle, struct smccc_res *smccc_ret)
{
uint64_t ret = 0;
if (act & MT_LPM_SMC_ACT_COMPAT) {
lp_id = mt_spm_compatible_smc_id(lp_id);
act &= ~(MT_LPM_SMC_ACT_COMPAT);
}
switch (lp_id) {
case MT_SPM_SMC_UID_STATUS:
if (!(arg2 & MT_SPM_STATUS_SUSPEND_SLEEP))
break;
if (act & MT_LPM_SMC_ACT_SET)
/* Legacy audio check from kernel */
mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SLEEP, NULL);
else if (act & MT_LPM_SMC_ACT_CLR)
mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SYSTEM_PDN,
NULL);
break;
case MT_SPM_SMC_UID_PCM_WDT:
if (act & MT_LPM_SMC_ACT_SET)
mt_spm_pcm_wdt(1, arg2);
else if (act & MT_LPM_SMC_ACT_CLR)
mt_spm_pcm_wdt(0, arg2);
break;
case MT_SPM_SMC_UID_PHYPLL_MODE:
if (act & MT_LPM_SMC_ACT_GET)
ret = mt_spm_phypll_mode_check();
break;
case MT_SPM_SMC_UID_SET_PENDING_IRQ_INIT:
spm_set_irq_num((uint32_t)arg1);
break;
default:
break;
}
return ret;
}
int mt_spm_dispatcher_init(void)
{
mt_lpm_dispatcher_registry(MT_LPM_SMC_USER_SPM,
mt_spm_dispatcher);
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_DISPATCHER_H
#define MT_SPM_DISPATCHER_H
int mt_spm_dispatcher_init(void);
#endif /* MT_SPM_DISPATCHER_H */

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_DOE_RESOURCE_CTRL_H
#define MT_SPM_DOE_RESOURCE_CTRL_H
#include <mt_spm_internal.h>
enum resource_ctrl_enum {
MT_SPM_RESOURCE_CTRL_BUS26M,
MT_SPM_RESOURCE_CTRL_INFRA,
MT_SPM_RESOURCE_CTRL_SYSPLL,
MT_SPM_RESOURCE_CTRL_DRAM_S0,
MT_SPM_RESOURCE_CTRL_DRAM_S1,
MT_SPM_RESORUCE_CTRL_VCORE,
MT_SPM_RESOURCE_CTRL_EMI,
MT_SPM_RESOURCE_CTRL_PMIC,
MT_SPM_RESOURCE_CTRL_MAX_NUM,
};
#endif /* MT_SPM_DOE_RESOURCE_CTRL_H */

View file

@ -0,0 +1,707 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <mt_spm_hwreq.h>
#include <mt_spm_reg.h>
/* Ddren, apsrc and emi resource have become hw resource_req.
* So we don't need to use HW CG for request resource.
*/
#define SPM_HWCG_DDREN_PWR_MB 0
#define SPM_HWCG_DDREN_PWR_MSB_MB 0
#define SPM_HWCG_DDREN_MODULE_BUSY_MB 0
/* VRF18 */
#define SPM_HWCG_VRF18_PWR_MB 0
#define SPM_HWCG_VRF18_PWR_MSB_MB 0
#define SPM_HWCG_VRF18_MODULE_BUSY_MB 0
/* INFRA */
#define SPM_HWCG_INFRA_PWR_MB SPM_HWCG_VRF18_PWR_MB
#define SPM_HWCG_INFRA_PWR_MSB_MB SPM_HWCG_VRF18_PWR_MSB_MB
#define SPM_HWCG_INFRA_MODULE_BUSY_MB 0
/* PMIC */
#define SPM_HWCG_PMIC_PWR_MB SPM_HWCG_VRF18_PWR_MB
#define SPM_HWCG_PMIC_PWR_MSB_MB SPM_HWCG_VRF18_PWR_MSB_MB
#define SPM_HWCG_PMIC_MODULE_BUSY_MB 0
/* F26M */
#define SPM_HWCG_F26M_PWR_MB SPM_HWCG_PMIC_PWR_MB
#define SPM_HWCG_F26M_PWR_MSB_MB SPM_HWCG_PMIC_PWR_MSB_MB
#define SPM_HWCG_F26M_MODULE_BUSY_MB 0
/* VCORE */
#define SPM_HWCG_VCORE_PWR_MB SPM_HWCG_F26M_PWR_MB
#define SPM_HWCG_VCORE_PWR_MSB_MB SPM_HWCG_F26M_PWR_MSB_MB
#define SPM_HWCG_VCORE_MODULE_BUSY_MB SPM_HWCG_F26M_MODULE_BUSY_MB
#define INFRA_SW_CG_MB 0
struct spm_hwcg_info {
uint32_t pwr;
uint32_t pwr_msb;
uint32_t module_busy;
};
#define HWCG_INFO_INIT(_info) ({ \
_info.pwr = _info.pwr_msb = _info.module_busy = 0; })
#define DECLARE_HWCG_REG(_name_, _info) ({ \
_info.pwr = REG_PWR_STATUS_##_name_##_REQ_MASK; \
_info.pwr_msb = REG_PWR_STATUS_MSB_##_name_##_REQ_MASK; \
_info.module_busy = REG_MODULE_BUSY_##_name_##_REQ_MASK; })
#define DECLARE_HWCG_DEFAULT(_name_, _info) ({ \
_info.pwr = SPM_HWCG_##_name_##_PWR_MB; \
_info.pwr_msb = SPM_HWCG_##_name_##_PWR_MSB_MB; \
_info.module_busy = SPM_HWCG_##_name_##_MODULE_BUSY_MB; })
#define PERI_REQ_EN_INFO_INIT(_info) ({_info.req_en = 0; })
#define PERI_REQ_STA_INFO_INIT(_info) ({_info.req_sta = 0; })
#define DECLARE_PERI_REQ_EN_REG(_offset, _info) ({ \
_info.req_en = REG_PERI_REQ_EN(_offset); })
#define DECLARE_PERI_REQ_STA_REG(_offset, _info) ({ \
_info.req_sta = REG_PERI_REQ_STA(_offset); })
#define DECLARE_PERI_REQ_DEFAULT(_name_, _info) ({ \
_info.req_en = PERI_REQ_##_name_##_MB; })
#define PERI_REQ_EN_MASK 0x3FFFFF
static uint32_t spm_hwcg_index2res(uint32_t idx)
{
uint32_t res;
if (idx >= HWCG_MAX)
return 0;
switch (idx) {
case HWCG_DDREN:
res = (MT_SPM_DRAM_S0 | MT_SPM_DRAM_S1 | MT_SPM_EMI);
break;
case HWCG_VRF18:
res = MT_SPM_SYSPLL;
break;
case HWCG_INFRA:
res = MT_SPM_INFRA;
break;
case HWCG_PMIC:
res = MT_SPM_PMIC;
break;
case HWCG_F26M:
res = MT_SPM_26M;
break;
case HWCG_VCORE:
res = MT_SPM_VCORE;
break;
default:
res = 0;
}
return res;
}
static uint32_t spm_hwcg_ctrl_get(struct spm_hwcg_info *info,
enum spm_hwcg_setting type)
{
uint32_t reg = 0;
if (!info)
return 0;
switch (type) {
case HWCG_PWR:
reg = info->pwr;
break;
case HWCG_PWR_MSB:
reg = info->pwr_msb;
break;
default:
reg = info->module_busy;
break;
}
return reg;
}
static void __spm_hwcg_ctrl(struct spm_hwcg_info *info,
enum spm_hwcg_setting type,
uint32_t is_set, uint32_t val)
{
uint32_t reg;
reg = spm_hwcg_ctrl_get(info, type);
if (!reg)
return;
if (is_set)
mmio_setbits_32(reg, val);
else
mmio_clrbits_32(reg, val);
}
void spm_hwcg_ctrl(uint32_t res, enum spm_hwcg_setting type,
uint32_t is_set, uint32_t val)
{
struct spm_hwcg_info info;
if (res & (MT_SPM_DRAM_S0 | MT_SPM_DRAM_S1 | MT_SPM_EMI))
DECLARE_HWCG_REG(DDREN, info);
else if (res & MT_SPM_SYSPLL)
DECLARE_HWCG_REG(VRF18, info);
else if (res & MT_SPM_INFRA)
DECLARE_HWCG_REG(INFRA, info);
else if (res & MT_SPM_PMIC)
DECLARE_HWCG_REG(PMIC, info);
else if (res & MT_SPM_26M)
DECLARE_HWCG_REG(F26M, info);
else if (res & MT_SPM_VCORE)
DECLARE_HWCG_REG(VCORE, info);
else
HWCG_INFO_INIT(info);
if (info.pwr)
__spm_hwcg_ctrl(&info, type, is_set, val);
}
void spm_hwcg_ctrl_by_index(uint32_t idx, enum spm_hwcg_setting type,
uint32_t is_set, uint32_t val)
{
uint32_t res = spm_hwcg_index2res(idx);
if (res)
spm_hwcg_ctrl(res, type, is_set, val);
}
static uint32_t spm_hwcg_mask_get(uint32_t res, enum spm_hwcg_setting type)
{
struct spm_hwcg_info info;
uint32_t raw_val = 0, reg = 0;
if (res & (MT_SPM_DRAM_S0 | MT_SPM_DRAM_S1 | MT_SPM_EMI))
DECLARE_HWCG_REG(DDREN, info);
else if (res & MT_SPM_SYSPLL)
DECLARE_HWCG_REG(VRF18, info);
else if (res & MT_SPM_INFRA)
DECLARE_HWCG_REG(INFRA, info);
else if (res & MT_SPM_PMIC)
DECLARE_HWCG_REG(PMIC, info);
else if (res & MT_SPM_26M)
DECLARE_HWCG_REG(F26M, info);
else if (res & MT_SPM_VCORE)
DECLARE_HWCG_REG(VCORE, info);
else
HWCG_INFO_INIT(info);
if (!info.pwr)
return 0;
reg = spm_hwcg_ctrl_get(&info, type);
if (!reg)
return 0;
raw_val = ~mmio_read_32(reg);
return raw_val;
}
static uint32_t spm_hwcg_get_default(uint32_t res, enum spm_hwcg_setting type)
{
struct spm_hwcg_info info;
if (res & (MT_SPM_DRAM_S0 | MT_SPM_DRAM_S1 | MT_SPM_EMI))
DECLARE_HWCG_DEFAULT(DDREN, info);
else if (res & MT_SPM_SYSPLL)
DECLARE_HWCG_DEFAULT(VRF18, info);
else if (res & MT_SPM_INFRA)
DECLARE_HWCG_DEFAULT(INFRA, info);
else if (res & MT_SPM_PMIC)
DECLARE_HWCG_DEFAULT(PMIC, info);
else if (res & MT_SPM_26M)
DECLARE_HWCG_DEFAULT(F26M, info);
else if (res & MT_SPM_VCORE)
DECLARE_HWCG_DEFAULT(VCORE, info);
else
HWCG_INFO_INIT(info);
if (!info.pwr)
return 0;
return spm_hwcg_ctrl_get(&info, type);
}
uint32_t spm_hwcg_get_status(uint32_t idx, enum spm_hwcg_setting type)
{
uint32_t val = 0;
switch (type) {
case HWCG_PWR:
val = mmio_read_32(PWR_STATUS);
break;
case HWCG_PWR_MSB:
val = mmio_read_32(PWR_STATUS_MSB);
break;
default:
break;
}
return val;
}
int spm_hwcg_get_setting(uint32_t res, enum spm_hwcg_sta_type sta_type,
enum spm_hwcg_setting type,
struct spm_hwcg_sta *sta)
{
int ret = 0;
if (!sta)
return -1;
switch (sta_type) {
case HWCG_STA_DEFAULT_MASK:
sta->sta = spm_hwcg_get_default(res, type);
break;
case HWCG_STA_MASK:
sta->sta = spm_hwcg_mask_get(res, type);
break;
default:
ret = -1;
MT_SPM_HW_CG_STA_INIT(sta);
break;
}
return ret;
}
int spm_hwcg_get_setting_by_index(uint32_t idx,
enum spm_hwcg_sta_type sta_type,
enum spm_hwcg_setting type,
struct spm_hwcg_sta *sta)
{
uint32_t res = spm_hwcg_index2res(idx);
return spm_hwcg_get_setting(res, sta_type, type, sta);
}
int spm_hwcg_name(uint32_t idex, char *name, size_t sz)
{
int ret = 0;
if (!name)
return -1;
switch (idex) {
case HWCG_DDREN:
ret = snprintf(name, sz - 1, "dram");
break;
case HWCG_VRF18:
ret = snprintf(name, sz - 1, "vrf18");
break;
case HWCG_INFRA:
ret = snprintf(name, sz - 1, "infra");
break;
case HWCG_PMIC:
ret = snprintf(name, sz - 1, "pmic");
break;
case HWCG_F26M:
ret = snprintf(name, sz - 1, "26m");
break;
case HWCG_VCORE:
ret = snprintf(name, sz - 1, "vcore");
break;
default:
ret = -1;
break;
}
if (ret < 0)
ret = -1;
name[sz-1] = '\0';
return ret;
}
static void spm_infra_swcg_init(void)
{
mmio_write_32(INFRA_SW_CG_MASK, ~INFRA_SW_CG_MB);
}
static void spm_hwcg_init(void)
{
/* HW CG for ddren, apsrc, emi resource req */
mmio_write_32(REG_PWR_STATUS_DDREN_REQ_MASK,
~SPM_HWCG_DDREN_PWR_MB);
mmio_write_32(REG_PWR_STATUS_MSB_DDREN_REQ_MASK,
~SPM_HWCG_DDREN_PWR_MSB_MB);
mmio_write_32(REG_MODULE_BUSY_DDREN_REQ_MASK,
~SPM_HWCG_DDREN_MODULE_BUSY_MB);
/* HW CG for vrf18 resource req */
mmio_write_32(REG_PWR_STATUS_VRF18_REQ_MASK,
~SPM_HWCG_VRF18_PWR_MB);
mmio_write_32(REG_PWR_STATUS_MSB_VRF18_REQ_MASK,
~SPM_HWCG_VRF18_PWR_MSB_MB);
mmio_write_32(REG_MODULE_BUSY_VRF18_REQ_MASK,
~SPM_HWCG_VRF18_MODULE_BUSY_MB);
/* HW CG for infra resource req */
mmio_write_32(REG_PWR_STATUS_INFRA_REQ_MASK,
~SPM_HWCG_INFRA_PWR_MB);
mmio_write_32(REG_PWR_STATUS_MSB_INFRA_REQ_MASK,
~SPM_HWCG_INFRA_PWR_MSB_MB);
mmio_write_32(REG_MODULE_BUSY_INFRA_REQ_MASK,
~SPM_HWCG_INFRA_MODULE_BUSY_MB);
/* HW CG for pmic resource req */
mmio_write_32(REG_PWR_STATUS_PMIC_REQ_MASK,
~SPM_HWCG_PMIC_PWR_MB);
mmio_write_32(REG_PWR_STATUS_MSB_PMIC_REQ_MASK,
~SPM_HWCG_PMIC_PWR_MSB_MB);
mmio_write_32(REG_MODULE_BUSY_PMIC_REQ_MASK,
~SPM_HWCG_PMIC_MODULE_BUSY_MB);
/* HW CG for f26m resource req */
mmio_write_32(REG_PWR_STATUS_F26M_REQ_MASK,
~SPM_HWCG_F26M_PWR_MB);
mmio_write_32(REG_PWR_STATUS_MSB_F26M_REQ_MASK,
~SPM_HWCG_F26M_PWR_MSB_MB);
mmio_write_32(REG_MODULE_BUSY_F26M_REQ_MASK,
~SPM_HWCG_F26M_MODULE_BUSY_MB);
/* HW CG for vcore resource req */
mmio_write_32(REG_PWR_STATUS_VCORE_REQ_MASK,
~SPM_HWCG_VCORE_PWR_MB);
mmio_write_32(REG_PWR_STATUS_MSB_VCORE_REQ_MASK,
~SPM_HWCG_VCORE_PWR_MSB_MB);
mmio_write_32(REG_MODULE_BUSY_VCORE_REQ_MASK,
~SPM_HWCG_VCORE_MODULE_BUSY_MB);
}
#define PERI_CG(ofs) (PERICFG_AO_BASE + 0x10 + (0x4 * (ofs)))
#define PERI_REQ_DEFAULT_MB (BIT(PERI_REQ_EN_FLASHIF) | \
BIT(PERI_REQ_EN_AP_DMA) | \
BIT(PERI_REQ_EN_UART1) | \
BIT(PERI_REQ_EN_UART2) | \
BIT(PERI_REQ_EN_UART4) | \
BIT(PERI_REQ_EN_UART5) | \
BIT(PERI_REQ_EN_PWM) | \
BIT(PERI_REQ_EN_SPI0) | \
BIT(PERI_REQ_EN_SPI0_INCR16) | \
BIT(PERI_REQ_EN_SPI1) | \
BIT(PERI_REQ_EN_SPI2) | \
BIT(PERI_REQ_EN_SPI3) | \
BIT(PERI_REQ_EN_SPI4) | \
BIT(PERI_REQ_EN_SPI5) | \
BIT(PERI_REQ_EN_SPI6) | \
BIT(PERI_REQ_EN_SPI7) | \
BIT(PERI_REQ_EN_IMP_IIC))
/* For MSDC reqesut WA: PERI_REQ_EN_RSV_FOR_MSDC */
#define PERI_REQ_APSRC_MB (PERI_REQ_DEFAULT_MB | \
BIT(PERI_REQ_EN_RSV_FOR_MSDC))
#define PERI_REQ_DDREN_MB (PERI_REQ_DEFAULT_MB | \
BIT(PERI_REQ_EN_USB) | \
BIT(PERI_REQ_EN_UFS0) | \
BIT(PERI_REQ_EN_PEXTP1) | \
BIT(PERI_REQ_EN_PEXTP0) | \
BIT(PERI_REQ_EN_PERI_BUS_TRAFFIC))
#define PERI_REQ_EMI_MB (PERI_REQ_DEFAULT_MB)
#define PERI_REQ_INFRA_MB (PERI_REQ_DEFAULT_MB)
#define PERI_REQ_SYSPLL_MB (PERI_REQ_DEFAULT_MB)
#define PERI_REQ_F26M_MB (PERI_REQ_DEFAULT_MB)
uint32_t spm_peri_req_get_status(uint32_t idx, enum spm_peri_req_status type)
{
uint32_t val = 0, reg = 0;
struct spm_peri_req_info info;
switch (type) {
case PERI_RES_REQ_EN:
switch (idx) {
case PERI_REQ_DDREN:
DECLARE_PERI_REQ_STA_REG(PERI_REQ_DDREN, info);
break;
case PERI_REQ_EMI:
DECLARE_PERI_REQ_STA_REG(PERI_REQ_EMI, info);
break;
case PERI_REQ_APSRC:
DECLARE_PERI_REQ_STA_REG(PERI_REQ_APSRC, info);
break;
case PERI_REQ_SYSPLL:
DECLARE_PERI_REQ_STA_REG(PERI_REQ_SYSPLL, info);
break;
case PERI_REQ_INFRA:
DECLARE_PERI_REQ_STA_REG(PERI_REQ_INFRA, info);
break;
case PERI_REQ_F26M:
DECLARE_PERI_REQ_STA_REG(PERI_REQ_F26M, info);
break;
default:
PERI_REQ_STA_INFO_INIT(info);
break;
}
if (!info.req_sta)
return 0;
reg = info.req_sta;
val = (mmio_read_32(reg) & PERI_REQ_EN_MASK);
break;
default:
break;
}
return val;
}
int spm_peri_req_name(uint32_t idex, char *name, size_t sz)
{
int ret = 0;
if (!name)
return -1;
switch (idex) {
case PERI_REQ_DDREN:
ret = snprintf(name, sz - 1, "ddren");
break;
case PERI_REQ_EMI:
ret = snprintf(name, sz - 1, "emi");
break;
case PERI_REQ_APSRC:
ret = snprintf(name, sz - 1, "apsrc");
break;
case PERI_REQ_SYSPLL:
ret = snprintf(name, sz - 1, "syspll");
break;
case PERI_REQ_INFRA:
ret = snprintf(name, sz - 1, "infra");
break;
case PERI_REQ_F26M:
ret = snprintf(name, sz - 1, "26m_pmic_vcore");
break;
default:
ret = -1;
break;
}
if (ret < 0)
ret = -1;
name[sz-1] = '\0';
return ret;
}
uint32_t spm_peri_req_get_status_raw(enum spm_peri_req_status_raw type,
uint32_t idx,
char *name, size_t sz)
{
return 0;
}
static uint32_t spm_peri_req_get_default(uint32_t res)
{
struct spm_peri_req_info info;
if (res & MT_SPM_DRAM_S1)
DECLARE_PERI_REQ_DEFAULT(DDREN, info);
else if (res & MT_SPM_EMI)
DECLARE_PERI_REQ_DEFAULT(EMI, info);
else if (res & MT_SPM_DRAM_S0)
DECLARE_PERI_REQ_DEFAULT(APSRC, info);
else if (res & MT_SPM_SYSPLL)
DECLARE_PERI_REQ_DEFAULT(SYSPLL, info);
else if (res & MT_SPM_INFRA)
DECLARE_PERI_REQ_DEFAULT(INFRA, info);
else if (res & (MT_SPM_PMIC | MT_SPM_26M | MT_SPM_VCORE))
DECLARE_PERI_REQ_DEFAULT(F26M, info);
else
PERI_REQ_EN_INFO_INIT(info);
return info.req_en;
}
static uint32_t spm_peri_req_mask_get(uint32_t res)
{
struct spm_peri_req_info info;
uint32_t raw_val = 0, reg = 0;
if (res & MT_SPM_DRAM_S1)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_DDREN, info);
else if (res & MT_SPM_EMI)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_EMI, info);
else if (res & MT_SPM_DRAM_S0)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_APSRC, info);
else if (res & MT_SPM_SYSPLL)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_SYSPLL, info);
else if (res & MT_SPM_INFRA)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_INFRA, info);
else if (res & (MT_SPM_PMIC | MT_SPM_26M | MT_SPM_VCORE))
DECLARE_PERI_REQ_EN_REG(PERI_REQ_F26M, info);
else
PERI_REQ_EN_INFO_INIT(info);
if (!info.req_en)
return 0;
reg = info.req_en;
raw_val = (mmio_read_32(reg) & PERI_REQ_EN_MASK);
return raw_val;
}
int spm_peri_req_get_setting(uint32_t res,
enum spm_peri_req_sta_type sta_type,
struct spm_peri_req_sta *sta)
{
int ret = 0;
if (!sta)
return -1;
switch (sta_type) {
case PERI_REQ_STA_DEFAULT_MASK:
sta->sta = spm_peri_req_get_default(res);
break;
case PERI_REQ_STA_MASK:
sta->sta = spm_peri_req_mask_get(res);
break;
default:
ret = -1;
MT_SPM_HW_CG_STA_INIT(sta);
break;
}
return ret;
}
static uint32_t spm_peri_req_index2res(uint32_t idx)
{
uint32_t res;
if (idx >= PERI_REQ_MAX)
return 0;
switch (idx) {
case PERI_REQ_DDREN:
res = MT_SPM_DRAM_S1;
break;
case PERI_REQ_EMI:
res = MT_SPM_EMI;
break;
case PERI_REQ_APSRC:
res = MT_SPM_DRAM_S0;
break;
case PERI_REQ_SYSPLL:
res = MT_SPM_SYSPLL;
break;
case PERI_REQ_INFRA:
res = MT_SPM_INFRA;
break;
case PERI_REQ_F26M:
res = (MT_SPM_PMIC | MT_SPM_26M | MT_SPM_VCORE);
break;
default:
res = 0;
}
return res;
}
int spm_peri_req_get_setting_by_index(uint32_t idx,
enum spm_peri_req_sta_type sta_type,
struct spm_peri_req_sta *sta)
{
uint32_t res = spm_peri_req_index2res(idx);
return spm_peri_req_get_setting(res, sta_type, sta);
}
static void __spm_peri_req_ctrl(struct spm_peri_req_info *info,
uint32_t is_set, uint32_t val)
{
uint32_t raw_val, reg;
reg = info->req_en;
if (!reg)
return;
raw_val = (mmio_read_32(reg) & PERI_REQ_EN_MASK);
if (is_set)
raw_val |= val;
else
raw_val &= ~val;
mmio_write_32(reg, raw_val);
}
void spm_peri_req_ctrl(uint32_t res,
uint32_t is_set, uint32_t val)
{
struct spm_peri_req_info info;
if (res & MT_SPM_DRAM_S1)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_DDREN, info);
else if (res & MT_SPM_EMI)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_EMI, info);
else if (res & MT_SPM_DRAM_S0)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_APSRC, info);
else if (res & MT_SPM_SYSPLL)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_SYSPLL, info);
else if (res & MT_SPM_INFRA)
DECLARE_PERI_REQ_EN_REG(PERI_REQ_INFRA, info);
else if (res & (MT_SPM_PMIC | MT_SPM_26M | MT_SPM_VCORE))
DECLARE_PERI_REQ_EN_REG(PERI_REQ_F26M, info);
else
PERI_REQ_EN_INFO_INIT(info);
if (info.req_en)
__spm_peri_req_ctrl(&info, is_set, val);
}
void spm_peri_req_ctrl_by_index(uint32_t idx,
uint32_t is_set, uint32_t val)
{
uint32_t res = spm_peri_req_index2res(idx);
if (res)
spm_peri_req_ctrl(res, is_set, val);
}
static void spm_peri_req_init(void)
{
mmio_write_32(REG_PERI_REQ_EN(PERI_REQ_DDREN), PERI_REQ_DDREN_MB);
mmio_write_32(REG_PERI_REQ_EN(PERI_REQ_EMI), PERI_REQ_EMI_MB);
mmio_write_32(REG_PERI_REQ_EN(PERI_REQ_APSRC), PERI_REQ_APSRC_MB);
mmio_write_32(REG_PERI_REQ_EN(PERI_REQ_INFRA), PERI_REQ_INFRA_MB);
mmio_write_32(REG_PERI_REQ_EN(PERI_REQ_SYSPLL), PERI_REQ_SYSPLL_MB);
mmio_write_32(REG_PERI_REQ_EN(PERI_REQ_F26M), PERI_REQ_F26M_MB);
}
void spm_hwreq_init(void)
{
spm_infra_swcg_init();
spm_hwcg_init();
spm_peri_req_init();
}

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_HWREQ_H
#define MT_SPM_HWREQ_H
#include <drivers/spm/mt_spm_resource_req.h>
/* Resource requirement which HW CG support */
enum {
HWCG_DDREN = 0,
HWCG_VRF18,
HWCG_INFRA,
HWCG_PMIC,
HWCG_F26M,
HWCG_VCORE,
HWCG_MAX
};
/* Signal that monitor by HW CG */
enum spm_hwcg_setting {
HWCG_PWR,
HWCG_PWR_MSB,
HWCG_MODULE_BUSY,
HWCG_SETTING_MAX
};
enum spm_pwr_status {
HWCG_PWR_MD1 = 0,
HWCG_PWR_CONN,
HWCG_PWR_APIFR_IO,
HWCG_PWR_APIFR_MEM,
HWCG_PWR_PERI,
HWCG_PWR_PERI_ETHER,
HWCG_PWR_SSUSB_PD_PHY_P0,
HWCG_PWR_SSUSB_P0,
HWCG_PWR_SSUSB_P1,
HWCG_PWR_SSUSB_P23,
HWCG_PWR_SSUSB_PHY_P2,
HWCG_PWR_UFS0,
HWCG_PWR_UFS0_PHY,
HWCG_PWR_PEXTP_MAC0,
HWCG_PWR_PEXTP_MAC1,
HWCG_PWR_PEXTP_MAC2,
HWCG_PWR_PEXTP_PHY0,
HWCG_PWR_PEXTP_PHY1,
HWCG_PWR_PEXTP_PHY3,
HWCG_PWR_AUDIO,
HWCG_PWR_ADSP_CORE1,
HWCG_PWR_ADSP_TOP,
HWCG_PWR_ADSP_INFRA,
HWCG_PWR_ADSP_AO,
HWCG_PWR_MM_PROC,
HWCG_PWR_SCP,
HWCG_PWR_SCP2,
HWCG_PWR_DPYD0,
HWCG_PWR_DPYD1,
HWCG_PWR_DPYD2,
HWCG_PWR_DPYD3,
HWCG_PWR_DPYA0
};
CASSERT(HWCG_PWR_SSUSB_P1 == 8, spm_pwr_status_err);
CASSERT(HWCG_PWR_PEXTP_PHY0 == 16, spm_pwr_status_err);
CASSERT(HWCG_PWR_MM_PROC == 24, spm_pwr_status_err);
enum spm_hwcg_module_busy {
HWCG_MODULE_ADSP = 0,
HWCG_MODULE_MMPLL,
HWCG_MODULE_TVDPLL,
HWCG_MODULE_MSDCPLL,
HWCG_MODULE_UNIVPLL
};
enum spm_hwcg_sta_type {
HWCG_STA_DEFAULT_MASK,
HWCG_STA_MASK
};
/* Signal that monitor by HW CG */
enum spm_peri_req_setting {
PERI_REQ_EN = 0,
PERI_REQ_SETTING_MAX
};
/* Resource requirement which PERI REQ support */
enum spm_peri_req {
PERI_REQ_F26M = 0,
PERI_REQ_INFRA,
PERI_REQ_SYSPLL,
PERI_REQ_APSRC,
PERI_REQ_EMI,
PERI_REQ_DDREN,
PERI_REQ_MAX
};
enum spm_peri_req_sta_type {
PERI_REQ_STA_DEFAULT_MASK,
PERI_REQ_STA_MASK,
PERI_REQ_STA_MAX
};
enum spm_peri_req_status {
PERI_RES_REQ_EN,
PERI_REQ_STATUS_MAX
};
enum spm_peri_req_status_raw {
PERI_REQ_STATUS_RAW_NUM,
PERI_REQ_STATUS_RAW_NAME,
PERI_REQ_STATUS_RAW_STA,
PERI_REQ_STATUS_RAW_MAX
};
enum spm_peri_req_en {
PERI_REQ_EN_FLASHIF = 0,
PERI_REQ_EN_AP_DMA,
PERI_REQ_EN_UART0,
PERI_REQ_EN_UART1,
PERI_REQ_EN_UART2,
PERI_REQ_EN_UART3,
PERI_REQ_EN_UART4,
PERI_REQ_EN_UART5,
PERI_REQ_EN_PWM,
PERI_REQ_EN_SPI0,
PERI_REQ_EN_SPI0_INCR16,
PERI_REQ_EN_SPI1,
PERI_REQ_EN_SPI2,
PERI_REQ_EN_SPI3,
PERI_REQ_EN_SPI4,
PERI_REQ_EN_SPI5,
PERI_REQ_EN_SPI6,
PERI_REQ_EN_SPI7,
PERI_REQ_EN_IMP_IIC,
PERI_REQ_EN_MSDC1,
PERI_REQ_EN_MSDC2,
PERI_REQ_EN_USB,
PERI_REQ_EN_UFS0,
PERI_REQ_EN_PEXTP1,
PERI_REQ_EN_PEXTP0,
PERI_REQ_EN_RSV_DUMMY0,
PERI_REQ_EN_PERI_BUS_TRAFFIC,
PERI_REQ_EN_RSV_DUMMY1,
PERI_REQ_EN_RSV_FOR_MSDC,
PERI_REQ_EN_MAX
};
CASSERT(PERI_REQ_EN_PWM == 8, spm_peri_req_en_err);
CASSERT(PERI_REQ_EN_SPI6 == 16, spm_peri_req_en_err);
CASSERT(PERI_REQ_EN_PEXTP0 == 24, spm_peri_req_en_err);
struct spm_peri_req_sta {
uint32_t sta;
};
struct spm_peri_req_info {
uint32_t req_en;
uint32_t req_sta;
};
struct spm_hwcg_sta {
uint32_t sta;
};
#define MT_SPM_HW_CG_STA_INIT(_x) ({ if (_x) _x->sta = 0; })
#define INFRA_AO_OFFSET(offset) (INFRACFG_AO_BASE + offset)
#define INFRA_SW_CG_MASK INFRA_AO_OFFSET(0x060)
#define REG_PERI_REQ_EN(N) (PERICFG_AO_BASE + 0x070 + 0x4 * (N))
#define REG_PERI_REQ_STA(N) (PERICFG_AO_BASE + 0x0A0 + 0x4 * (N))
void spm_hwreq_init(void);
/* Res:
* Please refer the mt_spm_resource_req.h.
* Section of SPM resource request internal bit_mask.
*/
void spm_hwcg_ctrl(uint32_t res, enum spm_hwcg_setting type,
uint32_t is_set, uint32_t val);
/* Idx:
* index of HWCG setting.
*/
void spm_hwcg_ctrl_by_index(uint32_t idx, enum spm_hwcg_setting type,
uint32_t is_set, uint32_t val);
/* Res:
* Please refer the mt_spm_resource_req.h.
* Section of SPM resource request internal bit_mask.
*/
int spm_hwcg_get_setting(uint32_t res, enum spm_hwcg_sta_type sta_type,
enum spm_hwcg_setting type,
struct spm_hwcg_sta *sta);
/* Idx:
* index of HWCG setting.
*/
int spm_hwcg_get_setting_by_index(uint32_t idx,
enum spm_hwcg_sta_type sta_type,
enum spm_hwcg_setting type,
struct spm_hwcg_sta *sta);
uint32_t spm_hwcg_get_status(uint32_t idx, enum spm_hwcg_setting type);
int spm_hwcg_name(uint32_t idex, char *name, size_t sz);
static inline uint32_t spm_hwcg_num(void)
{
return HWCG_MAX;
}
static inline uint32_t spm_hwcg_setting_num(void)
{
return HWCG_SETTING_MAX;
}
uint32_t spm_peri_req_get_status(uint32_t idx, enum spm_peri_req_status type);
uint32_t spm_peri_req_get_status_raw(enum spm_peri_req_status_raw type,
uint32_t idx,
char *name, size_t sz);
static inline uint32_t spm_peri_req_num(void)
{
return PERI_REQ_MAX;
}
static inline uint32_t spm_peri_req_setting_num(void)
{
return PERI_REQ_SETTING_MAX;
}
int spm_peri_req_get_setting_by_index(uint32_t idx,
enum spm_peri_req_sta_type sta_type,
struct spm_peri_req_sta *sta);
void spm_peri_req_ctrl_by_index(uint32_t idx,
uint32_t is_set, uint32_t val);
int spm_peri_req_name(uint32_t idex, char *name, size_t sz);
#endif /* MT_SPM_HWREQ_H */

View file

@ -0,0 +1,607 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <drivers/spm/mt_spm_resource_req.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_api.h>
#include <mt_spm.h>
#include <mt_spm_conservation.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <mt_spm_stats.h>
#define SPM_BYPASS_SYSPWREQ_GENERIC 1
/* Default will be the bus26m or deeper spm's low power mode*/
#define __WAKE_SRC_FOR_IDLE_COMMON__ ( \
(R12_PCM_TIMER_B) | \
(R12_KP_IRQ_B) | \
(R12_APWDT_EVENT_B) | \
(R12_APXGPT_EVENT_B) | \
(R12_CONN2AP_WAKEUP_B) | \
(R12_EINT_EVENT_B) | \
(R12_CONN_WDT_IRQ_B) | \
(R12_CCIF0_EVENT_B) | \
(R12_CCIF1_EVENT_B) | \
(R12_SSPM2SPM_WAKEUP_B) | \
(R12_SCP2SPM_WAKEUP_B) | \
(R12_ADSP2SPM_WAKEUP_B) | \
(R12_USB0_CDSC_B) | \
(R12_USB0_POWERDWN_B) | \
(R12_UART_EVENT_B) | \
(R12_SYS_TIMER_EVENT_B) | \
(R12_EINT_EVENT_SECURE_B) | \
(R12_AFE_IRQ_MCU_B) | \
(R12_SYS_CIRQ_IRQ_B) | \
(R12_MD_WDT_B) | \
(R12_AP2AP_PEER_WAKEUP_B) | \
(R12_CPU_WAKEUP) | \
(R12_APUSYS_WAKE_HOST_B) |\
(R12_PCIE_WAKE_B))
#if defined(CFG_MICROTRUST_TEE_SUPPORT)
#define WAKE_SRC_FOR_IDLE (__WAKE_SRC_FOR_IDLE_COMMON__)
#else
#define WAKE_SRC_FOR_IDLE \
(__WAKE_SRC_FOR_IDLE_COMMON__ | R12_SEJ_B)
#endif
static struct pwr_ctrl idle_spm_pwr = {
.wake_src = WAKE_SRC_FOR_IDLE,
/* SPM_SRC_REQ */
.reg_spm_adsp_mailbox_req = 0,
.reg_spm_apsrc_req = 1,
.reg_spm_ddren_req = 0,
.reg_spm_dvfs_req = 0,
.reg_spm_emi_req = 1,
.reg_spm_f26m_req = 0,
.reg_spm_infra_req = 0,
.reg_spm_pmic_req = 0,
.reg_spm_scp_mailbox_req = 0,
.reg_spm_sspm_mailbox_req = 0,
.reg_spm_sw_mailbox_req = 0,
.reg_spm_vcore_req = 0,
.reg_spm_vrf18_req = 0,
.adsp_mailbox_state = 0,
.apsrc_state = 0,
.ddren_state = 0,
.dvfs_state = 0,
.emi_state = 0,
.f26m_state = 0,
.infra_state = 0,
.pmic_state = 0,
.scp_mailbox_state = 0,
.sspm_mailbox_state = 0,
.sw_mailbox_state = 0,
.vcore_state = 0,
.vrf18_state = 0,
/* SPM_SRC_MASK_0 */
.reg_apifr_apsrc_rmb = 0,
.reg_apifr_ddren_rmb = 0,
.reg_apifr_emi_rmb = 0,
.reg_apifr_infra_rmb = 0,
.reg_apifr_pmic_rmb = 0,
.reg_apifr_srcclkena_mb = 0,
.reg_apifr_vcore_rmb = 0,
.reg_apifr_vrf18_rmb = 0,
.reg_apu_apsrc_rmb = 1,
.reg_apu_ddren_rmb = 0,
.reg_apu_emi_rmb = 1,
.reg_apu_infra_rmb = 1,
.reg_apu_pmic_rmb = 1,
.reg_apu_srcclkena_mb = 1,
.reg_apu_vcore_rmb = 1,
.reg_apu_vrf18_rmb = 1,
.reg_audio_apsrc_rmb = 1,
.reg_audio_ddren_rmb = 0,
.reg_audio_emi_rmb = 1,
.reg_audio_infra_rmb = 1,
.reg_audio_pmic_rmb = 0,
.reg_audio_srcclkena_mb = 1,
.reg_audio_vcore_rmb = 1,
.reg_audio_vrf18_rmb = 1,
/* SPM_SRC_MASK_1 */
.reg_audio_dsp_apsrc_rmb = 1,
.reg_audio_dsp_ddren_rmb = 0,
.reg_audio_dsp_emi_rmb = 1,
.reg_audio_dsp_infra_rmb = 1,
.reg_audio_dsp_pmic_rmb = 1,
.reg_audio_dsp_srcclkena_mb = 1,
.reg_audio_dsp_vcore_rmb = 1,
.reg_audio_dsp_vrf18_rmb = 1,
.reg_cam_apsrc_rmb = 0,
.reg_cam_ddren_rmb = 0,
.reg_cam_emi_rmb = 0,
.reg_cam_infra_rmb = 0,
.reg_cam_pmic_rmb = 0,
.reg_cam_srcclkena_mb = 0,
.reg_cam_vrf18_rmb = 0,
.reg_ccif_apsrc_rmb = 0xfff,
/* SPM_SRC_MASK_2 */
.reg_ccif_emi_rmb = 0xfff,
.reg_ccif_infra_rmb = 0xfff,
/* SPM_SRC_MASK_3 */
.reg_ccif_pmic_rmb = 0xfff,
.reg_ccif_srcclkena_mb = 0xfff,
/* SPM_SRC_MASK_4 */
.reg_ccif_vcore_rmb = 0xfff,
.reg_ccif_vrf18_rmb = 0xfff,
.reg_ccu_apsrc_rmb = 0,
.reg_ccu_ddren_rmb = 0,
.reg_ccu_emi_rmb = 0,
.reg_ccu_infra_rmb = 0,
.reg_ccu_pmic_rmb = 0,
.reg_ccu_srcclkena_mb = 0,
.reg_ccu_vrf18_rmb = 0,
.reg_cg_check_apsrc_rmb = 0,
/* SPM_SRC_MASK_5 */
.reg_cg_check_ddren_rmb = 0,
.reg_cg_check_emi_rmb = 0,
.reg_cg_check_infra_rmb = 0,
.reg_cg_check_pmic_rmb = 0,
.reg_cg_check_srcclkena_mb = 0,
/* for UFS HWCG vcore req */
.reg_cg_check_vcore_rmb = 1,
.reg_cg_check_vrf18_rmb = 0,
.reg_cksys_apsrc_rmb = 1,
.reg_cksys_ddren_rmb = 0,
.reg_cksys_emi_rmb = 1,
.reg_cksys_infra_rmb = 1,
.reg_cksys_pmic_rmb = 1,
.reg_cksys_srcclkena_mb = 1,
.reg_cksys_vcore_rmb = 1,
.reg_cksys_vrf18_rmb = 1,
.reg_cksys_1_apsrc_rmb = 1,
.reg_cksys_1_ddren_rmb = 0,
.reg_cksys_1_emi_rmb = 1,
.reg_cksys_1_infra_rmb = 1,
.reg_cksys_1_pmic_rmb = 1,
.reg_cksys_1_srcclkena_mb = 1,
.reg_cksys_1_vcore_rmb = 1,
.reg_cksys_1_vrf18_rmb = 1,
/* SPM_SRC_MASK_6 */
.reg_cksys_2_apsrc_rmb = 1,
.reg_cksys_2_ddren_rmb = 0,
.reg_cksys_2_emi_rmb = 1,
.reg_cksys_2_infra_rmb = 1,
.reg_cksys_2_pmic_rmb = 1,
.reg_cksys_2_srcclkena_mb = 1,
.reg_cksys_2_vcore_rmb = 1,
.reg_cksys_2_vrf18_rmb = 1,
.reg_conn_apsrc_rmb = 1,
.reg_conn_ddren_rmb = 0,
.reg_conn_emi_rmb = 1,
.reg_conn_infra_rmb = 1,
.reg_conn_pmic_rmb = 1,
.reg_conn_srcclkena_mb = 1,
.reg_conn_srcclkenb_mb = 1,
.reg_conn_vcore_rmb = 1,
.reg_conn_vrf18_rmb = 1,
.reg_corecfg_apsrc_rmb = 0,
.reg_corecfg_ddren_rmb = 0,
.reg_corecfg_emi_rmb = 0,
.reg_corecfg_infra_rmb = 0,
.reg_corecfg_pmic_rmb = 0,
.reg_corecfg_srcclkena_mb = 0,
.reg_corecfg_vcore_rmb = 0,
.reg_corecfg_vrf18_rmb = 0,
/* SPM_SRC_MASK_7 */
.reg_cpueb_apsrc_rmb = 1,
.reg_cpueb_ddren_rmb = 0,
.reg_cpueb_emi_rmb = 1,
.reg_cpueb_infra_rmb = 1,
.reg_cpueb_pmic_rmb = 1,
.reg_cpueb_srcclkena_mb = 1,
.reg_cpueb_vcore_rmb = 0,
.reg_cpueb_vrf18_rmb = 1,
.reg_disp0_apsrc_rmb = 0,
.reg_disp0_ddren_rmb = 0,
.reg_disp0_emi_rmb = 0,
.reg_disp0_infra_rmb = 0,
.reg_disp0_pmic_rmb = 0,
.reg_disp0_srcclkena_mb = 0,
.reg_disp0_vrf18_rmb = 0,
.reg_disp1_apsrc_rmb = 0,
.reg_disp1_ddren_rmb = 0,
.reg_disp1_emi_rmb = 0,
.reg_disp1_infra_rmb = 0,
.reg_disp1_pmic_rmb = 0,
.reg_disp1_srcclkena_mb = 0,
.reg_disp1_vrf18_rmb = 0,
.reg_dpm_apsrc_rmb = 0xf,
.reg_dpm_ddren_rmb = 0xf,
/* SPM_SRC_MASK_8 */
.reg_dpm_emi_rmb = 0xf,
.reg_dpm_infra_rmb = 0xf,
.reg_dpm_pmic_rmb = 0xf,
.reg_dpm_srcclkena_mb = 0xf,
.reg_dpm_vcore_rmb = 0xf,
.reg_dpm_vrf18_rmb = 0xf,
.reg_dpmaif_apsrc_rmb = 1,
.reg_dpmaif_ddren_rmb = 0,
.reg_dpmaif_emi_rmb = 1,
.reg_dpmaif_infra_rmb = 1,
.reg_dpmaif_pmic_rmb = 1,
.reg_dpmaif_srcclkena_mb = 1,
.reg_dpmaif_vcore_rmb = 1,
.reg_dpmaif_vrf18_rmb = 1,
/* SPM_SRC_MASK_9 */
.reg_dvfsrc_level_rmb = 1,
.reg_emisys_apsrc_rmb = 0,
.reg_emisys_ddren_rmb = 0,
.reg_emisys_emi_rmb = 0,
.reg_emisys_infra_rmb = 0,
.reg_emisys_pmic_rmb = 0,
.reg_emisys_srcclkena_mb = 0,
.reg_emisys_vcore_rmb = 0,
.reg_emisys_vrf18_rmb = 0,
.reg_gce_apsrc_rmb = 0,
.reg_gce_ddren_rmb = 0,
.reg_gce_emi_rmb = 0,
.reg_gce_infra_rmb = 0,
.reg_gce_pmic_rmb = 0,
.reg_gce_srcclkena_mb = 0,
.reg_gce_vcore_rmb = 0,
.reg_gce_vrf18_rmb = 0,
.reg_gpueb_apsrc_rmb = 1,
.reg_gpueb_ddren_rmb = 0,
.reg_gpueb_emi_rmb = 1,
.reg_gpueb_infra_rmb = 1,
.reg_gpueb_pmic_rmb = 1,
.reg_gpueb_srcclkena_mb = 1,
.reg_gpueb_vcore_rmb = 1,
.reg_gpueb_vrf18_rmb = 1,
.reg_hwccf_apsrc_rmb = 1,
.reg_hwccf_ddren_rmb = 0,
.reg_hwccf_emi_rmb = 1,
.reg_hwccf_infra_rmb = 1,
.reg_hwccf_pmic_rmb = 1,
.reg_hwccf_srcclkena_mb = 1,
.reg_hwccf_vcore_rmb = 1,
/* SPM_SRC_MASK_10 */
.reg_hwccf_vrf18_rmb = 1,
.reg_img_apsrc_rmb = 0,
.reg_img_ddren_rmb = 0,
.reg_img_emi_rmb = 0,
.reg_img_infra_rmb = 0,
.reg_img_pmic_rmb = 0,
.reg_img_srcclkena_mb = 0,
.reg_img_vrf18_rmb = 0,
.reg_infrasys_apsrc_rmb = 0,
.reg_infrasys_ddren_rmb = 0,
.reg_infrasys_emi_rmb = 0,
.reg_infrasys_infra_rmb = 0,
.reg_infrasys_pmic_rmb = 0,
.reg_infrasys_srcclkena_mb = 0,
.reg_infrasys_vcore_rmb = 0,
.reg_infrasys_vrf18_rmb = 0,
.reg_ipic_infra_rmb = 1,
.reg_ipic_vrf18_rmb = 1,
.reg_mcu_apsrc_rmb = 1,
.reg_mcu_ddren_rmb = 0,
.reg_mcu_emi_rmb = 1,
.reg_mcu_infra_rmb = 1,
.reg_mcu_pmic_rmb = 1,
.reg_mcu_srcclkena_mb = 1,
.reg_mcu_vcore_rmb = 0,
.reg_mcu_vrf18_rmb = 1,
.reg_md_apsrc_rmb = 1,
.reg_md_ddren_rmb = 0,
.reg_md_emi_rmb = 1,
.reg_md_infra_rmb = 1,
.reg_md_pmic_rmb = 1,
.reg_md_srcclkena_mb = 1,
/* SPM_SRC_MASK_11 */
.reg_md_srcclkena1_mb = 1,
.reg_md_vcore_rmb = 1,
.reg_md_vrf18_rmb = 1,
.reg_mm_proc_apsrc_rmb = 1,
.reg_mm_proc_ddren_rmb = 0,
.reg_mm_proc_emi_rmb = 1,
.reg_mm_proc_infra_rmb = 1,
.reg_mm_proc_pmic_rmb = 1,
.reg_mm_proc_srcclkena_mb = 1,
.reg_mm_proc_vcore_rmb = 1,
.reg_mm_proc_vrf18_rmb = 1,
.reg_mml0_apsrc_rmb = 0,
.reg_mml0_ddren_rmb = 0,
.reg_mml0_emi_rmb = 0,
.reg_mml0_infra_rmb = 0,
.reg_mml0_pmic_rmb = 0,
.reg_mml0_srcclkena_mb = 0,
.reg_mml0_vrf18_rmb = 0,
.reg_mml1_apsrc_rmb = 0,
.reg_mml1_ddren_rmb = 0,
.reg_mml1_emi_rmb = 0,
.reg_mml1_infra_rmb = 0,
.reg_mml1_pmic_rmb = 0,
.reg_mml1_srcclkena_mb = 0,
.reg_mml1_vrf18_rmb = 0,
.reg_ovl0_apsrc_rmb = 0,
.reg_ovl0_ddren_rmb = 0,
.reg_ovl0_emi_rmb = 0,
.reg_ovl0_infra_rmb = 0,
.reg_ovl0_pmic_rmb = 0,
.reg_ovl0_srcclkena_mb = 0,
.reg_ovl0_vrf18_rmb = 0,
/* SPM_SRC_MASK_12 */
.reg_ovl1_apsrc_rmb = 0,
.reg_ovl1_ddren_rmb = 0,
.reg_ovl1_emi_rmb = 0,
.reg_ovl1_infra_rmb = 0,
.reg_ovl1_pmic_rmb = 0,
.reg_ovl1_srcclkena_mb = 0,
.reg_ovl1_vrf18_rmb = 0,
.reg_pcie0_apsrc_rmb = 1,
.reg_pcie0_ddren_rmb = 0,
.reg_pcie0_emi_rmb = 1,
.reg_pcie0_infra_rmb = 1,
.reg_pcie0_pmic_rmb = 1,
.reg_pcie0_srcclkena_mb = 1,
.reg_pcie0_vcore_rmb = 1,
.reg_pcie0_vrf18_rmb = 1,
.reg_pcie1_apsrc_rmb = 1,
.reg_pcie1_ddren_rmb = 0,
.reg_pcie1_emi_rmb = 1,
.reg_pcie1_infra_rmb = 1,
.reg_pcie1_pmic_rmb = 1,
.reg_pcie1_srcclkena_mb = 1,
.reg_pcie1_vcore_rmb = 1,
.reg_pcie1_vrf18_rmb = 1,
.reg_perisys_apsrc_rmb = 1,
.reg_perisys_ddren_rmb = 0,
.reg_perisys_emi_rmb = 1,
.reg_perisys_infra_rmb = 1,
.reg_perisys_pmic_rmb = 1,
.reg_perisys_srcclkena_mb = 1,
.reg_perisys_vcore_rmb = 1,
.reg_perisys_vrf18_rmb = 1,
.reg_pmsr_apsrc_rmb = 1,
/* SPM_SRC_MASK_13 */
.reg_pmsr_ddren_rmb = 0,
.reg_pmsr_emi_rmb = 1,
.reg_pmsr_infra_rmb = 1,
.reg_pmsr_pmic_rmb = 1,
.reg_pmsr_srcclkena_mb = 1,
.reg_pmsr_vcore_rmb = 1,
.reg_pmsr_vrf18_rmb = 1,
.reg_scp_apsrc_rmb = 1,
.reg_scp_ddren_rmb = 0,
.reg_scp_emi_rmb = 1,
.reg_scp_infra_rmb = 1,
.reg_scp_pmic_rmb = 1,
.reg_scp_srcclkena_mb = 1,
.reg_scp_vcore_rmb = 1,
.reg_scp_vrf18_rmb = 1,
.reg_spu_hwr_apsrc_rmb = 1,
.reg_spu_hwr_ddren_rmb = 0,
.reg_spu_hwr_emi_rmb = 1,
.reg_spu_hwr_infra_rmb = 1,
.reg_spu_hwr_pmic_rmb = 1,
.reg_spu_hwr_srcclkena_mb = 1,
.reg_spu_hwr_vcore_rmb = 1,
.reg_spu_hwr_vrf18_rmb = 1,
.reg_spu_ise_apsrc_rmb = 1,
.reg_spu_ise_ddren_rmb = 0,
.reg_spu_ise_emi_rmb = 1,
.reg_spu_ise_infra_rmb = 1,
.reg_spu_ise_pmic_rmb = 1,
.reg_spu_ise_srcclkena_mb = 1,
.reg_spu_ise_vcore_rmb = 1,
.reg_spu_ise_vrf18_rmb = 1,
/* SPM_SRC_MASK_14 */
.reg_srcclkeni_infra_rmb = 0x3,
.reg_srcclkeni_pmic_rmb = 0x3,
.reg_srcclkeni_srcclkena_mb = 0x3,
.reg_srcclkeni_vcore_rmb = 0x3,
.reg_sspm_apsrc_rmb = 1,
.reg_sspm_ddren_rmb = 0,
.reg_sspm_emi_rmb = 1,
.reg_sspm_infra_rmb = 1,
.reg_sspm_pmic_rmb = 1,
.reg_sspm_srcclkena_mb = 1,
.reg_sspm_vrf18_rmb = 1,
.reg_ssrsys_apsrc_rmb = 1,
.reg_ssrsys_ddren_rmb = 0,
.reg_ssrsys_emi_rmb = 1,
.reg_ssrsys_infra_rmb = 1,
.reg_ssrsys_pmic_rmb = 1,
.reg_ssrsys_srcclkena_mb = 1,
.reg_ssrsys_vcore_rmb = 1,
.reg_ssrsys_vrf18_rmb = 1,
.reg_ssusb_apsrc_rmb = 1,
.reg_ssusb_ddren_rmb = 0,
.reg_ssusb_emi_rmb = 1,
.reg_ssusb_infra_rmb = 1,
.reg_ssusb_pmic_rmb = 1,
.reg_ssusb_srcclkena_mb = 1,
.reg_ssusb_vcore_rmb = 1,
.reg_ssusb_vrf18_rmb = 1,
.reg_uart_hub_infra_rmb = 1,
/* SPM_SRC_MASK_15 */
.reg_uart_hub_pmic_rmb = 1,
.reg_uart_hub_srcclkena_mb = 1,
.reg_uart_hub_vcore_rmb = 1,
.reg_uart_hub_vrf18_rmb = 1,
.reg_ufs_apsrc_rmb = 1,
.reg_ufs_ddren_rmb = 0,
.reg_ufs_emi_rmb = 1,
.reg_ufs_infra_rmb = 1,
.reg_ufs_pmic_rmb = 1,
.reg_ufs_srcclkena_mb = 1,
.reg_ufs_vcore_rmb = 1,
.reg_ufs_vrf18_rmb = 1,
.reg_vdec_apsrc_rmb = 0,
.reg_vdec_ddren_rmb = 0,
.reg_vdec_emi_rmb = 0,
.reg_vdec_infra_rmb = 0,
.reg_vdec_pmic_rmb = 0,
.reg_vdec_srcclkena_mb = 0,
.reg_vdec_vrf18_rmb = 0,
.reg_venc_apsrc_rmb = 0,
.reg_venc_ddren_rmb = 0,
.reg_venc_emi_rmb = 0,
.reg_venc_infra_rmb = 0,
.reg_venc_pmic_rmb = 0,
.reg_venc_srcclkena_mb = 0,
.reg_venc_vrf18_rmb = 0,
.reg_vlpcfg_apsrc_rmb = 1,
.reg_vlpcfg_ddren_rmb = 0,
.reg_vlpcfg_emi_rmb = 1,
.reg_vlpcfg_infra_rmb = 1,
.reg_vlpcfg_pmic_rmb = 1,
.reg_vlpcfg_srcclkena_mb = 1,
/* SPM_SRC_MASK_16 */
.reg_vlpcfg_vcore_rmb = 1,
.reg_vlpcfg_vrf18_rmb = 1,
.reg_vlpcfg1_apsrc_rmb = 1,
.reg_vlpcfg1_ddren_rmb = 0,
.reg_vlpcfg1_emi_rmb = 1,
.reg_vlpcfg1_infra_rmb = 1,
.reg_vlpcfg1_pmic_rmb = 0,
.reg_vlpcfg1_srcclkena_mb = 1,
.reg_vlpcfg1_vcore_rmb = 1,
.reg_vlpcfg1_vrf18_rmb = 1,
/* SPM_EVENT_CON_MISC */
.reg_srcclken_fast_resp = 0,
.reg_csyspwrup_ack_mask = 1,
/* SPM_SRC_MASK_17 */
.reg_spm_sw_vcore_rmb = 0x3,
.reg_spm_sw_pmic_rmb = 0,
/* SPM_SRC_MASK_18 */
.reg_spm_sw_srcclkena_mb = 0,
/* SPM_WAKE_MASK*/
.reg_wake_mask = 0x81322012,
/* SPM_WAKEUP_EVENT_EXT_MASK */
.reg_ext_wake_mask = 0xFFFFFFFF,
};
static struct dbg_ctrl idle_spm_dbg = {
.count = 0,
.duration = 0,
.ext = NULL,
};
static struct spm_lp_stat idle_lp_stat;
static struct spm_lp_scen idle_spm_lp = {
.pwrctrl = &idle_spm_pwr,
.dbgctrl = &idle_spm_dbg,
.lpstat = &idle_lp_stat,
};
static int determine_event_level(int state_id)
{
if (IS_MT_PLAT_PWR_STATE(state_id, MT_PLAT_PWR_STATE_SYSTEM_VCORE))
return MT_LP_SYSPOWER_LEVEL_VCORE0V;
else if (IS_MT_PLAT_PWR_STATE(state_id, MT_PLAT_PWR_STATE_SYSTEM_BUS))
return MT_LP_SYSPOWER_LEVEL_BUS26M;
else if (IS_MT_PLAT_PWR_STATE(state_id, MT_PLAT_PWR_STATE_SYSTEM_PLL))
return MT_LP_SYSPOWER_LEVEL_SYSPLL;
else if (IS_MT_PLAT_PWR_STATE(state_id, MT_PLAT_PWR_STATE_SYSTEM_MEM))
return MT_LP_SYSPOWER_LEVEL_DRAM;
else
return MT_LP_SYSPOWER_LEVEL_APMCU;
}
int mt_spm_idle_generic_enter(int state_id, uint32_t ext_opand,
spm_idle_conduct fn)
{
int ret = 0;
uint32_t src_req = 0;
struct mt_lp_publish_event event = {
.id = MT_LPM_PUBEVENTS_SYS_POWER_OFF,
.val.u32 = 0,
.level = 0,
};
event.level = determine_event_level(state_id);
if (fn)
fn(state_id, &idle_spm_lp, &src_req);
ret = spm_conservation(state_id, ext_opand, &idle_spm_lp, src_req);
if (ret) {
NOTICE("[%s:%d] - unknown issue !!\n", __func__, __LINE__);
panic();
}
mmio_write_32(SPM2SW_MAILBOX_0, 0x1);
if (ext_opand & MT_SPM_EX_OP_DEVICES_SAVE)
MT_LP_SUSPEND_PUBLISH_EVENT(&event);
else
MT_LP_PUBLISH_EVENT(&event);
return ret;
}
void mt_spm_idle_generic_resume(int state_id, uint32_t ext_opand,
struct wake_status **status,
spm_idle_conduct_restore fn)
{
struct mt_lp_publish_event event = {
.id = MT_LPM_PUBEVENTS_SYS_POWER_ON,
.val.u32 = 0,
};
event.level = determine_event_level(state_id);
ext_opand |= (MT_SPM_EX_OP_TIME_CHECK | MT_SPM_EX_OP_TIME_OBS);
spm_conservation_finish(state_id, ext_opand, &idle_spm_lp, status);
mt_spm_update_lp_stat(&idle_lp_stat);
if (spm_unlikely(fn))
fn(state_id, &idle_spm_lp, *status);
if (ext_opand & MT_SPM_EX_OP_DEVICES_SAVE) {
mmio_write_32(SPM2SW_MAILBOX_0, 0x0);
MT_LP_SUSPEND_PUBLISH_EVENT(&event);
} else
MT_LP_PUBLISH_EVENT(&event);
}
int mt_spm_idle_generic_get_spm_lp(struct spm_lp_scen **lp)
{
if (!lp)
return -1;
*lp = &idle_spm_lp;
return 0;
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_IDLE_H
#define MT_SPM_IDLE_H
#include <mt_spm_internal.h>
typedef int (*spm_idle_conduct)(int state_id, struct spm_lp_scen *spm_lp,
uint32_t *resource_req);
typedef int (*spm_idle_conduct_restore)(int state_id,
struct spm_lp_scen *spm_lp,
struct wake_status *status);
int mt_spm_idle_generic_enter(int state_id, uint32_t ext_opand,
spm_idle_conduct fn);
void mt_spm_idle_generic_resume(int state_id, uint32_t ext_opand,
struct wake_status **status,
spm_idle_conduct_restore fn);
int mt_spm_idle_generic_get_spm_lp(struct spm_lp_scen **lp);
#endif /* MT_SPM_IDLE_H */

View file

@ -0,0 +1,825 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <drivers/spm/mt_spm_resource_req.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <pmic_wrap/inc/mt_spm_pmic_wrap.h>
/**************************************
* Define and Declare
**************************************/
#define SPM_INIT_DONE_US 20 /* Simulation result */
wake_reason_t __spm_output_wake_reason(const struct wake_status *wakesta)
{
uint32_t i;
wake_reason_t wr = WR_UNKNOWN;
if (!wakesta)
return WR_UNKNOWN;
if (wakesta->is_abort) {
INFO("SPM EARLY WAKE r13 = 0x%x, ", wakesta->tr.comm.r13);
#ifndef MTK_PLAT_SPM_PMIC_WRAP_DUMP_UNSUPPORT
mt_spm_dump_pmic_warp_reg();
#endif
}
if (wakesta->tr.comm.r12 & R12_PCM_TIMER_B) {
if (wakesta->wake_misc & WAKE_MISC_PCM_TIMER_EVENT)
wr = WR_PCM_TIMER;
}
for (i = 2; i < 32; i++) {
if (wakesta->tr.comm.r12 & (1U << i))
wr = WR_WAKE_SRC;
}
return wr;
}
void __spm_init_pcm_register(void)
{
/* Disable r0 and r7 to control power */
mmio_write_32(PCM_PWR_IO_EN, 0);
}
void __spm_set_power_control(const struct pwr_ctrl *pwrctrl,
uint32_t resource_usage)
{
/* SPM_SRC_REQ */
mmio_write_32(SPM_SRC_REQ,
((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 0) |
(((pwrctrl->reg_spm_apsrc_req |
!!(resource_usage & MT_SPM_DRAM_S0)) & 0x1) << 1) |
(((pwrctrl->reg_spm_ddren_req |
!!(resource_usage & MT_SPM_DRAM_S1)) & 0x1) << 2) |
((pwrctrl->reg_spm_dvfs_req & 0x1) << 3) |
(((pwrctrl->reg_spm_emi_req |
!!(resource_usage & MT_SPM_EMI)) & 0x1) << 4) |
(((pwrctrl->reg_spm_f26m_req |
!!(resource_usage & (MT_SPM_26M |
MT_SPM_XO_FPM))) & 0x1) << 5) |
(((pwrctrl->reg_spm_infra_req |
!!(resource_usage & MT_SPM_INFRA)) & 0x1) << 6) |
(((pwrctrl->reg_spm_pmic_req |
!!(resource_usage & MT_SPM_PMIC)) & 0x1) << 7) |
(((u32)pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 8) |
(((u32)pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 9) |
(((u32)pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 10) |
((((u32)pwrctrl->reg_spm_vcore_req |
!!(resource_usage & MT_SPM_VCORE)) & 0x1) << 11) |
((((u32)pwrctrl->reg_spm_vrf18_req |
!!(resource_usage & MT_SPM_SYSPLL)) & 0x1) << 12) |
(((u32)pwrctrl->adsp_mailbox_state & 0x1) << 16) |
(((u32)pwrctrl->apsrc_state & 0x1) << 17) |
(((u32)pwrctrl->ddren_state & 0x1) << 18) |
(((u32)pwrctrl->dvfs_state & 0x1) << 19) |
(((u32)pwrctrl->emi_state & 0x1) << 20) |
(((u32)pwrctrl->f26m_state & 0x1) << 21) |
(((u32)pwrctrl->infra_state & 0x1) << 22) |
(((u32)pwrctrl->pmic_state & 0x1) << 23) |
(((u32)pwrctrl->scp_mailbox_state & 0x1) << 24) |
(((u32)pwrctrl->sspm_mailbox_state & 0x1) << 25) |
(((u32)pwrctrl->sw_mailbox_state & 0x1) << 26) |
(((u32)pwrctrl->vcore_state & 0x1) << 27) |
(((u32)pwrctrl->vrf18_state & 0x1) << 28));
/* SPM_SRC_MASK_0 */
mmio_write_32(SPM_SRC_MASK_0,
(((u32)pwrctrl->reg_apifr_apsrc_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_apifr_ddren_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_apifr_emi_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_apifr_infra_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_apifr_pmic_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_apifr_srcclkena_mb & 0x1) << 5) |
(((u32)pwrctrl->reg_apifr_vcore_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_apifr_vrf18_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_apu_apsrc_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_apu_ddren_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_apu_emi_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_apu_infra_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_apu_pmic_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_apu_srcclkena_mb & 0x1) << 13) |
(((u32)pwrctrl->reg_apu_vcore_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_apu_vrf18_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_audio_apsrc_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_audio_ddren_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_audio_emi_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_audio_infra_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_audio_pmic_rmb & 0x1) << 20) |
(((u32)pwrctrl->reg_audio_srcclkena_mb & 0x1) << 21) |
(((u32)pwrctrl->reg_audio_vcore_rmb & 0x1) << 22) |
(((u32)pwrctrl->reg_audio_vrf18_rmb & 0x1) << 23));
/* SPM_SRC_MASK_1 */
mmio_write_32(SPM_SRC_MASK_1,
(((u32)pwrctrl->reg_audio_dsp_apsrc_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_audio_dsp_ddren_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_audio_dsp_emi_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_audio_dsp_infra_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_audio_dsp_pmic_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_audio_dsp_srcclkena_mb & 0x1) << 5) |
(((u32)pwrctrl->reg_audio_dsp_vcore_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_audio_dsp_vrf18_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_cam_apsrc_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_cam_ddren_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_cam_emi_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_cam_infra_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_cam_pmic_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_cam_srcclkena_mb & 0x1) << 13) |
(((u32)pwrctrl->reg_cam_vrf18_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_ccif_apsrc_rmb & 0xfff) << 15));
/* SPM_SRC_MASK_2 */
mmio_write_32(SPM_SRC_MASK_2,
(((u32)pwrctrl->reg_ccif_emi_rmb & 0xfff) << 0) |
(((u32)pwrctrl->reg_ccif_infra_rmb & 0xfff) << 12));
/* SPM_SRC_MASK_3 */
mmio_write_32(SPM_SRC_MASK_3,
(((u32)pwrctrl->reg_ccif_pmic_rmb & 0xfff) << 0) |
(((u32)pwrctrl->reg_ccif_srcclkena_mb & 0xfff) << 12));
/* SPM_SRC_MASK_4 */
mmio_write_32(SPM_SRC_MASK_4,
(((u32)pwrctrl->reg_ccif_vcore_rmb & 0xfff) << 0) |
(((u32)pwrctrl->reg_ccif_vrf18_rmb & 0xfff) << 12) |
(((u32)pwrctrl->reg_ccu_apsrc_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_ccu_ddren_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_ccu_emi_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_ccu_infra_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_ccu_pmic_rmb & 0x1) << 28) |
(((u32)pwrctrl->reg_ccu_srcclkena_mb & 0x1) << 29) |
(((u32)pwrctrl->reg_ccu_vrf18_rmb & 0x1) << 30) |
(((u32)pwrctrl->reg_cg_check_apsrc_rmb & 0x1) << 31));
/* SPM_SRC_MASK_5 */
mmio_write_32(SPM_SRC_MASK_5,
(((u32)pwrctrl->reg_cg_check_ddren_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_cg_check_emi_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_cg_check_infra_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_cg_check_pmic_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_cg_check_srcclkena_mb & 0x1) << 4) |
(((u32)pwrctrl->reg_cg_check_vcore_rmb & 0x1) << 5) |
(((u32)pwrctrl->reg_cg_check_vrf18_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_cksys_apsrc_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_cksys_ddren_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_cksys_emi_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_cksys_infra_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_cksys_pmic_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_cksys_srcclkena_mb & 0x1) << 12) |
(((u32)pwrctrl->reg_cksys_vcore_rmb & 0x1) << 13) |
(((u32)pwrctrl->reg_cksys_vrf18_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_cksys_1_apsrc_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_cksys_1_ddren_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_cksys_1_emi_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_cksys_1_infra_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_cksys_1_pmic_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_cksys_1_srcclkena_mb & 0x1) << 20) |
(((u32)pwrctrl->reg_cksys_1_vcore_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_cksys_1_vrf18_rmb & 0x1) << 22));
/* SPM_SRC_MASK_6 */
mmio_write_32(SPM_SRC_MASK_6,
(((u32)pwrctrl->reg_cksys_2_apsrc_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_cksys_2_ddren_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_cksys_2_emi_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_cksys_2_infra_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_cksys_2_pmic_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_cksys_2_srcclkena_mb & 0x1) << 5) |
(((u32)pwrctrl->reg_cksys_2_vcore_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_cksys_2_vrf18_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_conn_apsrc_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_conn_ddren_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_conn_emi_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_conn_infra_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_conn_pmic_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_conn_srcclkena_mb & 0x1) << 13) |
(((u32)pwrctrl->reg_conn_srcclkenb_mb & 0x1) << 14) |
(((u32)pwrctrl->reg_conn_vcore_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_conn_vrf18_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_corecfg_apsrc_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_corecfg_ddren_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_corecfg_emi_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_corecfg_infra_rmb & 0x1) << 20) |
(((u32)pwrctrl->reg_corecfg_pmic_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_corecfg_srcclkena_mb & 0x1) << 22) |
(((u32)pwrctrl->reg_corecfg_vcore_rmb & 0x1) << 23) |
(((u32)pwrctrl->reg_corecfg_vrf18_rmb & 0x1) << 24));
/* SPM_SRC_MASK_7 */
mmio_write_32(SPM_SRC_MASK_7,
(((u32)pwrctrl->reg_cpueb_apsrc_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_cpueb_ddren_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_cpueb_emi_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_cpueb_infra_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_cpueb_pmic_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_cpueb_srcclkena_mb & 0x1) << 5) |
(((u32)pwrctrl->reg_cpueb_vcore_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_cpueb_vrf18_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_disp0_apsrc_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_disp0_ddren_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_disp0_emi_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_disp0_infra_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_disp0_pmic_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_disp0_srcclkena_mb & 0x1) << 13) |
(((u32)pwrctrl->reg_disp0_vrf18_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_disp1_apsrc_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_disp1_ddren_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_disp1_emi_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_disp1_infra_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_disp1_pmic_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_disp1_srcclkena_mb & 0x1) << 20) |
(((u32)pwrctrl->reg_disp1_vrf18_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_dpm_apsrc_rmb & 0xf) << 22) |
(((u32)pwrctrl->reg_dpm_ddren_rmb & 0xf) << 26));
/* SPM_SRC_MASK_8 */
mmio_write_32(SPM_SRC_MASK_8,
(((u32)pwrctrl->reg_dpm_emi_rmb & 0xf) << 0) |
(((u32)pwrctrl->reg_dpm_infra_rmb & 0xf) << 4) |
(((u32)pwrctrl->reg_dpm_pmic_rmb & 0xf) << 8) |
(((u32)pwrctrl->reg_dpm_srcclkena_mb & 0xf) << 12) |
(((u32)pwrctrl->reg_dpm_vcore_rmb & 0xf) << 16) |
(((u32)pwrctrl->reg_dpm_vrf18_rmb & 0xf) << 20) |
(((u32)pwrctrl->reg_dpmaif_apsrc_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_dpmaif_ddren_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_dpmaif_emi_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_dpmaif_infra_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_dpmaif_pmic_rmb & 0x1) << 28) |
(((u32)pwrctrl->reg_dpmaif_srcclkena_mb & 0x1) << 29) |
(((u32)pwrctrl->reg_dpmaif_vcore_rmb & 0x1) << 30) |
(((u32)pwrctrl->reg_dpmaif_vrf18_rmb & 0x1) << 31));
/* SPM_SRC_MASK_9 */
mmio_write_32(SPM_SRC_MASK_9,
(((u32)pwrctrl->reg_dvfsrc_level_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_emisys_apsrc_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_emisys_ddren_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_emisys_emi_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_emisys_infra_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_emisys_pmic_rmb & 0x1) << 5) |
(((u32)pwrctrl->reg_emisys_srcclkena_mb & 0x1) << 6) |
(((u32)pwrctrl->reg_emisys_vcore_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_emisys_vrf18_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_gce_apsrc_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_gce_ddren_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_gce_emi_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_gce_infra_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_gce_pmic_rmb & 0x1) << 13) |
(((u32)pwrctrl->reg_gce_srcclkena_mb & 0x1) << 14) |
(((u32)pwrctrl->reg_gce_vcore_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_gce_vrf18_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_gpueb_apsrc_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_gpueb_ddren_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_gpueb_emi_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_gpueb_infra_rmb & 0x1) << 20) |
(((u32)pwrctrl->reg_gpueb_pmic_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_gpueb_srcclkena_mb & 0x1) << 22) |
(((u32)pwrctrl->reg_gpueb_vcore_rmb & 0x1) << 23) |
(((u32)pwrctrl->reg_gpueb_vrf18_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_hwccf_apsrc_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_hwccf_ddren_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_hwccf_emi_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_hwccf_infra_rmb & 0x1) << 28) |
(((u32)pwrctrl->reg_hwccf_pmic_rmb & 0x1) << 29) |
(((u32)pwrctrl->reg_hwccf_srcclkena_mb & 0x1) << 30) |
(((u32)pwrctrl->reg_hwccf_vcore_rmb & 0x1) << 31));
/* SPM_SRC_MASK_10 */
mmio_write_32(SPM_SRC_MASK_10,
(((u32)pwrctrl->reg_hwccf_vrf18_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_img_apsrc_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_img_ddren_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_img_emi_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_img_infra_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_img_pmic_rmb & 0x1) << 5) |
(((u32)pwrctrl->reg_img_srcclkena_mb & 0x1) << 6) |
(((u32)pwrctrl->reg_img_vrf18_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_infrasys_apsrc_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_infrasys_ddren_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_infrasys_emi_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_infrasys_infra_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_infrasys_pmic_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_infrasys_srcclkena_mb & 0x1) << 13) |
(((u32)pwrctrl->reg_infrasys_vcore_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_infrasys_vrf18_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_ipic_infra_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_ipic_vrf18_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_mcu_apsrc_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_mcu_ddren_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_mcu_emi_rmb & 0x1) << 20) |
(((u32)pwrctrl->reg_mcu_infra_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_mcu_pmic_rmb & 0x1) << 22) |
(((u32)pwrctrl->reg_mcu_srcclkena_mb & 0x1) << 23) |
(((u32)pwrctrl->reg_mcu_vcore_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_mcu_vrf18_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_md_apsrc_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_md_ddren_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_md_emi_rmb & 0x1) << 28) |
(((u32)pwrctrl->reg_md_infra_rmb & 0x1) << 29) |
(((u32)pwrctrl->reg_md_pmic_rmb & 0x1) << 30) |
(((u32)pwrctrl->reg_md_srcclkena_mb & 0x1) << 31));
/* SPM_SRC_MASK_11 */
mmio_write_32(SPM_SRC_MASK_11,
(((u32)pwrctrl->reg_md_srcclkena1_mb & 0x1) << 0) |
(((u32)pwrctrl->reg_md_vcore_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_md_vrf18_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_mm_proc_apsrc_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_mm_proc_ddren_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_mm_proc_emi_rmb & 0x1) << 5) |
(((u32)pwrctrl->reg_mm_proc_infra_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_mm_proc_pmic_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_mm_proc_srcclkena_mb & 0x1) << 8) |
(((u32)pwrctrl->reg_mm_proc_vcore_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_mm_proc_vrf18_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_mml0_apsrc_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_mml0_ddren_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_mml0_emi_rmb & 0x1) << 13) |
(((u32)pwrctrl->reg_mml0_infra_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_mml0_pmic_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_mml0_srcclkena_mb & 0x1) << 16) |
(((u32)pwrctrl->reg_mml0_vrf18_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_mml1_apsrc_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_mml1_ddren_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_mml1_emi_rmb & 0x1) << 20) |
(((u32)pwrctrl->reg_mml1_infra_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_mml1_pmic_rmb & 0x1) << 22) |
(((u32)pwrctrl->reg_mml1_srcclkena_mb & 0x1) << 23) |
(((u32)pwrctrl->reg_mml1_vrf18_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_ovl0_apsrc_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_ovl0_ddren_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_ovl0_emi_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_ovl0_infra_rmb & 0x1) << 28) |
(((u32)pwrctrl->reg_ovl0_pmic_rmb & 0x1) << 29) |
(((u32)pwrctrl->reg_ovl0_srcclkena_mb & 0x1) << 30) |
(((u32)pwrctrl->reg_ovl0_vrf18_rmb & 0x1) << 31));
mmio_write_32(SPM_SRC_MASK_12,
(((u32)pwrctrl->reg_ovl1_apsrc_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_ovl1_ddren_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_ovl1_emi_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_ovl1_infra_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_ovl1_pmic_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_ovl1_srcclkena_mb & 0x1) << 5) |
(((u32)pwrctrl->reg_ovl1_vrf18_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_pcie0_apsrc_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_pcie0_ddren_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_pcie0_emi_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_pcie0_infra_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_pcie0_pmic_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_pcie0_srcclkena_mb & 0x1) << 12) |
(((u32)pwrctrl->reg_pcie0_vcore_rmb & 0x1) << 13) |
(((u32)pwrctrl->reg_pcie0_vrf18_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_pcie1_apsrc_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_pcie1_ddren_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_pcie1_emi_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_pcie1_infra_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_pcie1_pmic_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_pcie1_srcclkena_mb & 0x1) << 20) |
(((u32)pwrctrl->reg_pcie1_vcore_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_pcie1_vrf18_rmb & 0x1) << 22) |
(((u32)pwrctrl->reg_perisys_apsrc_rmb & 0x1) << 23) |
(((u32)pwrctrl->reg_perisys_ddren_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_perisys_emi_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_perisys_infra_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_perisys_pmic_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_perisys_srcclkena_mb & 0x1) << 28) |
(((u32)pwrctrl->reg_perisys_vcore_rmb & 0x1) << 29) |
(((u32)pwrctrl->reg_perisys_vrf18_rmb & 0x1) << 30) |
(((u32)pwrctrl->reg_pmsr_apsrc_rmb & 0x1) << 31));
/* SPM_SRC_MASK_13 */
mmio_write_32(SPM_SRC_MASK_13,
(((u32)pwrctrl->reg_pmsr_ddren_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_pmsr_emi_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_pmsr_infra_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_pmsr_pmic_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_pmsr_srcclkena_mb & 0x1) << 4) |
(((u32)pwrctrl->reg_pmsr_vcore_rmb & 0x1) << 5) |
(((u32)pwrctrl->reg_pmsr_vrf18_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_scp_apsrc_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_scp_ddren_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_scp_emi_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_scp_infra_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_scp_pmic_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_scp_srcclkena_mb & 0x1) << 12) |
(((u32)pwrctrl->reg_scp_vcore_rmb & 0x1) << 13) |
(((u32)pwrctrl->reg_scp_vrf18_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_spu_hwr_apsrc_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_spu_hwr_ddren_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_spu_hwr_emi_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_spu_hwr_infra_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_spu_hwr_pmic_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_spu_hwr_srcclkena_mb & 0x1) << 20) |
(((u32)pwrctrl->reg_spu_hwr_vcore_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_spu_hwr_vrf18_rmb & 0x1) << 22) |
(((u32)pwrctrl->reg_spu_ise_apsrc_rmb & 0x1) << 23) |
(((u32)pwrctrl->reg_spu_ise_ddren_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_spu_ise_emi_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_spu_ise_infra_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_spu_ise_pmic_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_spu_ise_srcclkena_mb & 0x1) << 28) |
(((u32)pwrctrl->reg_spu_ise_vcore_rmb & 0x1) << 29) |
(((u32)pwrctrl->reg_spu_ise_vrf18_rmb & 0x1) << 30));
/* SPM_SRC_MASK_14 */
mmio_write_32(SPM_SRC_MASK_14,
(((u32)pwrctrl->reg_srcclkeni_infra_rmb & 0x3) << 0) |
(((u32)pwrctrl->reg_srcclkeni_pmic_rmb & 0x3) << 2) |
(((u32)pwrctrl->reg_srcclkeni_srcclkena_mb & 0x3) << 4) |
(((u32)pwrctrl->reg_srcclkeni_vcore_rmb & 0x3) << 6) |
(((u32)pwrctrl->reg_sspm_apsrc_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_sspm_ddren_rmb & 0x1) << 9) |
(((u32)pwrctrl->reg_sspm_emi_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_sspm_infra_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_sspm_pmic_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_sspm_srcclkena_mb & 0x1) << 13) |
(((u32)pwrctrl->reg_sspm_vrf18_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_ssrsys_apsrc_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_ssrsys_ddren_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_ssrsys_emi_rmb & 0x1) << 17) |
(((u32)pwrctrl->reg_ssrsys_infra_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_ssrsys_pmic_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_ssrsys_srcclkena_mb & 0x1) << 20) |
(((u32)pwrctrl->reg_ssrsys_vcore_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_ssrsys_vrf18_rmb & 0x1) << 22) |
(((u32)pwrctrl->reg_ssusb_apsrc_rmb & 0x1) << 23) |
(((u32)pwrctrl->reg_ssusb_ddren_rmb & 0x1) << 24) |
(((u32)pwrctrl->reg_ssusb_emi_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_ssusb_infra_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_ssusb_pmic_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_ssusb_srcclkena_mb & 0x1) << 28) |
(((u32)pwrctrl->reg_ssusb_vcore_rmb & 0x1) << 29) |
(((u32)pwrctrl->reg_ssusb_vrf18_rmb & 0x1) << 30) |
(((u32)pwrctrl->reg_uart_hub_infra_rmb & 0x1) << 31));
/* SPM_SRC_MASK_15 */
mmio_write_32(SPM_SRC_MASK_15,
(((u32)pwrctrl->reg_uart_hub_pmic_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_uart_hub_srcclkena_mb & 0x1) << 1) |
(((u32)pwrctrl->reg_uart_hub_vcore_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_uart_hub_vrf18_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_ufs_apsrc_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_ufs_ddren_rmb & 0x1) << 5) |
(((u32)pwrctrl->reg_ufs_emi_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_ufs_infra_rmb & 0x1) << 7) |
(((u32)pwrctrl->reg_ufs_pmic_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_ufs_srcclkena_mb & 0x1) << 9) |
(((u32)pwrctrl->reg_ufs_vcore_rmb & 0x1) << 10) |
(((u32)pwrctrl->reg_ufs_vrf18_rmb & 0x1) << 11) |
(((u32)pwrctrl->reg_vdec_apsrc_rmb & 0x1) << 12) |
(((u32)pwrctrl->reg_vdec_ddren_rmb & 0x1) << 13) |
(((u32)pwrctrl->reg_vdec_emi_rmb & 0x1) << 14) |
(((u32)pwrctrl->reg_vdec_infra_rmb & 0x1) << 15) |
(((u32)pwrctrl->reg_vdec_pmic_rmb & 0x1) << 16) |
(((u32)pwrctrl->reg_vdec_srcclkena_mb & 0x1) << 17) |
(((u32)pwrctrl->reg_vdec_vrf18_rmb & 0x1) << 18) |
(((u32)pwrctrl->reg_venc_apsrc_rmb & 0x1) << 19) |
(((u32)pwrctrl->reg_venc_ddren_rmb & 0x1) << 20) |
(((u32)pwrctrl->reg_venc_emi_rmb & 0x1) << 21) |
(((u32)pwrctrl->reg_venc_infra_rmb & 0x1) << 22) |
(((u32)pwrctrl->reg_venc_pmic_rmb & 0x1) << 23) |
(((u32)pwrctrl->reg_venc_srcclkena_mb & 0x1) << 24) |
(((u32)pwrctrl->reg_venc_vrf18_rmb & 0x1) << 25) |
(((u32)pwrctrl->reg_vlpcfg_apsrc_rmb & 0x1) << 26) |
(((u32)pwrctrl->reg_vlpcfg_ddren_rmb & 0x1) << 27) |
(((u32)pwrctrl->reg_vlpcfg_emi_rmb & 0x1) << 28) |
(((u32)pwrctrl->reg_vlpcfg_infra_rmb & 0x1) << 29) |
(((u32)pwrctrl->reg_vlpcfg_pmic_rmb & 0x1) << 30) |
(((u32)pwrctrl->reg_vlpcfg_srcclkena_mb & 0x1) << 31));
/* SPM_SRC_MASK_16 */
mmio_write_32(SPM_SRC_MASK_16,
(((u32)pwrctrl->reg_vlpcfg_vcore_rmb & 0x1) << 0) |
(((u32)pwrctrl->reg_vlpcfg_vrf18_rmb & 0x1) << 1) |
(((u32)pwrctrl->reg_vlpcfg1_apsrc_rmb & 0x1) << 2) |
(((u32)pwrctrl->reg_vlpcfg1_ddren_rmb & 0x1) << 3) |
(((u32)pwrctrl->reg_vlpcfg1_emi_rmb & 0x1) << 4) |
(((u32)pwrctrl->reg_vlpcfg1_infra_rmb & 0x1) << 5) |
(((u32)pwrctrl->reg_vlpcfg1_pmic_rmb & 0x1) << 6) |
(((u32)pwrctrl->reg_vlpcfg1_srcclkena_mb & 0x1) << 7) |
(((u32)pwrctrl->reg_vlpcfg1_vcore_rmb & 0x1) << 8) |
(((u32)pwrctrl->reg_vlpcfg1_vrf18_rmb & 0x1) << 9));
/* SPM_SRC_MASK_17 */
mmio_write_32(SPM_SRC_MASK_17,
(((u32)pwrctrl->reg_spm_sw_vcore_rmb & 0xffff) << 0) |
(((u32)pwrctrl->reg_spm_sw_pmic_rmb & 0xffff) << 16));
/* SPM_SRC_MASK_18 */
mmio_write_32(SPM_SRC_MASK_18,
(((u32)pwrctrl->reg_spm_sw_srcclkena_mb & 0xffff) << 0));
/* SPM_EVENT_CON_MISC */
mmio_write_32(SPM_EVENT_CON_MISC,
(((u32)pwrctrl->reg_srcclken_fast_resp & 0x1) << 0) |
(((u32)pwrctrl->reg_csyspwrup_ack_mask & 0x1) << 1));
/* SPM_WAKE_MASK*/
mmio_write_32(SPM_WAKEUP_EVENT_MASK,
(((u32)pwrctrl->reg_wake_mask & 0xffffffff) << 0));
/* SPM_WAKEUP_EVENT_EXT_MASK */
mmio_write_32(SPM_WAKEUP_EVENT_EXT_MASK,
(((u32)pwrctrl->reg_ext_wake_mask & 0xffffffff) << 0));
}
#define CHECK_ONE 0xffffffff
#define CHECK_ZERO 0x0
static int32_t __spm_check_ack(u32 reg, u32 mask, u32 check_en)
{
u32 val;
val = mmio_read_32(reg);
if ((val & mask) == (mask & check_en))
return 0;
return -1;
}
int32_t __spm_wait_spm_request_ack(u32 spm_resource_req, u32 timeout_us)
{
u32 spm_ctrl0_mask, spm_ctrl1_mask;
int32_t ret, retry;
if (spm_resource_req == 0)
return 0;
spm_ctrl0_mask = 0;
spm_ctrl1_mask = 0;
if (spm_resource_req & (MT_SPM_XO_FPM | MT_SPM_26M))
spm_ctrl0_mask |= CTRL0_SC_MD26M_CK_OFF;
if (spm_resource_req & MT_SPM_VCORE)
spm_ctrl1_mask |= CTRL1_SPM_VCORE_INTERNAL_ACK;
if (spm_resource_req & MT_SPM_PMIC)
spm_ctrl1_mask |= CTRL1_SPM_PMIC_INTERNAL_ACK;
if (spm_resource_req & MT_SPM_INFRA)
spm_ctrl1_mask |= CTRL1_SPM_INFRA_INTERNAL_ACK;
if (spm_resource_req & MT_SPM_SYSPLL)
spm_ctrl1_mask |= CTRL1_SPM_VRF18_INTERNAL_ACK;
if (spm_resource_req & MT_SPM_EMI)
spm_ctrl1_mask |= CTRL1_SPM_EMI_INTERNAL_ACK;
if (spm_resource_req & MT_SPM_DRAM_S0)
spm_ctrl1_mask |= CTRL1_SPM_APSRC_INTERNAL_ACK;
if (spm_resource_req & MT_SPM_DRAM_S1)
spm_ctrl1_mask |= CTRL1_SPM_DDREN_INTERNAL_ACK;
retry = -1;
ret = 0;
while (retry++ < timeout_us) {
udelay(1);
if (spm_ctrl0_mask != 0) {
ret = __spm_check_ack(MD32PCM_SCU_CTRL0,
spm_ctrl0_mask,
CHECK_ZERO);
if (ret)
continue;
}
if (spm_ctrl1_mask != 0) {
ret = __spm_check_ack(MD32PCM_SCU_CTRL1,
spm_ctrl1_mask,
CHECK_ONE);
if (ret)
continue;
}
break;
}
return ret;
}
void __spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
{
u32 val, mask;
/* Toggle event counter clear */
mmio_write_32(SPM_EVENT_COUNTER_CLEAR, REG_SPM_EVENT_COUNTER_CLR_LSB);
/* Toggle for reset SYS TIMER start point */
mmio_setbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
if (pwrctrl->timer_val_cust == 0)
val = pwrctrl->timer_val ? pwrctrl->timer_val : PCM_TIMER_MAX;
else
val = pwrctrl->timer_val_cust;
mmio_write_32(PCM_TIMER_VAL, val);
mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | REG_PCM_TIMER_EN_LSB);
/* Unmask AP wakeup source */
if (pwrctrl->wake_src_cust == 0)
mask = pwrctrl->wake_src;
else
mask = pwrctrl->wake_src_cust;
if (pwrctrl->reg_csyspwrup_ack_mask)
mask &= ~R12_CSYSPWREQ_B;
mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~mask);
/* Unmask SPM ISR (keep TWAM setting) */
mmio_setbits_32(SPM_IRQ_MASK, ISRM_RET_IRQ_AUX);
/* Toggle event counter clear */
mmio_write_32(SPM_EVENT_COUNTER_CLEAR, 0);
/* Toggle for reset SYS TIMER start point */
mmio_clrbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
}
void __spm_set_fw_resume_option(struct pwr_ctrl *pwrctrl)
{
#if SPM_FW_NO_RESUME
/* Do Nothing */
#else
pwrctrl->pcm_flags1 |= SPM_FLAG1_DISABLE_NO_RESUME;
#endif
}
void __spm_set_pcm_flags(struct pwr_ctrl *pwrctrl)
{
/* Set PCM flags and data */
if (pwrctrl->pcm_flags_cust_clr != 0)
pwrctrl->pcm_flags &= ~pwrctrl->pcm_flags_cust_clr;
if (pwrctrl->pcm_flags_cust_set != 0)
pwrctrl->pcm_flags |= pwrctrl->pcm_flags_cust_set;
if (pwrctrl->pcm_flags1_cust_clr != 0)
pwrctrl->pcm_flags1 &= ~pwrctrl->pcm_flags1_cust_clr;
if (pwrctrl->pcm_flags1_cust_set != 0)
pwrctrl->pcm_flags1 |= pwrctrl->pcm_flags1_cust_set;
mmio_write_32(SPM_SW_FLAG_0, pwrctrl->pcm_flags);
mmio_write_32(SPM_SW_FLAG_1, pwrctrl->pcm_flags1);
mmio_write_32(SPM_SW_RSV_7, pwrctrl->pcm_flags);
mmio_write_32(SPM_SW_RSV_8, pwrctrl->pcm_flags1);
}
void __spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl)
{
/* Waiting for loading SPMFW done*/
while (mmio_read_32(MD32PCM_DMA0_RLCT) != 0x0)
;
__spm_set_pcm_flags(pwrctrl);
udelay(SPM_INIT_DONE_US);
}
void __spm_get_wakeup_status(struct wake_status *wakesta,
uint32_t ext_status)
{
/* Get wakeup event */
wakesta->tr.comm.r12 = mmio_read_32(SPM_BK_WAKE_EVENT);
wakesta->r12_ext = mmio_read_32(SPM_WAKEUP_EXT_STA);
wakesta->tr.comm.raw_sta = mmio_read_32(SPM_WAKEUP_STA);
wakesta->raw_ext_sta = mmio_read_32(SPM_WAKEUP_EXT_STA);
wakesta->md32pcm_wakeup_sta = mmio_read_32(MD32PCM_WAKEUP_STA);
wakesta->md32pcm_event_sta = mmio_read_32(MD32PCM_EVENT_STA);
wakesta->wake_misc = mmio_read_32(SPM_BK_WAKE_MISC);
/* Get sleep time */
wakesta->tr.comm.timer_out = mmio_read_32(SPM_BK_PCM_TIMER);
wakesta->tr.comm.r13 = mmio_read_32(MD32PCM_SCU_STA0);
wakesta->tr.comm.req_sta0 = mmio_read_32(SPM_REQ_STA_0);
wakesta->tr.comm.req_sta1 = mmio_read_32(SPM_REQ_STA_1);
wakesta->tr.comm.req_sta2 = mmio_read_32(SPM_REQ_STA_2);
wakesta->tr.comm.req_sta3 = mmio_read_32(SPM_REQ_STA_3);
wakesta->tr.comm.req_sta4 = mmio_read_32(SPM_REQ_STA_4);
wakesta->tr.comm.req_sta5 = mmio_read_32(SPM_REQ_STA_5);
wakesta->tr.comm.req_sta6 = mmio_read_32(SPM_REQ_STA_6);
wakesta->tr.comm.req_sta7 = mmio_read_32(SPM_REQ_STA_7);
wakesta->tr.comm.req_sta8 = mmio_read_32(SPM_REQ_STA_8);
wakesta->tr.comm.req_sta9 = mmio_read_32(SPM_REQ_STA_9);
wakesta->tr.comm.req_sta10 = mmio_read_32(SPM_REQ_STA_10);
wakesta->tr.comm.req_sta11 = mmio_read_32(SPM_REQ_STA_11);
wakesta->tr.comm.req_sta12 = mmio_read_32(SPM_REQ_STA_12);
wakesta->tr.comm.req_sta13 = mmio_read_32(SPM_REQ_STA_13);
wakesta->tr.comm.req_sta14 = mmio_read_32(SPM_REQ_STA_14);
wakesta->tr.comm.req_sta15 = mmio_read_32(SPM_REQ_STA_15);
wakesta->tr.comm.req_sta16 = mmio_read_32(SPM_REQ_STA_16);
/* Get debug flag for PCM execution check */
wakesta->tr.comm.debug_flag = mmio_read_32(PCM_WDT_LATCH_SPARE_0);
wakesta->tr.comm.debug_flag1 = mmio_read_32(PCM_WDT_LATCH_SPARE_1);
/* Get backup SW flag status */
wakesta->tr.comm.b_sw_flag0 = mmio_read_32(SPM_SW_RSV_7);
wakesta->tr.comm.b_sw_flag1 = mmio_read_32(SPM_SW_RSV_8);
/* Get ISR status */
wakesta->isr = mmio_read_32(SPM_IRQ_STA);
/* Get SW flag status */
wakesta->sw_flag0 = mmio_read_32(SPM_SW_FLAG_0);
wakesta->sw_flag1 = mmio_read_32(SPM_SW_FLAG_1);
/* Check abort */
wakesta->is_abort = wakesta->tr.comm.debug_flag1 & DEBUG_ABORT_MASK_1;
}
void __spm_clean_after_wakeup(void)
{
/*
* Copy SPM_WAKEUP_STA to SPM_BK_WAKE_EVENT
* before clear SPM_WAKEUP_STA
*
* CPU dormant driver @kernel will copy edge-trig IRQ pending
* (recorded @SPM_BK_WAKE_EVENT) to GIC
*/
mmio_write_32(SPM_BK_WAKE_EVENT, mmio_read_32(SPM_WAKEUP_STA) |
mmio_read_32(SPM_BK_WAKE_EVENT));
mmio_write_32(SPM_CPU_WAKEUP_EVENT, 0);
/* Clean wakeup event raw status (for edge trigger event) */
mmio_write_32(SPM_WAKEUP_EVENT_MASK, 0xefffffff);
/* Clean ISR status (except TWAM) */
mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM);
mmio_write_32(SPM_IRQ_STA, ISRC_ALL_EXC_TWAM);
mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT_ALL);
}
void __spm_set_pcm_wdt(int en)
{
/* Enable PCM WDT (normal mode) to start count if needed */
if (en) {
mmio_clrsetbits_32(PCM_CON1, REG_PCM_WDT_WAKE_LSB,
SPM_REGWR_CFG_KEY);
if (mmio_read_32(PCM_TIMER_VAL) > PCM_TIMER_MAX)
mmio_write_32(PCM_TIMER_VAL, PCM_TIMER_MAX);
mmio_write_32(PCM_WDT_VAL, mmio_read_32(PCM_TIMER_VAL) +
PCM_WDT_TIMEOUT);
mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY |
REG_PCM_WDT_EN_LSB);
} else {
mmio_clrsetbits_32(PCM_CON1, REG_PCM_WDT_EN_LSB,
SPM_REGWR_CFG_KEY);
}
}
u32 __spm_get_pcm_timer_val(void)
{
return mmio_read_32(PCM_TIMER_VAL) >> 15;
}
void __spm_send_cpu_wakeup_event(void)
{
mmio_write_32(SPM_CPU_WAKEUP_EVENT, 1);
}
void __spm_ext_int_wakeup_req_clr(void)
{
u32 cpu = plat_my_core_pos();
mmio_write_32(EXT_INT_WAKEUP_REQ_CLR, (1U << cpu));
/* Clear spm2mcupm wakeup interrupt status */
mmio_clrbits_32(SPM2MCUPM_CON, SPM2MCUPM_SW_INT_LSB);
}
void __spm_hw_s1_state_monitor(int en, uint32_t *status)
{
uint32_t reg;
if (en) {
mmio_clrsetbits_32(SPM_ACK_CHK_CON_3,
SPM_ACK_CHK_3_CON_CLR_ALL,
SPM_ACK_CHK_3_CON_EN);
} else {
reg = mmio_read_32(SPM_ACK_CHK_CON_3);
if (reg & SPM_ACK_CHK_3_CON_RESULT) {
if (status)
*status |= SPM_INTERNAL_STATUS_HW_S1;
}
mmio_clrsetbits_32(SPM_ACK_CHK_CON_3, SPM_ACK_CHK_3_CON_EN,
(SPM_ACK_CHK_3_CON_HW_MODE_TRIG |
SPM_ACK_CHK_3_CON_CLR_ALL));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,255 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <drivers/pmic/pmic_set_lowpower.h>
#include <drivers/spmi/spmi_common.h>
#include <lib/mtk_init/mtk_init.h>
#include <mt_spm_constraint.h>
#include <mt_spm_pmic_lp.h>
#include <mt_spm_reg.h>
/* SPMI_M: 6363, SPMI_P: 6373/6316 */
/* SPMI_M: 6363, SPMI_P: 6373/6316 */
static struct lp_pmic_cfg {
uint8_t slave;
uint8_t master;
char *name;
} pmics[] = {
[LP_MT6363] = {MT6363_SLAVE, SPMI_MASTER_1, "MT6363"},
[LP_MT6373] = {MT6373_SLAVE, SPMI_MASTER_P_1, "MT6373"},
[LP_MT6316_1] = {MT6316_S8_SLAVE, SPMI_MASTER_P_1, "MT6316_S8"},
[LP_MT6316_2] = {MT6316_S6_SLAVE, SPMI_MASTER_P_1, "MT6316_S6"},
[LP_MT6316_3] = {MT6316_S7_SLAVE, SPMI_MASTER_P_1, "MT6316_S7"},
[LP_MT6316_4] = {MT6316_S15_SLAVE, SPMI_MASTER_P_1, "MT6316_S15"},
};
#ifdef MTK_SPM_PMIC_GS_DUMP
static struct pmic_gs_info pmic_gs_dump_info;
static char *pmic_str[] = {
[LP_MT6363] = "MT6363",
[LP_MT6373] = "MT6373",
[LP_MT6316_1] = "MT6316_1",
[LP_MT6316_2] = "MT6316_2",
[LP_MT6316_3] = "MT6316_3",
[LP_MT6316_4] = "MT6316_4",
};
#endif
struct spmi_device *lp_sdev[LP_PMIC_SLAVE_NUM];
#define VSRAM_CORE_0_35V 56
#define VSRAM_CORE_0_55V 88
#define VSRAM_CORE_0_75V 120
/* VSRAM_CORE Low bound */
#ifdef MTK_AGING_FLAVOR_LOAD
#define SUSPEND_AGING_VAL_SHIFT 3
#define SUSPEND_AGING_VAL_DEFAULT 85
#define VSRAM_CORE_LOWBOUND (74 - SUSPEND_AGING_VAL_SHIFT)
#else
#define VSRAM_CORE_LOWBOUND 74
#endif
#define MT6363_LP_REG 0x1687
#define MT6363_VIO18_SWITCH 0x53
#define MT6373_VIO18_SWITCH 0x58
static uint32_t vcore_sram_suspend_vol = VSRAM_CORE_0_55V;
static bool vcore_sram_lp_enable = true;
static bool vcore_lp_enable = true;
static uint32_t get_vcore_sram_suspend_vol(void)
{
uint8_t value;
/* Set vcore_sram to 0.55V by default */
value = VSRAM_CORE_0_55V;
#ifdef MTK_AGING_FLAVOR_LOAD
value -= SUSPEND_AGING_VAL_SHIFT;
if (value > SUSPEND_AGING_VAL_DEFAULT)
value = SUSPEND_AGING_VAL_DEFAULT;
INFO("%s(%d) enable aging with value: %u\n",
__func__, __LINE__, value);
#endif
return value;
}
#ifdef MTK_SPM_PMIC_GS_DUMP
static void mt_spm_dump_pmic_gs(uint32_t cmd)
{
#ifdef MTK_SPM_PMIC_GS_DUMP_SUSPEND
if (cmd & MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND) { /* Suspend enter */
mt_spm_pmic_gs_dump(SUSPEND, LP_MT6363);
mt_spm_pmic_gs_dump(SUSPEND, LP_MT6373);
}
#endif
if (cmd & MT_RM_CONSTRAINT_ALLOW_VCORE_LP) {
if (cmd & MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF) { /* SODI3 */
#ifdef MTK_SPM_PMIC_GS_DUMP_SODI3
mt_spm_pmic_gs_dump(SODI3, LP_MT6363);
mt_spm_pmic_gs_dump(SODI3, LP_MT6373);
#endif
} else { /* DPIDLE enter */
#ifdef MTK_SPM_PMIC_GS_DUMP_DPIDLE
mt_spm_pmic_gs_dump(DPIDLE, LP_MT6363);
mt_spm_pmic_gs_dump(DPIDLE, LP_MT6373);
#endif
}
}
}
#endif
int spm_lp_setting_init(void)
{
uint8_t i, slvid, spmi_master;
for (i = 0; i < ARRAY_SIZE(pmics); i++) {
slvid = pmics[i].slave;
spmi_master = pmics[i].master;
lp_sdev[i] = get_spmi_device(spmi_master, slvid);
if (!lp_sdev[i])
return -ENODEV;
}
PMIC_SLVID_BUCK_SET_LP(MT6316, S8, VBUCK1, RC8,
false, OP_MODE_LP, HW_OFF);
/* Get suspend case vcore_sram sleep voltage */
vcore_sram_suspend_vol = get_vcore_sram_suspend_vol();
#ifdef MTK_SPM_PMIC_GS_DUMP
pmic_gs_dump_info.lp_sdev = lp_sdev;
pmic_gs_dump_info.pmic_str = pmic_str;
pmic_gs_dump_info.pmic_num = LP_PMIC_SLAVE_NUM;
#ifdef MTK_SPM_PMIC_GS_DUMP_SUSPEND
pmic_gs_dump_info.scen_gs[SUSPEND].data = pmic_gs_suspend;
#endif
#ifdef MTK_SPM_PMIC_GS_DUMP_SODI3
pmic_gs_dump_info.scen_gs[SODI3].data = pmic_gs_sodi3;
#endif
#ifdef MTK_SPM_PMIC_GS_DUMP_DPIDLE
pmic_gs_dump_info.scen_gs[DPIDLE].data = pmic_gs_dpidle;
#endif
return register_pmic_gs_info(&pmic_gs_dump_info);
#else
return 0;
#endif
}
#ifdef MTK_SPM_PMIC_LP_SUPPORT
MTK_PLAT_SETUP_0_INIT(spm_lp_setting_init);
#endif
void set_vcore_lp_enable(bool enable)
{
vcore_lp_enable = enable;
}
bool get_vcore_lp_enable(void)
{
return vcore_lp_enable;
}
void set_vsram_lp_enable(bool enable)
{
vcore_sram_lp_enable = enable;
}
bool get_vsram_lp_enable(void)
{
return vcore_sram_lp_enable;
}
void set_vsram_lp_volt(uint32_t volt)
{
/* Allow 0.35V ~ 0.75V */
if (volt < VSRAM_CORE_0_35V || volt > VSRAM_CORE_0_75V)
return;
vcore_sram_suspend_vol = volt;
}
uint32_t get_vsram_lp_volt(void)
{
return vcore_sram_suspend_vol;
}
static int pmic_lp_setting(uint8_t data)
{
int ret;
if (data != 0x0 && data != 0x1)
return -ENODEV;
/* SUSPEND:VS1 HW2&RC9 normal mode */
PMIC_BUCK_SET_LP(MT6363, VS1, HW2,
false, OP_MODE_LP, HW_LP);
PMIC_BUCK_SET_LP(MT6363, VS1, RC9,
false, OP_MODE_MU, HW_ON);
PMIC_LDO_SET_LP(MT6363, VIO18, HW2,
false, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VIO18, RC9,
false, OP_MODE_MU, HW_ON);
/* Switch DIG18 to VIO18 for power saving */
ret = spmi_ext_register_writel(lp_sdev[LP_MT6363], MT6363_VIO18_SWITCH, &data, 1);
if (ret)
INFO("MT6363 RG_VIO18 spmi failed\n");
ret = spmi_ext_register_writel(lp_sdev[LP_MT6373], MT6373_VIO18_SWITCH, &data, 1);
if (ret)
INFO("MT6373 RG_VIO18 spmi failed\n");
return ret;
}
int do_spm_low_power(enum SPM_PWR_TYPE type, uint32_t cmd)
{
int ret;
uint8_t value;
bool enter_suspend, vcore_sram_lp = false;
if (type == SPM_LP_ENTER) {
enter_suspend = true;
vcore_sram_lp = vcore_sram_lp_enable;
if (cmd & MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND) {
value = vcore_sram_suspend_vol;
if (value < VSRAM_CORE_LOWBOUND ||
value > VSRAM_CORE_0_75V) {
INFO("Vsram_core voltage wrong\n");
panic();
}
} else {
value = VSRAM_CORE_0_55V;
}
} else {
enter_suspend = false;
vcore_sram_lp = false;
value = VSRAM_CORE_0_75V;
}
/* Enable VA12_2/VSRAM_CPUL HW_LP for suspend/idle */
PMIC_LDO_SET_LP(MT6363, VA12_2, HW2, enter_suspend, OP_MODE_LP, HW_LP);
PMIC_LDO_SET_LP(MT6363, VSRAM_CPUL, HW2,
enter_suspend, OP_MODE_LP, HW_LP);
if (!(cmd & MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND))
return 0;
PMIC_SLVID_BUCK_SET_LP(MT6316, S8, VBUCK1, HW2, vcore_lp_enable,
OP_MODE_LP, HW_LP);
PMIC_BUCK_SET_LP(MT6363, VBUCK4, HW0, vcore_sram_lp,
OP_MODE_LP, HW_LP);
PMIC_BUCK_SET_LP(MT6363, VBUCK4, HW2, !enter_suspend,
OP_MODE_LP, HW_LP);
ret = spmi_ext_register_writel(lp_sdev[LP_MT6363], MT6363_LP_REG, &value, 1);
if (ret)
INFO("BUCK(VSRAM_CORE) spmi write failed\n");
if (cmd & MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND)
pmic_lp_setting(enter_suspend ? 1 : 0);
return 0;
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_PMIC_LP_H
#define MT_SPM_PMIC_LP_H
enum SPM_PWR_TYPE {
SPM_LP_ENTER,
SPM_LP_RESUME
};
enum {
LP_MT6363 = 0,
LP_MT6373,
LP_MT6316_1,
LP_MT6316_2,
LP_MT6316_3,
LP_MT6316_4,
LP_PMIC_SLAVE_NUM,
};
#ifdef MTK_SPM_PMIC_LP_SUPPORT
void set_vcore_lp_enable(bool enable);
bool get_vcore_lp_enable(void);
void set_vsram_lp_enable(bool enable);
bool get_vsram_lp_enable(void);
void set_vsram_lp_volt(uint32_t volt);
uint32_t get_vsram_lp_volt(void);
int do_spm_low_power(enum SPM_PWR_TYPE type, uint32_t cmd);
#else
static inline void set_vcore_lp_enable(bool enable)
{
(void)enable;
}
static inline bool get_vcore_lp_enable(void)
{
return false;
}
static inline void set_vsram_lp_enable(bool enable)
{
(void)enable;
}
static inline bool get_vsram_lp_enable(void)
{
return false;
}
static inline void set_vsram_lp_volt(uint32_t volt)
{
(void)volt;
}
static inline uint32_t get_vsram_lp_volt(void)
{
return 0;
}
static inline int do_spm_low_power(enum SPM_PWR_TYPE type, uint32_t cmd)
{
(void)type;
(void)cmd;
return 0;
}
#endif /* MTK_SPM_PMIC_LP_SUPPORT */
#endif /* MT_SPM_PMIC_LP_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
#include <mt_spm.h>
#include <mt_spm_reg.h>
#include <mt_spm_stats.h>
#define READ_AND_MASK_16BIT(addr) (mmio_read_32(addr) & 0xFFFF)
void mt_spm_update_lp_stat(struct spm_lp_stat *stat)
{
if (!stat)
return;
stat->record[SPM_STAT_MCUSYS].count += 1;
stat->record[SPM_STAT_MCUSYS].duration +=
mmio_read_32(SPM_BK_PCM_TIMER);
stat->record[SPM_STAT_D1_2].count +=
READ_AND_MASK_16BIT(SPM_APSRC_EVENT_COUNT_STA);
stat->record[SPM_STAT_D2].count +=
READ_AND_MASK_16BIT(SPM_EMI_EVENT_COUNT_STA);
stat->record[SPM_STAT_D3].count +=
READ_AND_MASK_16BIT(SPM_VRF18_EVENT_COUNT_STA);
stat->record[SPM_STAT_D4].count +=
READ_AND_MASK_16BIT(SPM_INFRA_EVENT_COUNT_STA);
stat->record[SPM_STAT_D6X].count +=
READ_AND_MASK_16BIT(SPM_PMIC_EVENT_COUNT_STA);
stat->record[SPM_STAT_F26M].count +=
READ_AND_MASK_16BIT(SPM_SRCCLKENA_EVENT_COUNT_STA);
stat->record[SPM_STAT_F26M].duration +=
READ_AND_MASK_16BIT(SPM_BK_VTCXO_DUR);
stat->record[SPM_STAT_VCORE].count +=
READ_AND_MASK_16BIT(SPM_VCORE_EVENT_COUNT_STA);
stat->record[SPM_STAT_VCORE].duration +=
mmio_read_32(SPM_SW_RSV_4);
}
uint64_t mt_spm_get_lp_stat(struct spm_lp_stat *stat,
uint32_t index, uint32_t type)
{
uint64_t ret;
if (!stat || index >= NUM_SPM_STAT)
return 0;
switch (type) {
case SPM_SLP_COUNT:
ret = stat->record[index].count;
break;
case SPM_SLP_DURATION:
ret = stat->record[index].duration;
break;
default:
ret = 0;
break;
}
return ret;
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_STATS_H
#define MT_SPM_STATS_H
#include <stdint.h>
enum spm_stat_type {
SPM_SLP_COUNT,
SPM_SLP_DURATION,
};
enum spm_stat_state {
SPM_STAT_MCUSYS,
SPM_STAT_F26M,
SPM_STAT_VCORE,
SPM_STAT_D1_2,
SPM_STAT_D2,
SPM_STAT_D3,
SPM_STAT_D4,
SPM_STAT_D6X,
NUM_SPM_STAT,
};
struct spm_lp_stat_record {
uint64_t count;
uint64_t duration;
};
struct spm_lp_stat {
struct spm_lp_stat_record record[NUM_SPM_STAT];
};
void mt_spm_update_lp_stat(struct spm_lp_stat *stat);
uint64_t mt_spm_get_lp_stat(struct spm_lp_stat *stat,
uint32_t index, uint32_t type);
#endif /* MT_SPM_STATS_H */

View file

@ -0,0 +1,711 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <stdio.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/gpio.h>
#include <lib/mmio.h>
#include <constraints/mt_spm_rc_internal.h>
#include <drivers/spm/mt_spm_resource_req.h>
#include <lib/pm/mtk_pm.h>
#include <lpm_v2/mt_lp_api.h>
#include <lpm_v2/mt_lp_rqm.h>
#include <mt_spm.h>
#include <mt_spm_conservation.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <mt_spm_stats.h>
#include <mt_spm_suspend.h>
#if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
#include <mt_spm_vcorefs_exp.h>
#endif
#define SPM_SUSPEND_SLEEP_PCM_FLAG (SPM_FLAG_DISABLE_DDR_DFS | \
SPM_FLAG_DISABLE_EMI_DFS | \
SPM_FLAG_DISABLE_VLP_PDN | \
SPM_FLAG_DISABLE_BUS_DFS | \
SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
SPM_FLAG_ENABLE_AOV | \
SPM_FLAG_ENABLE_MD_MUMTAS | \
SPM_FLAG_SRAM_SLEEP_CTRL)
#define SPM_SUSPEND_SLEEP_PCM_FLAG1 (SPM_FLAG1_ENABLE_ALCO_TRACE | \
SPM_FLAG1_ENABLE_SUSPEND_AVS)
#define SPM_SUSPEND_PCM_FLAG (SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_MCUPM_PDN | \
SPM_FLAG_DISABLE_VLP_PDN | \
SPM_FLAG_DISABLE_DDR_DFS | \
SPM_FLAG_DISABLE_EMI_DFS | \
SPM_FLAG_DISABLE_BUS_DFS | \
SPM_FLAG_ENABLE_MD_MUMTAS | \
SPM_FLAG_SRAM_SLEEP_CTRL)
#define SPM_SUSPEND_PCM_FLAG1 (SPM_FLAG1_ENABLE_ALCO_TRACE | \
SPM_FLAG1_ENABLE_SUSPEND_AVS | \
SPM_FLAG1_ENABLE_CSOPLU_OFF)
/* Suspend spm power control */
#define __WAKE_SRC_FOR_SUSPEND_COMMON__ ( \
(R12_KP_IRQ_B) | \
(R12_APWDT_EVENT_B) | \
(R12_CONN2AP_WAKEUP_B) | \
(R12_EINT_EVENT_B) | \
(R12_CONN_WDT_IRQ_B) | \
(R12_CCIF0_EVENT_B) | \
(R12_CCIF1_EVENT_B) | \
(R12_SCP2SPM_WAKEUP_B) | \
(R12_ADSP2SPM_WAKEUP_B) | \
(R12_USB0_CDSC_B) | \
(R12_USB0_POWERDWN_B) | \
(R12_UART_EVENT_B) |\
(R12_SYS_TIMER_EVENT_B) | \
(R12_EINT_EVENT_SECURE_B) | \
(R12_SYS_CIRQ_IRQ_B) | \
(R12_MD_WDT_B) | \
(R12_AP2AP_PEER_WAKEUP_B) | \
(R12_CPU_WAKEUP) | \
(R12_APUSYS_WAKE_HOST_B)|\
(R12_PCIE_WAKE_B))
#if defined(CFG_MICROTRUST_TEE_SUPPORT)
#define WAKE_SRC_FOR_SUSPEND \
(__WAKE_SRC_FOR_SUSPEND_COMMON__)
#else
#define WAKE_SRC_FOR_SUSPEND \
(__WAKE_SRC_FOR_SUSPEND_COMMON__ | \
R12_SEJ_B)
#endif
static uint32_t gpio_bk1;
static uint32_t gpio_bk2;
static uint32_t gpio_bk3;
static struct pwr_ctrl suspend_ctrl = {
.wake_src = WAKE_SRC_FOR_SUSPEND,
/* SPM_SRC_REQ */
.reg_spm_adsp_mailbox_req = 0,
.reg_spm_apsrc_req = 0,
.reg_spm_ddren_req = 0,
.reg_spm_dvfs_req = 0,
.reg_spm_emi_req = 0,
.reg_spm_f26m_req = 0,
.reg_spm_infra_req = 0,
.reg_spm_pmic_req = 0,
.reg_spm_scp_mailbox_req = 0,
.reg_spm_sspm_mailbox_req = 0,
.reg_spm_sw_mailbox_req = 0,
.reg_spm_vcore_req = 1,
.reg_spm_vrf18_req = 0,
.adsp_mailbox_state = 0,
.apsrc_state = 0,
.ddren_state = 0,
.dvfs_state = 0,
.emi_state = 0,
.f26m_state = 0,
.infra_state = 0,
.pmic_state = 0,
.scp_mailbox_state = 0,
.sspm_mailbox_state = 0,
.sw_mailbox_state = 0,
.vcore_state = 0,
.vrf18_state = 0,
/* SPM_SRC_MASK_0 */
.reg_apifr_apsrc_rmb = 0,
.reg_apifr_ddren_rmb = 0,
.reg_apifr_emi_rmb = 0,
.reg_apifr_infra_rmb = 0,
.reg_apifr_pmic_rmb = 0,
.reg_apifr_srcclkena_mb = 0,
.reg_apifr_vcore_rmb = 0,
.reg_apifr_vrf18_rmb = 0,
.reg_apu_apsrc_rmb = 1,
.reg_apu_ddren_rmb = 0,
.reg_apu_emi_rmb = 1,
.reg_apu_infra_rmb = 1,
.reg_apu_pmic_rmb = 1,
.reg_apu_srcclkena_mb = 1,
.reg_apu_vcore_rmb = 1,
.reg_apu_vrf18_rmb = 1,
.reg_audio_apsrc_rmb = 1,
.reg_audio_ddren_rmb = 0,
.reg_audio_emi_rmb = 1,
.reg_audio_infra_rmb = 1,
.reg_audio_pmic_rmb = 0,
.reg_audio_srcclkena_mb = 1,
.reg_audio_vcore_rmb = 1,
.reg_audio_vrf18_rmb = 1,
/* SPM_SRC_MASK_1 */
.reg_audio_dsp_apsrc_rmb = 1,
.reg_audio_dsp_ddren_rmb = 0,
.reg_audio_dsp_emi_rmb = 1,
.reg_audio_dsp_infra_rmb = 1,
.reg_audio_dsp_pmic_rmb = 1,
.reg_audio_dsp_srcclkena_mb = 1,
.reg_audio_dsp_vcore_rmb = 1,
.reg_audio_dsp_vrf18_rmb = 1,
.reg_cam_apsrc_rmb = 0,
.reg_cam_ddren_rmb = 0,
.reg_cam_emi_rmb = 0,
.reg_cam_infra_rmb = 0,
.reg_cam_pmic_rmb = 0,
.reg_cam_srcclkena_mb = 0,
.reg_cam_vrf18_rmb = 0,
.reg_ccif_apsrc_rmb = 0xfff,
/* SPM_SRC_MASK_2 */
.reg_ccif_emi_rmb = 0xfff,
.reg_ccif_infra_rmb = 0xfff,
/* SPM_SRC_MASK_3 */
.reg_ccif_pmic_rmb = 0xfff,
.reg_ccif_srcclkena_mb = 0xfff,
/* SPM_SRC_MASK_4 */
.reg_ccif_vcore_rmb = 0xfff,
.reg_ccif_vrf18_rmb = 0xfff,
.reg_ccu_apsrc_rmb = 0,
.reg_ccu_ddren_rmb = 0,
.reg_ccu_emi_rmb = 0,
.reg_ccu_infra_rmb = 0,
.reg_ccu_pmic_rmb = 0,
.reg_ccu_srcclkena_mb = 0,
.reg_ccu_vrf18_rmb = 0,
.reg_cg_check_apsrc_rmb = 0,
/* SPM_SRC_MASK_5 */
.reg_cg_check_ddren_rmb = 0,
.reg_cg_check_emi_rmb = 0,
.reg_cg_check_infra_rmb = 0,
.reg_cg_check_pmic_rmb = 0,
.reg_cg_check_srcclkena_mb = 0,
.reg_cg_check_vcore_rmb = 1,
.reg_cg_check_vrf18_rmb = 0,
.reg_cksys_apsrc_rmb = 1,
.reg_cksys_ddren_rmb = 0,
.reg_cksys_emi_rmb = 1,
.reg_cksys_infra_rmb = 1,
.reg_cksys_pmic_rmb = 1,
.reg_cksys_srcclkena_mb = 1,
.reg_cksys_vcore_rmb = 1,
.reg_cksys_vrf18_rmb = 1,
.reg_cksys_1_apsrc_rmb = 1,
.reg_cksys_1_ddren_rmb = 0,
.reg_cksys_1_emi_rmb = 1,
.reg_cksys_1_infra_rmb = 1,
.reg_cksys_1_pmic_rmb = 1,
.reg_cksys_1_srcclkena_mb = 1,
.reg_cksys_1_vcore_rmb = 1,
.reg_cksys_1_vrf18_rmb = 1,
/* SPM_SRC_MASK_6 */
.reg_cksys_2_apsrc_rmb = 1,
.reg_cksys_2_ddren_rmb = 0,
.reg_cksys_2_emi_rmb = 1,
.reg_cksys_2_infra_rmb = 1,
.reg_cksys_2_pmic_rmb = 1,
.reg_cksys_2_srcclkena_mb = 1,
.reg_cksys_2_vcore_rmb = 1,
.reg_cksys_2_vrf18_rmb = 1,
.reg_conn_apsrc_rmb = 1,
.reg_conn_ddren_rmb = 0,
.reg_conn_emi_rmb = 1,
.reg_conn_infra_rmb = 1,
.reg_conn_pmic_rmb = 1,
.reg_conn_srcclkena_mb = 1,
.reg_conn_srcclkenb_mb = 1,
.reg_conn_vcore_rmb = 1,
.reg_conn_vrf18_rmb = 1,
.reg_corecfg_apsrc_rmb = 0,
.reg_corecfg_ddren_rmb = 0,
.reg_corecfg_emi_rmb = 0,
.reg_corecfg_infra_rmb = 0,
.reg_corecfg_pmic_rmb = 0,
.reg_corecfg_srcclkena_mb = 0,
.reg_corecfg_vcore_rmb = 0,
.reg_corecfg_vrf18_rmb = 0,
/* SPM_SRC_MASK_7 */
.reg_cpueb_apsrc_rmb = 1,
.reg_cpueb_ddren_rmb = 0,
.reg_cpueb_emi_rmb = 1,
.reg_cpueb_infra_rmb = 1,
.reg_cpueb_pmic_rmb = 1,
.reg_cpueb_srcclkena_mb = 1,
.reg_cpueb_vcore_rmb = 0,
.reg_cpueb_vrf18_rmb = 1,
.reg_disp0_apsrc_rmb = 0,
.reg_disp0_ddren_rmb = 0,
.reg_disp0_emi_rmb = 0,
.reg_disp0_infra_rmb = 0,
.reg_disp0_pmic_rmb = 0,
.reg_disp0_srcclkena_mb = 0,
.reg_disp0_vrf18_rmb = 0,
.reg_disp1_apsrc_rmb = 0,
.reg_disp1_ddren_rmb = 0,
.reg_disp1_emi_rmb = 0,
.reg_disp1_infra_rmb = 0,
.reg_disp1_pmic_rmb = 0,
.reg_disp1_srcclkena_mb = 0,
.reg_disp1_vrf18_rmb = 0,
.reg_dpm_apsrc_rmb = 0xf,
.reg_dpm_ddren_rmb = 0xf,
/* SPM_SRC_MASK_8 */
.reg_dpm_emi_rmb = 0xf,
.reg_dpm_infra_rmb = 0xf,
.reg_dpm_pmic_rmb = 0xf,
.reg_dpm_srcclkena_mb = 0xf,
.reg_dpm_vcore_rmb = 0xf,
.reg_dpm_vrf18_rmb = 0xf,
.reg_dpmaif_apsrc_rmb = 1,
.reg_dpmaif_ddren_rmb = 0,
.reg_dpmaif_emi_rmb = 1,
.reg_dpmaif_infra_rmb = 1,
.reg_dpmaif_pmic_rmb = 1,
.reg_dpmaif_srcclkena_mb = 1,
.reg_dpmaif_vcore_rmb = 1,
.reg_dpmaif_vrf18_rmb = 1,
/* SPM_SRC_MASK_9 */
.reg_dvfsrc_level_rmb = 1,
.reg_emisys_apsrc_rmb = 0,
.reg_emisys_ddren_rmb = 0,
.reg_emisys_emi_rmb = 0,
.reg_emisys_infra_rmb = 0,
.reg_emisys_pmic_rmb = 0,
.reg_emisys_srcclkena_mb = 0,
.reg_emisys_vcore_rmb = 0,
.reg_emisys_vrf18_rmb = 0,
.reg_gce_apsrc_rmb = 0,
.reg_gce_ddren_rmb = 0,
.reg_gce_emi_rmb = 0,
.reg_gce_infra_rmb = 0,
.reg_gce_pmic_rmb = 0,
.reg_gce_srcclkena_mb = 0,
.reg_gce_vcore_rmb = 0,
.reg_gce_vrf18_rmb = 0,
.reg_gpueb_apsrc_rmb = 1,
.reg_gpueb_ddren_rmb = 0,
.reg_gpueb_emi_rmb = 1,
.reg_gpueb_infra_rmb = 1,
.reg_gpueb_pmic_rmb = 1,
.reg_gpueb_srcclkena_mb = 1,
.reg_gpueb_vcore_rmb = 1,
.reg_gpueb_vrf18_rmb = 1,
.reg_hwccf_apsrc_rmb = 1,
.reg_hwccf_ddren_rmb = 0,
.reg_hwccf_emi_rmb = 1,
.reg_hwccf_infra_rmb = 1,
.reg_hwccf_pmic_rmb = 1,
.reg_hwccf_srcclkena_mb = 1,
.reg_hwccf_vcore_rmb = 1,
/* SPM_SRC_MASK_10 */
.reg_hwccf_vrf18_rmb = 1,
.reg_img_apsrc_rmb = 0,
.reg_img_ddren_rmb = 0,
.reg_img_emi_rmb = 0,
.reg_img_infra_rmb = 0,
.reg_img_pmic_rmb = 0,
.reg_img_srcclkena_mb = 0,
.reg_img_vrf18_rmb = 0,
.reg_infrasys_apsrc_rmb = 0,
.reg_infrasys_ddren_rmb = 0,
.reg_infrasys_emi_rmb = 0,
.reg_infrasys_infra_rmb = 0,
.reg_infrasys_pmic_rmb = 0,
.reg_infrasys_srcclkena_mb = 0,
.reg_infrasys_vcore_rmb = 0,
.reg_infrasys_vrf18_rmb = 0,
.reg_ipic_infra_rmb = 1,
.reg_ipic_vrf18_rmb = 1,
.reg_mcu_apsrc_rmb = 1,
.reg_mcu_ddren_rmb = 0,
.reg_mcu_emi_rmb = 1,
.reg_mcu_infra_rmb = 1,
.reg_mcu_pmic_rmb = 1,
.reg_mcu_srcclkena_mb = 1,
.reg_mcu_vcore_rmb = 0,
.reg_mcu_vrf18_rmb = 1,
.reg_md_apsrc_rmb = 1,
.reg_md_ddren_rmb = 0,
.reg_md_emi_rmb = 1,
.reg_md_infra_rmb = 1,
.reg_md_pmic_rmb = 1,
.reg_md_srcclkena_mb = 1,
/* SPM_SRC_MASK_11 */
.reg_md_srcclkena1_mb = 1,
.reg_md_vcore_rmb = 1,
.reg_md_vrf18_rmb = 1,
.reg_mm_proc_apsrc_rmb = 1,
.reg_mm_proc_ddren_rmb = 0,
.reg_mm_proc_emi_rmb = 1,
.reg_mm_proc_infra_rmb = 1,
.reg_mm_proc_pmic_rmb = 1,
.reg_mm_proc_srcclkena_mb = 1,
.reg_mm_proc_vcore_rmb = 1,
.reg_mm_proc_vrf18_rmb = 1,
.reg_mml0_apsrc_rmb = 0,
.reg_mml0_ddren_rmb = 0,
.reg_mml0_emi_rmb = 0,
.reg_mml0_infra_rmb = 0,
.reg_mml0_pmic_rmb = 0,
.reg_mml0_srcclkena_mb = 0,
.reg_mml0_vrf18_rmb = 0,
.reg_mml1_apsrc_rmb = 0,
.reg_mml1_ddren_rmb = 0,
.reg_mml1_emi_rmb = 0,
.reg_mml1_infra_rmb = 0,
.reg_mml1_pmic_rmb = 0,
.reg_mml1_srcclkena_mb = 0,
.reg_mml1_vrf18_rmb = 0,
.reg_ovl0_apsrc_rmb = 0,
.reg_ovl0_ddren_rmb = 0,
.reg_ovl0_emi_rmb = 0,
.reg_ovl0_infra_rmb = 0,
.reg_ovl0_pmic_rmb = 0,
.reg_ovl0_srcclkena_mb = 0,
.reg_ovl0_vrf18_rmb = 0,
/* SPM_SRC_MASK_12 */
.reg_ovl1_apsrc_rmb = 0,
.reg_ovl1_ddren_rmb = 0,
.reg_ovl1_emi_rmb = 0,
.reg_ovl1_infra_rmb = 0,
.reg_ovl1_pmic_rmb = 0,
.reg_ovl1_srcclkena_mb = 0,
.reg_ovl1_vrf18_rmb = 0,
.reg_pcie0_apsrc_rmb = 1,
.reg_pcie0_ddren_rmb = 0,
.reg_pcie0_emi_rmb = 1,
.reg_pcie0_infra_rmb = 1,
.reg_pcie0_pmic_rmb = 1,
.reg_pcie0_srcclkena_mb = 1,
.reg_pcie0_vcore_rmb = 1,
.reg_pcie0_vrf18_rmb = 1,
.reg_pcie1_apsrc_rmb = 1,
.reg_pcie1_ddren_rmb = 0,
.reg_pcie1_emi_rmb = 1,
.reg_pcie1_infra_rmb = 1,
.reg_pcie1_pmic_rmb = 1,
.reg_pcie1_srcclkena_mb = 1,
.reg_pcie1_vcore_rmb = 1,
.reg_pcie1_vrf18_rmb = 1,
.reg_perisys_apsrc_rmb = 1,
.reg_perisys_ddren_rmb = 0,
.reg_perisys_emi_rmb = 1,
.reg_perisys_infra_rmb = 1,
.reg_perisys_pmic_rmb = 1,
.reg_perisys_srcclkena_mb = 1,
.reg_perisys_vcore_rmb = 1,
.reg_perisys_vrf18_rmb = 1,
.reg_pmsr_apsrc_rmb = 1,
/* SPM_SRC_MASK_13 */
.reg_pmsr_ddren_rmb = 0,
.reg_pmsr_emi_rmb = 1,
.reg_pmsr_infra_rmb = 1,
.reg_pmsr_pmic_rmb = 1,
.reg_pmsr_srcclkena_mb = 1,
.reg_pmsr_vcore_rmb = 1,
.reg_pmsr_vrf18_rmb = 1,
.reg_scp_apsrc_rmb = 1,
.reg_scp_ddren_rmb = 0,
.reg_scp_emi_rmb = 1,
.reg_scp_infra_rmb = 1,
.reg_scp_pmic_rmb = 1,
.reg_scp_srcclkena_mb = 1,
.reg_scp_vcore_rmb = 1,
.reg_scp_vrf18_rmb = 1,
.reg_spu_hwr_apsrc_rmb = 1,
.reg_spu_hwr_ddren_rmb = 0,
.reg_spu_hwr_emi_rmb = 1,
.reg_spu_hwr_infra_rmb = 1,
.reg_spu_hwr_pmic_rmb = 1,
.reg_spu_hwr_srcclkena_mb = 1,
.reg_spu_hwr_vcore_rmb = 1,
.reg_spu_hwr_vrf18_rmb = 1,
.reg_spu_ise_apsrc_rmb = 1,
.reg_spu_ise_ddren_rmb = 0,
.reg_spu_ise_emi_rmb = 1,
.reg_spu_ise_infra_rmb = 1,
.reg_spu_ise_pmic_rmb = 1,
.reg_spu_ise_srcclkena_mb = 1,
.reg_spu_ise_vcore_rmb = 1,
.reg_spu_ise_vrf18_rmb = 1,
/* SPM_SRC_MASK_14 */
.reg_srcclkeni_infra_rmb = 0x3,
.reg_srcclkeni_pmic_rmb = 0x3,
.reg_srcclkeni_srcclkena_mb = 0x3,
.reg_srcclkeni_vcore_rmb = 0x3,
.reg_sspm_apsrc_rmb = 1,
.reg_sspm_ddren_rmb = 0,
.reg_sspm_emi_rmb = 1,
.reg_sspm_infra_rmb = 1,
.reg_sspm_pmic_rmb = 1,
.reg_sspm_srcclkena_mb = 1,
.reg_sspm_vrf18_rmb = 1,
.reg_ssrsys_apsrc_rmb = 1,
.reg_ssrsys_ddren_rmb = 0,
.reg_ssrsys_emi_rmb = 1,
.reg_ssrsys_infra_rmb = 1,
.reg_ssrsys_pmic_rmb = 1,
.reg_ssrsys_srcclkena_mb = 1,
.reg_ssrsys_vcore_rmb = 1,
.reg_ssrsys_vrf18_rmb = 1,
.reg_ssusb_apsrc_rmb = 1,
.reg_ssusb_ddren_rmb = 0,
.reg_ssusb_emi_rmb = 1,
.reg_ssusb_infra_rmb = 1,
.reg_ssusb_pmic_rmb = 1,
.reg_ssusb_srcclkena_mb = 1,
.reg_ssusb_vcore_rmb = 1,
.reg_ssusb_vrf18_rmb = 1,
.reg_uart_hub_infra_rmb = 1,
/* SPM_SRC_MASK_15 */
.reg_uart_hub_pmic_rmb = 1,
.reg_uart_hub_srcclkena_mb = 1,
.reg_uart_hub_vcore_rmb = 1,
.reg_uart_hub_vrf18_rmb = 1,
.reg_ufs_apsrc_rmb = 1,
.reg_ufs_ddren_rmb = 0,
.reg_ufs_emi_rmb = 1,
.reg_ufs_infra_rmb = 1,
.reg_ufs_pmic_rmb = 1,
.reg_ufs_srcclkena_mb = 1,
.reg_ufs_vcore_rmb = 1,
.reg_ufs_vrf18_rmb = 1,
.reg_vdec_apsrc_rmb = 0,
.reg_vdec_ddren_rmb = 0,
.reg_vdec_emi_rmb = 0,
.reg_vdec_infra_rmb = 0,
.reg_vdec_pmic_rmb = 0,
.reg_vdec_srcclkena_mb = 0,
.reg_vdec_vrf18_rmb = 0,
.reg_venc_apsrc_rmb = 0,
.reg_venc_ddren_rmb = 0,
.reg_venc_emi_rmb = 0,
.reg_venc_infra_rmb = 0,
.reg_venc_pmic_rmb = 0,
.reg_venc_srcclkena_mb = 0,
.reg_venc_vrf18_rmb = 0,
.reg_vlpcfg_apsrc_rmb = 1,
.reg_vlpcfg_ddren_rmb = 0,
.reg_vlpcfg_emi_rmb = 1,
.reg_vlpcfg_infra_rmb = 1,
.reg_vlpcfg_pmic_rmb = 1,
.reg_vlpcfg_srcclkena_mb = 1,
/* SPM_SRC_MASK_16 */
.reg_vlpcfg_vcore_rmb = 1,
.reg_vlpcfg_vrf18_rmb = 1,
.reg_vlpcfg1_apsrc_rmb = 1,
.reg_vlpcfg1_ddren_rmb = 0,
.reg_vlpcfg1_emi_rmb = 1,
.reg_vlpcfg1_infra_rmb = 1,
.reg_vlpcfg1_pmic_rmb = 0,
.reg_vlpcfg1_srcclkena_mb = 1,
.reg_vlpcfg1_vcore_rmb = 1,
.reg_vlpcfg1_vrf18_rmb = 1,
/* SPM_EVENT_CON_MISC */
.reg_srcclken_fast_resp = 0,
.reg_csyspwrup_ack_mask = 1,
/* SPM_SRC_MASK_17 */
.reg_spm_sw_vcore_rmb = 0x3,
.reg_spm_sw_pmic_rmb = 0,
/* SPM_SRC_MASK_18 */
.reg_spm_sw_srcclkena_mb = 0,
/* SPM_WAKE_MASK*/
.reg_wake_mask = 0x81322012,
/* SPM_WAKEUP_EVENT_EXT_MASK */
.reg_ext_wake_mask = 0xFFFFFFFF,
/*SW flag setting */
.pcm_flags = SPM_SUSPEND_PCM_FLAG,
.pcm_flags1 = SPM_SUSPEND_PCM_FLAG1,
};
static struct suspend_dbg_ctrl suspend_spm_dbg_ext = {
.sleep_suspend_cnt = 0,
};
static struct dbg_ctrl suspend_spm_dbg = {
.count = 0,
.duration = 0,
.ext = &suspend_spm_dbg_ext,
};
static struct spm_lp_stat suspend_lp_stat;
struct spm_lp_scen __spm_suspend = {
.pwrctrl = &suspend_ctrl,
.dbgctrl = &suspend_spm_dbg,
.lpstat = &suspend_lp_stat,
};
static uint8_t bak_spm_vcore_req;
int mt_spm_suspend_mode_set(enum mt_spm_suspend_mode mode, void *prv)
{
if (mode == MT_SPM_SUSPEND_SLEEP) {
suspend_ctrl.pcm_flags = SPM_SUSPEND_SLEEP_PCM_FLAG;
suspend_ctrl.pcm_flags1 = SPM_SUSPEND_SLEEP_PCM_FLAG1;
suspend_ctrl.reg_spm_vcore_req = 1;
} else {
suspend_ctrl.pcm_flags = SPM_SUSPEND_PCM_FLAG;
suspend_ctrl.pcm_flags1 = SPM_SUSPEND_PCM_FLAG1;
}
return 0;
}
static void spm_CSOPLU_ctrl_leave_suspend(void)
{
mmio_setbits_32(SPM_RSV_CSOPLU_REQ, (0x1));
}
static void mt_spm_suspend_ec_pin(void)
{
gpio_bk1 = mmio_read_32(MODE_BACKUP_REG);
gpio_bk2 = mmio_read_32(DIR_BACKUP_REG);
gpio_bk3 = mmio_read_32(DOUT_BACKUP_REG);
mmio_write_32(MODE_SET, SET_GPIO_MODE);
gpio_set_direction(EC_SUSPEND_BK_PIN, GPIO_DIR_OUT);
/* GPIO111 LOW */
gpio_set_value(EC_SUSPEND_BK_PIN, GPIO_LEVEL_LOW);
/* GPIO38 LOW */
gpio_set_value(EC_SUSPEND_PIN, GPIO_LEVEL_LOW);
}
static void mt_spm_resume_ec_pin(void)
{
/* GPIO38 HIGH */
gpio_set_value(EC_SUSPEND_PIN, GPIO_LEVEL_HIGH);
/* GPIO111 HIGH */
gpio_set_value(EC_SUSPEND_BK_PIN, GPIO_LEVEL_HIGH);
udelay(10);
mmio_write_32(MODE_BACKUP_REG, gpio_bk1);
mmio_write_32(DIR_BACKUP_REG, gpio_bk2);
mmio_write_32(DOUT_BACKUP_REG, gpio_bk3);
}
int mt_spm_suspend_enter(int state_id,
uint32_t ext_opand, uint32_t resource_req)
{
int ret = 0;
bak_spm_vcore_req = suspend_ctrl.reg_spm_vcore_req;
/* if FMAudio, ADSP, USB headset is active, change to sleep mode */
if (ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE)
mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SLEEP,
&resource_req);
else
mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SYSTEM_PDN,
&resource_req);
mmio_write_32(SPM2SW_MAILBOX_0, 0x1);
ext_opand |= MT_SPM_EX_OP_DEVICES_SAVE;
#if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
/* Notify vcoredvfs suspend enter */
spm_vcorefs_plat_suspend();
#endif
ret = spm_conservation(state_id, ext_opand,
&__spm_suspend, resource_req);
if (ret == 0) {
struct mt_lp_publish_event event = {
.id = MT_LPM_PUBEVENTS_SYS_POWER_OFF,
.val.u32 = 0,
.level = MT_LP_SYSPOWER_LEVEL_SUSPEND,
};
MT_LP_SUSPEND_PUBLISH_EVENT(&event);
}
mt_spm_suspend_ec_pin();
return ret;
}
void mt_spm_suspend_resume(int state_id, uint32_t ext_opand,
struct wake_status **status)
{
struct mt_lp_publish_event event;
struct wake_status *st = NULL;
ext_opand |= MT_SPM_EX_OP_DEVICES_SAVE;
mt_spm_resume_ec_pin();
spm_conservation_finish(state_id, ext_opand, &__spm_suspend, &st);
spm_CSOPLU_ctrl_leave_suspend();
mt_spm_update_lp_stat(&suspend_lp_stat);
#if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
/* Notify vcoredvfs suspend enter */
spm_vcorefs_plat_resume();
mmio_write_32(SPM2SW_MAILBOX_0, 0x0);
#endif
/*****************************************
* If FMAudio, ADSP, USB headset is active,
* change back to suspend mode and counting in resume
*****************************************/
if (ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) {
mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SYSTEM_PDN, NULL);
suspend_spm_dbg_ext.sleep_suspend_cnt += 1;
}
suspend_ctrl.reg_spm_vcore_req = bak_spm_vcore_req;
suspend_spm_dbg.count += 1;
event.id = MT_LPM_PUBEVENTS_SYS_POWER_ON;
event.val.u32 = 0;
event.level = MT_LP_SYSPOWER_LEVEL_SUSPEND;
if (st) {
if (st->tr.comm.r12 & R12_AP2AP_PEER_WAKEUP_B)
event.val.u32 = MT_LPM_WAKE_MD_WAKEUP_DPMAIF;
if (st->tr.comm.r12 & R12_CCIF0_EVENT_B)
event.val.u32 = MT_LPM_WAKE_MD_WAKEUP_CCIF0;
if (st->tr.comm.r12 & R12_CCIF1_EVENT_B)
event.val.u32 = MT_LPM_WAKE_MD_WAKEUP_CCIF1;
}
if (status)
*status = st;
MT_LP_SUSPEND_PUBLISH_EVENT(&event);
}
int mt_spm_suspend_get_spm_lp(struct spm_lp_scen **lp)
{
if (!lp)
return -1;
*lp = &__spm_suspend;
return 0;
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_SUSPEND_H
#define MT_SPM_SUSPEND_H
#include <mt_spm_internal.h>
struct suspend_dbg_ctrl {
uint32_t sleep_suspend_cnt;
};
enum mt_spm_suspend_mode {
MT_SPM_SUSPEND_SYSTEM_PDN,
MT_SPM_SUSPEND_SLEEP,
};
int mt_spm_suspend_mode_set(enum mt_spm_suspend_mode mode, void *prv);
int mt_spm_suspend_enter(int state_id, uint32_t ext_opand,
uint32_t reosuce_req);
void mt_spm_suspend_resume(int state_id, uint32_t ext_opand,
struct wake_status **status);
int mt_spm_suspend_get_spm_lp(struct spm_lp_scen **lp);
#endif /* MT_SPM_SUSPEND_H */

View file

@ -0,0 +1,609 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <drivers/spmi_api.h>
#include <lib/pm/mtk_pm.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <pmic_wrap/inc/mt_spm_pmic_wrap.h>
#define VCORE_BASE_UV 0
#ifdef MT8196_VCORE_SUPPORT
#define VCORE_STEP_UV 6250
#else
#define VCORE_STEP_UV 5000
#endif
#define VCORE_UV_TO_PMIC(uv) /* pmic >= uv */ \
((((uv) - VCORE_BASE_UV) + (VCORE_STEP_UV - 1)) / VCORE_STEP_UV)
#define VCORE_PMIC_TO_UV(pmic) \
(((pmic) * VCORE_STEP_UV) + VCORE_BASE_UV)
#define VSRAM_BASE_UV 0
#define VSRAM_STEP_UV 6250
#define VSRAM_UV_TO_PMIC(uv) /* pmic >= uv */ \
((((uv) - VSRAM_BASE_UV) + (VSRAM_STEP_UV - 1)) / VSRAM_STEP_UV)
#define VSRAM_PMIC_TO_UV(pmic) \
(((pmic) * VSRAM_STEP_UV) + VSRAM_BASE_UV)
static int spm_dvfs_init_done;
static struct pwr_ctrl vcorefs_ctrl = {
.wake_src = R12_CPU_WAKEUP,
/* default VCORE DVFS is disabled */
.pcm_flags = (SPM_FLAG_RUN_COMMON_SCENARIO |
SPM_FLAG_DISABLE_VCORE_DVS |
SPM_FLAG_DISABLE_DDR_DFS |
SPM_FLAG_DISABLE_EMI_DFS | SPM_FLAG_DISABLE_BUS_DFS),
/* SPM_SRC_REQ */
.reg_spm_adsp_mailbox_req = 0,
.reg_spm_apsrc_req = 0,
.reg_spm_ddren_req = 0,
.reg_spm_dvfs_req = 0,
.reg_spm_emi_req = 0,
.reg_spm_f26m_req = 0,
.reg_spm_infra_req = 0,
.reg_spm_pmic_req = 0,
.reg_spm_scp_mailbox_req = 0,
.reg_spm_sspm_mailbox_req = 0,
.reg_spm_sw_mailbox_req = 0,
.reg_spm_vcore_req = 1,
.reg_spm_vrf18_req = 0,
.adsp_mailbox_state = 0,
.apsrc_state = 0,
.ddren_state = 0,
.dvfs_state = 0,
.emi_state = 0,
.f26m_state = 0,
.infra_state = 0,
.pmic_state = 0,
.scp_mailbox_state = 0,
.sspm_mailbox_state = 0,
.sw_mailbox_state = 0,
.vcore_state = 0,
.vrf18_state = 0,
/* SPM_SRC_MASK_0 */
.reg_apifr_apsrc_rmb = 0,
.reg_apifr_ddren_rmb = 0,
.reg_apifr_emi_rmb = 0,
.reg_apifr_infra_rmb = 0,
.reg_apifr_pmic_rmb = 0,
.reg_apifr_srcclkena_mb = 0,
.reg_apifr_vcore_rmb = 0,
.reg_apifr_vrf18_rmb = 0,
.reg_apu_apsrc_rmb = 1,
.reg_apu_ddren_rmb = 0,
.reg_apu_emi_rmb = 1,
.reg_apu_infra_rmb = 1,
.reg_apu_pmic_rmb = 1,
.reg_apu_srcclkena_mb = 1,
.reg_apu_vcore_rmb = 1,
.reg_apu_vrf18_rmb = 1,
.reg_audio_apsrc_rmb = 1,
.reg_audio_ddren_rmb = 0,
.reg_audio_emi_rmb = 1,
.reg_audio_infra_rmb = 1,
.reg_audio_pmic_rmb = 1,
.reg_audio_srcclkena_mb = 1,
.reg_audio_vcore_rmb = 1,
.reg_audio_vrf18_rmb = 1,
/* SPM_SRC_MASK_1 */
.reg_audio_dsp_apsrc_rmb = 1,
.reg_audio_dsp_ddren_rmb = 0,
.reg_audio_dsp_emi_rmb = 1,
.reg_audio_dsp_infra_rmb = 1,
.reg_audio_dsp_pmic_rmb = 1,
.reg_audio_dsp_srcclkena_mb = 1,
.reg_audio_dsp_vcore_rmb = 1,
.reg_audio_dsp_vrf18_rmb = 1,
.reg_cam_apsrc_rmb = 0,
.reg_cam_ddren_rmb = 0,
.reg_cam_emi_rmb = 0,
.reg_cam_infra_rmb = 0,
.reg_cam_pmic_rmb = 0,
.reg_cam_srcclkena_mb = 0,
.reg_cam_vrf18_rmb = 0,
.reg_ccif_apsrc_rmb = 0xfff,
/* SPM_SRC_MASK_2 */
.reg_ccif_emi_rmb = 0xfff,
.reg_ccif_infra_rmb = 0xfff,
/* SPM_SRC_MASK_3 */
.reg_ccif_pmic_rmb = 0xfff,
.reg_ccif_srcclkena_mb = 0xfff,
/* SPM_SRC_MASK_4 */
.reg_ccif_vcore_rmb = 0xfff,
.reg_ccif_vrf18_rmb = 0xfff,
.reg_ccu_apsrc_rmb = 0,
.reg_ccu_ddren_rmb = 0,
.reg_ccu_emi_rmb = 0,
.reg_ccu_infra_rmb = 0,
.reg_ccu_pmic_rmb = 0,
.reg_ccu_srcclkena_mb = 0,
.reg_ccu_vrf18_rmb = 0,
.reg_cg_check_apsrc_rmb = 0,
/* SPM_SRC_MASK_5 */
.reg_cg_check_ddren_rmb = 0,
.reg_cg_check_emi_rmb = 0,
.reg_cg_check_infra_rmb = 0,
.reg_cg_check_pmic_rmb = 0,
.reg_cg_check_srcclkena_mb = 0,
.reg_cg_check_vcore_rmb = 1,
.reg_cg_check_vrf18_rmb = 0,
.reg_cksys_apsrc_rmb = 1,
.reg_cksys_ddren_rmb = 0,
.reg_cksys_emi_rmb = 1,
.reg_cksys_infra_rmb = 1,
.reg_cksys_pmic_rmb = 1,
.reg_cksys_srcclkena_mb = 1,
.reg_cksys_vcore_rmb = 1,
.reg_cksys_vrf18_rmb = 1,
.reg_cksys_1_apsrc_rmb = 1,
.reg_cksys_1_ddren_rmb = 0,
.reg_cksys_1_emi_rmb = 1,
.reg_cksys_1_infra_rmb = 1,
.reg_cksys_1_pmic_rmb = 1,
.reg_cksys_1_srcclkena_mb = 1,
.reg_cksys_1_vcore_rmb = 1,
.reg_cksys_1_vrf18_rmb = 1,
/* SPM_SRC_MASK_6 */
.reg_cksys_2_apsrc_rmb = 1,
.reg_cksys_2_ddren_rmb = 0,
.reg_cksys_2_emi_rmb = 1,
.reg_cksys_2_infra_rmb = 1,
.reg_cksys_2_pmic_rmb = 1,
.reg_cksys_2_srcclkena_mb = 1,
.reg_cksys_2_vcore_rmb = 1,
.reg_cksys_2_vrf18_rmb = 1,
.reg_conn_apsrc_rmb = 1,
.reg_conn_ddren_rmb = 0,
.reg_conn_emi_rmb = 1,
.reg_conn_infra_rmb = 1,
.reg_conn_pmic_rmb = 1,
.reg_conn_srcclkena_mb = 1,
.reg_conn_srcclkenb_mb = 1,
.reg_conn_vcore_rmb = 1,
.reg_conn_vrf18_rmb = 1,
.reg_corecfg_apsrc_rmb = 0,
.reg_corecfg_ddren_rmb = 0,
.reg_corecfg_emi_rmb = 0,
.reg_corecfg_infra_rmb = 0,
.reg_corecfg_pmic_rmb = 0,
.reg_corecfg_srcclkena_mb = 0,
.reg_corecfg_vcore_rmb = 0,
.reg_corecfg_vrf18_rmb = 0,
/* SPM_SRC_MASK_7 */
.reg_cpueb_apsrc_rmb = 1,
.reg_cpueb_ddren_rmb = 0,
.reg_cpueb_emi_rmb = 1,
.reg_cpueb_infra_rmb = 1,
.reg_cpueb_pmic_rmb = 1,
.reg_cpueb_srcclkena_mb = 1,
.reg_cpueb_vcore_rmb = 1,
.reg_cpueb_vrf18_rmb = 1,
.reg_disp0_apsrc_rmb = 0,
.reg_disp0_ddren_rmb = 0,
.reg_disp0_emi_rmb = 0,
.reg_disp0_infra_rmb = 0,
.reg_disp0_pmic_rmb = 0,
.reg_disp0_srcclkena_mb = 0,
.reg_disp0_vrf18_rmb = 0,
.reg_disp1_apsrc_rmb = 0,
.reg_disp1_ddren_rmb = 0,
.reg_disp1_emi_rmb = 0,
.reg_disp1_infra_rmb = 0,
.reg_disp1_pmic_rmb = 0,
.reg_disp1_srcclkena_mb = 0,
.reg_disp1_vrf18_rmb = 0,
.reg_dpm_apsrc_rmb = 0xf,
.reg_dpm_ddren_rmb = 0xf,
/* SPM_SRC_MASK_8 */
.reg_dpm_emi_rmb = 0xf,
.reg_dpm_infra_rmb = 0xf,
.reg_dpm_pmic_rmb = 0xf,
.reg_dpm_srcclkena_mb = 0xf,
.reg_dpm_vcore_rmb = 0xf,
.reg_dpm_vrf18_rmb = 0xf,
.reg_dpmaif_apsrc_rmb = 1,
.reg_dpmaif_ddren_rmb = 0,
.reg_dpmaif_emi_rmb = 1,
.reg_dpmaif_infra_rmb = 1,
.reg_dpmaif_pmic_rmb = 1,
.reg_dpmaif_srcclkena_mb = 1,
.reg_dpmaif_vcore_rmb = 1,
.reg_dpmaif_vrf18_rmb = 1,
/* SPM_SRC_MASK_9 */
.reg_dvfsrc_level_rmb = 1,
.reg_emisys_apsrc_rmb = 0,
.reg_emisys_ddren_rmb = 0,
.reg_emisys_emi_rmb = 0,
.reg_emisys_infra_rmb = 0,
.reg_emisys_pmic_rmb = 0,
.reg_emisys_srcclkena_mb = 0,
.reg_emisys_vcore_rmb = 0,
.reg_emisys_vrf18_rmb = 0,
.reg_gce_apsrc_rmb = 0,
.reg_gce_ddren_rmb = 0,
.reg_gce_emi_rmb = 0,
.reg_gce_infra_rmb = 0,
.reg_gce_pmic_rmb = 0,
.reg_gce_srcclkena_mb = 0,
.reg_gce_vcore_rmb = 0,
.reg_gce_vrf18_rmb = 0,
.reg_gpueb_apsrc_rmb = 1,
.reg_gpueb_ddren_rmb = 0,
.reg_gpueb_emi_rmb = 1,
.reg_gpueb_infra_rmb = 1,
.reg_gpueb_pmic_rmb = 1,
.reg_gpueb_srcclkena_mb = 1,
.reg_gpueb_vcore_rmb = 1,
.reg_gpueb_vrf18_rmb = 1,
.reg_hwccf_apsrc_rmb = 1,
.reg_hwccf_ddren_rmb = 0,
.reg_hwccf_emi_rmb = 1,
.reg_hwccf_infra_rmb = 1,
.reg_hwccf_pmic_rmb = 1,
.reg_hwccf_srcclkena_mb = 1,
.reg_hwccf_vcore_rmb = 1,
/* SPM_SRC_MASK_10 */
.reg_hwccf_vrf18_rmb = 1,
.reg_img_apsrc_rmb = 0,
.reg_img_ddren_rmb = 0,
.reg_img_emi_rmb = 0,
.reg_img_infra_rmb = 0,
.reg_img_pmic_rmb = 0,
.reg_img_srcclkena_mb = 0,
.reg_img_vrf18_rmb = 0,
.reg_infrasys_apsrc_rmb = 0,
.reg_infrasys_ddren_rmb = 0,
.reg_infrasys_emi_rmb = 0,
.reg_infrasys_infra_rmb = 0,
.reg_infrasys_pmic_rmb = 0,
.reg_infrasys_srcclkena_mb = 0,
.reg_infrasys_vcore_rmb = 0,
.reg_infrasys_vrf18_rmb = 0,
.reg_ipic_infra_rmb = 1,
.reg_ipic_vrf18_rmb = 1,
.reg_mcu_apsrc_rmb = 1,
.reg_mcu_ddren_rmb = 0,
.reg_mcu_emi_rmb = 1,
.reg_mcu_infra_rmb = 1,
.reg_mcu_pmic_rmb = 1,
.reg_mcu_srcclkena_mb = 1,
.reg_mcu_vcore_rmb = 1,
.reg_mcu_vrf18_rmb = 1,
.reg_md_apsrc_rmb = 1,
.reg_md_ddren_rmb = 0,
.reg_md_emi_rmb = 1,
.reg_md_infra_rmb = 1,
.reg_md_pmic_rmb = 1,
.reg_md_srcclkena_mb = 1,
/* SPM_SRC_MASK_11 */
.reg_md_srcclkena1_mb = 1,
.reg_md_vcore_rmb = 1,
.reg_md_vrf18_rmb = 1,
.reg_mm_proc_apsrc_rmb = 1,
.reg_mm_proc_ddren_rmb = 0,
.reg_mm_proc_emi_rmb = 1,
.reg_mm_proc_infra_rmb = 1,
.reg_mm_proc_pmic_rmb = 1,
.reg_mm_proc_srcclkena_mb = 1,
.reg_mm_proc_vcore_rmb = 1,
.reg_mm_proc_vrf18_rmb = 1,
.reg_mml0_apsrc_rmb = 0,
.reg_mml0_ddren_rmb = 0,
.reg_mml0_emi_rmb = 0,
.reg_mml0_infra_rmb = 0,
.reg_mml0_pmic_rmb = 0,
.reg_mml0_srcclkena_mb = 0,
.reg_mml0_vrf18_rmb = 0,
.reg_mml1_apsrc_rmb = 0,
.reg_mml1_ddren_rmb = 0,
.reg_mml1_emi_rmb = 0,
.reg_mml1_infra_rmb = 0,
.reg_mml1_pmic_rmb = 0,
.reg_mml1_srcclkena_mb = 0,
.reg_mml1_vrf18_rmb = 0,
.reg_ovl0_apsrc_rmb = 0,
.reg_ovl0_ddren_rmb = 0,
.reg_ovl0_emi_rmb = 0,
.reg_ovl0_infra_rmb = 0,
.reg_ovl0_pmic_rmb = 0,
.reg_ovl0_srcclkena_mb = 0,
.reg_ovl0_vrf18_rmb = 0,
/* SPM_SRC_MASK_12 */
.reg_ovl1_apsrc_rmb = 0,
.reg_ovl1_ddren_rmb = 0,
.reg_ovl1_emi_rmb = 0,
.reg_ovl1_infra_rmb = 0,
.reg_ovl1_pmic_rmb = 0,
.reg_ovl1_srcclkena_mb = 0,
.reg_ovl1_vrf18_rmb = 0,
.reg_pcie0_apsrc_rmb = 1,
.reg_pcie0_ddren_rmb = 0,
.reg_pcie0_emi_rmb = 1,
.reg_pcie0_infra_rmb = 1,
.reg_pcie0_pmic_rmb = 1,
.reg_pcie0_srcclkena_mb = 1,
.reg_pcie0_vcore_rmb = 1,
.reg_pcie0_vrf18_rmb = 1,
.reg_pcie1_apsrc_rmb = 1,
.reg_pcie1_ddren_rmb = 0,
.reg_pcie1_emi_rmb = 1,
.reg_pcie1_infra_rmb = 1,
.reg_pcie1_pmic_rmb = 1,
.reg_pcie1_srcclkena_mb = 1,
.reg_pcie1_vcore_rmb = 1,
.reg_pcie1_vrf18_rmb = 1,
.reg_perisys_apsrc_rmb = 1,
.reg_perisys_ddren_rmb = 0,
.reg_perisys_emi_rmb = 1,
.reg_perisys_infra_rmb = 1,
.reg_perisys_pmic_rmb = 1,
.reg_perisys_srcclkena_mb = 1,
.reg_perisys_vcore_rmb = 1,
.reg_perisys_vrf18_rmb = 1,
.reg_pmsr_apsrc_rmb = 1,
/* SPM_SRC_MASK_13 */
.reg_pmsr_ddren_rmb = 0,
.reg_pmsr_emi_rmb = 1,
.reg_pmsr_infra_rmb = 1,
.reg_pmsr_pmic_rmb = 1,
.reg_pmsr_srcclkena_mb = 1,
.reg_pmsr_vcore_rmb = 1,
.reg_pmsr_vrf18_rmb = 1,
.reg_scp_apsrc_rmb = 1,
.reg_scp_ddren_rmb = 0,
.reg_scp_emi_rmb = 1,
.reg_scp_infra_rmb = 1,
.reg_scp_pmic_rmb = 1,
.reg_scp_srcclkena_mb = 1,
.reg_scp_vcore_rmb = 1,
.reg_scp_vrf18_rmb = 1,
.reg_spu_hwr_apsrc_rmb = 1,
.reg_spu_hwr_ddren_rmb = 0,
.reg_spu_hwr_emi_rmb = 1,
.reg_spu_hwr_infra_rmb = 1,
.reg_spu_hwr_pmic_rmb = 1,
.reg_spu_hwr_srcclkena_mb = 1,
.reg_spu_hwr_vcore_rmb = 1,
.reg_spu_hwr_vrf18_rmb = 1,
.reg_spu_ise_apsrc_rmb = 1,
.reg_spu_ise_ddren_rmb = 0,
.reg_spu_ise_emi_rmb = 1,
.reg_spu_ise_infra_rmb = 1,
.reg_spu_ise_pmic_rmb = 1,
.reg_spu_ise_srcclkena_mb = 1,
.reg_spu_ise_vcore_rmb = 1,
.reg_spu_ise_vrf18_rmb = 1,
/* SPM_SRC_MASK_14 */
.reg_srcclkeni_infra_rmb = 0x3,
.reg_srcclkeni_pmic_rmb = 0x3,
.reg_srcclkeni_srcclkena_mb = 0x3,
.reg_srcclkeni_vcore_rmb = 0x3,
.reg_sspm_apsrc_rmb = 1,
.reg_sspm_ddren_rmb = 0,
.reg_sspm_emi_rmb = 1,
.reg_sspm_infra_rmb = 1,
.reg_sspm_pmic_rmb = 1,
.reg_sspm_srcclkena_mb = 1,
.reg_sspm_vrf18_rmb = 1,
.reg_ssrsys_apsrc_rmb = 1,
.reg_ssrsys_ddren_rmb = 0,
.reg_ssrsys_emi_rmb = 1,
.reg_ssrsys_infra_rmb = 1,
.reg_ssrsys_pmic_rmb = 1,
.reg_ssrsys_srcclkena_mb = 1,
.reg_ssrsys_vcore_rmb = 1,
.reg_ssrsys_vrf18_rmb = 1,
.reg_ssusb_apsrc_rmb = 1,
.reg_ssusb_ddren_rmb = 0,
.reg_ssusb_emi_rmb = 1,
.reg_ssusb_infra_rmb = 1,
.reg_ssusb_pmic_rmb = 1,
.reg_ssusb_srcclkena_mb = 1,
.reg_ssusb_vcore_rmb = 1,
.reg_ssusb_vrf18_rmb = 1,
.reg_uart_hub_infra_rmb = 1,
/* SPM_SRC_MASK_15 */
.reg_uart_hub_pmic_rmb = 1,
.reg_uart_hub_srcclkena_mb = 1,
.reg_uart_hub_vcore_rmb = 1,
.reg_uart_hub_vrf18_rmb = 1,
.reg_ufs_apsrc_rmb = 1,
.reg_ufs_ddren_rmb = 0,
.reg_ufs_emi_rmb = 1,
.reg_ufs_infra_rmb = 1,
.reg_ufs_pmic_rmb = 1,
.reg_ufs_srcclkena_mb = 1,
.reg_ufs_vcore_rmb = 1,
.reg_ufs_vrf18_rmb = 1,
.reg_vdec_apsrc_rmb = 0,
.reg_vdec_ddren_rmb = 0,
.reg_vdec_emi_rmb = 0,
.reg_vdec_infra_rmb = 0,
.reg_vdec_pmic_rmb = 0,
.reg_vdec_srcclkena_mb = 0,
.reg_vdec_vrf18_rmb = 0,
.reg_venc_apsrc_rmb = 0,
.reg_venc_ddren_rmb = 0,
.reg_venc_emi_rmb = 0,
.reg_venc_infra_rmb = 0,
.reg_venc_pmic_rmb = 0,
.reg_venc_srcclkena_mb = 0,
.reg_venc_vrf18_rmb = 0,
.reg_vlpcfg_apsrc_rmb = 1,
.reg_vlpcfg_ddren_rmb = 0,
.reg_vlpcfg_emi_rmb = 1,
.reg_vlpcfg_infra_rmb = 1,
.reg_vlpcfg_pmic_rmb = 1,
.reg_vlpcfg_srcclkena_mb = 1,
/* SPM_SRC_MASK_16 */
.reg_vlpcfg_vcore_rmb = 1,
.reg_vlpcfg_vrf18_rmb = 1,
.reg_vlpcfg1_apsrc_rmb = 1,
.reg_vlpcfg1_ddren_rmb = 0,
.reg_vlpcfg1_emi_rmb = 1,
.reg_vlpcfg1_infra_rmb = 1,
.reg_vlpcfg1_pmic_rmb = 1,
.reg_vlpcfg1_srcclkena_mb = 1,
.reg_vlpcfg1_vcore_rmb = 1,
.reg_vlpcfg1_vrf18_rmb = 1,
/* SPM_EVENT_CON_MISC */
.reg_srcclken_fast_resp = 0,
.reg_csyspwrup_ack_mask = 1,
/* SPM_SRC_MASK_17 */
/* SPM D7X WA for wakeup source */
.reg_spm_sw_vcore_rmb = 0x3,
.reg_spm_sw_pmic_rmb = 0,
/* SPM_SRC_MASK_18 */
.reg_spm_sw_srcclkena_mb = 0,
/* SPM_WAKE_MASK*/
#ifdef MT_SPM_COMMON_SODI_SUPPORT
#if defined(CFG_MICROTRUST_TEE_SUPPORT)
.reg_wake_mask = 0x81302012,
#else
.reg_wake_mask = 0x89302012,
#endif
#else
.reg_wake_mask = 0xEFFFFFF7,
#endif
.reg_ext_wake_mask = 0xFFFFFFFF,
};
struct spm_lp_scen __spm_vcorefs = {
.pwrctrl = &vcorefs_ctrl,
};
static int get_vsram_pmic_voltage(void)
{
uint8_t vsram_pmic = 0x78;
int spmi_ret = 0;
#ifdef CONFIG_MTK_SPMI
struct spmi_device *spmi_dev;
spmi_dev = get_spmi_device(SPMI_MASTER_1, SPMI_SLAVE_4);
if (spmi_dev == NULL)
return vsram_pmic;
spmi_ret = spmi_ext_register_readl(spmi_dev, 0x250, &vsram_pmic, 1);
#endif
if (spmi_ret != 0)
vsram_pmic = 0x78;
return vsram_pmic;
}
static int get_vcore_pmic_voltage(void)
{
uint8_t vcore_pmic = 0x91;
int spmi_ret = 0;
#ifdef CONFIG_MTK_SPMI
struct spmi_device *spmi_dev;
uint16_t vcore_addr;
vcore_addr = (uint16_t)((mmio_read_32(SPM_PWRAP_CMD0) >> 16) & 0xFFFF);
spmi_dev = get_spmi_device(SPMI_MASTER_P_1, SPMI_SLAVE_8);
if (spmi_dev == NULL)
return vcore_pmic;
spmi_ret = spmi_ext_register_readl(spmi_dev, vcore_addr, &vcore_pmic, 1);
#endif
if (spmi_ret != 0)
vcore_pmic = 0x91;
return vcore_pmic;
}
void spm_dvfsfw_init(uint64_t boot_up_opp, uint64_t dram_issue)
{
uint32_t pmic_val;
pmic_val = get_vsram_pmic_voltage();
pmic_val = VCORE_UV_TO_PMIC(VSRAM_PMIC_TO_UV(pmic_val));
mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_ALLINONE, CMD_17, pmic_val);
pmic_val = get_vcore_pmic_voltage();
mmio_write_32(PCM_WDT_LATCH_SPARE_5, pmic_val);
if (spm_dvfs_init_done)
return;
mmio_clrsetbits_32(SPM_DVFS_CON, SPM_DVFS_FORCE_ENABLE_LSB, SPM_DVFSRC_ENABLE_LSB);
mmio_write_32(SPM_SW_RSV_3, 0x08000000);
mmio_write_32(SPM_DVS_DFS_LEVEL, 0x10080080);
mmio_write_32(PCM_WDT_LATCH_SPARE_4, 0x08008002);
spm_dvfs_init_done = 1;
}
void __spm_sync_vcore_dvfs_pcm_flags(uint32_t *dest_pcm_flags,
const uint32_t *src_pcm_flags)
{
uint32_t dvfs_mask = SPM_FLAG_DISABLE_VCORE_DVS |
SPM_FLAG_DISABLE_DDR_DFS |
SPM_FLAG_DISABLE_EMI_DFS |
SPM_FLAG_DISABLE_BUS_DFS;
*dest_pcm_flags = (*dest_pcm_flags & (~dvfs_mask)) |
(*src_pcm_flags & dvfs_mask);
}
void __spm_sync_vcore_dvfs_power_control(struct pwr_ctrl *dest_pwr_ctrl,
const struct pwr_ctrl *src_pwr_ctrl)
{
__spm_sync_vcore_dvfs_pcm_flags(&dest_pwr_ctrl->pcm_flags,
&src_pwr_ctrl->pcm_flags);
if (dest_pwr_ctrl->pcm_flags_cust)
__spm_sync_vcore_dvfs_pcm_flags(&dest_pwr_ctrl->pcm_flags_cust,
&src_pwr_ctrl->pcm_flags);
}
void spm_go_to_vcorefs(uint64_t spm_flags)
{
set_pwrctrl_pcm_flags(__spm_vcorefs.pwrctrl, spm_flags);
__spm_set_power_control(__spm_vcorefs.pwrctrl, 0);
__spm_set_wakeup_event(__spm_vcorefs.pwrctrl);
__spm_set_pcm_flags(__spm_vcorefs.pwrctrl);
__spm_send_cpu_wakeup_event();
}

View file

@ -0,0 +1,12 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_VCOREFS_H
#define MT_SPM_VCOREFS_H
void spm_go_to_vcorefs(uint64_t spm_flags);
#endif /* MT_SPM_VCOREFS_H */

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_VCORE_DVFSRC_EXT_H
#define MT_VCORE_DVFSRC_EXT_H
#define MTK_VCORE_DVFS_RES_MEM
int spm_vcorefs_rsc_mem_req(bool request);
#endif /* MT_VCORE_DVFSRC_EXT_H */

View file

@ -0,0 +1,598 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_VCOREFS_REG_6991_H
#define MT_SPM_VCOREFS_REG_6991_H
#include <platform_def.h>
/*************************************************************************
* DVFSRC related constants
*************************************************************************/
#define DVFSRC_BASE (IO_PHYS + 0x0C013000)
#define EFUSEC_BASE (IO_PHYS + 0x03260000)
#define EFUSE_SIZE (0x1000)
#define DVFSRC_REG_SIZE (0x1000)
#define DVFSRC_BASIC_CONTROL (DVFSRC_BASE + 0x0)
#define DVFSRC_BASIC_CONTROL_4 (DVFSRC_BASE + 0xC)
#define DVFSRC_SW_REQ1 (DVFSRC_BASE + 0x10)
#define DVFSRC_SW_REQ2 (DVFSRC_BASE + 0x14)
#define DVFSRC_SW_REQ3 (DVFSRC_BASE + 0x18)
#define DVFSRC_SW_REQ4 (DVFSRC_BASE + 0x1C)
#define DVFSRC_SW_REQ5 (DVFSRC_BASE + 0x20)
#define DVFSRC_SW_REQ6 (DVFSRC_BASE + 0x24)
#define DVFSRC_SW_REQ7 (DVFSRC_BASE + 0x28)
#define DVFSRC_SW_REQ8 (DVFSRC_BASE + 0x2C)
#define DVFSRC_EMI_REQUEST (DVFSRC_BASE + 0x30)
#define DVFSRC_EMI_REQUEST3 (DVFSRC_BASE + 0x38)
#define DVFSRC_EMI_REQUEST5 (DVFSRC_BASE + 0x40)
#define DVFSRC_EMI_QOS0 (DVFSRC_BASE + 0x4C)
#define DVFSRC_EMI_QOS1 (DVFSRC_BASE + 0x50)
#define DVFSRC_EMI_QOS2 (DVFSRC_BASE + 0x54)
#define DVFSRC_EMI_QOS3 (DVFSRC_BASE + 0x58)
#define DVFSRC_EMI_QOS4 (DVFSRC_BASE + 0x5C)
#define DVFSRC_EMI_QOS5 (DVFSRC_BASE + 0x60)
#define DVFSRC_EMI_QOS6 (DVFSRC_BASE + 0x64)
#define DVFSRC_VCORE_REQUEST (DVFSRC_BASE + 0x80)
#define DVFSRC_VCORE_REQUEST3 (DVFSRC_BASE + 0x88)
#define DVFSRC_VCORE_QOS0 (DVFSRC_BASE + 0x94)
#define DVFSRC_VCORE_QOS1 (DVFSRC_BASE + 0x98)
#define DVFSRC_VCORE_QOS2 (DVFSRC_BASE + 0x9C)
#define DVFSRC_VCORE_QOS3 (DVFSRC_BASE + 0xA0)
#define DVFSRC_VCORE_QOS4 (DVFSRC_BASE + 0xA4)
#define DVFSRC_HALT_SW_CONTROL (DVFSRC_BASE + 0xC4)
#define DVFSRC_INT (DVFSRC_BASE + 0xC8)
#define DVFSRC_INT_EN (DVFSRC_BASE + 0xCC)
#define DVFSRC_INT_CLR (DVFSRC_BASE + 0xD0)
#define DVFSRC_BW_MON_WINDOW (DVFSRC_BASE + 0xD4)
#define DVFSRC_BW_MON_THRES_1 (DVFSRC_BASE + 0xD8)
#define DVFSRC_BW_MON_THRES_2 (DVFSRC_BASE + 0xDC)
#define DVFSRC_MD_TURBO (DVFSRC_BASE + 0xE0)
#define DVFSRC_PCIE_VCORE_REQ (DVFSRC_BASE + 0xE4)
#define DVFSRC_VCORE_USER_REQ (DVFSRC_BASE + 0xE8)
#define DVFSRC_BW_USER_REQ (DVFSRC_BASE + 0xEC)
#define DVFSRC_TIMEOUT_NEXTREQ (DVFSRC_BASE + 0xF8)
#define DVFSRC_LEVEL_LABEL_0_1 (DVFSRC_BASE + 0xFC)
#define DVFSRC_LEVEL_LABEL_2_3 (DVFSRC_BASE + 0x100)
#define DVFSRC_LEVEL_LABEL_4_5 (DVFSRC_BASE + 0x104)
#define DVFSRC_LEVEL_LABEL_6_7 (DVFSRC_BASE + 0x108)
#define DVFSRC_LEVEL_LABEL_8_9 (DVFSRC_BASE + 0x10C)
#define DVFSRC_LEVEL_LABEL_10_11 (DVFSRC_BASE + 0x110)
#define DVFSRC_LEVEL_LABEL_12_13 (DVFSRC_BASE + 0x114)
#define DVFSRC_LEVEL_LABEL_14_15 (DVFSRC_BASE + 0x118)
#define DVFSRC_LEVEL_LABEL_16_17 (DVFSRC_BASE + 0x11C)
#define DVFSRC_LEVEL_LABEL_18_19 (DVFSRC_BASE + 0x120)
#define DVFSRC_LEVEL_LABEL_20_21 (DVFSRC_BASE + 0x124)
#define DVFSRC_LEVEL_LABEL_22_23 (DVFSRC_BASE + 0x128)
#define DVFSRC_LEVEL_LABEL_24_25 (DVFSRC_BASE + 0x12C)
#define DVFSRC_LEVEL_LABEL_26_27 (DVFSRC_BASE + 0x130)
#define DVFSRC_LEVEL_LABEL_28_29 (DVFSRC_BASE + 0x134)
#define DVFSRC_LEVEL_LABEL_30_31 (DVFSRC_BASE + 0x138)
#define DVFSRC_LEVEL_LABEL_32_33 (DVFSRC_BASE + 0x13C)
#define DVFSRC_LEVEL_LABEL_34_35 (DVFSRC_BASE + 0x140)
#define DVFSRC_LEVEL_LABEL_36_37 (DVFSRC_BASE + 0x144)
#define DVFSRC_LEVEL_LABEL_38_39 (DVFSRC_BASE + 0x148)
#define DVFSRC_LEVEL_LABEL_40_41 (DVFSRC_BASE + 0x14C)
#define DVFSRC_LEVEL_LABEL_42_43 (DVFSRC_BASE + 0x150)
#define DVFSRC_LEVEL_LABEL_44_45 (DVFSRC_BASE + 0x154)
#define DVFSRC_LEVEL_LABEL_46_47 (DVFSRC_BASE + 0x158)
#define DVFSRC_LEVEL_LABEL_48_49 (DVFSRC_BASE + 0x15C)
#define DVFSRC_LEVEL_LABEL_50_51 (DVFSRC_BASE + 0x160)
#define DVFSRC_LEVEL_LABEL_52_53 (DVFSRC_BASE + 0x164)
#define DVFSRC_LEVEL_LABEL_54_55 (DVFSRC_BASE + 0x168)
#define DVFSRC_LEVEL_LABEL_56_57 (DVFSRC_BASE + 0x16C)
#define DVFSRC_LEVEL_LABEL_58_59 (DVFSRC_BASE + 0x170)
#define DVFSRC_LEVEL_LABEL_60_61 (DVFSRC_BASE + 0x174)
#define DVFSRC_LEVEL_LABEL_62_63 (DVFSRC_BASE + 0x178)
#define DVFSRC_SW_BW_0 (DVFSRC_BASE + 0x1DC)
#define DVFSRC_SW_BW_1 (DVFSRC_BASE + 0x1E0)
#define DVFSRC_SW_BW_2 (DVFSRC_BASE + 0x1E4)
#define DVFSRC_SW_BW_3 (DVFSRC_BASE + 0x1E8)
#define DVFSRC_SW_BW_4 (DVFSRC_BASE + 0x1EC)
#define DVFSRC_SW_BW_5 (DVFSRC_BASE + 0x1F0)
#define DVFSRC_SW_BW_6 (DVFSRC_BASE + 0x1F4)
#define DVFSRC_SW_BW_7 (DVFSRC_BASE + 0x1F8)
#define DVFSRC_SW_BW_8 (DVFSRC_BASE + 0x1FC)
#define DVFSRC_SW_BW_9 (DVFSRC_BASE + 0x200)
#define DVFSRC_QOS_EN (DVFSRC_BASE + 0x204)
#define DVFSRC_ISP_HRT (DVFSRC_BASE + 0x20C)
#define DVFSRC_HRT_BW_BASE (DVFSRC_BASE + 0x210)
#define DVFSRC_SEC_SW_REQ (DVFSRC_BASE + 0x214)
#define DVFSRC_EMI_MON_DEBOUNCE_TIME (DVFSRC_BASE + 0x218)
#define DVFSRC_MD_LATENCY_IMPROVE (DVFSRC_BASE + 0x21C)
#define DVFSRC_DEBOUNCE_TIME (DVFSRC_BASE + 0x220)
#define DVFSRC_LEVEL_MASK_MD_1 (DVFSRC_BASE + 0x224)
#define DVFSRC_LEVEL_MASK_MD_2 (DVFSRC_BASE + 0x228)
#define DVFSRC_DEFAULT_OPP_1 (DVFSRC_BASE + 0x22C)
#define DVFSRC_DEFAULT_OPP_2 (DVFSRC_BASE + 0x230)
#define DVFSRC_95MD_SCEN_EMI0 (DVFSRC_BASE + 0x234)
#define DVFSRC_95MD_SCEN_EMI1 (DVFSRC_BASE + 0x238)
#define DVFSRC_95MD_SCEN_EMI2 (DVFSRC_BASE + 0x23C)
#define DVFSRC_95MD_SCEN_EMI3 (DVFSRC_BASE + 0x240)
#define DVFSRC_95MD_SCEN_EMI0_T (DVFSRC_BASE + 0x244)
#define DVFSRC_95MD_SCEN_EMI1_T (DVFSRC_BASE + 0x248)
#define DVFSRC_95MD_SCEN_EMI2_T (DVFSRC_BASE + 0x24C)
#define DVFSRC_95MD_SCEN_EMI3_T (DVFSRC_BASE + 0x250)
#define DVFSRC_95MD_SCEN_EMIU (DVFSRC_BASE + 0x254)
#define DVFSRC_95MD_SCEN_BW0 (DVFSRC_BASE + 0x258)
#define DVFSRC_95MD_SCEN_BW1 (DVFSRC_BASE + 0x25C)
#define DVFSRC_95MD_SCEN_BW2 (DVFSRC_BASE + 0x260)
#define DVFSRC_95MD_SCEN_BW3 (DVFSRC_BASE + 0x264)
#define DVFSRC_95MD_SCEN_BW0_T (DVFSRC_BASE + 0x268)
#define DVFSRC_95MD_SCEN_BW1_T (DVFSRC_BASE + 0x26C)
#define DVFSRC_95MD_SCEN_BW2_T (DVFSRC_BASE + 0x270)
#define DVFSRC_95MD_SCEN_BW3_T (DVFSRC_BASE + 0x274)
#define DVFSRC_95MD_SCEN_BWU (DVFSRC_BASE + 0x278)
#define DVFSRC_MD_LEVEL_SW_REG (DVFSRC_BASE + 0x27C)
#define DVFSRC_RSRV_0 (DVFSRC_BASE + 0x280)
#define DVFSRC_RSRV_1 (DVFSRC_BASE + 0x284)
#define DVFSRC_RSRV_2 (DVFSRC_BASE + 0x288)
#define DVFSRC_RSRV_3 (DVFSRC_BASE + 0x28C)
#define DVFSRC_RSRV_4 (DVFSRC_BASE + 0x290)
#define DVFSRC_RSRV_5 (DVFSRC_BASE + 0x294)
#define DVFSRC_SPM_RESEND (DVFSRC_BASE + 0x298)
#define DVFSRC_DEBUG_STA_0 (DVFSRC_BASE + 0x29C)
#define DVFSRC_DEBUG_STA_1 (DVFSRC_BASE + 0x2A0)
#define DVFSRC_DEBUG_STA_2 (DVFSRC_BASE + 0x2A4)
#define DVFSRC_DEBUG_STA_3 (DVFSRC_BASE + 0x2A8)
#define DVFSRC_DEBUG_STA_4 (DVFSRC_BASE + 0x2AC)
#define DVFSRC_DEBUG_STA_5 (DVFSRC_BASE + 0x2B0)
#define DVFSRC_DEBUG_STA_6 (DVFSRC_BASE + 0x2B4)
#define DVFSRC_DEBUG_STA_8 (DVFSRC_BASE + 0x2BC)
#define DVFSRC_DEBUG_STA_9 (DVFSRC_BASE + 0x2C0)
#define DVFSRC_DEBUG_STA_10 (DVFSRC_BASE + 0x2C4)
#define DVFSRC_DDR_REQUEST (DVFSRC_BASE + 0x2C8)
#define DVFSRC_DDR_REQUEST3 (DVFSRC_BASE + 0x2D0)
#define DVFSRC_DDR_REQUEST5 (DVFSRC_BASE + 0x2D8)
#define DVFSRC_DDR_QOS0 (DVFSRC_BASE + 0x2E8)
#define DVFSRC_DDR_QOS1 (DVFSRC_BASE + 0x2EC)
#define DVFSRC_DDR_QOS2 (DVFSRC_BASE + 0x2F0)
#define DVFSRC_DDR_QOS3 (DVFSRC_BASE + 0x2F4)
#define DVFSRC_DDR_QOS4 (DVFSRC_BASE + 0x2F8)
#define DVFSRC_DDR_QOS5 (DVFSRC_BASE + 0x2FC)
#define DVFSRC_DDR_QOS6 (DVFSRC_BASE + 0x300)
#define DVFSRC_RSRV_6 (DVFSRC_BASE + 0x304)
#define DVFSRC_RSRV_7 (DVFSRC_BASE + 0x308)
#define DVFSRC_RSRV_8 (DVFSRC_BASE + 0x30C)
#define DVFSRC_RSRV_9 (DVFSRC_BASE + 0x310)
#define DVFSRC_RSRV_10 (DVFSRC_BASE + 0x314)
#define DVFSRC_RSRV_11 (DVFSRC_BASE + 0x318)
#define DVFSRC_HRT_REQ_MD_URG (DVFSRC_BASE + 0x320)
#define DVFSRC_HRT_REQ_MD_BW_0 (DVFSRC_BASE + 0x324)
#define DVFSRC_HRT_REQ_MD_BW_1 (DVFSRC_BASE + 0x328)
#define DVFSRC_HRT_REQ_MD_BW_2 (DVFSRC_BASE + 0x32C)
#define DVFSRC_HRT_REQ_MD_BW_3 (DVFSRC_BASE + 0x330)
#define DVFSRC_HRT_REQ_MD_BW_4 (DVFSRC_BASE + 0x334)
#define DVFSRC_HRT_REQ_MD_BW_5 (DVFSRC_BASE + 0x338)
#define DVFSRC_HRT_REQ_MD_BW_6 (DVFSRC_BASE + 0x33C)
#define DVFSRC_HRT_REQ_MD_BW_7 (DVFSRC_BASE + 0x340)
#define DVFSRC_HRT_REQ_MD_BW_8 (DVFSRC_BASE + 0x344)
#define DVFSRC_HRT_REQ_MD_BW_9 (DVFSRC_BASE + 0x348)
#define DVFSRC_HRT_REQ_MD_BW_10 (DVFSRC_BASE + 0x34C)
#define DVFSRC_HRT1_REQ_MD_BW_0 (DVFSRC_BASE + 0x350)
#define DVFSRC_HRT1_REQ_MD_BW_1 (DVFSRC_BASE + 0x354)
#define DVFSRC_HRT1_REQ_MD_BW_2 (DVFSRC_BASE + 0x358)
#define DVFSRC_HRT1_REQ_MD_BW_3 (DVFSRC_BASE + 0x35C)
#define DVFSRC_HRT1_REQ_MD_BW_4 (DVFSRC_BASE + 0x360)
#define DVFSRC_HRT1_REQ_MD_BW_5 (DVFSRC_BASE + 0x364)
#define DVFSRC_HRT1_REQ_MD_BW_6 (DVFSRC_BASE + 0x368)
#define DVFSRC_HRT1_REQ_MD_BW_7 (DVFSRC_BASE + 0x36C)
#define DVFSRC_HRT1_REQ_MD_BW_8 (DVFSRC_BASE + 0x370)
#define DVFSRC_HRT1_REQ_MD_BW_9 (DVFSRC_BASE + 0x374)
#define DVFSRC_HRT1_REQ_MD_BW_10 (DVFSRC_BASE + 0x378)
#define DVFSRC_HRT_REQUEST (DVFSRC_BASE + 0x380)
#define DVFSRC_HRT_HIGH_3 (DVFSRC_BASE + 0x384)
#define DVFSRC_HRT_HIGH_2 (DVFSRC_BASE + 0x388)
#define DVFSRC_HRT_HIGH_1 (DVFSRC_BASE + 0x38C)
#define DVFSRC_HRT_HIGH (DVFSRC_BASE + 0x390)
#define DVFSRC_HRT_LOW_3 (DVFSRC_BASE + 0x394)
#define DVFSRC_HRT_LOW_2 (DVFSRC_BASE + 0x398)
#define DVFSRC_HRT_LOW_1 (DVFSRC_BASE + 0x39C)
#define DVFSRC_HRT_LOW (DVFSRC_BASE + 0x3A0)
#define DVFSRC_DDR_ADD_REQUEST (DVFSRC_BASE + 0x3A4)
#define DVFSRC_EMI_ADD_REQUEST (DVFSRC_BASE + 0x3A8)
#define DVFSRC_LAST (DVFSRC_BASE + 0x3AC)
#define DVFSRC_LAST_L (DVFSRC_BASE + 0x3B0)
#define DVFSRC_MD_SCENARIO (DVFSRC_BASE + 0x3B4)
#define DVFSRC_RECORD_0_0 (DVFSRC_BASE + 0x3B8)
#define DVFSRC_RECORD_0_1 (DVFSRC_BASE + 0x3BC)
#define DVFSRC_RECORD_0_2 (DVFSRC_BASE + 0x3C0)
#define DVFSRC_RECORD_0_3 (DVFSRC_BASE + 0x3C4)
#define DVFSRC_RECORD_0_4 (DVFSRC_BASE + 0x3C8)
#define DVFSRC_RECORD_0_5 (DVFSRC_BASE + 0x3CC)
#define DVFSRC_RECORD_0_6 (DVFSRC_BASE + 0x3D0)
#define DVFSRC_RECORD_0_7 (DVFSRC_BASE + 0x3D4)
#define DVFSRC_RECORD_1_0 (DVFSRC_BASE + 0x3D8)
#define DVFSRC_RECORD_1_1 (DVFSRC_BASE + 0x3DC)
#define DVFSRC_RECORD_1_2 (DVFSRC_BASE + 0x3E0)
#define DVFSRC_RECORD_1_3 (DVFSRC_BASE + 0x3E4)
#define DVFSRC_RECORD_1_4 (DVFSRC_BASE + 0x3E8)
#define DVFSRC_RECORD_1_5 (DVFSRC_BASE + 0x3EC)
#define DVFSRC_RECORD_1_6 (DVFSRC_BASE + 0x3F0)
#define DVFSRC_RECORD_1_7 (DVFSRC_BASE + 0x3F4)
#define DVFSRC_RECORD_2_0 (DVFSRC_BASE + 0x3F8)
#define DVFSRC_RECORD_2_1 (DVFSRC_BASE + 0x3FC)
#define DVFSRC_RECORD_2_2 (DVFSRC_BASE + 0x400)
#define DVFSRC_RECORD_2_3 (DVFSRC_BASE + 0x404)
#define DVFSRC_RECORD_2_4 (DVFSRC_BASE + 0x408)
#define DVFSRC_RECORD_2_5 (DVFSRC_BASE + 0x40C)
#define DVFSRC_RECORD_2_6 (DVFSRC_BASE + 0x410)
#define DVFSRC_RECORD_2_7 (DVFSRC_BASE + 0x414)
#define DVFSRC_RECORD_3_0 (DVFSRC_BASE + 0x418)
#define DVFSRC_RECORD_3_1 (DVFSRC_BASE + 0x41C)
#define DVFSRC_RECORD_3_2 (DVFSRC_BASE + 0x420)
#define DVFSRC_RECORD_3_3 (DVFSRC_BASE + 0x424)
#define DVFSRC_RECORD_3_4 (DVFSRC_BASE + 0x428)
#define DVFSRC_RECORD_3_5 (DVFSRC_BASE + 0x42C)
#define DVFSRC_RECORD_3_6 (DVFSRC_BASE + 0x430)
#define DVFSRC_RECORD_3_7 (DVFSRC_BASE + 0x434)
#define DVFSRC_RECORD_4_0 (DVFSRC_BASE + 0x438)
#define DVFSRC_RECORD_4_1 (DVFSRC_BASE + 0x43C)
#define DVFSRC_RECORD_4_2 (DVFSRC_BASE + 0x440)
#define DVFSRC_RECORD_4_3 (DVFSRC_BASE + 0x444)
#define DVFSRC_RECORD_4_4 (DVFSRC_BASE + 0x448)
#define DVFSRC_RECORD_4_5 (DVFSRC_BASE + 0x44C)
#define DVFSRC_RECORD_4_6 (DVFSRC_BASE + 0x450)
#define DVFSRC_RECORD_4_7 (DVFSRC_BASE + 0x454)
#define DVFSRC_RECORD_5_0 (DVFSRC_BASE + 0x458)
#define DVFSRC_RECORD_5_1 (DVFSRC_BASE + 0x45C)
#define DVFSRC_RECORD_5_2 (DVFSRC_BASE + 0x460)
#define DVFSRC_RECORD_5_3 (DVFSRC_BASE + 0x464)
#define DVFSRC_RECORD_5_4 (DVFSRC_BASE + 0x468)
#define DVFSRC_RECORD_5_5 (DVFSRC_BASE + 0x46C)
#define DVFSRC_RECORD_5_6 (DVFSRC_BASE + 0x470)
#define DVFSRC_RECORD_5_7 (DVFSRC_BASE + 0x474)
#define DVFSRC_RECORD_6_0 (DVFSRC_BASE + 0x478)
#define DVFSRC_RECORD_6_1 (DVFSRC_BASE + 0x47C)
#define DVFSRC_RECORD_6_2 (DVFSRC_BASE + 0x480)
#define DVFSRC_RECORD_6_3 (DVFSRC_BASE + 0x484)
#define DVFSRC_RECORD_6_4 (DVFSRC_BASE + 0x488)
#define DVFSRC_RECORD_6_5 (DVFSRC_BASE + 0x48C)
#define DVFSRC_RECORD_6_6 (DVFSRC_BASE + 0x490)
#define DVFSRC_RECORD_6_7 (DVFSRC_BASE + 0x494)
#define DVFSRC_RECORD_7_0 (DVFSRC_BASE + 0x498)
#define DVFSRC_RECORD_7_1 (DVFSRC_BASE + 0x49C)
#define DVFSRC_RECORD_7_2 (DVFSRC_BASE + 0x4A0)
#define DVFSRC_RECORD_7_3 (DVFSRC_BASE + 0x4A4)
#define DVFSRC_RECORD_7_4 (DVFSRC_BASE + 0x4A8)
#define DVFSRC_RECORD_7_5 (DVFSRC_BASE + 0x4AC)
#define DVFSRC_RECORD_7_6 (DVFSRC_BASE + 0x4B0)
#define DVFSRC_RECORD_7_7 (DVFSRC_BASE + 0x4B4)
#define DVFSRC_RECORD_0_L_0 (DVFSRC_BASE + 0x4B8)
#define DVFSRC_RECORD_0_L_1 (DVFSRC_BASE + 0x4BC)
#define DVFSRC_RECORD_0_L_2 (DVFSRC_BASE + 0x4C0)
#define DVFSRC_RECORD_0_L_3 (DVFSRC_BASE + 0x4C4)
#define DVFSRC_RECORD_0_L_4 (DVFSRC_BASE + 0x4C8)
#define DVFSRC_RECORD_0_L_5 (DVFSRC_BASE + 0x4CC)
#define DVFSRC_RECORD_0_L_6 (DVFSRC_BASE + 0x4D0)
#define DVFSRC_RECORD_0_L_7 (DVFSRC_BASE + 0x4D4)
#define DVFSRC_RECORD_1_L_0 (DVFSRC_BASE + 0x4D8)
#define DVFSRC_RECORD_1_L_1 (DVFSRC_BASE + 0x4DC)
#define DVFSRC_RECORD_1_L_2 (DVFSRC_BASE + 0x4E0)
#define DVFSRC_RECORD_1_L_3 (DVFSRC_BASE + 0x4E4)
#define DVFSRC_RECORD_1_L_4 (DVFSRC_BASE + 0x4E8)
#define DVFSRC_RECORD_1_L_5 (DVFSRC_BASE + 0x4EC)
#define DVFSRC_RECORD_1_L_6 (DVFSRC_BASE + 0x4F0)
#define DVFSRC_RECORD_1_L_7 (DVFSRC_BASE + 0x4F4)
#define DVFSRC_RECORD_2_L_0 (DVFSRC_BASE + 0x4F8)
#define DVFSRC_RECORD_2_L_1 (DVFSRC_BASE + 0x4FC)
#define DVFSRC_RECORD_2_L_2 (DVFSRC_BASE + 0x500)
#define DVFSRC_RECORD_2_L_3 (DVFSRC_BASE + 0x504)
#define DVFSRC_RECORD_2_L_4 (DVFSRC_BASE + 0x508)
#define DVFSRC_RECORD_2_L_5 (DVFSRC_BASE + 0x50C)
#define DVFSRC_RECORD_2_L_6 (DVFSRC_BASE + 0x510)
#define DVFSRC_RECORD_2_L_7 (DVFSRC_BASE + 0x514)
#define DVFSRC_RECORD_3_L_0 (DVFSRC_BASE + 0x518)
#define DVFSRC_RECORD_3_L_1 (DVFSRC_BASE + 0x51C)
#define DVFSRC_RECORD_3_L_2 (DVFSRC_BASE + 0x520)
#define DVFSRC_RECORD_3_L_3 (DVFSRC_BASE + 0x524)
#define DVFSRC_RECORD_3_L_4 (DVFSRC_BASE + 0x528)
#define DVFSRC_RECORD_3_L_5 (DVFSRC_BASE + 0x52C)
#define DVFSRC_RECORD_3_L_6 (DVFSRC_BASE + 0x530)
#define DVFSRC_RECORD_3_L_7 (DVFSRC_BASE + 0x534)
#define DVFSRC_RECORD_4_L_0 (DVFSRC_BASE + 0x538)
#define DVFSRC_RECORD_4_L_1 (DVFSRC_BASE + 0x53C)
#define DVFSRC_RECORD_4_L_2 (DVFSRC_BASE + 0x540)
#define DVFSRC_RECORD_4_L_3 (DVFSRC_BASE + 0x544)
#define DVFSRC_RECORD_4_L_4 (DVFSRC_BASE + 0x548)
#define DVFSRC_RECORD_4_L_5 (DVFSRC_BASE + 0x54C)
#define DVFSRC_RECORD_4_L_6 (DVFSRC_BASE + 0x550)
#define DVFSRC_RECORD_4_L_7 (DVFSRC_BASE + 0x554)
#define DVFSRC_RECORD_5_L_0 (DVFSRC_BASE + 0x558)
#define DVFSRC_RECORD_5_L_1 (DVFSRC_BASE + 0x55C)
#define DVFSRC_RECORD_5_L_2 (DVFSRC_BASE + 0x560)
#define DVFSRC_RECORD_5_L_3 (DVFSRC_BASE + 0x564)
#define DVFSRC_RECORD_5_L_4 (DVFSRC_BASE + 0x568)
#define DVFSRC_RECORD_5_L_5 (DVFSRC_BASE + 0x56C)
#define DVFSRC_RECORD_5_L_6 (DVFSRC_BASE + 0x570)
#define DVFSRC_RECORD_5_L_7 (DVFSRC_BASE + 0x574)
#define DVFSRC_RECORD_6_L_0 (DVFSRC_BASE + 0x578)
#define DVFSRC_RECORD_6_L_1 (DVFSRC_BASE + 0x57C)
#define DVFSRC_RECORD_6_L_2 (DVFSRC_BASE + 0x580)
#define DVFSRC_RECORD_6_L_3 (DVFSRC_BASE + 0x584)
#define DVFSRC_RECORD_6_L_4 (DVFSRC_BASE + 0x588)
#define DVFSRC_RECORD_6_L_5 (DVFSRC_BASE + 0x58C)
#define DVFSRC_RECORD_6_L_6 (DVFSRC_BASE + 0x590)
#define DVFSRC_RECORD_6_L_7 (DVFSRC_BASE + 0x594)
#define DVFSRC_RECORD_7_L_0 (DVFSRC_BASE + 0x598)
#define DVFSRC_RECORD_7_L_1 (DVFSRC_BASE + 0x59C)
#define DVFSRC_RECORD_7_L_2 (DVFSRC_BASE + 0x5A0)
#define DVFSRC_RECORD_7_L_3 (DVFSRC_BASE + 0x5A4)
#define DVFSRC_RECORD_7_L_4 (DVFSRC_BASE + 0x5A8)
#define DVFSRC_RECORD_7_L_5 (DVFSRC_BASE + 0x5AC)
#define DVFSRC_RECORD_7_L_6 (DVFSRC_BASE + 0x5B0)
#define DVFSRC_RECORD_7_L_7 (DVFSRC_BASE + 0x5B4)
#define DVFSRC_CURRENT_LEVEL_1 (DVFSRC_BASE + 0x5C4)
#define DVFSRC_CURRENT_LEVEL_2 (DVFSRC_BASE + 0x5C8)
#define DVFSRC_TARGET_LEVEL_1 (DVFSRC_BASE + 0x5CC)
#define DVFSRC_TARGET_LEVEL_2 (DVFSRC_BASE + 0x5D0)
#define DVFSRC_CURRENT_FORCE_1 (DVFSRC_BASE + 0x5D4)
#define DVFSRC_CURRENT_FORCE_2 (DVFSRC_BASE + 0x5D8)
#define DVFSRC_TARGET_FORCE_1 (DVFSRC_BASE + 0x5DC)
#define DVFSRC_TARGET_FORCE_2 (DVFSRC_BASE + 0x5E0)
#define DVFSRC_MD_DDR_FLOOR_REQUEST (DVFSRC_BASE + 0x5E4)
#define DVFSRC_QOS_DDR_REQUEST (DVFSRC_BASE + 0x5E8)
#define DVFSRC_FORCE_MASK (DVFSRC_BASE + 0x5EC)
#define DVFSRC_LEVEL_HEX (DVFSRC_BASE + 0x5F0)
#define DVFSRC_AVS_RETRY (DVFSRC_BASE + 0x5F4)
#define DVFSRC_SW_REQ9 (DVFSRC_BASE + 0x5F8)
#define DVFSRC_SW_REQ10 (DVFSRC_BASE + 0x5FC)
#define DVFSRC_SW_REQ11 (DVFSRC_BASE + 0x600)
#define DVFSRC_SW_REQ12 (DVFSRC_BASE + 0x604)
#define DVFSRC_LEVEL_MASK_SW_1 (DVFSRC_BASE + 0x608)
#define DVFSRC_LEVEL_MASK_SW_2 (DVFSRC_BASE + 0x60C)
#define DVFSRC_ACCEPT_RETRY (DVFSRC_BASE + 0x610)
#define DVFSRC_TARGET_LEVEL_SPM_1 (DVFSRC_BASE + 0x614)
#define DVFSRC_TARGET_LEVEL_SPM_2 (DVFSRC_BASE + 0x618)
#define DVFSRC_EMI_REQUEST8 (DVFSRC_BASE + 0x620)
#define DVFSRC_DDR_REQUEST8 (DVFSRC_BASE + 0x62C)
#define DVFSRC_EMI_QOS7 (DVFSRC_BASE + 0x64C)
#define DVFSRC_EMI_QOS8 (DVFSRC_BASE + 0x650)
#define DVFSRC_EMI_QOS9 (DVFSRC_BASE + 0x654)
#define DVFSRC_EMI_QOS10 (DVFSRC_BASE + 0x658)
#define DVFSRC_DDR_QOS7 (DVFSRC_BASE + 0x65C)
#define DVFSRC_DDR_QOS8 (DVFSRC_BASE + 0x660)
#define DVFSRC_DDR_QOS9 (DVFSRC_BASE + 0x664)
#define DVFSRC_DDR_QOS10 (DVFSRC_BASE + 0x668)
#define DVFSRC_HRT_HIGH_7 (DVFSRC_BASE + 0x66C)
#define DVFSRC_HRT_HIGH_6 (DVFSRC_BASE + 0x670)
#define DVFSRC_HRT_HIGH_5 (DVFSRC_BASE + 0x674)
#define DVFSRC_HRT_HIGH_4 (DVFSRC_BASE + 0x678)
#define DVFSRC_HRT_LOW_7 (DVFSRC_BASE + 0x67C)
#define DVFSRC_HRT_LOW_6 (DVFSRC_BASE + 0x680)
#define DVFSRC_HRT_LOW_5 (DVFSRC_BASE + 0x684)
#define DVFSRC_HRT_LOW_4 (DVFSRC_BASE + 0x688)
#define DVFSRC_DDR_ADD_REQUEST_1 (DVFSRC_BASE + 0x68C)
#define DVFSRC_EMI_ADD_REQUEST_1 (DVFSRC_BASE + 0x690)
#define DVFSRC_HRT_REQUEST_1 (DVFSRC_BASE + 0x694)
#define DVFSRC_VCORE_QOS5 (DVFSRC_BASE + 0x69C)
#define DVFSRC_VCORE_QOS6 (DVFSRC_BASE + 0x6A0)
#define DVFSRC_VCORE_QOS7 (DVFSRC_BASE + 0x6A4)
#define DVFSRC_CEILING_SET (DVFSRC_BASE + 0x6A8)
#define DVFSRC_CUR_TARGET_GEAR (DVFSRC_BASE + 0x6AC)
#define DVFSRC_LEVEL_LABEL_64_65 (DVFSRC_BASE + 0x6B0)
#define DVFSRC_LEVEL_LABEL_66_67 (DVFSRC_BASE + 0x6B4)
#define DVFSRC_LEVEL_LABEL_68_69 (DVFSRC_BASE + 0x6B8)
#define DVFSRC_LEVEL_LABEL_70_71 (DVFSRC_BASE + 0x6BC)
#define DVFSRC_LEVEL_LABEL_72_73 (DVFSRC_BASE + 0x6C0)
#define DVFSRC_LEVEL_LABEL_74_75 (DVFSRC_BASE + 0x6C4)
#define DVFSRC_LEVEL_LABEL_76_77 (DVFSRC_BASE + 0x6C8)
#define DVFSRC_LEVEL_LABEL_78_79 (DVFSRC_BASE + 0x6CC)
#define DVFSRC_LEVEL_LABEL_80_81 (DVFSRC_BASE + 0x6D0)
#define DVFSRC_LEVEL_LABEL_82_83 (DVFSRC_BASE + 0x6D4)
#define DVFSRC_LEVEL_LABEL_84_85 (DVFSRC_BASE + 0x6D8)
#define DVFSRC_LEVEL_LABEL_86_87 (DVFSRC_BASE + 0x6DC)
#define DVFSRC_LEVEL_LABEL_88_89 (DVFSRC_BASE + 0x6E0)
#define DVFSRC_LEVEL_LABEL_90_91 (DVFSRC_BASE + 0x6E4)
#define DVFSRC_LEVEL_LABEL_92_93 (DVFSRC_BASE + 0x6E8)
#define DVFSRC_LEVEL_LABEL_94_95 (DVFSRC_BASE + 0x6EC)
#define DVFSRC_LEVEL_LABEL_96_97 (DVFSRC_BASE + 0x6F0)
#define DVFSRC_LEVEL_LABEL_98_99 (DVFSRC_BASE + 0x6F4)
#define DVFSRC_LEVEL_LABEL_100_101 (DVFSRC_BASE + 0x6F8)
#define DVFSRC_LEVEL_LABEL_102_103 (DVFSRC_BASE + 0x6FC)
#define DVFSRC_LEVEL_LABEL_104_105 (DVFSRC_BASE + 0x700)
#define DVFSRC_LEVEL_LABEL_106_107 (DVFSRC_BASE + 0x704)
#define DVFSRC_LEVEL_LABEL_108_109 (DVFSRC_BASE + 0x708)
#define DVFSRC_LEVEL_LABEL_110_111 (DVFSRC_BASE + 0x70C)
#define DVFSRC_LEVEL_LABEL_112_113 (DVFSRC_BASE + 0x710)
#define DVFSRC_LEVEL_LABEL_114_115 (DVFSRC_BASE + 0x714)
#define DVFSRC_LEVEL_LABEL_116_117 (DVFSRC_BASE + 0x718)
#define DVFSRC_LEVEL_LABEL_118_119 (DVFSRC_BASE + 0x71C)
#define DVFSRC_LEVEL_LABEL_120_121 (DVFSRC_BASE + 0x720)
#define DVFSRC_LEVEL_LABEL_122_123 (DVFSRC_BASE + 0x724)
#define DVFSRC_LEVEL_LABEL_124_125 (DVFSRC_BASE + 0x728)
#define DVFSRC_LEVEL_LABEL_126_127 (DVFSRC_BASE + 0x72C)
#define DVFSRC_LEVEL_MASK_MD_3 (DVFSRC_BASE + 0x738)
#define DVFSRC_LEVEL_MASK_MD_4 (DVFSRC_BASE + 0x73C)
#define DVFSRC_DEFAULT_OPP_3 (DVFSRC_BASE + 0x740)
#define DVFSRC_DEFAULT_OPP_4 (DVFSRC_BASE + 0x744)
#define DVFSRC_LEVEL_MASK_SW_3 (DVFSRC_BASE + 0x748)
#define DVFSRC_LEVEL_MASK_SW_4 (DVFSRC_BASE + 0x74C)
#define DVFSRC_TARGET_LEVEL_SPM_3 (DVFSRC_BASE + 0x750)
#define DVFSRC_TARGET_LEVEL_SPM_4 (DVFSRC_BASE + 0x754)
#define DVFSRC_CURRENT_LEVEL_3 (DVFSRC_BASE + 0x758)
#define DVFSRC_CURRENT_LEVEL_4 (DVFSRC_BASE + 0x75C)
#define DVFSRC_TARGET_LEVEL_3 (DVFSRC_BASE + 0x760)
#define DVFSRC_TARGET_LEVEL_4 (DVFSRC_BASE + 0x764)
#define DVFSRC_CURRENT_FORCE_3 (DVFSRC_BASE + 0x768)
#define DVFSRC_CURRENT_FORCE_4 (DVFSRC_BASE + 0x76C)
#define DVFSRC_TARGET_FORCE_3 (DVFSRC_BASE + 0x770)
#define DVFSRC_TARGET_FORCE_4 (DVFSRC_BASE + 0x774)
#define DVFSRC_DDR_REQUEST10 (DVFSRC_BASE + 0x778)
#define DVFSRC_EMI_REQUEST10 (DVFSRC_BASE + 0x77C)
#define DVFSRC_DDR_REQUEST11 (DVFSRC_BASE + 0x780)
#define DVFSRC_EMI_REQUEST11 (DVFSRC_BASE + 0x784)
#define DVFSRC_TARGET_FORCE_5 (DVFSRC_BASE + 0x788)
#define DVFSRC_TARGET_FORCE_6 (DVFSRC_BASE + 0x78C)
#define DVFSRC_TARGET_FORCE_7 (DVFSRC_BASE + 0x790)
#define DVFSRC_TARGET_FORCE_8 (DVFSRC_BASE + 0x794)
#define DVFSRC_PMQOS_HRT_UNIT_SW_BW (DVFSRC_BASE + 0x798)
#define DVFSRC_DISP_HRT_UNIT_SW_BW (DVFSRC_BASE + 0x79C)
#define DVFSRC_ISP_HRT_UNIT_SW_BW (DVFSRC_BASE + 0x7A0)
#define DVFSRC_MD_HRT_UNIT_SW_BW (DVFSRC_BASE + 0x7A4)
#define DVFSRC_HRT_BASE_HRT_UNIT_SW_BW (DVFSRC_BASE + 0x7A8)
#define DVFSRC_APU_HRT_UNIT_SW_BW (DVFSRC_BASE + 0x7AC)
#define DVFSRC_SMMU_HRT_UNIT_SW_BW (DVFSRC_BASE + 0x7B0)
#define DVFSRC_SMAP_CG_SET (DVFSRC_BASE + 0x814)
#define DVFSRC_LEVEL_MASK_MD_5 (DVFSRC_BASE + 0x818)
#define DVFSRC_LEVEL_MASK_MD_6 (DVFSRC_BASE + 0x81C)
#define DVFSRC_LEVEL_MASK_MD_7 (DVFSRC_BASE + 0x820)
#define DVFSRC_LEVEL_MASK_MD_8 (DVFSRC_BASE + 0x824)
#define DVFSRC_DEFAULT_OPP_5 (DVFSRC_BASE + 0x828)
#define DVFSRC_DEFAULT_OPP_6 (DVFSRC_BASE + 0x82C)
#define DVFSRC_DEFAULT_OPP_7 (DVFSRC_BASE + 0x830)
#define DVFSRC_DEFAULT_OPP_8 (DVFSRC_BASE + 0x834)
#define DVFSRC_LEVEL_MASK_SW_5 (DVFSRC_BASE + 0x838)
#define DVFSRC_LEVEL_MASK_SW_6 (DVFSRC_BASE + 0x83C)
#define DVFSRC_LEVEL_MASK_SW_7 (DVFSRC_BASE + 0x840)
#define DVFSRC_LEVEL_MASK_SW_8 (DVFSRC_BASE + 0x844)
#define DVFSRC_TARGET_LEVEL_SPM_5 (DVFSRC_BASE + 0x848)
#define DVFSRC_TARGET_LEVEL_SPM_6 (DVFSRC_BASE + 0x84C)
#define DVFSRC_TARGET_LEVEL_SPM_7 (DVFSRC_BASE + 0x850)
#define DVFSRC_TARGET_LEVEL_SPM_8 (DVFSRC_BASE + 0x854)
#define DVFSRC_CURRENT_LEVEL_5 (DVFSRC_BASE + 0x858)
#define DVFSRC_CURRENT_LEVEL_6 (DVFSRC_BASE + 0x85C)
#define DVFSRC_CURRENT_LEVEL_7 (DVFSRC_BASE + 0x860)
#define DVFSRC_CURRENT_LEVEL_8 (DVFSRC_BASE + 0x864)
#define DVFSRC_TARGET_LEVEL_5 (DVFSRC_BASE + 0x868)
#define DVFSRC_TARGET_LEVEL_6 (DVFSRC_BASE + 0x86C)
#define DVFSRC_TARGET_LEVEL_7 (DVFSRC_BASE + 0x870)
#define DVFSRC_TARGET_LEVEL_8 (DVFSRC_BASE + 0x874)
#define DVFSRC_CURRENT_FORCE_5 (DVFSRC_BASE + 0x878)
#define DVFSRC_CURRENT_FORCE_6 (DVFSRC_BASE + 0x87C)
#define DVFSRC_CURRENT_FORCE_7 (DVFSRC_BASE + 0x880)
#define DVFSRC_CURRENT_FORCE_8 (DVFSRC_BASE + 0x884)
#define DVFSRC_HRT_REQ_MD_BW_11 (DVFSRC_BASE + 0x88C)
#define DVFSRC_HRT_REQ_MD_BW_12 (DVFSRC_BASE + 0x890)
#define DVFSRC_HRT_REQ_MD_BW_13 (DVFSRC_BASE + 0x894)
#define DVFSRC_HRT_REQ_MD_BW_14 (DVFSRC_BASE + 0x898)
#define DVFSRC_HRT_REQ_MD_BW_15 (DVFSRC_BASE + 0x89C)
#define DVFSRC_HRT_REQ_MD_BW_16 (DVFSRC_BASE + 0x8A0)
#define DVFSRC_HRT_REQ_MD_BW_17 (DVFSRC_BASE + 0x8A4)
#define DVFSRC_HRT_REQ_MD_BW_18 (DVFSRC_BASE + 0x8A8)
#define DVFSRC_HRT_REQ_MD_BW_19 (DVFSRC_BASE + 0x8AC)
#define DVFSRC_HRT_REQ_MD_BW_20 (DVFSRC_BASE + 0x8B0)
#define DVFSRC_HRT_REQ_MD_BW_21 (DVFSRC_BASE + 0x8B4)
#define DVFSRC_HRT1_REQ_MD_BW_11 (DVFSRC_BASE + 0x8B8)
#define DVFSRC_HRT1_REQ_MD_BW_12 (DVFSRC_BASE + 0x8BC)
#define DVFSRC_HRT1_REQ_MD_BW_13 (DVFSRC_BASE + 0x8C0)
#define DVFSRC_HRT1_REQ_MD_BW_14 (DVFSRC_BASE + 0x8C4)
#define DVFSRC_HRT1_REQ_MD_BW_15 (DVFSRC_BASE + 0x8C8)
#define DVFSRC_HRT1_REQ_MD_BW_16 (DVFSRC_BASE + 0x8CC)
#define DVFSRC_HRT1_REQ_MD_BW_17 (DVFSRC_BASE + 0x8D0)
#define DVFSRC_HRT1_REQ_MD_BW_18 (DVFSRC_BASE + 0x8D4)
#define DVFSRC_HRT1_REQ_MD_BW_19 (DVFSRC_BASE + 0x8D8)
#define DVFSRC_HRT1_REQ_MD_BW_20 (DVFSRC_BASE + 0x8DC)
#define DVFSRC_HRT1_REQ_MD_BW_21 (DVFSRC_BASE + 0x8E0)
#define DVFSRC_95MD_SCEN_EMI4 (DVFSRC_BASE + 0x904)
#define DVFSRC_95MD_SCEN_EMI5 (DVFSRC_BASE + 0x908)
#define DVFSRC_95MD_SCEN_EMI6 (DVFSRC_BASE + 0x90C)
#define DVFSRC_95MD_SCEN_EMI7 (DVFSRC_BASE + 0x910)
#define DVFSRC_95MD_SCEN_EMI4_T (DVFSRC_BASE + 0x914)
#define DVFSRC_95MD_SCEN_EMI5_T (DVFSRC_BASE + 0x918)
#define DVFSRC_95MD_SCEN_EMI6_T (DVFSRC_BASE + 0x91C)
#define DVFSRC_95MD_SCEN_EMI7_T (DVFSRC_BASE + 0x920)
#define DVFSRC_95MD_SCEN_BW4 (DVFSRC_BASE + 0x924)
#define DVFSRC_95MD_SCEN_BW5 (DVFSRC_BASE + 0x928)
#define DVFSRC_95MD_SCEN_BW6 (DVFSRC_BASE + 0x92C)
#define DVFSRC_95MD_SCEN_BW7 (DVFSRC_BASE + 0x930)
#define DVFSRC_95MD_SCEN_BW4_T (DVFSRC_BASE + 0x934)
#define DVFSRC_95MD_SCEN_BW5_T (DVFSRC_BASE + 0x938)
#define DVFSRC_95MD_SCEN_BW6_T (DVFSRC_BASE + 0x93C)
#define DVFSRC_95MD_SCEN_BW7_T (DVFSRC_BASE + 0x940)
#define DVFSRC_LEVEL_LABEL_128_129 (DVFSRC_BASE + 0x944)
#define DVFSRC_LEVEL_LABEL_130_131 (DVFSRC_BASE + 0x948)
#define DVFSRC_LEVEL_LABEL_132_133 (DVFSRC_BASE + 0x94C)
#define DVFSRC_LEVEL_LABEL_134_135 (DVFSRC_BASE + 0x950)
#define DVFSRC_LEVEL_LABEL_136_137 (DVFSRC_BASE + 0x954)
#define DVFSRC_LEVEL_LABEL_138_139 (DVFSRC_BASE + 0x958)
#define DVFSRC_LEVEL_LABEL_140_141 (DVFSRC_BASE + 0x95C)
#define DVFSRC_LEVEL_LABEL_142_143 (DVFSRC_BASE + 0x960)
#define DVFSRC_LEVEL_LABEL_144_145 (DVFSRC_BASE + 0x964)
#define DVFSRC_LEVEL_LABEL_146_147 (DVFSRC_BASE + 0x968)
#define DVFSRC_LEVEL_LABEL_148_149 (DVFSRC_BASE + 0x96C)
#define DVFSRC_LEVEL_LABEL_150_151 (DVFSRC_BASE + 0x970)
#define DVFSRC_LEVEL_LABEL_152_153 (DVFSRC_BASE + 0x974)
#define DVFSRC_LEVEL_LABEL_154_155 (DVFSRC_BASE + 0x978)
#define DVFSRC_LEVEL_LABEL_156_157 (DVFSRC_BASE + 0x97C)
#define DVFSRC_LEVEL_LABEL_158_159 (DVFSRC_BASE + 0x980)
#define DVFSRC_LEVEL_LABEL_160_161 (DVFSRC_BASE + 0x984)
#define DVFSRC_LEVEL_LABEL_162_163 (DVFSRC_BASE + 0x988)
#define DVFSRC_LEVEL_LABEL_164_165 (DVFSRC_BASE + 0x98C)
#define DVFSRC_LEVEL_LABEL_166_167 (DVFSRC_BASE + 0x990)
#define DVFSRC_LEVEL_LABEL_168_169 (DVFSRC_BASE + 0x994)
#define DVFSRC_LEVEL_LABEL_170_171 (DVFSRC_BASE + 0x998)
#define DVFSRC_LEVEL_LABEL_172_173 (DVFSRC_BASE + 0x99C)
#define DVFSRC_LEVEL_LABEL_174_175 (DVFSRC_BASE + 0x9A0)
#define DVFSRC_LEVEL_LABEL_176_177 (DVFSRC_BASE + 0x9A4)
#define DVFSRC_LEVEL_LABEL_178_179 (DVFSRC_BASE + 0x9A8)
#define DVFSRC_LEVEL_LABEL_180_181 (DVFSRC_BASE + 0x9AC)
#define DVFSRC_LEVEL_LABEL_182_183 (DVFSRC_BASE + 0x9B0)
#define DVFSRC_LEVEL_LABEL_184_185 (DVFSRC_BASE + 0x9B4)
#define DVFSRC_LEVEL_LABEL_186_187 (DVFSRC_BASE + 0x9B8)
#define DVFSRC_LEVEL_LABEL_188_189 (DVFSRC_BASE + 0x9BC)
#define DVFSRC_LEVEL_LABEL_190_191 (DVFSRC_BASE + 0x9C0)
#define DVFSRC_LEVEL_LABEL_192_193 (DVFSRC_BASE + 0x9C4)
#define DVFSRC_LEVEL_LABEL_194_195 (DVFSRC_BASE + 0x9C8)
#define DVFSRC_LEVEL_LABEL_196_197 (DVFSRC_BASE + 0x9CC)
#define DVFSRC_LEVEL_LABEL_198_199 (DVFSRC_BASE + 0x9D0)
#define DVFSRC_LEVEL_LABEL_200_201 (DVFSRC_BASE + 0x9D4)
#define DVFSRC_LEVEL_LABEL_202_203 (DVFSRC_BASE + 0x9D8)
#define DVFSRC_LEVEL_LABEL_204_205 (DVFSRC_BASE + 0x9DC)
#define DVFSRC_LEVEL_LABEL_206_207 (DVFSRC_BASE + 0x9E0)
#define DVFSRC_LEVEL_LABEL_208_209 (DVFSRC_BASE + 0x9E4)
#define DVFSRC_LEVEL_LABEL_210_211 (DVFSRC_BASE + 0x9E8)
#define DVFSRC_LEVEL_LABEL_212_213 (DVFSRC_BASE + 0x9EC)
#define DVFSRC_LEVEL_LABEL_214_215 (DVFSRC_BASE + 0x9F0)
#define DVFSRC_LEVEL_LABEL_216_217 (DVFSRC_BASE + 0x9F4)
#define DVFSRC_LEVEL_LABEL_218_219 (DVFSRC_BASE + 0x9F8)
#define DVFSRC_LEVEL_LABEL_220_221 (DVFSRC_BASE + 0x9FC)
#define DVFSRC_LEVEL_LABEL_222_223 (DVFSRC_BASE + 0xA00)
#define DVFSRC_LEVEL_LABEL_224_225 (DVFSRC_BASE + 0xA04)
#define DVFSRC_LEVEL_LABEL_226_227 (DVFSRC_BASE + 0xA08)
#define DVFSRC_LEVEL_LABEL_228_229 (DVFSRC_BASE + 0xA0C)
#define DVFSRC_LEVEL_LABEL_230_231 (DVFSRC_BASE + 0xA10)
#define DVFSRC_LEVEL_LABEL_232_233 (DVFSRC_BASE + 0xA14)
#define DVFSRC_LEVEL_LABEL_234_235 (DVFSRC_BASE + 0xA18)
#define DVFSRC_LEVEL_LABEL_236_237 (DVFSRC_BASE + 0xA1C)
#define DVFSRC_LEVEL_LABEL_238_239 (DVFSRC_BASE + 0xA20)
#define DVFSRC_LEVEL_LABEL_240_241 (DVFSRC_BASE + 0xA24)
#define DVFSRC_LEVEL_LABEL_242_243 (DVFSRC_BASE + 0xA28)
#define DVFSRC_LEVEL_LABEL_244_245 (DVFSRC_BASE + 0xA2C)
#define DVFSRC_LEVEL_LABEL_246_247 (DVFSRC_BASE + 0xA30)
#define DVFSRC_LEVEL_LABEL_248_249 (DVFSRC_BASE + 0xA34)
#define DVFSRC_LEVEL_LABEL_250_251 (DVFSRC_BASE + 0xA38)
#define DVFSRC_LEVEL_LABEL_252_253 (DVFSRC_BASE + 0xA3C)
#define DVFSRC_LEVEL_LABEL_254_255 (DVFSRC_BASE + 0xA40)
#define DVFSRC_HRT_HIGH_15 (DVFSRC_BASE + 0xA44)
#define DVFSRC_HRT_HIGH_14 (DVFSRC_BASE + 0xA48)
#define DVFSRC_HRT_HIGH_13 (DVFSRC_BASE + 0xA4C)
#define DVFSRC_HRT_HIGH_12 (DVFSRC_BASE + 0xA50)
#define DVFSRC_HRT_HIGH_11 (DVFSRC_BASE + 0xA54)
#define DVFSRC_HRT_HIGH_10 (DVFSRC_BASE + 0xA58)
#define DVFSRC_HRT_HIGH_9 (DVFSRC_BASE + 0xA5C)
#define DVFSRC_HRT_HIGH_8 (DVFSRC_BASE + 0xA60)
#define DVFSRC_HRT_LOW_15 (DVFSRC_BASE + 0xA64)
#define DVFSRC_HRT_LOW_14 (DVFSRC_BASE + 0xA68)
#define DVFSRC_HRT_LOW_13 (DVFSRC_BASE + 0xA6C)
#define DVFSRC_HRT_LOW_12 (DVFSRC_BASE + 0xA70)
#define DVFSRC_HRT_LOW_11 (DVFSRC_BASE + 0xA74)
#define DVFSRC_HRT_LOW_10 (DVFSRC_BASE + 0xA78)
#define DVFSRC_HRT_LOW_9 (DVFSRC_BASE + 0xA7C)
#define DVFSRC_HRT_LOW_8 (DVFSRC_BASE + 0xA80)
#define DVFSRC_DDR_QOS11 (DVFSRC_BASE + 0xA84)
#define DVFSRC_DDR_QOS12 (DVFSRC_BASE + 0xA88)
#define DVFSRC_DDR_QOS13 (DVFSRC_BASE + 0xA8C)
#define DVFSRC_DDR_QOS14 (DVFSRC_BASE + 0xA90)
#define DVFSRC_DDR_QOS15 (DVFSRC_BASE + 0xA94)
#define DVFSRC_EMI_QOS11 (DVFSRC_BASE + 0xA98)
#define DVFSRC_EMI_QOS12 (DVFSRC_BASE + 0xA9C)
#define DVFSRC_EMI_QOS13 (DVFSRC_BASE + 0xAA0)
#define DVFSRC_EMI_QOS14 (DVFSRC_BASE + 0xAA4)
#define DVFSRC_EMI_QOS15 (DVFSRC_BASE + 0xAA8)
#define DVFSRC_TARGET_REQ_MASK BIT(16)
#define DVFSRC_EN_MASK 1
#endif /* MT_SPM_VCOREFS_REG_6991_H */

View file

@ -0,0 +1,463 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <drivers/dbgtop.h>
#include <drivers/dramc.h>
#include <drivers/spmi/spmi_common.h>
#include <drivers/spmi_api.h>
#include <drivers/sramrc.h>
#include <lib/mtk_init/mtk_init.h>
#include <mt_plat_spm_setting.h>
#include <mt_spm.h>
#include <mt_spm_reg.h>
#include <mt_spm_vcorefs.h>
#include <mt_spm_vcorefs_common.h>
#include <mt_spm_vcorefs_ext.h>
#include <mt_spm_vcorefs_reg.h>
#include <mt_vcore_dvfsrc_plat_def.h>
#include <mtk_mmap_pool.h>
#include <mtk_sip_svc.h>
#include <pmic_wrap/inc/mt_spm_pmic_wrap.h>
#include <sleep_def.h>
#define VCORE_SPM_INIT_PCM_FLAG (SPM_FLAG_RUN_COMMON_SCENARIO | \
SPM_FLAG_DISABLE_VLP_PDN)
#define V_VB_EN BIT(5)
#define V_DRM_ENABLE BIT(31)
#define V_B0_EN_SHIFT BIT(23)
#define V_VMODE_SHIFT 0
#define V_VMODE_MASK 0x3
#define V_OPP_TYPE_SHIFT 20
#define V_OPP_TYPE_SHIFT_MASK 0x3
#define DVFSRC_DISABLE_DVS 0x1
#define DVFSRC_DISABLE_DFS 0x2
#define CFG_DVFSRC_BW_ASYM_ENABLE
#ifdef MT8196_VCORE_SUPPORT
#define VCORE_MAX_OPP 6
#define DRAM_MAX_OPP 11
#define VCORE_OPP0_UV 850000
#define VCORE_OPP1_UV 750000
#define VCORE_OPP2_UV 675000
#define VCORE_OPP3_UV 625000
#define VCORE_OPP4_UV 600000
static unsigned int v_opp_uv[VCORE_MAX_OPP] = {
VCORE_OPP0_UV,
VCORE_OPP0_UV,
VCORE_OPP1_UV,
VCORE_OPP2_UV,
VCORE_OPP3_UV,
VCORE_OPP4_UV
};
#else
#define VCORE_MAX_OPP 6
#define DRAM_MAX_OPP 11
#define VCORE_OPP0_UV 875000
#define VCORE_OPP1_UV 825000
#define VCORE_OPP2_UV 725000
#define VCORE_OPP3_UV 650000
#define VCORE_OPP4_UV 600000
#define VCORE_OPP5_UV 575000
static unsigned int v_opp_uv[VCORE_MAX_OPP] = {
VCORE_OPP0_UV,
VCORE_OPP1_UV,
VCORE_OPP2_UV,
VCORE_OPP3_UV,
VCORE_OPP4_UV,
VCORE_OPP5_UV,
};
static unsigned int v_opp_df_uv[VCORE_MAX_OPP] = {
VCORE_OPP0_UV,
VCORE_OPP1_UV,
VCORE_OPP2_UV,
VCORE_OPP3_UV,
VCORE_OPP4_UV,
VCORE_OPP5_UV,
};
#endif
#ifdef CONFIG_MTK_VCOREDVFS_SUPPORT
static int opp_type;
static unsigned int b0_en;
static unsigned int v_roundup(unsigned int x, unsigned int y)
{
return round_up(x, y);
}
static unsigned int v_rounddown(unsigned int x, unsigned int y)
{
return round_down(x, y);
}
static void spm_vcorefs_pwarp_cmd(uint64_t cmd, uint64_t val)
{
if (cmd < NR_IDX_ALL)
mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_ALLINONE, cmd, val);
else
INFO("cmd out of range!\n");
}
static void dvfsrc_init(void)
{
int i;
static int dvfs_enable_done;
if (dvfs_enable_done)
return;
for (i = 0; i < ARRAY_SIZE(dvfsrc_init_configs); i++)
mmio_write_32(dvfsrc_init_configs[i].offset,
dvfsrc_init_configs[i].val);
#ifdef MT8196_VCORE_SUPPORT
for (i = 0; i < ARRAY_SIZE(lp5_8533_init_configs_auto); i++)
mmio_write_32(lp5_8533_init_configs_auto[i].offset,
lp5_8533_init_configs_auto[i].val);
#endif
if (opp_type == 2) {
for (i = 0; i < ARRAY_SIZE(lp5_7500_init_configs); i++)
mmio_write_32(lp5_7500_init_configs[i].offset,
lp5_7500_init_configs[i].val);
} else if (opp_type == 0) {
for (i = 0; i < ARRAY_SIZE(lp5_8533_init_configs); i++)
mmio_write_32(lp5_8533_init_configs[i].offset,
lp5_8533_init_configs[i].val);
} else if (opp_type == 3) {
for (i = 0; i < ARRAY_SIZE(lp5_10677_init_configs); i++)
mmio_write_32(lp5_10677_init_configs[i].offset,
lp5_10677_init_configs[i].val);
}
#ifdef CFG_DVFSRC_BW_ASYM_ENABLE
if (b0_en) {
mmio_write_32(DVFSRC_LEVEL_LABEL_210_211, 0x20100000);
mmio_write_32(DVFSRC_LEVEL_LABEL_212_213, 0x00504030);
mmio_write_32(DVFSRC_LEVEL_LABEL_220_221, 0x00400000);
mmio_write_32(DVFSRC_LEVEL_LABEL_224_225, 0x00000050);
mmio_write_32(DVFSRC_LEVEL_LABEL_226_227, 0x00300000);
mmio_write_32(DVFSRC_LEVEL_LABEL_252_253, 0x000040F5);
mmio_write_32(DVFSRC_LEVEL_LABEL_248_249, 0x30450000);
mmio_write_32(DVFSRC_LEVEL_LABEL_246_247, 0x00002065);
mmio_write_32(DVFSRC_LEVEL_LABEL_242_243, 0x10960000);
mmio_write_32(DVFSRC_LEVEL_LABEL_202_203, 0x00010040);
mmio_write_32(DVFSRC_LEVEL_LABEL_200_201, 0xE0420030);
}
#endif
mmio_write_32(DVFSRC_SW_REQ4, 0x00000030);
/* ENABLE */
mmio_write_32(DVFSRC_CURRENT_FORCE_4, 0x00000001);
#ifdef MT8196_VCORE_SUPPORT
mmio_write_32(DVFSRC_BASIC_CONTROL, 0xD460213B);
mmio_write_32(DVFSRC_BASIC_CONTROL, 0xD46001BB);
#else
mmio_write_32(DVFSRC_BASIC_CONTROL, 0xD560213B);
mmio_write_32(DVFSRC_BASIC_CONTROL, 0xD56001BB);
#endif
mmio_write_32(DVFSRC_CURRENT_FORCE_4, 0x00000000);
#ifdef CONFIG_MTK_DBGTOP
mtk_dbgtop_cfg_dvfsrc(1);
#endif
dvfs_enable_done = 1;
}
static void spm_vcorefs_vcore_setting(void)
{
int i;
uint32_t dvfs_v_mode, dvfsrc_rsrv;
#ifndef MT8196_VCORE_SUPPORT
uint32_t rsrv0, rsrv1;
rsrv0 = mmio_read_32(DVFSRC_RSRV_0);
rsrv1 = mmio_read_32(DVFSRC_RSRV_1);
#endif
dvfsrc_rsrv = mmio_read_32(DVFSRC_RSRV_4);
dvfs_v_mode = (dvfsrc_rsrv >> V_VMODE_SHIFT) & V_VMODE_MASK;
if (dvfs_v_mode == 3) { /* LV */
for (i = 0; i < VCORE_MAX_OPP; i++)
v_opp_uv[i] =
v_rounddown((v_opp_uv[i] * 95) / 100,
VCORE_STEP_UV);
} else if (dvfs_v_mode == 1) { /* HV */
for (i = 0; i < VCORE_MAX_OPP; i++)
v_opp_uv[i] =
v_roundup((v_opp_uv[i] * 105) / 100,
VCORE_STEP_UV);
}
#ifndef MT8196_VCORE_SUPPORT
else if (dvfsrc_rsrv & V_VB_EN) { /* NV & AVS1.0 */
v_opp_uv[5] = VCORE_PMIC_TO_UV(((rsrv1 >> 24) & 0xFF) + 7);
v_opp_uv[4] = VCORE_PMIC_TO_UV(((rsrv1 >> 16) & 0xFF) + 5);
v_opp_uv[3] = VCORE_PMIC_TO_UV(((rsrv1 >> 8) & 0xFF) + 4);
v_opp_uv[2] = VCORE_PMIC_TO_UV(((rsrv0 >> 24) & 0xFF) + 4);
v_opp_uv[1] = VCORE_PMIC_TO_UV(((rsrv0 >> 16) & 0xFF) + 3);
v_opp_uv[0] = VCORE_PMIC_TO_UV((rsrv0 & 0xFF) + 3);
for (i = 0; i < VCORE_MAX_OPP; i++)
v_opp_uv[i] = v_min(v_opp_uv[i], v_opp_df_uv[i]);
}
#endif
#ifdef MT8196_VCORE_SUPPORT
spm_vcorefs_pwarp_cmd(CMD_0, VCORE_UV_TO_PMIC(v_opp_uv[5]));
spm_vcorefs_pwarp_cmd(CMD_1, VCORE_UV_TO_PMIC(v_opp_uv[5]));
spm_vcorefs_pwarp_cmd(CMD_2, VCORE_UV_TO_PMIC(v_opp_uv[4]));
spm_vcorefs_pwarp_cmd(CMD_3, VCORE_UV_TO_PMIC(v_opp_uv[3]));
spm_vcorefs_pwarp_cmd(CMD_4, VCORE_UV_TO_PMIC(v_opp_uv[2]));
spm_vcorefs_pwarp_cmd(CMD_5, VCORE_UV_TO_PMIC(v_opp_uv[2]));
spm_vcorefs_pwarp_cmd(CMD_6, VCORE_UV_TO_PMIC(v_opp_uv[1]));
spm_vcorefs_pwarp_cmd(CMD_7, VCORE_UV_TO_PMIC(v_opp_uv[1]));
spm_vcorefs_pwarp_cmd(CMD_8, VCORE_UV_TO_PMIC(v_opp_uv[0]));
spm_vcorefs_pwarp_cmd(CMD_9, VCORE_UV_TO_PMIC(v_opp_uv[5]));
spm_vcorefs_pwarp_cmd(CMD_10, VCORE_UV_TO_PMIC(v_opp_uv[4]));
spm_vcorefs_pwarp_cmd(CMD_11, VCORE_UV_TO_PMIC(v_opp_uv[3]));
spm_vcorefs_pwarp_cmd(CMD_12, VCORE_UV_TO_PMIC(v_opp_uv[2]));
spm_vcorefs_pwarp_cmd(CMD_13, VCORE_UV_TO_PMIC(v_opp_uv[1]));
spm_vcorefs_pwarp_cmd(CMD_14, VCORE_UV_TO_PMIC(v_opp_uv[0]));
#else
spm_vcorefs_pwarp_cmd(CMD_9, VCORE_UV_TO_PMIC(v_opp_uv[5]));
spm_vcorefs_pwarp_cmd(CMD_10, VCORE_UV_TO_PMIC(v_opp_uv[4]));
spm_vcorefs_pwarp_cmd(CMD_11, VCORE_UV_TO_PMIC(v_opp_uv[3]));
spm_vcorefs_pwarp_cmd(CMD_12, VCORE_UV_TO_PMIC(v_opp_uv[2]));
spm_vcorefs_pwarp_cmd(CMD_13, VCORE_UV_TO_PMIC(v_opp_uv[1]));
spm_vcorefs_pwarp_cmd(CMD_14, VCORE_UV_TO_PMIC(v_opp_uv[0]));
#endif
}
int spm_vcorefs_plat_init(uint32_t dvfsrc_flag,
uint32_t dvfsrc_vmode, uint32_t *dram_type)
{
uint64_t spm_flags = VCORE_SPM_INIT_PCM_FLAG;
uint32_t dvfsrc_rsrv = 0;
if (mmio_read_32(MD32PCM_PC) == 0)
return MTK_SIP_E_NOT_SUPPORTED;
/* set high opp */
mmio_write_32(DVFSRC_SW_BW_9, 0x3FF);
spm_dvfsfw_init(0, 0);
spm_vcorefs_vcore_setting();
dvfsrc_rsrv = mmio_read_32(DVFSRC_RSRV_4);
opp_type = (dvfsrc_rsrv >> V_OPP_TYPE_SHIFT) & V_OPP_TYPE_SHIFT_MASK;
b0_en = dvfsrc_rsrv & V_B0_EN_SHIFT;
if (dvfsrc_flag & DVFSRC_DISABLE_DVS)
spm_flags |= SPM_FLAG_DISABLE_VCORE_DVS;
if (dvfsrc_flag & DVFSRC_DISABLE_DFS) {
spm_flags |= (SPM_FLAG_DISABLE_DDR_DFS |
SPM_FLAG_DISABLE_EMI_DFS |
SPM_FLAG_DISABLE_BUS_DFS);
mmio_write_32(DVFSRC_SW_BW_8, 0x3FF);
}
if (dvfsrc_rsrv & V_DRM_ENABLE) {
spm_flags |= (SPM_FLAG_DISABLE_VCORE_DVS |
SPM_FLAG_DISABLE_DDR_DFS |
SPM_FLAG_DISABLE_EMI_DFS |
SPM_FLAG_DISABLE_BUS_DFS);
return MTK_SIP_E_NOT_SUPPORTED;
}
spm_go_to_vcorefs(spm_flags);
dvfsrc_init();
*dram_type = 0;
return VCOREFS_SUCCESS;
}
int spm_vcorefs_plat_kick(void)
{
/* release high opp if not in drm mode*/
if (!(mmio_read_32(DVFSRC_RSRV_4) & V_DRM_ENABLE))
mmio_write_32(DVFSRC_SW_BW_9, 0);
mmio_write_32(DVFSRC_AVS_RETRY, 1);
mmio_write_32(DVFSRC_AVS_RETRY, 0);
return VCOREFS_SUCCESS;
}
void spm_vcorefs_plat_suspend(void)
{
mmio_write_32(DVFSRC_MD_TURBO, 0x1FFF0000);
}
void spm_vcorefs_plat_resume(void)
{
mmio_write_32(DVFSRC_MD_TURBO, 0x00000000);
}
#else
int spm_vcorefs_plat_kick(void)
{
return MTK_SIP_E_NOT_SUPPORTED;
}
int spm_vcorefs_plat_init(uint32_t dvfsrc_flag,
uint32_t dvfsrc_vmode, uint32_t *dram_type)
{
return MTK_SIP_E_NOT_SUPPORTED;
}
void spm_vcorefs_plat_suspend(void)
{
}
void spm_vcorefs_plat_resume(void)
{
}
#endif
int spm_vcorefs_get_vcore_uv(uint32_t gear, uint32_t *val)
{
if (gear < VCORE_MAX_OPP)
*val = v_opp_uv[VCORE_MAX_OPP - gear - 1];
else
*val = 0;
return VCOREFS_SUCCESS;
}
int spm_vcorefs_get_dram_freq(uint32_t gear, uint32_t *val)
{
#ifdef CONFIG_MTK_DRAMC
if (gear < DRAM_MAX_OPP)
*val = get_dram_step_freq((DRAM_MAX_OPP - gear - 1)) * 1000;
else
*val = 0;
#else
*val = 0;
#endif
return VCOREFS_SUCCESS;
}
int spm_vcorefs_get_vcore_opp_num(uint32_t *val)
{
*val = VCORE_MAX_OPP;
return VCOREFS_SUCCESS;
}
int spm_vcorefs_get_dram_opp_num(uint32_t *val)
{
*val = DRAM_MAX_OPP;
return VCOREFS_SUCCESS;
}
int spm_vcorefs_get_opp_type(uint32_t *val)
{
*val = 0;
return VCOREFS_SUCCESS;
}
int spm_vcorefs_get_fw_type(uint32_t *val)
{
*val = 0;
return VCOREFS_SUCCESS;
}
int spm_vcorefs_get_vcore_info(uint32_t idx, uint32_t *data)
{
if (idx == 0)
*data = mmio_read_32(VCORE_VB_INFO0);
else if (idx == 1)
*data = mmio_read_32(VCORE_VB_INFO1);
else if (idx == 2)
*data = mmio_read_32(VCORE_VB_INFO2);
else
*data = 0;
return VCOREFS_SUCCESS;
}
#define MMPC_FLAG 0x3333
int spm_vcorefs_qos_mode(uint32_t data)
{
#ifdef CFG_DVFSRC_BW_ASYM_ENABLE
uint32_t mode, value;
bool mm_flag;
mm_flag = (mmio_read_32(DVFSRC_VCORE_QOS7) == 0xFFFFFE);
mode = data >> 16;
if ((mode == 0x3333) && b0_en && mm_flag) {
value = data & 0xFFFF;
if (value == 1)
mmio_write_32(DVFSRC_QOS_EN, 0x00F3007C);
else
mmio_write_32(DVFSRC_QOS_EN, 0x20F1007C);
return VCOREFS_SUCCESS;
}
#endif
return MTK_SIP_E_NOT_SUPPORTED;
}
int spm_vcorefs_pause_enable(uint32_t enable)
{
#ifdef CONFIG_MTK_DBGTOP
mtk_dbgtop_dfd_pause_dvfsrc(1);
#endif
return VCOREFS_SUCCESS;
}
#ifdef MTK_VCORE_DVFS_RES_MEM
static int vcorefs_rsc_ctrl(unsigned int rsc, bool hold)
{
static struct mt_lp_resource_user vcorefs_res_user;
int ret = -1;
if (!vcorefs_res_user.uid) {
ret = mt_lp_resource_user_register("VCOREFS",
&vcorefs_res_user);
if (ret) {
WARN("%s: register lp resource failed", __func__);
return ret;
}
}
if (hold)
ret = vcorefs_res_user.request(&vcorefs_res_user, rsc);
else
ret = vcorefs_res_user.release(&vcorefs_res_user);
if (ret)
WARN("%s: RSC_%d %s failed",
__func__, rsc, hold ? "req" : "rel");
return ret;
}
int spm_vcorefs_rsc_mem_req(bool request)
{
vcorefs_rsc_ctrl(MT_LP_RQ_DRAM, request);
return VCOREFS_SUCCESS;
}
#endif

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_VCORE_DVFSRC_PLAT_DEF_H
#define MT_VCORE_DVFSRC_PLAT_DEF_H
#include <lib/utils_def.h>
#ifdef MT8196_VCORE_SUPPORT
#define VCORE_BASE_UV 0
#define VCORE_STEP_UV 6250
/* PMIC */
#define VCORE_PMIC_TO_UV(pmic) \
(((pmic) * VCORE_STEP_UV) + VCORE_BASE_UV)
#define VCORE_UV_TO_PMIC(uv) /* pmic >= uv */ \
((((uv) - VCORE_BASE_UV) + (VCORE_STEP_UV - 1)) / VCORE_STEP_UV)
#else
#define VCORE_BASE_UV 0
#define VCORE_STEP_UV 5000
/* PMIC */
#define VCORE_PMIC_TO_UV(pmic) \
(((pmic) * VCORE_STEP_UV) + VCORE_BASE_UV)
#define VCORE_UV_TO_PMIC(uv) /* pmic >= uv */ \
((((uv) - VCORE_BASE_UV) + (VCORE_STEP_UV - 1)) / VCORE_STEP_UV)
#ifndef v_min
#define v_min(a, b) MIN(a, b)
#endif
#ifndef v_max
#define v_max(a, b) MAZ(a, b)
#endif
#endif
#define VCORE_VB_INFO0 (EFUSEC_BASE + 0xD24)
#define VCORE_VB_INFO1 (EFUSEC_BASE + 0xD28)
#define VCORE_VB_INFO2 (EFUSEC_BASE + 0xD84)
static const struct reg_config dvfsrc_init_configs[] = {
{ DVFSRC_TIMEOUT_NEXTREQ, 0x00001AFF },
{ DVFSRC_VCORE_USER_REQ, 0x00010F51 },
{ DVFSRC_BW_USER_REQ, 0x00010033 },
/* EMI MONITOR */
{ DVFSRC_DDR_REQUEST3, 0x44444321 },
{ DVFSRC_DDR_REQUEST10, 0x44444321 },
/* SW QOS */
{ DVFSRC_QOS_EN, 0x20F1007C },
{ DVFSRC_DDR_QOS0, 0x0000004B },
{ DVFSRC_DDR_QOS1, 0x0000009A },
{ DVFSRC_DDR_QOS2, 0x000000CE },
{ DVFSRC_DDR_QOS3, 0x00000134 },
{ DVFSRC_DDR_QOS4, 0x00000185 },
{ DVFSRC_DDR_QOS5, 0x000001F9 },
{ DVFSRC_DDR_QOS6, 0x0000024C },
{ DVFSRC_DDR_QOS7, 0x000002B4 },
{ DVFSRC_DDR_QOS8, 0x00000354 },
{ DVFSRC_DDR_REQUEST5, 0x87654321 },
{ DVFSRC_DDR_REQUEST8, 0x00000009 },
/* LEVEL */
{ DVFSRC_LEVEL_LABEL_0_1, 0x9055A055 },
{ DVFSRC_LEVEL_LABEL_2_3, 0x80458055 },
{ DVFSRC_LEVEL_LABEL_4_5, 0x70558044 },
{ DVFSRC_LEVEL_LABEL_6_7, 0x70447045 },
{ DVFSRC_LEVEL_LABEL_8_9, 0x60456055 },
{ DVFSRC_LEVEL_LABEL_10_11, 0x60446035 },
{ DVFSRC_LEVEL_LABEL_12_13, 0x60336034 },
{ DVFSRC_LEVEL_LABEL_14_15, 0x50455055 },
{ DVFSRC_LEVEL_LABEL_16_17, 0x50445035 },
{ DVFSRC_LEVEL_LABEL_18_19, 0x50335034 },
{ DVFSRC_LEVEL_LABEL_20_21, 0x40454055 },
{ DVFSRC_LEVEL_LABEL_22_23, 0x40254035 },
{ DVFSRC_LEVEL_LABEL_24_25, 0x40344044 },
{ DVFSRC_LEVEL_LABEL_26_27, 0x40334024 },
{ DVFSRC_LEVEL_LABEL_28_29, 0x40224023 },
{ DVFSRC_LEVEL_LABEL_30_31, 0x30453055 },
{ DVFSRC_LEVEL_LABEL_32_33, 0x30253035 },
{ DVFSRC_LEVEL_LABEL_34_35, 0x30443015 },
{ DVFSRC_LEVEL_LABEL_36_37, 0x30243034 },
{ DVFSRC_LEVEL_LABEL_38_39, 0x30333014 },
{ DVFSRC_LEVEL_LABEL_40_41, 0x30133023 },
{ DVFSRC_LEVEL_LABEL_42_43, 0x30123022 },
{ DVFSRC_LEVEL_LABEL_44_45, 0x20553011 },
{ DVFSRC_LEVEL_LABEL_46_47, 0x20352045 },
{ DVFSRC_LEVEL_LABEL_48_49, 0x20152025 },
{ DVFSRC_LEVEL_LABEL_50_51, 0x20442005 },
{ DVFSRC_LEVEL_LABEL_52_53, 0x20242034 },
{ DVFSRC_LEVEL_LABEL_54_55, 0x20042014 },
{ DVFSRC_LEVEL_LABEL_56_57, 0x20232033 },
{ DVFSRC_LEVEL_LABEL_58_59, 0x20032013 },
{ DVFSRC_LEVEL_LABEL_60_61, 0x20122022 },
{ DVFSRC_LEVEL_LABEL_62_63, 0x20112002 },
{ DVFSRC_LEVEL_LABEL_64_65, 0x20002001 },
{ DVFSRC_LEVEL_LABEL_66_67, 0x10451055 },
{ DVFSRC_LEVEL_LABEL_68_69, 0x10251035 },
{ DVFSRC_LEVEL_LABEL_70_71, 0x10051015 },
{ DVFSRC_LEVEL_LABEL_72_73, 0x10341044 },
{ DVFSRC_LEVEL_LABEL_74_75, 0x10141024 },
{ DVFSRC_LEVEL_LABEL_76_77, 0x10331004 },
{ DVFSRC_LEVEL_LABEL_78_79, 0x10131023 },
{ DVFSRC_LEVEL_LABEL_80_81, 0x10221003 },
{ DVFSRC_LEVEL_LABEL_82_83, 0x10021012 },
{ DVFSRC_LEVEL_LABEL_84_85, 0x10011011 },
{ DVFSRC_LEVEL_LABEL_86_87, 0x00001000 },
/* HRT */
{ DVFSRC_PMQOS_HRT_UNIT_SW_BW, 0x00000120 },
{ DVFSRC_ISP_HRT_UNIT_SW_BW, 0x0000010F },
{ DVFSRC_MD_HRT_UNIT_SW_BW, 0x0000010F },
{ DVFSRC_HRT_BASE_HRT_UNIT_SW_BW, 0x0000010F },
{ DVFSRC_HRT_REQUEST, 0x87654321 },
{ DVFSRC_HRT_REQUEST_1, 0x00000009 },
{ DVFSRC_HRT_HIGH, 0x000006A8 },
{ DVFSRC_HRT_HIGH_1, 0x00000DD7 },
{ DVFSRC_HRT_HIGH_2, 0x000012A8 },
{ DVFSRC_HRT_HIGH_3, 0x00001C0B },
{ DVFSRC_HRT_HIGH_4, 0x00002644 },
{ DVFSRC_HRT_HIGH_5, 0x000031AC },
{ DVFSRC_HRT_HIGH_6, 0x000039FD },
{ DVFSRC_HRT_HIGH_7, 0x00004435 },
{ DVFSRC_HRT_HIGH_8, 0x000053B6 },
{ DVFSRC_HRT_LOW, 0x000006A7 },
{ DVFSRC_HRT_LOW_1, 0x00000DD7 },
{ DVFSRC_HRT_LOW_2, 0x000012A8 },
{ DVFSRC_HRT_LOW_3, 0x00001C0B },
{ DVFSRC_HRT_LOW_4, 0x00002643 },
{ DVFSRC_HRT_LOW_5, 0x000031AB },
{ DVFSRC_HRT_LOW_6, 0x000039FD },
{ DVFSRC_HRT_LOW_7, 0x00004435 },
{ DVFSRC_HRT_LOW_8, 0x000053B6 },
/* MDDDR */
{ DVFSRC_HRT_REQ_MD_URG, 0x003FF3FF },
{ DVFSRC_95MD_SCEN_BW7, 0x90000000 },
{ DVFSRC_95MD_SCEN_BW7_T, 0x90000000 },
{ DVFSRC_95MD_SCEN_BWU, 0x00000009 },
{ DVFSRC_MD_LATENCY_IMPROVE, 0x00000021 },
{ DVFSRC_DEBOUNCE_TIME, 0x0000179E },
/* RISING */
{ DVFSRC_DDR_ADD_REQUEST, 0x76543210 },
{ DVFSRC_DDR_ADD_REQUEST_1, 0x99999998 },
{ DVFSRC_EMI_MON_DEBOUNCE_TIME, 0x4C2D0000 },
/* MISC */
{ DVFSRC_DEFAULT_OPP_1, 0x00000000 },
{ DVFSRC_DEFAULT_OPP_2, 0x00000000 },
{ DVFSRC_DEFAULT_OPP_3, 0x00000000 },
{ DVFSRC_DEFAULT_OPP_4, 0x00000000 },
{ DVFSRC_DEFAULT_OPP_5, 0x00000000 },
{ DVFSRC_DEFAULT_OPP_6, 0x00000000 },
{ DVFSRC_DEFAULT_OPP_7, 0x00000000 },
{ DVFSRC_DEFAULT_OPP_8, 0x00000001 },
{ DVFSRC_BASIC_CONTROL_4, 0x0000020F },
{ DVFSRC_INT_EN, 0x00000002 },
};
static const struct reg_config lp5_7500_init_configs[] = {
/* SW QOS */
{ DVFSRC_DDR_REQUEST5, 0x77654321 },
{ DVFSRC_DDR_REQUEST8, 0x00000007 },
/* HRT */
{ DVFSRC_HRT_REQUEST, 0x77654321 },
{ DVFSRC_HRT_REQUEST_1, 0x00000007 },
/* MDDDR */
{ DVFSRC_95MD_SCEN_BW7, 0x70000000 },
{ DVFSRC_95MD_SCEN_BW7_T, 0x70000000 },
{ DVFSRC_95MD_SCEN_BWU, 0x00000007 },
};
static const struct reg_config lp5_8533_init_configs[] = {
/* SW QOS */
{ DVFSRC_DDR_REQUEST5, 0x87654321 },
{ DVFSRC_DDR_REQUEST8, 0x00000008 },
/* HRT */
{ DVFSRC_HRT_REQUEST, 0x87654321 },
{ DVFSRC_HRT_REQUEST_1, 0x00000008 },
/* MDDDR */
{ DVFSRC_95MD_SCEN_BW7, 0x80000000 },
{ DVFSRC_95MD_SCEN_BW7_T, 0x80000000 },
{ DVFSRC_95MD_SCEN_BWU, 0x00000008 },
};
static const struct reg_config lp5_10677_init_configs[] = {
/* SW QOS */
{ DVFSRC_DDR_QOS9, 0x000003C0 },
{ DVFSRC_DDR_REQUEST5, 0x87654321 },
{ DVFSRC_DDR_REQUEST8, 0x000000A9 },
/* HRT */
{ DVFSRC_HRT_HIGH_9, 0x00005E80 },
{ DVFSRC_HRT_LOW_9, 0x00005E7F },
{ DVFSRC_HRT_REQUEST, 0x87654321 },
{ DVFSRC_HRT_REQUEST_1, 0x000000A9 },
};
static const struct reg_config lp5_8533_init_configs_auto[] = {
/* LEVEL */
{ DVFSRC_LEVEL_LABEL_0_1, 0x80449045 },
{ DVFSRC_LEVEL_LABEL_2_3, 0x70448044 },
{ DVFSRC_LEVEL_LABEL_4_5, 0x60346044 },
{ DVFSRC_LEVEL_LABEL_6_7, 0x50446033 },
{ DVFSRC_LEVEL_LABEL_8_9, 0x50335034 },
{ DVFSRC_LEVEL_LABEL_10_11, 0x40344044 },
{ DVFSRC_LEVEL_LABEL_12_13, 0x40334024 },
{ DVFSRC_LEVEL_LABEL_14_15, 0x40224023 },
{ DVFSRC_LEVEL_LABEL_16_17, 0x30343044 },
{ DVFSRC_LEVEL_LABEL_18_19, 0x30143024 },
{ DVFSRC_LEVEL_LABEL_20_21, 0x30233033 },
{ DVFSRC_LEVEL_LABEL_22_23, 0x30223013 },
{ DVFSRC_LEVEL_LABEL_24_25, 0x30113012 },
{ DVFSRC_LEVEL_LABEL_26_27, 0x20342044 },
{ DVFSRC_LEVEL_LABEL_28_29, 0x20142024 },
{ DVFSRC_LEVEL_LABEL_30_31, 0x20332004 },
{ DVFSRC_LEVEL_LABEL_32_33, 0x20132023 },
{ DVFSRC_LEVEL_LABEL_34_35, 0x20222003 },
{ DVFSRC_LEVEL_LABEL_36_37, 0x20022012 },
{ DVFSRC_LEVEL_LABEL_38_39, 0x20012011 },
{ DVFSRC_LEVEL_LABEL_40_41, 0x10442000 },
{ DVFSRC_LEVEL_LABEL_42_43, 0x10241034 },
{ DVFSRC_LEVEL_LABEL_44_45, 0x10041014 },
{ DVFSRC_LEVEL_LABEL_46_47, 0x10231033 },
{ DVFSRC_LEVEL_LABEL_48_49, 0x10031013 },
{ DVFSRC_LEVEL_LABEL_50_51, 0x10121022 },
{ DVFSRC_LEVEL_LABEL_52_53, 0x10111002 },
{ DVFSRC_LEVEL_LABEL_54_55, 0x10001001 },
{ DVFSRC_LEVEL_LABEL_56_57, 0x10341044 },
{ DVFSRC_LEVEL_LABEL_58_59, 0x10141024 },
{ DVFSRC_LEVEL_LABEL_60_61, 0x10331004 },
{ DVFSRC_LEVEL_LABEL_62_63, 0x10131023 },
{ DVFSRC_LEVEL_LABEL_64_65, 0x10221003 },
{ DVFSRC_LEVEL_LABEL_66_67, 0x10021012 },
{ DVFSRC_LEVEL_LABEL_68_69, 0x10011011 },
{ DVFSRC_LEVEL_LABEL_70_71, 0x00001000 },
{ DVFSRC_LEVEL_LABEL_72_73, 0x00000000 },
{ DVFSRC_LEVEL_LABEL_74_75, 0x00000000 },
{ DVFSRC_LEVEL_LABEL_76_77, 0x00000000 },
{ DVFSRC_LEVEL_LABEL_78_79, 0x00000000 },
{ DVFSRC_LEVEL_LABEL_80_81, 0x00000000 },
{ DVFSRC_LEVEL_LABEL_82_83, 0x00000000 },
{ DVFSRC_LEVEL_LABEL_84_85, 0x00000000 },
{ DVFSRC_LEVEL_LABEL_86_87, 0x00000000 },
};
#endif /* MT_VCORE_DVFSRC_PLAT_DEF_H */

View file

@ -0,0 +1,209 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PCM_DEF_H
#define PCM_DEF_H
#define CTRL0_SC_26M_CK_OFF BIT(0)
#define CTRL0_SC_VLP_BUS_CK_OFF BIT(1)
#define CTRL0_SC_PMIF_CK_OFF BIT(2)
#define CTRL0_SC_AXI_CK_OFF BIT(3)
#define CTRL0_SC_AXI_MEM_CK_OFF BIT(4)
#define CTRL0_SC_MD26M_CK_OFF BIT(5)
#define CTRL0_SC_MD32K_CK_OFF BIT(6)
#define CTRL0_SC_VLP_26M_CLK_SEL BIT(7)
#define CTRL0_SC_26M_CK_SEL BIT(8)
#define CTRL0_SC_TOP_26M_CLK_SEL BIT(9)
#define CTRL0_SC_SYS_TIMER_CLK_32K_SEL BIT(10)
#define CTRL0_SC_CIRQ_CLK_32K_SEL BIT(11)
#define CTRL0_SC_AXI_DCM_DIS BIT(12)
#define CTRL0_SC_CKSQ0_OFF BIT(13)
#define CTRL0_SC_CKSQ1_OFF BIT(14)
#define CTRL0_VCORE_PWR_ISO BIT(15)
#define CTRL0_VCORE_PWR_ISO_PRE BIT(16)
#define CTRL0_VCORE_PWR_RST_B BIT(17)
#define CTRL0_VCORE_RESTORE_ENABLE BIT(18)
#define CTRL0_SC_TOP_RESTORE_26M_CLK_SEL BIT(19)
#define CTRL0_AOC_VCORE_SRAM_ISO_DIN BIT(20)
#define CTRL0_AOC_VCORE_SRAM_LATCH_ENB BIT(21)
#define CTRL0_AOC_VCORE_ANA_ISO BIT(22)
#define CTRL0_AOC_VCORE_ANA_ISO_PRE BIT(23)
#define CTRL0_AOC_VLPTOP_SRAM_ISO_DIN BIT(24)
#define CTRL0_AOC_VLPTOP_SRAM_LATCH_ENB BIT(25)
#define CTRL0_AOC_VCORE_IO_ISO BIT(26)
#define CTRL0_AOC_VCORE_IO_LATCH_ENB BIT(27)
#define CTRL0_RTFF_VCORE_SAVE BIT(28)
#define CTRL0_RTFF_VCORE_NRESTORE BIT(29)
#define CTRL0_RTFF_VCORE_CLK_DIS BIT(30)
#define CTRL1_PWRAP_SLEEP_REQ BIT(0)
#define CTRL1_IM_SLP_EN BIT(1)
#define CTRL1_SPM_LEAVE_VCORE_OFF_REQ BIT(2)
#define CTRL1_SPM_CK_SEL0 BIT(4)
#define CTRL1_SPM_CK_SEL1 BIT(5)
#define CTRL1_TIMER_SET BIT(6)
#define CTRL1_TIMER_CLR BIT(7)
#define CTRL1_SPM_LEAVE_DEEPIDLE_REQ BIT(8)
#define CTRL1_SPM_LEAVE_SUSPEND_REQ BIT(9)
#define CTRL1_CSYSPWRUPACK BIT(10)
#define CTRL1_SRCCLKENO0 BIT(11)
#define CTRL1_SRCCLKENO1 BIT(12)
#define CTRL1_SRCCLKENO2 BIT(13)
#define CTRL1_SPM_APSRC_INTERNAL_ACK BIT(14)
#define CTRL1_SPM_EMI_INTERNAL_ACK BIT(15)
#define CTRL1_SPM_DDREN_INTERNAL_ACK BIT(16)
#define CTRL1_SPM_INFRA_INTERNAL_ACK BIT(17)
#define CTRL1_SPM_VRF18_INTERNAL_ACK BIT(18)
#define CTRL1_SPM_VCORE_INTERNAL_ACK BIT(19)
#define CTRL1_SPM_VCORE_RESTORE_ACK BIT(20)
#define CTRL1_SPM_PMIC_INTERNAL_ACK BIT(21)
#define CTRL1_PMIC_IRQ_REQ_EN BIT(22)
#define CTRL1_WDT_KICK_P BIT(23)
#define CTRL1_FORCE_DDREN_WAKE BIT(24)
#define CTRL1_FORCE_F26M_WAKE BIT(25)
#define CTRL1_FORCE_APSRC_WAKE BIT(26)
#define CTRL1_FORCE_INFRA_WAKE BIT(27)
#define CTRL1_FORCE_VRF18_WAKE BIT(28)
#define CTRL1_FORCE_VCORE_WAKE BIT(29)
#define CTRL1_FORCE_EMI_WAKE BIT(30)
#define CTRL1_FORCE_PMIC_WAKE BIT(31)
#define CTRL2_MD32PCM_IRQ_TRIG_BIT BIT(31)
#define STA0_SRCCLKENI0 BIT(0)
#define STA0_SRCCLKENI1 BIT(1)
#define STA0_MD_SRCCLKENA BIT(2)
#define STA0_MD_SRCCLKENA1 BIT(3)
#define STA0_MD_DDREN_REQ BIT(4)
#define STA0_CONN_DDREN_REQ BIT(5)
#define STA0_SSPM_SRCCLKENA BIT(6)
#define STA0_SSPM_APSRC_REQ BIT(7)
#define STA0_MD_STATE BIT(8)
#define STA0_RC2SPM_SRCCLKENO_0_ACK BIT(9)
#define STA0_MM_STATE BIT(10)
#define STA0_SSPM_STATE BIT(11)
#define STA0_CPUEB_STATE BIT(12)
#define STA0_CONN_STATE BIT(13)
#define STA0_CONN_VCORE_REQ BIT(14)
#define STA0_CONN_SRCCLKENA BIT(15)
#define STA0_CONN_SRCCLKENB BIT(16)
#define STA0_CONN_APSRC_REQ BIT(17)
#define STA0_SCP_STATE BIT(18)
#define STA0_CSYSPWRUPREQ BIT(19)
#define STA0_PWRAP_SLEEP_ACK BIT(20)
#define STA0_DPM_STATE BIT(21)
#define STA0_AUDIO_DSP_STATE BIT(22)
#define STA0_PMIC_IRQ_ACK BIT(23)
#define STA0_RESERVED_BIT_24 BIT(24)
#define STA0_RESERVED_BIT_25 BIT(25)
#define STA0_RESERVED_BIT_26 BIT(26)
#define STA0_DVFS_STATE BIT(27)
#define STA0_RESERVED_BIT_28 BIT(28)
#define STA0_RESERVED_BIT_29 BIT(29)
#define STA0_SC_HW_S1_ACK_ALL BIT(30)
#define STA0_DDREN_STATE BIT(31)
#define R12_PCM_TIMER_B BIT(0)
#define R12_TWAM_PMSR_DVFSRC_ALCO BIT(1)
#define R12_KP_IRQ_B BIT(2)
#define R12_APWDT_EVENT_B BIT(3)
#define R12_APXGPT_EVENT_B BIT(4)
#define R12_CONN2AP_WAKEUP_B BIT(5)
#define R12_EINT_EVENT_B BIT(6)
#define R12_CONN_WDT_IRQ_B BIT(7)
#define R12_CCIF0_EVENT_B BIT(8)
#define R12_CCIF1_EVENT_B BIT(9)
#define R12_SSPM2SPM_WAKEUP_B BIT(10)
#define R12_SCP2SPM_WAKEUP_B BIT(11)
#define R12_ADSP2SPM_WAKEUP_B BIT(12)
#define R12_PCM_WDT_WAKEUP_B BIT(13)
#define R12_USB0_CDSC_B BIT(14)
#define R12_USB0_POWERDWN_B BIT(15)
#define R12_UART_EVENT_B BIT(16)
#define R12_DEBUGTOP_FLAG_IRQ_B BIT(17)
#define R12_SYS_TIMER_EVENT_B BIT(18)
#define R12_EINT_EVENT_SECURE_B BIT(19)
#define R12_AFE_IRQ_MCU_B BIT(20)
#define R12_THERM_CTRL_EVENT_B BIT(21)
#define R12_SYS_CIRQ_IRQ_B BIT(22)
#define R12_PBUS_EVENT_B BIT(23)
#define R12_CSYSPWREQ_B BIT(24)
#define R12_MD_WDT_B BIT(25)
#define R12_AP2AP_PEER_WAKEUP_B BIT(26)
#define R12_SEJ_B BIT(27)
#define R12_CPU_WAKEUP BIT(28)
#define R12_APUSYS_WAKE_HOST_B BIT(29)
#define R12_PCIE_WAKE_B BIT(30)
#define R12_MSDC_WAKE_B BIT(31)
#define EVENT_F26M_WAKE BIT(0)
#define EVENT_F26M_SLEEP BIT(1)
#define EVENT_INFRA_WAKE BIT(2)
#define EVENT_INFRA_SLEEP BIT(3)
#define EVENT_EMI_WAKE BIT(4)
#define EVENT_EMI_SLEEP BIT(5)
#define EVENT_APSRC_WAKE BIT(6)
#define EVENT_APSRC_SLEEP BIT(7)
#define EVENT_VRF18_WAKE BIT(8)
#define EVENT_VRF18_SLEEP BIT(9)
#define EVENT_DVFS_WAKE BIT(10)
#define EVENT_DDREN_WAKE BIT(11)
#define EVENT_DDREN_SLEEP BIT(12)
#define EVENT_VCORE_WAKE BIT(13)
#define EVENT_VCORE_SLEEP BIT(14)
#define EVENT_PMIC_WAKE BIT(15)
#define EVENT_PMIC_SLEEP BIT(16)
#define EVENT_CPUEB_STATE BIT(17)
#define EVENT_SSPM_STATE BIT(18)
#define EVENT_DPM_STATE BIT(19)
#define EVENT_SPM_LEAVE_VCORE_OFF_ACK BIT(20)
#define EVENT_SW_SSPM_ADSP_SCP_MAILBOX_WAKE BIT(21)
#define EVENT_SPM_LEAVE_SUSPEND_ACK BIT(22)
#define EVENT_SPM_LEAVE_DEEPIDLE_ACK BIT(23)
#define EVENT_CROSS_REQ_APU_l3 BIT(24)
#define EVENT_DFD_SOC_MTCMOS_REQ_IPIC_WAKE BIT(25)
#define EVENT_AOVBUS_WAKE BIT(26)
#define EVENT_AOVBUS_SLEEP BIT(27)
enum SPM_WAKE_SRC_LIST {
WAKE_SRC_STA1_PCM_TIMER = BIT(0),
WAKE_SRC_STA1_TWAM_PMSR_DVFSRC = BIT(1),
WAKE_SRC_STA1_KP_IRQ_B = BIT(2),
WAKE_SRC_STA1_APWDT_EVENT_B = BIT(3),
WAKE_SRC_STA1_APXGPT1_EVENT_B = BIT(4),
WAKE_SRC_STA1_CONN2AP_SPM_WAKEUP_B = BIT(5),
WAKE_SRC_STA1_EINT_EVENT_B = BIT(6),
WAKE_SRC_STA1_CONN_WDT_IRQ_B = BIT(7),
WAKE_SRC_STA1_CCIF0_EVENT_B = BIT(8),
WAKE_SRC_STA1_CCIF1_EVENT_B = BIT(9),
WAKE_SRC_STA1_SC_SSPM2SPM_WAKEUP_B = BIT(10),
WAKE_SRC_STA1_SC_SCP2SPM_WAKEUP_B = BIT(11),
WAKE_SRC_STA1_SC_ADSP2SPM_WAKEUP_B = BIT(12),
WAKE_SRC_STA1_PCM_WDT_WAKEUP_B = BIT(13),
WAKE_SRC_STA1_USB_CDSC_B = BIT(14),
WAKE_SRC_STA1_USB_POWERDWN_B = BIT(15),
WAKE_SRC_STA1_AP_UART_B = BIT(16),
WAKE_SRC_STA1_DEBUGTOP_FLAG_IRQ_B = BIT(17),
WAKE_SRC_STA1_SYS_TIMER_EVENT_B = BIT(18),
WAKE_SRC_STA1_EINT_EVENT_SECURE_B = BIT(19),
WAKE_SRC_STA1_AFE_IRQ_MCU_B = BIT(20),
WAKE_SRC_STA1_THERM_CTRL_EVENT_B = BIT(21),
WAKE_SRC_STA1_SYS_CIRQ_IRQ_B = BIT(22),
WAKE_SRC_STA1_PBUS_EVENT_B = BIT(23),
WAKE_SRC_STA1_CSYSPWREQ_B = BIT(24),
WAKE_SRC_STA1_MD1_WDT_B = BIT(25),
WAKE_SRC_STA1_AP2AP_PEER_WAKEUPEVENT_B = BIT(26),
WAKE_SRC_STA1_SEJ_EVENT_B = BIT(27),
WAKE_SRC_STA1_SPM_CPU_WAKEUPEVENT_B = BIT(28),
WAKE_SRC_STA1_APUSYS_WAKE_HOST_B = BIT(29),
WAKE_SRC_STA1_PCIE_B = BIT(30),
WAKE_SRC_STA1_MSDC_B = BIT(31),
};
extern const char *wakesrc_str[32];
#endif /* PCM_DEF_H */

View file

@ -0,0 +1,117 @@
#
# Copyright (c) 2025, MediaTek Inc. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
NOTIFIER_VER := v4
PMIC_WRAP_VER := v1
MTK_SPM_COMMON_DRV := y
# Enable or disable spm feature
MT_SPM_FEATURE_SUPPORT := y
# Enable or disable cirq restore
MT_SPM_CIRQ_FEATURE_SUPPORT := y
# Enable or disable get dram type from dramc
MT_SPMFW_LOAD_BY_DRAM_TYPE := n
# Enable or disable sspm sram
MT_SPMFW_SPM_SRAM_SLEEP_SUPPORT := n
# Enable or disable uart save/restore at tf-a spm driver
# mt8196 uart is restore by RTFF
MT_SPM_UART_SUSPEND_SUPPORT := n
# Enable or disable pmic wrap reg dump
MT_SPM_PMIC_WRAP_DUMP_SUPPORT := n
# spm timestamp support
MT_SPM_TIMESTAMP_SUPPORT := n
MTK_SPM_PMIC_LP_SUPPORT := y
MTK_SPM_LVTS_SUPPORT := FIXME
MT_SPM_COMMON_SODI_SUPPORT := n
#spm emi thermal threshold control
MT_SPM_EMI_THERMAL_CONTROL_SUPPORT := FIXME
# spm rgu workaround
MT_SPM_RGU_WA := y
CONSTRAINT_ID_ALL := 0xff
$(eval $(call add_defined_option,CONSTRAINT_ID_ALL))
ifneq (${PMIC_GS_DUMP_VER},)
$(eval $(call add_define,MTK_SPM_PMIC_GS_DUMP))
$(eval $(call add_define,MTK_SPM_PMIC_GS_DUMP_SUSPEND))
$(eval $(call add_define,MTK_SPM_PMIC_GS_DUMP_SODI3))
$(eval $(call add_define,MTK_SPM_PMIC_GS_DUMP_DPIDLE))
endif
ifeq (${MT_SPM_FEATURE_SUPPORT},n)
$(eval $(call add_define,MTK_PLAT_SPM_UNSUPPORT))
else
$(eval $(call add_define,MT_SPM_FEATURE_SUPPORT))
endif
ifeq (${MT_SPMFW_LOAD_BY_DRAM_TYPE},n)
$(eval $(call add_define,MTK_PLAT_DRAMC_UNSUPPORT))
endif
ifeq (${MT_SPM_CIRQ_FEATURE_SUPPORT},n)
$(eval $(call add_define,MTK_PLAT_CIRQ_UNSUPPORT))
endif
ifeq (${MT_SPMFW_SPM_SRAM_SLEEP_SUPPORT},n)
$(eval $(call add_define,MTK_PLAT_SPM_SRAM_SLP_UNSUPPORT))
endif
ifeq (${NOTIFIER_VER},)
$(eval $(call add_define,MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT))
endif
ifeq (${MT_SPM_UART_SUSPEND_SUPPORT},n)
$(eval $(call add_define,MTK_PLAT_SPM_UART_UNSUPPORT))
endif
ifeq (${MT_SPM_PMIC_WRAP_DUMP_SUPPORT},n)
$(eval $(call add_define,MTK_PLAT_SPM_PMIC_WRAP_DUMP_UNSUPPORT))
endif
ifeq (${TRACER_VER},)
$(eval $(call add_define,MTK_PLAT_SPM_TRACE_UNSUPPORT))
endif
ifeq (${MT_SPM_TIMESTAMP_SUPPORT},y)
$(eval $(call add_define,MT_SPM_TIMESTAMP_SUPPORT))
endif
ifeq ($(MTK_VOLTAGE_BIN_VCORE),y)
$(eval $(call add_define,MTK_VOLTAGE_BIN_VCORE_SUPPORT))
endif
ifeq (${MTK_SPM_PMIC_LP_SUPPORT},y)
$(eval $(call add_define,MTK_SPM_PMIC_LP_SUPPORT))
endif
ifeq (${MTK_SPM_LVTS_SUPPORT},y)
$(eval $(call add_define,MTK_SPM_LVTS_SUPPORT))
endif
ifeq (${MT_SPM_COMMON_SODI_SUPPORT},y)
$(eval $(call add_define,MT_SPM_COMMON_SODI_SUPPORT))
endif
ifeq (${MT_SPM_EMI_THERMAL_CONTROL_SUPPORT},y)
$(eval $(call add_define,MT_SPM_EMI_THERMAL_CONTROL_SUPPORT))
endif
ifeq (${MT_SPM_RGU_WA},y)
$(eval $(call add_define,MT_SPM_RGU_WA))
endif

View file

@ -0,0 +1,37 @@
#
# 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 := spm_${MTK_SOC}
#Add your source code here
LOCAL_SRCS-${CONFIG_MTK_SPM_SUPPORT} := ${LOCAL_DIR}/mt_spm.c
LOCAL_SRCS-${CONFIG_MTK_SPM_SUPPORT} += ${LOCAL_DIR}/mt_spm_conservation.c
LOCAL_SRCS-${CONFIG_MTK_SPM_SUPPORT} += ${LOCAL_DIR}/mt_spm_internal.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/mt_plat_spm_setting.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/mt_spm_dispatcher.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/mt_spm_idle.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/mt_spm_suspend.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/mt_spm_stats.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/constraints/mt_spm_rc_api.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/constraints/mt_spm_rc_bus26m.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/constraints/mt_spm_rc_vcore.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/constraints/mt_spm_rc_syspll.c
LOCAL_SRCS-${MTK_SPM_PMIC_LP_SUPPORT} += ${LOCAL_DIR}/mt_spm_pmic_lp.c
LOCAL_SRCS-${MT_SPM_FEATURE_SUPPORT} += ${LOCAL_DIR}/mt_spm_hwreq.c
LOCAL_SRCS-${CONFIG_MTK_VCOREDVFS_SUPPORT} += ${LOCAL_DIR}/mt_spm_vcorefs.c
LOCAL_SRCS-${CONFIG_MTK_VCOREDVFS_SUPPORT} += ${LOCAL_DIR}/mt_vcore_dvfsrc_plat.c
#Epilogue, build as module
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
$(eval $(call add_defined_option,CONFIG_MTK_VCOREDVFS_SUPPORT))
$(eval $(call add_defined_option,CONFIG_MTK_VCOREDVFS_LK_SUPPORT))
$(eval $(call add_defined_option,CONFIG_MTK_VCOREDVFS_PLAT_CMD))
$(eval $(call add_defined_option,MTK_VCORE_DVFS_PAUSE))

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SLEEP_DEF_H
#define SLEEP_DEF_H
/* --- SPM Flag Define --- */
#define SPM_FLAG_DISABLE_INFRA_PDN BIT(0)
#define SPM_FLAG_DISABLE_DPM_PDN BIT(1)
#define SPM_FLAG_DISABLE_MCUPM_PDN BIT(2)
#define SPM_FLAG_RESERVED_BIT_3 BIT(3)
#define SPM_FLAG_DISABLE_VLP_PDN BIT(4)
#define SPM_FLAG_DISABLE_VLPCLK_SWITCH BIT(5)
#define SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP BIT(6)
#define SPM_FLAG_RESERVED_BIT_7 BIT(7)
#define SPM_FLAG_DISABLE_VCORE_DVS BIT(8)
#define SPM_FLAG_DISABLE_DDR_DFS BIT(9)
#define SPM_FLAG_DISABLE_EMI_DFS BIT(10)
#define SPM_FLAG_DISABLE_BUS_DFS BIT(11)
#define SPM_FLAG_DISABLE_COMMON_SCENARIO BIT(12)
#define SPM_FLAG_RESERVED_BIT_13 BIT(13)
#define SPM_FLAG_RESERVED_BIT_14 BIT(14)
#define SPM_FLAG_RESERVED_BIT_15 BIT(15)
#define SPM_FLAG_KEEP_CSYSPWRACK_HIGH BIT(16)
#define SPM_FLAG_ENABLE_MT8196_IVI BIT(17)
#define SPM_FLAG_ENABLE_SPM_DBG_WDT_DUMP BIT(18)
#define SPM_FLAG_RUN_COMMON_SCENARIO BIT(19)
#define SPM_FLAG_USE_SRCCLKENO2 BIT(20)
#define SPM_FLAG_ENABLE_AOV BIT(21)
#define SPM_FLAG_ENABLE_MD_MUMTAS BIT(22)
#define SPM_FLAG_ENABLE_COMMON_SODI5 BIT(23)
#define SPM_FLAG_ENABLE_MT8196_E1_WA BIT(24)
#define SPM_FLAG_ENABLE_MT8196_EMI_E1_WA BIT(25)
#define SPM_FLAG_VCORE_STATE BIT(26)
#define SPM_FLAG_VTCXO_STATE BIT(27)
#define SPM_FLAG_INFRA_STATE BIT(28)
#define SPM_FLAG_APSRC_STATE BIT(29)
#define SPM_FLAG_VRF18_STATE BIT(30)
#define SPM_FLAG_DDREN_STATE BIT(31)
/* --- SPM Flag1 Define --- */
#define SPM_FLAG1_DISABLE_AXI_BUS_TO_26M BIT(0)
#define SPM_FLAG1_DISABLE_SYSPLL_OFF BIT(1)
#define SPM_FLAG1_DISABLE_PWRAP_CLK_SWITCH BIT(2)
#define SPM_FLAG1_DISABLE_CSOPLU_OFF BIT(3)
#define SPM_FLAG1_FW_SET_CSOPLU_ON BIT(4)
#define SPM_FLAG1_DISABLE_EMI_CLK_TO_CSOPLU BIT(5)
#define SPM_FLAG1_DISABLE_NO_RESUME BIT(6)
#define SPM_FLAG1_RESERVED_BIT_7 BIT(7)
#define SPM_FLAG1_RESERVED_BIT_8 BIT(8)
#define SPM_FLAG1_RESERVED_BIT_9 BIT(9)
#define SPM_FLAG1_DISABLE_SRCLKEN_LOW BIT(10)
#define SPM_FLAG1_DISABLE_SCP_CLK_SWITCH BIT(11)
#define SPM_FLAG1_DISABLE_TOP_26M_CK_OFF BIT(12)
#define SPM_FLAG1_DISABLE_PCM_26M_SWITCH BIT(13)
#define SPM_FLAG1_DISABLE_CKSQ_OFF BIT(14)
#define SPM_FLAG1_DO_DPSW_0P725V BIT(15)
#define SPM_FLAG1_ENABLE_ALCO_TRACE BIT(16)
#define SPM_FLAG1_ENABLE_SUSPEND_AVS BIT(17)
#define SPM_FLAG1_DISABLE_TVCORE_OFF BIT(18)
#define SPM_FLAG1_ENABLE_CSOPLU_OFF BIT(19)
#define SPM_FLAG1_DISABLE_INFRA_SRAM_SLEEP BIT(20)
#define SPM_FLAG1_DISABLE_AXI_MEM_CLK_OFF BIT(21)
#define SPM_FLAG1_RESERVED_BIT_22 BIT(22)
#define SPM_FLAG1_RESERVED_BIT_23 BIT(23)
#define SPM_FLAG1_DISABLE_SCP_VREQ_MASK_CONTROL BIT(24)
#define SPM_FLAG1_RESERVED_BIT_25 BIT(25)
#define SPM_FLAG1_RESERVED_BIT_26 BIT(26)
#define SPM_FLAG1_RESERVED_BIT_27 BIT(27)
#define SPM_FLAG1_RESERVED_BIT_28 BIT(28)
#define SPM_FLAG1_RESERVED_BIT_29 BIT(29)
#define SPM_FLAG1_ENABLE_WAKE_PROF BIT(30)
#define SPM_FLAG1_ENABLE_SLEEP_PROF BIT(31)
/* --- SPM DEBUG Define --- */
#define SPM_DBG_DEBUG_IDX_26M_WAKE BIT(0)
#define SPM_DBG_DEBUG_IDX_26M_SLEEP BIT(1)
#define SPM_DBG_DEBUG_IDX_INFRA_WAKE BIT(2)
#define SPM_DBG_DEBUG_IDX_INFRA_SLEEP BIT(3)
#define SPM_DBG_DEBUG_IDX_APSRC_WAKE BIT(4)
#define SPM_DBG_DEBUG_IDX_APSRC_SLEEP BIT(5)
#define SPM_DBG_DEBUG_IDX_VRF18_WAKE BIT(6)
#define SPM_DBG_DEBUG_IDX_VRF18_SLEEP BIT(7)
#define SPM_DBG_DEBUG_IDX_VCORE_WAKE BIT(8)
#define SPM_DBG_DEBUG_IDX_VCORE_SLEEP BIT(9)
#define SPM_DBG_DEBUG_IDX_DDREN_WAKE BIT(10)
#define SPM_DBG_DEBUG_IDX_DDREN_SLEEP BIT(11)
#define SPM_DBG_DEBUG_IDX_PMIC_WAKE BIT(12)
#define SPM_DBG_DEBUG_IDX_PMIC_SLEEP BIT(13)
#define SPM_DBG_DEBUG_IDX_EMI_WAKE BIT(14)
#define SPM_DBG_DEBUG_IDX_EMI_SLEEP BIT(15)
#define SPM_DBG_DEBUG_IDX_AOVBUS_WAKE BIT(16)
#define SPM_DBG_DEBUG_IDX_AOVBUS_SLEEP BIT(17)
#define SPM_DBG_DEBUG_IDX_CURRENT_IS_CM BIT(18)
#define SPM_DBG_DEBUG_IDX_SYSRAM_ON BIT(19)
#define SPM_DBG_DEBUG_IDX_WAIT_SSPM BIT(20)
#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_SLP BIT(21)
#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_ON BIT(22)
#define SPM_DBG_DEBUG_IDX_SPM_DVFS_NO_REQ BIT(23)
#define SPM_DBG_DEBUG_IDX_VCORE_LP_MODE BIT(24)
#define SPM_DBG_DEBUG_IDX_SPM_NORMAL_WAKEUP BIT(28)
#define SPM_DBG_DEBUG_IDX_SPM_WAKEUP_BY_NONE BIT(29)
/* --- SPM DEBUG1 Define --- */
#define SPM_DBG1_DEBUG_IDX_CURRENT_IS_LP BIT(0)
#define SPM_DBG1_DEBUG_IDX_VCORE_DVFS_START BIT(1)
#define SPM_DBG1_DEBUG_IDX_SYSPLL_OFF BIT(2)
#define SPM_DBG1_DEBUG_IDX_SYSPLL_ON BIT(3)
#define SPM_DBG1_DEBUG_IDX_VMDDRVDDQ_ON BIT(4)
#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_OFF BIT(5)
#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_ON BIT(6)
#define SPM_DBG1_DEBUG_IDX_VTCXO_SLEEP_ABORT_0 BIT(7)
#define SPM_DBG1_DEBUG_IDX_VTCXO_SLEEP_ABORT_1 BIT(8)
#define SPM_DBG1_DEBUG_IDX_VCORE_SLEEP_ABORT_0 BIT(9)
#define SPM_DBG1_DEBUG_IDX_VCORE_SLEEP_ABORT_1 BIT(10)
#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_CSOPLU BIT(11)
#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_26M BIT(12)
#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_32K BIT(13)
#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_26M BIT(14)
#define SPM_DBG1_DEBUG_IDX_BUS_CLK_OFF BIT(15)
#define SPM_DBG1_DEBUG_IDX_BUS_CLK_ON BIT(16)
#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_LOW BIT(17)
#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_HIGH BIT(18)
#define SPM_DBG1_RESERVED_BIT_19 BIT(19)
#define SPM_DBG1_DEBUG_IDX_CSOPLU_IS_OFF_BUT_SHOULD_ON BIT(20)
#define SPM_DBG1_DEBUG_IDX_PMIC_IRQ_ACK_LOW_ABORT BIT(21)
#define SPM_DBG1_DEBUG_IDX_PMIC_IRQ_ACK_HIGH_ABORT BIT(22)
#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_LOW_ABORT BIT(23)
#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_HIGH_ABORT BIT(24)
#define SPM_DBG1_DEBUG_IDX_VMDDRVDDQ_OFF BIT(25)
#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_LOW_ABORT BIT(26)
#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_HIGH_ABORT BIT(27)
#define SPM_DBG1_DEBUG_IDX_SPM_PMIF_CMD_RDY_ABORT BIT(28)
#define SPM_DBG1_DEBUG_IDX_EMI_PDN_RDY_ABORT BIT(29)
#define SPM_DBG1_DEBUG_IDX_LVTS_WRONG_DEVICE_ID BIT(30)
#define SPM_DBG1_DEBUG_IDX_DISABLE_DVFSRC BIT(31)
/* --- SPM PCM_WDT_LATCH3 Define --- */
#define SPM_WDT_LATCH3_RESOURCE_STATE_AOV_INFRA_ON BIT(0)
#define SPM_WDT_LATCH3_RESOURCE_STATE_26M_INFRA_ON BIT(1)
#define SPM_WDT_LATCH3_RESOURCE_STATE_AOV_CLK_ON BIT(2)
#define SPM_WDT_LATCH3_RESOURCE_STATE_26M_CLK_ON BIT(3)
#define SPM_WDT_LATCH3_RESOURCE_STATE_AOV_EMI_ON BIT(4)
#define SPM_WDT_LATCH3_RESOURCE_STATE_26M_EMI_ON BIT(5)
#endif /* SLEEP_DEF_H */

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_VCOREFS_COMMON_H
#define MT_SPM_VCOREFS_COMMON_H
#include <lib/utils_def.h>
/*******************************************************************
*
* DVFSRC Function Return Value & Other Macro Definition
*
*******************************************************************/
#define VCOREFS_SUCCESS 0
#define VCOREFS_E_NOT_SUPPORTED -1
#define VCOREFS_E_SPMFW_NOT_READY 0
#define TAG "vcorefs: "
#define v_min(a, b) MAX(a, b)
#define v_max(a, b) MIN(a, b)
/*******************************************************************
*
* VCOREFS CMD
*
********************************************************************/
enum vcorefs_smc_cmd {
VCOREFS_SMC_VCORE_DVFS_INIT = 0,
VCOREFS_SMC_VCORE_DVFS_KICK = 1,
VCOREFS_SMC_CMD_OPP_TYPE = 2,
VCOREFS_SMC_CMD_FW_TYPE = 3,
VCOREFS_SMC_CMD_GET_UV = 4,
VCOREFS_SMC_CMD_GET_FREQ = 5,
VCOREFS_SMC_CMD_GET_NUM_V = 6,
VCOREFS_SMC_CMD_GET_NUM_F = 7,
/*chip specific setting */
VCOREFS_SMC_CMD_GET_VCORE_INFO = 18,
/*qos specific setting */
VCOREFS_SMC_CMD_QOS_MODE = 32,
VCOREFS_SMC_CMD_PAUSE_ENABLE = 33,
/*spm resource request */
VCOREFS_SMC_RSC_MEM_REQ = 64,
VCOREFS_SMC_RSC_MEM_REL = 65,
};
struct reg_config {
uint32_t offset;
uint32_t val;
};
#endif /* MT_SPM_VCOREFS_COMMON_H */

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_VCOREFS_EXP_H
#define MT_SPM_VCOREFS_EXP_H
int spm_vcorefs_plat_init(uint32_t dvfsrc_flag,
uint32_t dvfsrc_vmode, uint32_t *dram_type);
int spm_vcorefs_plat_kick(void);
int spm_vcorefs_get_opp_type(uint32_t *val);
int spm_vcorefs_get_fw_type(uint32_t *val);
int spm_vcorefs_get_dram_freq(uint32_t gear, uint32_t *freq);
int spm_vcorefs_get_vcore_opp_num(uint32_t *val);
int spm_vcorefs_get_dram_opp_num(uint32_t *val);
int spm_vcorefs_get_vcore_info(uint32_t idx, uint32_t *val);
int spm_vcorefs_qos_mode(uint32_t mode);
int spm_vcorefs_pause_enable(uint32_t enable);
void spm_vcorefs_plat_suspend(void);
void spm_vcorefs_plat_resume(void);
void dvfsrc_md_ddr_turbo(int is_turbo);
#endif /* MT_SPM_VCOREFS_EXP_H */

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <common/debug.h>
#include <drivers/spm/mt_spm_vcorefs_api.h>
#include <mt_spm_vcorefs_common.h>
#include <mt_spm_vcorefs_exp.h>
#include <mt_spm_vcorefs_ext.h>
#include <mtk_sip_svc.h>
static u_register_t mtk_vcorefs_handler(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 ret = VCOREFS_E_NOT_SUPPORTED;
uint64_t cmd = x1;
uint32_t val = 0;
switch (cmd) {
case VCOREFS_SMC_VCORE_DVFS_INIT:
ret = spm_vcorefs_plat_init(x2, x3, &val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_VCORE_DVFS_KICK:
ret = spm_vcorefs_plat_kick();
break;
case VCOREFS_SMC_CMD_OPP_TYPE:
ret = spm_vcorefs_get_opp_type(&val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_CMD_FW_TYPE:
ret = spm_vcorefs_get_fw_type(&val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_CMD_GET_UV:
ret = spm_vcorefs_get_vcore_uv(x2, &val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_CMD_GET_FREQ:
ret = spm_vcorefs_get_dram_freq(x2, &val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_CMD_GET_NUM_V:
ret = spm_vcorefs_get_vcore_opp_num(&val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_CMD_GET_NUM_F:
ret = spm_vcorefs_get_dram_opp_num(&val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_CMD_GET_VCORE_INFO:
ret = spm_vcorefs_get_vcore_info(x2, &val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_CMD_QOS_MODE:
ret = spm_vcorefs_qos_mode(x2);
break;
#ifdef MTK_VCORE_DVFS_PAUSE
case VCOREFS_SMC_CMD_PAUSE_ENABLE:
ret = spm_vcorefs_pause_enable(x2);
break;
#endif
#ifdef MTK_VCORE_DVFS_RES_MEM
case VCOREFS_SMC_RSC_MEM_REQ:
ret = spm_vcorefs_rsc_mem_req(true);
break;
case VCOREFS_SMC_RSC_MEM_REL:
ret = spm_vcorefs_rsc_mem_req(false);
break;
#endif
default:
break;
}
return ret;
}
DECLARE_SMC_HANDLER(MTK_SIP_VCORE_CONTROL, mtk_vcorefs_handler);
#ifdef CONFIG_MTK_VCOREDVFS_LK_SUPPORT
static u_register_t mtk_vcorefs_bl_handler(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 = VCOREFS_E_NOT_SUPPORTED;
uint32_t val = 0;
switch (x1) {
case VCOREFS_SMC_VCORE_DVFS_INIT:
ret = spm_vcorefs_plat_init(x2, x3, &val);
smccc_ret->a1 = val;
break;
case VCOREFS_SMC_VCORE_DVFS_KICK:
ret = spm_vcorefs_plat_kick();
break;
default:
break;
}
return ret;
}
DECLARE_SMC_HANDLER(MTK_SIP_BL_SPM_VCOREFS_CONTROL, mtk_vcorefs_bl_handler);
#endif

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2023, 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,8 +7,6 @@
LOCAL_DIR := $(call GET_LOCAL_DIR) LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := spm MODULE := spm
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
ifneq ($(CONFIG_MTK_SPM_VERSION),) ifneq ($(CONFIG_MTK_SPM_VERSION),)
PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC) PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC)
PLAT_INCLUDES += -I${LOCAL_DIR}/version/notifier/inc PLAT_INCLUDES += -I${LOCAL_DIR}/version/notifier/inc
@ -17,4 +15,36 @@ SUB_RULES-y += ${LOCAL_DIR}/$(CONFIG_MTK_SPM_VERSION)
$(eval $(call add_define,SPM_PLAT_IMPL)) $(eval $(call add_define,SPM_PLAT_IMPL))
endif endif
ifeq ($(CONFIG_MTK_SPM_VERSION), mt8196)
ifeq ($(CONFIG_MTK_SPM_SUPPORT), y)
ifeq ($(CONFIG_MTK_SPM_COMMON_SUPPORT), y)
include ${LOCAL_DIR}/$(CONFIG_MTK_SPM_VERSION)/plat_conf.mk
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/version
PLAT_INCLUDES += -I${LOCAL_DIR}/common
endif
endif
$(eval $(call add_defined_option,CONFIG_MTK_VCOREDVFS_SUPPORT))
ifneq ($(CONFIG_MTK_SPM_COMMON_SUPPORT), y)
LOCAL_SRCS-${CONFIG_MTK_SPM_SUPPORT} += ${LOCAL_DIR}/mt_spm_early_init.c
endif
ifneq ($(CONFIG_MTK_SPM_COMMON_SUPPORT), y)
LOCAL_SRCS-${CONFIG_MTK_SPM_SUPPORT} += ${LOCAL_DIR}/mt_spm_early_init.c
endif
LOCAL_SRCS-${CONFIG_MTK_VCOREDVFS_SUPPORT} += ${LOCAL_DIR}/mt_spm_vcorefs_smc.c
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
SUB_RULES-${MTK_SPM_COMMON_DRV} += ${LOCAL_DIR}/common
SUB_RULES-${MTK_SPM_COMMON_DRV} += ${LOCAL_DIR}/version
$(eval $(call add_defined_option,CONFIG_MTK_SPM_COMMON_SUPPORT))
else
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
endif
$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y))) $(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_VER_H
#define MT_SPM_VER_H
#include <stdint.h>
enum mt_plat_dram_to_spm_type {
SPMFW_DEFAULT_TYPE = 0,
SPMFW_LP4_2CH_3200,
SPMFW_LP4X_2CH_3600,
SPMFW_LP3_1CH_1866,
SPMFW_LP4X_2CH_3733,
SPMFW_LP4X_2CH_4266,
SPMFW_LP4X_2CH_3200,
SPMFW_LP5_2CH_6400,
SPMFW_LP5X_4CH_7500,
SPMFW_TYPE_NOT_FOUND,
};
enum pwrctrl_selection {
SPM_INIT_PWRCTRL = 0,
SPM_VCOREDVFS_PWRCTRL,
SPM_IDLE_PWRCTRL,
SPM_SUSPEND_PWRCTRL,
SPM_PWRCTRL_MAX,
};
struct pcm_desc {
const char *version; /* PCM code version */
uint32_t *base; /* Binary array base */
uintptr_t base_dma; /* DMA addr of base */
uint32_t pmem_words;
uint32_t total_words;
uint32_t pmem_start;
uint32_t dmem_start;
};
#define DYNA_LOAD_PCM_PATH_SIZE 128
#define PCM_FIRMWARE_VERSION_SIZE 128
struct dyna_load_pcm_t {
char path[DYNA_LOAD_PCM_PATH_SIZE];
char version[PCM_FIRMWARE_VERSION_SIZE];
char *buf;
struct pcm_desc desc;
int ready;
};
struct load_pcm_fw_t {
unsigned int fw_max_num;
char **pcm_name_str;
struct dyna_load_pcm_t *dyna_load_pcm;
unsigned int (*is_fw_running)(void);
unsigned int (*get_fw_index)(unsigned int fw_type);
int (*fw_init)(struct pcm_desc *desc);
int (*fw_run)(unsigned int first, void *pwrctrl);
};
/* SPM firmware restart definition */
#define SPM_FW_FORCE_RESET BIT(0)
#define SPM_FW_FORCE_RESUME BIT(1)
int spm_firmware_restart(unsigned int force, void *pwrctrl);
int spm_firmware_type_get(void);
void spm_firmware_type_probe(unsigned int type);
void spm_firmware_init(uint64_t addr, uint64_t size);
uint64_t spm_load_firmware_status(void);
void register_load_fw(struct load_pcm_fw_t *info);
#endif /* MT_SPM_VER_H */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2023, 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,7 +10,9 @@
enum mt_spm_sspm_notify_id { enum mt_spm_sspm_notify_id {
MT_SPM_NOTIFY_LP_ENTER = 0, MT_SPM_NOTIFY_LP_ENTER = 0,
MT_SPM_NOTIFY_LP_LEAVE, MT_SPM_NOTIFY_LP_LEAVE,
MT_SPM_NOTIFY_SUSPEND_VCORE_VOLTAGE, MT_SPM_NOTIFY_SUSPEND_VCORE,
MT_SPM_NOTIFY_IDLE_ENTER,
MT_SPM_NOTIFY_IDLE_LEAVE,
}; };
#ifdef MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT #ifdef MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_SSPM_INTC_H
#define MT_SPM_SSPM_INTC_H
#define MT_SPM_SSPM_INTC_SEL_0 0x10
#define MT_SPM_SSPM_INTC_SEL_1 0x20
#define MT_SPM_SSPM_INTC_SEL_2 0x40
#define MT_SPM_SSPM_INTC_SEL_3 0x80
#define MT_SPM_SSPM_INTC_TRIGGER(id, sg) \
(((0x10 << (id)) | ((sg) << (id))) & 0xFF)
#define SSPM_CFGREG_ADDR(ofs) (SSPM_CFGREG_BASE + (ofs))
#define AP_SSPM_IRQ SSPM_CFGREG_ADDR(0x018)
#define DO_SPM_SSPM_LP_NOTIFY() mmio_write_32(AP_SSPM_IRQ, 1)
#endif /* MT_SPM_SSPM_INTC_H */

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/libc/errno.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <mtk_mmap_pool.h>
#include <notifier/inc/mt_spm_notifier.h>
#include <notifier/v4/mt_spm_sspm_intc.h>
#define MT_SPM_SSPM_MBOX_OFF(x) (SSPM_MBOX_3_BASE + x)
#define MT_SPM_MBOX(slot) MT_SPM_SSPM_MBOX_OFF((slot<<2UL))
/* LOOKUP SSPM_MBOX_SPM_LP1 */
#define SSPM_MBOX_SPM_LP_LOOKUP1 MT_SPM_MBOX(0)
/* LOOKUP SSPM_MBOX_SPM_LP2 */
#define SSPM_MBOX_SPM_LP_LOOKUP2 MT_SPM_MBOX(1)
#define SSPM_MBOX_SPM_LP1 MT_SPM_MBOX(2)
#define SSPM_MBOX_SPM_LP2 MT_SPM_MBOX(3)
#define SSPM_MBOX_SPM_SIZE 16
/* 4 mbox is in usage */
#define MT_SPM_MBOX_OFFSET(slot) MT_SPM_MBOX((slot + 4))
enum SSPM_SLEEP_CMD {
SLP_TASK_NONE = 0,
SLP_TASK_AP_SUSPEND,
SLP_TASK_AP_RESUME,
SLP_TASK_APSRC_OFF,
SLP_TASK_APSRC_ON,
SLP_TASK_INFRA_OFF,
SLP_TASK_INFRA_ON,
SLP_TASK_VCORE_OFF,
SLP_TASK_VCORE_ON,
SLP_TASK_IDLE_OFF,
SLP_TASK_IDLE_ON,
SLP_TASK_INFRA_noPERI_OFF,
SLP_TASK_INFRA_noPERI_ON,
SLP_TASK_ERR = 32,
};
static unsigned int cur_mbox_index;
static int __mt_spm_is_available_index(int cur_idx)
{
unsigned int val;
val = mmio_read_32(MT_SPM_MBOX_OFFSET(cur_idx));
val = (val >> 30);
if (val == 0 || val == 3)
return 1;
return 0;
}
static int __mt_spm_get_available_index(void)
{
unsigned int idx = cur_mbox_index;
int i = 0;
for (i = 0 ; i < SSPM_MBOX_SPM_SIZE ; i++) {
if (__mt_spm_is_available_index(idx)) {
cur_mbox_index = (idx + 1) % SSPM_MBOX_SPM_SIZE;
return idx;
}
idx = (idx + 1) % SSPM_MBOX_SPM_SIZE;
}
return -EBUSY;
}
static int __mt_spm_sspm_write_cmd_queue(int idx, int value)
{
unsigned int val;
val = mmio_read_32(MT_SPM_MBOX_OFFSET(idx));
val = val ^ BIT(31);
val = (value & 0x3fffffff) | (val & 0xc0000000);
mmio_write_32(MT_SPM_MBOX_OFFSET(idx), val);
return 0;
}
void mt_spm_sspm_cmd_enqueue(int cmd)
{
int idx;
idx = __mt_spm_get_available_index();
/* Block when queue full */
if (idx == -EBUSY) {
while (!__mt_spm_is_available_index(cur_mbox_index))
;
idx = cur_mbox_index;
cur_mbox_index = (cur_mbox_index+1) % SSPM_MBOX_SPM_SIZE;
}
__mt_spm_sspm_write_cmd_queue(idx, cmd);
}
int mt_spm_sspm_notify_u32(int type, unsigned int val)
{
switch (type) {
case MT_SPM_NOTIFY_LP_ENTER:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_AP_SUSPEND);
DO_SPM_SSPM_LP_NOTIFY();
break;
case MT_SPM_NOTIFY_LP_LEAVE:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_AP_RESUME);
DO_SPM_SSPM_LP_NOTIFY();
break;
case MT_SPM_NOTIFY_IDLE_ENTER:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_IDLE_OFF);
DO_SPM_SSPM_LP_NOTIFY();
break;
case MT_SPM_NOTIFY_IDLE_LEAVE:
mmio_write_32(SSPM_MBOX_SPM_LP1, val);
mt_spm_sspm_cmd_enqueue(SLP_TASK_IDLE_ON);
DO_SPM_SSPM_LP_NOTIFY();
break;
default:
break;
}
return 0;
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_PMIC_WRAP_H
#define MT_SPM_PMIC_WRAP_H
struct pmic_wrap_cmd_setting {
uint32_t spm_pwrap_addr;
uint32_t cmd_addr;
uint32_t cmd_data;
};
struct pmic_wrap_phase_setting {
struct pmic_wrap_cmd_setting *cmd;
unsigned int nr_idx;
};
struct pmic_wrap_setting {
struct pmic_wrap_phase_setting *phase;
const unsigned int phase_nr_idx;
};
int mt_spm_pmic_wrap_set_phase(unsigned int phase);
int mt_spm_pmic_wrap_set_cmd(unsigned int phase,
unsigned int idx, unsigned int cmd_data);
unsigned long mt_spm_pmic_wrap_get_cmd(unsigned int phase, unsigned int idx);
void mt_spm_pmic_wrap_set_table(struct pmic_wrap_setting *pw);
#endif /* MT_SPM_PMIC_WRAP_H */

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/libc/errno.h>
#include <lib/mmio.h>
#include <pmic_wrap/inc/mt_spm_pmic_wrap.h>
#define SPM_DATA_SHIFT 16
static struct pmic_wrap_setting *pmic_wrap;
int mt_spm_pmic_wrap_set_phase(unsigned int phase)
{
int idx;
uint32_t cmd_addr, cmd_data;
struct pmic_wrap_phase_setting *current_phase;
if (!pmic_wrap)
return -ENODEV;
if (phase >= pmic_wrap->phase_nr_idx)
return -EINVAL;
current_phase = &pmic_wrap->phase[phase];
for (idx = 0; idx < current_phase->nr_idx; idx++) {
cmd_addr = current_phase->cmd[idx].cmd_addr;
cmd_data = current_phase->cmd[idx].cmd_data;
mmio_write_32(current_phase->cmd[idx].spm_pwrap_addr,
(cmd_addr << SPM_DATA_SHIFT) | cmd_data);
}
return 0;
}
int mt_spm_pmic_wrap_set_cmd(unsigned int phase,
unsigned int idx, unsigned int cmd_data)
{
uint32_t cmd_addr;
struct pmic_wrap_phase_setting *current_phase;
if (!pmic_wrap)
return -ENODEV;
if (phase >= pmic_wrap->phase_nr_idx)
return -EINVAL;
if (idx >= pmic_wrap->phase[phase].nr_idx)
return -EINVAL;
current_phase = &pmic_wrap->phase[phase];
current_phase->cmd[idx].cmd_data = cmd_data;
cmd_addr = current_phase->cmd[idx].cmd_addr;
mmio_write_32(current_phase->cmd[idx].spm_pwrap_addr,
(cmd_addr << SPM_DATA_SHIFT) | cmd_data);
return 0;
}
unsigned long mt_spm_pmic_wrap_get_cmd(unsigned int phase, unsigned int idx)
{
if (!pmic_wrap)
return 0;
if (phase >= pmic_wrap->phase_nr_idx)
return 0;
if (idx >= pmic_wrap->phase[phase].nr_idx)
return 0;
return pmic_wrap->phase[phase].cmd[idx].cmd_data;
}
void mt_spm_pmic_wrap_set_table(struct pmic_wrap_setting *pw)
{
pmic_wrap = pw;
}

View file

@ -0,0 +1,23 @@
#
# Copyright (c) 2025, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := spm_version
LOCAL_SRCS-y :=
ifneq (${NOTIFIER_VER},)
LOCAL_SRCS-y += ${LOCAL_DIR}/notifier/${NOTIFIER_VER}/mt_spm_sspm_notifier.c
endif
ifneq (${PMIC_GS_DUMP_VER},)
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_gs/${PMIC_GS_DUMP_VER}/mt_spm_pmic_gs_dump.c
endif
ifneq (${PMIC_WRAP_VER},)
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_wrap/${PMIC_WRAP_VER}/mt_spm_pmic_wrap.c
endif
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
$(eval $(call add_defined_option,CONFIG_MTK_VCOREDVFS_SUPPORT))

View file

@ -0,0 +1,290 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/utils_def.h>
#include <drivers/spmi/pmif_common.h>
#include <drivers/spmi/pmif_v1/pmif.h>
#include <drivers/spmi/spmi_common.h>
#include <drivers/spmi/spmi_sw.h>
#include <drivers/spmi_api.h>
#include <lib/mtk_init/mtk_init.h>
#include <mtk_mmap_pool.h>
#define SPMI_GROUP_ID 0xB
#define SPMI_DEBUG 0
static const mmap_region_t pmif_spmi_mmap[] MTK_MMAP_SECTION = {
MAP_REGION_FLAT(PMIF_SPMI_M_BASE, PMIF_SPMI_SIZE,
MT_DEVICE | MT_RW | MT_NS),
MAP_REGION_FLAT(SPMI_MST_M_BASE, SPMI_MST_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(PMIF_SPMI_P_BASE, PMIF_SPMI_SIZE,
MT_DEVICE | MT_RW | MT_NS),
{0}
};
DECLARE_MTK_MMAP_REGIONS(pmif_spmi_mmap);
static uint16_t mt6xxx_spmi_regs[] = {
[SPMI_OP_ST_CTRL] = 0x0000,
[SPMI_GRP_ID_EN] = 0x0004,
[SPMI_OP_ST_STA] = 0x0008,
[SPMI_MST_SAMPL] = 0x000C,
[SPMI_MST_REQ_EN] = 0x0010,
[SPMI_RCS_CTRL] = 0x0014,
[SPMI_SLV_3_0_EINT] = 0x0020,
[SPMI_SLV_7_4_EINT] = 0x0024,
[SPMI_SLV_B_8_EINT] = 0x0028,
[SPMI_SLV_F_C_EINT] = 0x002C,
[SPMI_REC_CTRL] = 0x0040,
[SPMI_REC0] = 0x0044,
[SPMI_REC1] = 0x0048,
[SPMI_REC2] = 0x004C,
[SPMI_REC3] = 0x0050,
[SPMI_REC4] = 0x0054,
[SPMI_REC_CMD_DEC] = 0x005C,
[SPMI_DEC_DBG] = 0x00F8,
[SPMI_MST_DBG] = 0x00FC,
};
static uint16_t mt6xxx_regs[] = {
[PMIF_INIT_DONE] = 0x0000,
[PMIF_INF_EN] = 0x0024,
[PMIF_ARB_EN] = 0x0150,
[PMIF_IRQ_EVENT_EN_0] = 0x0420,
[PMIF_IRQ_FLAG_0] = 0x0428,
[PMIF_IRQ_CLR_0] = 0x042C,
[PMIF_IRQ_EVENT_EN_2] = 0x0440,
[PMIF_IRQ_FLAG_2] = 0x0448,
[PMIF_IRQ_CLR_2] = 0x044C,
[PMIF_WDT_CTRL] = 0x0470,
[PMIF_WDT_EVENT_EN_1] = 0x047C,
[PMIF_WDT_FLAG_1] = 0x0480,
[PMIF_SWINF_2_ACC] = 0x0880,
[PMIF_SWINF_2_WDATA_31_0] = 0x0884,
[PMIF_SWINF_2_WDATA_63_32] = 0x0888,
[PMIF_SWINF_2_RDATA_31_0] = 0x0894,
[PMIF_SWINF_2_RDATA_63_32] = 0x0898,
[PMIF_SWINF_2_VLD_CLR] = 0x08A4,
[PMIF_SWINF_2_STA] = 0x08A8,
[PMIF_SWINF_3_ACC] = 0x08C0,
[PMIF_SWINF_3_WDATA_31_0] = 0x08C4,
[PMIF_SWINF_3_WDATA_63_32] = 0x08C8,
[PMIF_SWINF_3_RDATA_31_0] = 0x08D4,
[PMIF_SWINF_3_RDATA_63_32] = 0x08D8,
[PMIF_SWINF_3_VLD_CLR] = 0x08E4,
[PMIF_SWINF_3_STA] = 0x08E8,
/* hw mpu */
[PMIF_PMIC_ALL_RGN_EN_1] = 0x09B0,
[PMIF_PMIC_ALL_RGN_EN_2] = 0x0D30,
[PMIF_PMIC_ALL_RGN_0_START] = 0x09B4,
[PMIF_PMIC_ALL_RGN_0_END] = 0x09B8,
[PMIF_PMIC_ALL_RGN_1_START] = 0x09BC,
[PMIF_PMIC_ALL_RGN_1_END] = 0x09C0,
[PMIF_PMIC_ALL_RGN_2_START] = 0x09C4,
[PMIF_PMIC_ALL_RGN_2_END] = 0x09C8,
[PMIF_PMIC_ALL_RGN_3_START] = 0x09CC,
[PMIF_PMIC_ALL_RGN_3_END] = 0x09D0,
[PMIF_PMIC_ALL_RGN_31_START] = 0x0D34,
[PMIF_PMIC_ALL_RGN_31_END] = 0x0D38,
[PMIF_PMIC_ALL_INVLD_SLVID] = 0x0AAC,
[PMIF_PMIC_ALL_RGN_0_PER0] = 0x0AB0,
[PMIF_PMIC_ALL_RGN_0_PER1] = 0x0AB4,
[PMIF_PMIC_ALL_RGN_1_PER0] = 0x0AB8,
[PMIF_PMIC_ALL_RGN_2_PER0] = 0x0AC0,
[PMIF_PMIC_ALL_RGN_3_PER0] = 0x0AC8,
[PMIF_PMIC_ALL_RGN_31_PER0] = 0x0DB4,
[PMIF_PMIC_ALL_RGN_31_PER1] = 0x0DB8,
[PMIF_PMIC_ALL_RGN_OTHERS_PER0] = 0x0BA8,
[PMIF_PMIC_ALL_RGN_OTHERS_PER1] = 0x0BAC,
};
struct pmif pmif_spmi_arb[] = {
{
.base = (void *)PMIF_SPMI_M_BASE,
.regs = mt6xxx_regs,
.spmimst_base = (void *)SPMI_MST_M_BASE,
.spmimst_regs = mt6xxx_spmi_regs,
.mstid = SPMI_MASTER_0,
.read_cmd = pmif_spmi_read_cmd,
.write_cmd = pmif_spmi_write_cmd,
}, {
.base = (void *)PMIF_SPMI_M_BASE,
.regs = mt6xxx_regs,
.spmimst_base = (void *)SPMI_MST_M_BASE,
.spmimst_regs = mt6xxx_spmi_regs,
.mstid = SPMI_MASTER_1,
.read_cmd = pmif_spmi_read_cmd,
.write_cmd = pmif_spmi_write_cmd,
}, {
.base = (void *)PMIF_SPMI_P_BASE,
.regs = mt6xxx_regs,
.spmimst_base = (void *)SPMI_MST_P_BASE,
.spmimst_regs = mt6xxx_spmi_regs,
.mstid = SPMI_MASTER_P_1,
.read_cmd = pmif_spmi_read_cmd,
.write_cmd = pmif_spmi_write_cmd,
},
};
static struct spmi_device spmi_dev[] = {
{
.slvid = SPMI_SLAVE_4,
.grpiden = 0x1 << SPMI_GROUP_ID,
.mstid = SPMI_MASTER_1,
.hwcid_addr = 0x09,
.hwcid_val = 0x63,
.swcid_addr = 0x0B,
.swcid_val = 0x63,
.wpk_key_addr = 0x3A7,
.wpk_key_val = 0x9C,
.wpk_key_h_val = 0x9C,
.tma_key_addr = 0x39E,
.tma_key_val = 0x9C,
.tma_key_h_val = 0x9C,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_1],
}, {
.slvid = SPMI_SLAVE_9,
.grpiden = 0x1 << SPMI_GROUP_ID,
.mstid = SPMI_MASTER_1,
.hwcid_addr = 0x09,
.hwcid_val = 0x85,
.swcid_addr = 0x0B,
.swcid_val = 0x85,
.wpk_key_addr = 0x3AA,
.wpk_key_val = 0x30,
.wpk_key_h_val = 0x63,
.tma_key_addr = 0x39E,
.tma_key_val = 0x7A,
.tma_key_h_val = 0x99,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_1],
}, {
.slvid = SPMI_SLAVE_5,
.grpiden = 0x800,
.mstid = SPMI_MASTER_1,/* spmi-m */
.hwcid_addr = 0x09,
.hwcid_val = 0x73,
.swcid_addr = 0x0B,
.swcid_val = 0x73,
.wpk_key_addr = 0x3A7,
.wpk_key_val = 0x8C,
.wpk_key_h_val = 0x9C,
.tma_key_addr = 0x39E,
.tma_key_val = 0x8C,
.tma_key_h_val = 0x9C,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_1],
}, {
.slvid = SPMI_SLAVE_14, /* MT6379 */
.grpiden = 0x800,
.mstid = SPMI_MASTER_1,/* spmi-m */
.hwcid_addr = 0x00,
.hwcid_val = 0x70,
.hwcid_mask = 0xF0,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_1],
}, {
.slvid = SPMI_SLAVE_6, /* MT6316 */
.grpiden = 0x800,
.mstid = SPMI_MASTER_P_1,/* spmi-m */
.hwcid_addr = 0x209,
.hwcid_val = 0x16,
.swcid_addr = 0x20B,
.swcid_val = 0x16,
.wpk_key_addr = 0x3B1,
.wpk_key_val = 0xE9,
.wpk_key_h_val = 0xE6,
.tma_key_addr = 0x3A8,
.tma_key_val = 0xE9,
.tma_key_h_val = 0xE6,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_P_1],
}, {
.slvid = SPMI_SLAVE_7,
.grpiden = 0x800,
.mstid = SPMI_MASTER_P_1,/* spmi-m */
.hwcid_addr = 0x209,
.hwcid_val = 0x16,
.swcid_addr = 0x20B,
.swcid_val = 0x16,
.wpk_key_addr = 0x3B1,
.wpk_key_val = 0xE9,
.wpk_key_h_val = 0xE6,
.tma_key_addr = 0x3A8,
.tma_key_val = 0xE9,
.tma_key_h_val = 0xE6,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_P_1],
}, {
.slvid = SPMI_SLAVE_8,
.grpiden = 0x800,
.mstid = SPMI_MASTER_P_1,/* spmi-m */
.hwcid_addr = 0x209,
.hwcid_val = 0x16,
.swcid_addr = 0x20B,
.swcid_val = 0x16,
.wpk_key_addr = 0x3B1,
.wpk_key_val = 0xE9,
.wpk_key_h_val = 0xE6,
.tma_key_addr = 0x3A8,
.tma_key_val = 0xE9,
.tma_key_h_val = 0xE6,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_P_1],
}, {
.slvid = SPMI_SLAVE_15,
.grpiden = 0x800,
.mstid = SPMI_MASTER_P_1,/* spmi-m */
.hwcid_addr = 0x209,
.hwcid_val = 0x16,
.swcid_addr = 0x20B,
.swcid_val = 0x16,
.wpk_key_addr = 0x3B1,
.wpk_key_val = 0xE9,
.wpk_key_h_val = 0xE6,
.tma_key_addr = 0x3A8,
.tma_key_val = 0xE9,
.tma_key_h_val = 0xE6,
.pmif_arb = &pmif_spmi_arb[SPMI_MASTER_P_1],
},
};
#if SPMI_DEBUG
static void spmi_read_check(struct spmi_device *dev)
{
uint8_t rdata = 0;
spmi_ext_register_readl(dev, dev->hwcid_addr, &rdata, 1);
if (dev->hwcid_mask) {
if ((rdata & dev->hwcid_mask) == (dev->hwcid_val & dev->hwcid_mask))
SPMI_INFO("%s pass, slvid:%d rdata = 0x%x\n", __func__,
dev->slvid, rdata);
else
SPMI_ERR("%s fail, slvid:%d rdata = 0x%x\n", __func__,
dev->slvid, rdata);
} else {
if (rdata == dev->hwcid_val)
SPMI_INFO("%s pass, slvid:%d rdata = 0x%x\n", __func__,
dev->slvid, rdata);
else
SPMI_ERR("%s fail, slvid:%d rdata = 0x%x\n", __func__,
dev->slvid, rdata);
}
}
void spmi_test(void)
{
for (int k = 0; k < ARRAY_SIZE(spmi_dev); k++)
spmi_read_check(&spmi_dev[k]);
}
#endif
int platform_pmif_spmi_init(void)
{
spmi_device_register(spmi_dev, ARRAY_SIZE(spmi_dev));
#if SPMI_DEBUG
spmi_test();
#endif
return 0;
}
MTK_ARCH_INIT(platform_pmif_spmi_init);

View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <lib/mmio.h>
#include <lib/spinlock.h>
#include <pmif.h>
#include "pmif_common.h"
#include "spmi_common.h"
#include "spmi_sw.h"
#define PMIF_CMD_REG_0 0
#define PMIF_CMD_REG 1
#define PMIF_CMD_EXT_REG 2
#define PMIF_CMD_EXT_REG_LONG 3
#define PMIF_READ_CMD_MIN 0x60
#define PMIF_READ_CMD_MAX 0x7F
#define PMIF_READ_CMD_EXT_MIN 0x20
#define PMIF_READ_CMD_EXT_MAX 0x2F
#define PMIF_READ_CMD_EXT_LONG_MIN 0x38
#define PMIF_READ_CMD_EXT_LONG_MAX 0x3F
#define PMIF_WRITE_CMD_MIN 0x40
#define PMIF_WRITE_CMD_MAX 0x5F
#define PMIF_WRITE_CMD_EXT_MAX 0xF
#define PMIF_WRITE_CMD_EXT_LONG_MIN 0x30
#define PMIF_WRITE_CMD_EXT_LONG_MAX 0x37
#define PMIF_WRITE_CMD_0_MIN 0x80
/* macro for SWINF_FSM */
#define SWINF_FSM_IDLE 0x00
#define SWINF_FSM_REQ 0x02
#define SWINF_FSM_WFDLE 0x04
#define SWINF_FSM_WFVLDCLR 0x06
#define GET_SWINF_FSM(x) (((x) >> 1) & 0x7)
#define GET_PMIF_INIT_DONE(x) (((x) >> 15) & 0x1)
#define TIMEOUT_WAIT_IDLE_US 10000 /* 10ms */
#define PMIF_RW_CMD_SET(opc, rw, sid, bc, addr) \
(((opc) << 30) | ((rw) << 29) | ((sid) << 24) | ((bc) << 16) | (addr))
static spinlock_t pmif_lock;
struct pmif *get_pmif_controller(int inf, int mstid)
{
return &pmif_spmi_arb[mstid];
}
static int pmif_check_idle(int mstid)
{
struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid);
unsigned int reg_rdata, offset = 0;
do {
offset = arb->regs[PMIF_SWINF_3_STA];
reg_rdata = mmio_read_32((uintptr_t)(arb->base + offset));
} while (GET_SWINF_FSM(reg_rdata) != SWINF_FSM_IDLE);
return 0;
}
static int pmif_check_vldclr(int mstid)
{
struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid);
unsigned int reg_rdata, offset = 0;
do {
offset = arb->regs[PMIF_SWINF_3_STA];
reg_rdata = mmio_read_32((uintptr_t)(arb->base + offset));
} while (GET_SWINF_FSM(reg_rdata) != SWINF_FSM_WFVLDCLR);
return 0;
}
int pmif_spmi_read_cmd(struct pmif *arb, uint8_t opc, uint8_t sid,
uint16_t addr, uint8_t *buf, uint8_t len)
{
int ret;
uint32_t offset = 0, data = 0;
uint8_t bc = len - 1;
if (sid > SPMI_MAX_SLAVE_ID || len > PMIF_BYTECNT_MAX)
return -EINVAL;
/* Check the opcode */
if (opc >= PMIF_READ_CMD_MIN && opc <= PMIF_READ_CMD_MAX)
opc = PMIF_CMD_REG;
else if (opc >= PMIF_READ_CMD_EXT_MIN && opc <= PMIF_READ_CMD_EXT_MAX)
opc = PMIF_CMD_EXT_REG;
else if (opc >= PMIF_READ_CMD_EXT_LONG_MIN && opc <= PMIF_READ_CMD_EXT_LONG_MAX)
opc = PMIF_CMD_EXT_REG_LONG;
else
return -EINVAL;
spin_lock(&pmif_lock);
/* Wait for Software Interface FSM state to be IDLE. */
ret = pmif_check_idle(arb->mstid);
if (ret)
goto done;
/* Send the command. */
offset = arb->regs[PMIF_SWINF_3_ACC];
mmio_write_32((uintptr_t)(arb->base + offset), PMIF_RW_CMD_SET(opc, 0, sid, bc, addr));
/*
* Wait for Software Interface FSM state to be WFVLDCLR,
* read the data and clear the valid flag.
*/
ret = pmif_check_vldclr(arb->mstid);
if (ret)
goto done;
offset = arb->regs[PMIF_SWINF_3_RDATA_31_0];
data = mmio_read_32((uintptr_t)(arb->base + offset));
memcpy(buf, &data, (bc & 3) + 1);
offset = arb->regs[PMIF_SWINF_3_VLD_CLR];
mmio_write_32((uintptr_t)(arb->base + offset), 0x1);
done:
spin_unlock(&pmif_lock);
return ret;
}
int pmif_spmi_write_cmd(struct pmif *arb, uint8_t opc, uint8_t sid, uint16_t addr,
const uint8_t *buf, uint8_t len)
{
int ret;
uint32_t offset = 0, data = 0;
uint8_t bc = len - 1;
if (sid > SPMI_MAX_SLAVE_ID || len > PMIF_BYTECNT_MAX)
return -EINVAL;
/* Check the opcode */
if (opc >= PMIF_WRITE_CMD_MIN && opc <= PMIF_WRITE_CMD_MAX)
opc = PMIF_CMD_REG;
else if (opc <= PMIF_WRITE_CMD_EXT_MAX)
opc = PMIF_CMD_EXT_REG;
else if (opc >= PMIF_WRITE_CMD_EXT_LONG_MIN && opc <= PMIF_WRITE_CMD_EXT_LONG_MAX)
opc = PMIF_CMD_EXT_REG_LONG;
else if (opc >= PMIF_WRITE_CMD_0_MIN)
opc = PMIF_CMD_REG_0;
else
return -EINVAL;
spin_lock(&pmif_lock);
/* Wait for Software Interface FSM state to be IDLE. */
ret = pmif_check_idle(arb->mstid);
if (ret)
goto done;
/* Set the write data. */
offset = arb->regs[PMIF_SWINF_3_WDATA_31_0];
memcpy(&data, buf, (bc & 3) + 1);
mmio_write_32((uintptr_t)(arb->base + offset), data);
/* Send the command. */
offset = arb->regs[PMIF_SWINF_3_ACC];
mmio_write_32((uintptr_t)(arb->base + offset), PMIF_RW_CMD_SET(opc, 1, sid, bc, addr));
done:
spin_unlock(&pmif_lock);
return ret;
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PMIF_COMMON_H
#define PMIF_COMMON_H
#include <stdint.h>
enum {
PMIF_CMD_REG_0,
PMIF_CMD_REG,
PMIF_CMD_EXT_REG,
PMIF_CMD_EXT_REG_LONG,
};
struct pmif {
void *base;
uint16_t *regs;
void *spmimst_base;
uint16_t *spmimst_regs;
uint32_t mstid;
int (*read_cmd)(struct pmif *arb, uint8_t opc, uint8_t sid, uint16_t addr, uint8_t *buf,
uint8_t len);
int (*write_cmd)(struct pmif *arb, uint8_t opc, uint8_t sid, uint16_t addr,
const uint8_t *buf, uint8_t len);
};
enum {
PMIF_SPMI,
PMIF_SPI
};
int pmif_spmi_read_cmd(struct pmif *arb, uint8_t opc, uint8_t sid, uint16_t addr, uint8_t *buf,
uint8_t len);
int pmif_spmi_write_cmd(struct pmif *arb, uint8_t opc, uint8_t sid, uint16_t addr,
const uint8_t *buf, uint8_t len);
struct pmif *get_pmif_controller(int inf, int mstid);
extern struct pmif pmif_spmi_arb[];
#endif

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2025, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PMIF_H
#define PMIF_H
#include <stdint.h>
#include <platform_def.h>
#include <drivers/spmi/pmif_common.h>
#include <drivers/spmi/spmi_common.h>
enum pmif_regs {
PMIF_INIT_DONE,
PMIF_INF_EN,
PMIF_ARB_EN,
PMIF_IRQ_EVENT_EN_0,
PMIF_IRQ_FLAG_0,
PMIF_IRQ_CLR_0,
PMIF_IRQ_EVENT_EN_2,
PMIF_IRQ_FLAG_2,
PMIF_IRQ_CLR_2,
PMIF_WDT_CTRL,
PMIF_WDT_EVENT_EN_1,
PMIF_WDT_FLAG_1,
PMIF_SWINF_2_ACC,
PMIF_SWINF_2_WDATA_31_0,
PMIF_SWINF_2_WDATA_63_32,
PMIF_SWINF_2_RDATA_31_0,
PMIF_SWINF_2_RDATA_63_32,
PMIF_SWINF_2_VLD_CLR,
PMIF_SWINF_2_STA,
PMIF_SWINF_3_ACC,
PMIF_SWINF_3_WDATA_31_0,
PMIF_SWINF_3_WDATA_63_32,
PMIF_SWINF_3_RDATA_31_0,
PMIF_SWINF_3_RDATA_63_32,
PMIF_SWINF_3_VLD_CLR,
PMIF_SWINF_3_STA,
/* HW MPU */
PMIF_PMIC_ALL_RGN_EN_1,
PMIF_PMIC_ALL_RGN_EN_2,
PMIF_PMIC_ALL_RGN_0_START,
PMIF_PMIC_ALL_RGN_0_END,
PMIF_PMIC_ALL_RGN_1_START,
PMIF_PMIC_ALL_RGN_1_END,
PMIF_PMIC_ALL_RGN_2_START,
PMIF_PMIC_ALL_RGN_2_END,
PMIF_PMIC_ALL_RGN_3_START,
PMIF_PMIC_ALL_RGN_3_END,
PMIF_PMIC_ALL_RGN_31_START,
PMIF_PMIC_ALL_RGN_31_END,
PMIF_PMIC_ALL_INVLD_SLVID,
PMIF_PMIC_ALL_RGN_0_PER0,
PMIF_PMIC_ALL_RGN_0_PER1,
PMIF_PMIC_ALL_RGN_1_PER0,
PMIF_PMIC_ALL_RGN_2_PER0,
PMIF_PMIC_ALL_RGN_3_PER0,
PMIF_PMIC_ALL_RGN_31_PER0,
PMIF_PMIC_ALL_RGN_31_PER1,
PMIF_PMIC_ALL_RGN_OTHERS_PER0,
PMIF_PMIC_ALL_RGN_OTHERS_PER1,
};
#endif

View file

@ -0,0 +1,19 @@
#
# Copyright (c) 2025, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := spmi
PLAT_INCLUDES += -I${MTK_PLAT}/drivers/spmi/pmif_v1
#Add your source code here
LOCAL_SRCS-y := ${LOCAL_DIR}/pmif_common.c
LOCAL_SRCS-y += ${LOCAL_DIR}/spmi_common.c
LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/platform_pmif_spmi.c
#Epilogue, build as module
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))

View file

@ -0,0 +1,199 @@
/*
* Copyright (c) 2025, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include "spmi_common.h"
#include "spmi_sw.h"
/* SPMI Commands */
#define SPMI_CMD_EXT_WRITE 0x00
#define SPMI_CMD_EXT_READ 0x20
#define SPMI_CMD_EXT_WRITEL 0x30
#define SPMI_CMD_EXT_READL 0x38
#define SPMI_CMD_WRITE 0x40
#define SPMI_CMD_READ 0x60
#define SPMI_CMD_ZERO_WRITE 0x80
#define SPMI_READ_ADDR_MAX 0x1F
static struct spmi_device *spmi_dev[SPMI_MAX_SLAVE_ID];
int spmi_register_zero_write(struct spmi_device *dev, uint8_t data)
{
return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_ZERO_WRITE,
dev->slvid, 0, &data, 1);
}
int spmi_register_read(struct spmi_device *dev, uint8_t addr, uint8_t *buf)
{
/* 5-bit register address */
if (addr > SPMI_READ_ADDR_MAX)
return -EINVAL;
return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_READ, dev->slvid, addr, buf, 1);
}
int spmi_register_write(struct spmi_device *dev, uint8_t addr, uint8_t data)
{
/* 5-bit register address */
if (addr > SPMI_READ_ADDR_MAX)
return -EINVAL;
return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_WRITE,
dev->slvid, addr, &data, 1);
}
int spmi_ext_register_read(struct spmi_device *dev, uint8_t addr, uint8_t *buf,
uint8_t len)
{
/* 8-bit register address, up to 16 bytes */
if (len == 0 || len > 16)
return -EINVAL;
return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READ,
dev->slvid, addr, buf, len);
}
int spmi_ext_register_write(struct spmi_device *dev, uint8_t addr,
const uint8_t *buf, uint8_t len)
{
/* 8-bit register address, up to 16 bytes */
if (len == 0 || len > 16)
return -EINVAL;
return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITE,
dev->slvid, addr, buf, len);
}
int spmi_ext_register_readl(struct spmi_device *dev, uint16_t addr,
uint8_t *buf, uint8_t len)
{
/* 8-bit register address, up to 16 bytes */
if (len == 0 || len > 16)
return -EINVAL;
return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READL,
dev->slvid, addr, buf, len);
}
int spmi_ext_register_writel(struct spmi_device *dev, uint16_t addr,
const uint8_t *buf, uint8_t len)
{
/* 8-bit register address, up to 16 bytes */
if (len == 0 || len > 16)
return -EINVAL;
return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITEL,
dev->slvid, addr, buf, len);
}
int spmi_ext_register_readl_field(struct spmi_device *dev, uint16_t addr,
uint8_t *buf, uint16_t mask, uint16_t shift)
{
int ret;
uint8_t rdata = 0;
ret = dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READL,
dev->slvid, addr, &rdata, 1);
if (!ret)
*buf = (rdata >> shift) & mask;
return ret;
}
int spmi_ext_register_writel_field(struct spmi_device *dev, uint16_t addr,
uint8_t data, uint16_t mask, uint16_t shift)
{
int ret;
uint8_t tmp = 0;
ret = spmi_ext_register_readl(dev, addr, &tmp, 1);
if (ret)
return ret;
tmp &= ~(mask << shift);
tmp |= (data << shift);
return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITEL,
dev->slvid, addr, &tmp, 1);
}
struct spmi_device *get_spmi_device(int mstid, int slvid)
{
if (slvid >= SPMI_MAX_SLAVE_ID || slvid < 0) {
SPMI_ERR("failed to get spmi_device with slave id %d\n", slvid);
return NULL;
}
return spmi_dev[slvid];
}
int spmi_device_register(struct spmi_device *platform_spmi_dev, unsigned int num_devs)
{
int i;
if (!platform_spmi_dev || num_devs == 0)
return -EINVAL;
for (i = 0; i < num_devs; i++) {
if (platform_spmi_dev[i].slvid >= SPMI_MAX_SLAVE_ID ||
platform_spmi_dev[i].slvid < 0) {
SPMI_INFO("invalid slave id %d\n", platform_spmi_dev[i].slvid);
continue;
}
if (!spmi_dev[platform_spmi_dev[i].slvid])
spmi_dev[platform_spmi_dev[i].slvid] = &platform_spmi_dev[i];
else {
SPMI_INFO("duplicated slave id %d\n", platform_spmi_dev[i].slvid);
return -EINVAL;
}
}
return 0;
}
static int spmi_ctrl_op_st(int mstid, unsigned int grpiden, unsigned int sid,
unsigned int cmd)
{
struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid);
unsigned int rdata = 0x0;
uintptr_t spmi_grp_id_en_addr =
(uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_GRP_ID_EN]);
uintptr_t spmi_op_st_ctrl_addr =
(uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_OP_ST_CTRL]);
uintptr_t spmi_op_st_sta_addr =
(uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_OP_ST_STA]);
/* gid is 0x800 */
mmio_write_32(spmi_grp_id_en_addr, grpiden);
if (grpiden == (1 << SPMI_GROUP_ID))
mmio_write_32(spmi_op_st_ctrl_addr, (cmd << 0x4) | SPMI_GROUP_ID);
else
mmio_write_32(spmi_op_st_ctrl_addr, (cmd << 0x4) | sid);
SPMI_INFO("%s 0x%x\n", __func__, mmio_read_32(spmi_op_st_ctrl_addr));
do {
rdata = mmio_read_32(spmi_op_st_sta_addr);
SPMI_INFO("%s 0x%x\n", __func__, rdata);
if (((rdata >> 0x1) & SPMI_OP_ST_NACK) == SPMI_OP_ST_NACK) {
SPMI_ERR("SPMI_OP_ST_NACK occurs! OP_ST_STA = 0x%x\n", rdata);
break;
}
} while ((rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY);
return 0;
}
int spmi_command_shutdown(int mstid, struct spmi_device *dev, unsigned int grpiden)
{
if (grpiden != (1 << SPMI_GROUP_ID))
dev->slvid = grpiden;
return spmi_ctrl_op_st(mstid, grpiden, dev->slvid, SPMI_SHUTDOWN);
}

Some files were not shown because too many files have changed in this diff Show more