feat(mediatek): add new features of LPM

Add new functions and intefaces of LPM to support more interactions
between LPM providers and users.

Change-Id: I8ebbda0c0ef5be3a7a388a38c09424ebf785996f
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
index 0bafc66..807614a 100644
--- a/plat/mediatek/common/lpm/mt_lp_rm.c
+++ b/plat/mediatek/common/lpm/mt_lp_rm.c
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2020-2023, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include <mt_lp_rm.h>
 #include <stddef.h>
+#include <lpm/mt_lp_rm.h>
 
 struct platform_mt_resource_manager {
 	unsigned int count;
@@ -54,6 +54,29 @@
 	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_find_and_run_constraint(int idx, unsigned int cpuid,
 				     int stateid, void *priv)
 {
diff --git a/plat/mediatek/common/lpm/mt_lp_rm.h b/plat/mediatek/common/lpm/mt_lp_rm.h
index e93dac3..bda3ba1 100644
--- a/plat/mediatek/common/lpm/mt_lp_rm.h
+++ b/plat/mediatek/common/lpm/mt_lp_rm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ * Copyright (c) 2020-2023, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,14 +9,34 @@
 
 #include <stdbool.h>
 
-#define MT_RM_STATUS_OK		0
-#define MT_RM_STATUS_BAD	-1
+#define MT_RM_STATUS_OK		(0)
+#define MT_RM_STATUS_BAD	(-1)
+#define MT_RM_STATUS_STOP	(-2)
 
 enum PLAT_MT_LPM_RC_TYPE {
 	PLAT_RC_UPDATE_CONDITION,
-	PLAT_RC_UPDATE_REMAIN_IRQS
+	PLAT_RC_STATUS,
+	PLAT_RC_UPDATE_REMAIN_IRQS,
+	PLAT_RC_IS_FMAUDIO,
+	PLAT_RC_IS_ADSP,
+	PLAT_RC_ENTER_CNT,
+	PLAT_RC_CLKBUF_STATUS,
+	PLAT_RC_UFS_STATUS,
+	PLAT_RC_IS_USB_PERI,
+	PLAT_RC_IS_USB_INFRA,
+	PLAT_RC_MAX,
 };
 
+enum plat_mt_lpm_hw_ctrl_type {
+	PLAT_AP_MDSRC_REQ,
+	PLAT_AP_MDSRC_ACK,
+	PLAT_AP_IS_MD_SLEEP,
+	PLAT_AP_MDSRC_SETTLE,
+	PLAT_AP_GPUEB_PLL_CONTROL,
+	PLAT_AP_GPUEB_GET_PWR_STATUS,
+	PLAT_AP_HW_CTRL_MAX,
+};
+
 struct mt_resource_constraint {
 	int level;
 	int (*init)(void);
@@ -24,6 +44,7 @@
 	int (*update)(int stateid, int type, const void *p);
 	int (*run)(unsigned int cpu, int stateid);
 	int (*reset)(unsigned int cpu, int stateid);
+	int (*get_status)(unsigned int type, void *priv);
 	unsigned int (*allow)(int stateid);
 };
 
@@ -39,4 +60,6 @@
 extern int mt_lp_rm_reset_constraint(int constraint_id, unsigned int cpuid,
 				     int stateid);
 extern int mt_lp_rm_do_update(int stateid, int type, void const *p);
+extern int mt_lp_rm_get_status(unsigned int type, void *priv);
+
 #endif /* MT_LP_RM_H */
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
index 87a212a..eb68e03 100644
--- a/plat/mediatek/common/lpm/rules.mk
+++ b/plat/mediatek/common/lpm/rules.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+# Copyright (c) 2023, MediaTek Inc. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -7,7 +7,10 @@
 LOCAL_DIR := $(call GET_LOCAL_DIR)
 
 MODULE := lpm
-LOCAL_SRCS-y := $(LOCAL_DIR)/mt_lp_rm.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_rq.c
 
 PLAT_INCLUDES += -I${LOCAL_DIR}