diff options
Diffstat (limited to 'plat/mediatek/common/lpm/mt_lp_rq.c')
-rw-r--r-- | plat/mediatek/common/lpm/mt_lp_rq.c | 204 |
1 files changed, 204 insertions, 0 deletions
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; +} |