summaryrefslogtreecommitdiffstats
path: root/plat/mediatek/common/lpm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 17:43:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 17:43:51 +0000
commitbe58c81aff4cd4c0ccf43dbd7998da4a6a08c03b (patch)
tree779c248fb61c83f65d1f0dc867f2053d76b4e03a /plat/mediatek/common/lpm
parentInitial commit. (diff)
downloadarm-trusted-firmware-upstream.tar.xz
arm-trusted-firmware-upstream.zip
Adding upstream version 2.10.0+dfsg.upstream/2.10.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/mediatek/common/lpm')
-rw-r--r--plat/mediatek/common/lpm/mt_lp_api.c48
-rw-r--r--plat/mediatek/common/lpm/mt_lp_rm.c162
-rw-r--r--plat/mediatek/common/lpm/mt_lp_rq.c204
-rw-r--r--plat/mediatek/common/lpm/rules.mk17
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)))