diff options
Diffstat (limited to 'plat/mediatek/common/lpm')
-rw-r--r-- | plat/mediatek/common/lpm/mt_lp_api.c | 48 | ||||
-rw-r--r-- | plat/mediatek/common/lpm/mt_lp_rm.c | 162 | ||||
-rw-r--r-- | plat/mediatek/common/lpm/mt_lp_rq.c | 204 | ||||
-rw-r--r-- | plat/mediatek/common/lpm/rules.mk | 17 |
4 files changed, 431 insertions, 0 deletions
diff --git a/plat/mediatek/common/lpm/mt_lp_api.c b/plat/mediatek/common/lpm/mt_lp_api.c new file mode 100644 index 0000000..2a1da6a --- /dev/null +++ b/plat/mediatek/common/lpm/mt_lp_api.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <lpm/mt_lp_api.h> + +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; + 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; + ret = mt_lp_rm_do_update(-1, PLAT_RC_IS_ADSP, &val); + break; + default: + ret = -1; + break; + } + + return ret; +} + +int mtk_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; + default: + ret = -1; + break; + } + + return ret; +} diff --git a/plat/mediatek/common/lpm/mt_lp_rm.c b/plat/mediatek/common/lpm/mt_lp_rm.c new file mode 100644 index 0000000..9f07968 --- /dev/null +++ b/plat/mediatek/common/lpm/mt_lp_rm.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2020-2023, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stddef.h> +#include <lpm/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; +} diff --git a/plat/mediatek/common/lpm/mt_lp_rq.c b/plat/mediatek/common/lpm/mt_lp_rq.c new file mode 100644 index 0000000..7b83fed --- /dev/null +++ b/plat/mediatek/common/lpm/mt_lp_rq.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2023, 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/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_request(struct mt_lp_resource_user *this, unsigned int resource) +{ + int i; + struct mt_lp_res_req *const *rs; + + 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); + + return MT_LP_RQ_STA_OK; +} + +static int mt_lp_resource_release(struct mt_lp_resource_user *this) +{ + int i; + struct mt_lp_res_req *const *rs; + + 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); + + return MT_LP_RQ_STA_OK; +} + +int mt_lp_resource_request_manager_register(struct mt_resource_req_manager *rqm) +{ + unsigned int count; + struct mt_lp_res_req *const *rs; + + if ((rqm == NULL) || (rqm->res == NULL) || (plat_mt_rqm.plat_rqm != NULL)) { + return MT_LP_RQ_STA_BAD; + } + + rs = rqm->res; + count = 0; + while (*rs != NULL) { + count++; + rs++; + } + + plat_mt_rqm.plat_rqm = rqm; + 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) || (plat_mt_rqm.user_num >= MT_LP_RQ_USER_MAX) || + (user == NULL)) { + ru->uid = MT_LP_RQ_USER_INVALID; + ru->umask = 0; + ru->request = NULL; + ru->release = NULL; + ERROR("rqm register user invalid\n"); + return MT_LP_RQ_STA_BAD; + } + + 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); + 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; +} + +int mt_lp_rq_get_status(int type, void *p) +{ + int i; + unsigned int update_sta; + struct mt_lp_res_req *const *rs; + struct resource_req_status *rq_sta = (struct resource_req_status *)p; + + if (plat_mt_rqm.flag != 0) { + spin_lock(&mt_lp_rq_lock); + + update_sta = 0; + rs = (plat_mt_rqm.plat_rqm)->res; + for (i = 0; i < plat_mt_rqm.resource_num; i++) { + update_sta |= ((rs[i]->res_usage & plat_mt_rqm.user_valid) != 0) ? + rs[i]->res_rq : 0; + } + + plat_mt_rqm.generic_resource_req = update_sta; + plat_mt_rqm.flag = MT_LP_RQ_FLAG_DONE; + spin_unlock(&mt_lp_rq_lock); + } + + switch (type) { + case PLAT_RQ_REQ_USAGE: + rs = (plat_mt_rqm.plat_rqm)->res; + rq_sta->val = (rq_sta->id < plat_mt_rqm.resource_num) ? + rs[rq_sta->id]->res_usage : plat_mt_rqm.generic_resource_req; + 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; + } + + return MT_LP_RQ_STA_OK; +} + +int mt_lp_rq_update_status(int type, void *p) +{ + unsigned int user_mask; + struct resource_req_status *rq_sta = (struct resource_req_status *)p; + + switch (type) { + case PLAT_RQ_USER_VALID: + if (rq_sta->id < plat_mt_rqm.user_num) { + user_mask = BIT(rq_sta->id); + spin_lock(&mt_lp_rq_lock); + plat_mt_rqm.user_valid = (rq_sta->val == 0) ? + (plat_mt_rqm.user_valid & ~(user_mask)) : + (plat_mt_rqm.user_valid | user_mask); + plat_mt_rqm.flag = MT_LP_RQ_FLAG_NEED_UPDATE; + spin_unlock(&mt_lp_rq_lock); + } + break; + default: + break; + } + + return MT_LP_RQ_STA_OK; +} diff --git a/plat/mediatek/common/lpm/rules.mk b/plat/mediatek/common/lpm/rules.mk new file mode 100644 index 0000000..eb68e03 --- /dev/null +++ b/plat/mediatek/common/lpm/rules.mk @@ -0,0 +1,17 @@ +# +# Copyright (c) 2023, MediaTek Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +LOCAL_DIR := $(call GET_LOCAL_DIR) + +MODULE := lpm + +LOCAL_SRCS-y := $(LOCAL_DIR)/mt_lp_api.c +LOCAL_SRCS-y += $(LOCAL_DIR)/mt_lp_rm.c +LOCAL_SRCS-y += $(LOCAL_DIR)/mt_lp_rq.c + +PLAT_INCLUDES += -I${LOCAL_DIR} + +$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL))) |