mediatek: mt8192: Add lpm driver

Low Power Management (LPM) helps find a suitable configuration
for letting system entering idle or suspend with the most
resources off.

Change-Id: Ie6a7063b666cf338cff5bc972c9025b26de482eb
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..f3148fe
--- /dev/null
+++ b/plat/mediatek/common/lpm/mt_lp_rm.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mt_lp_rm.h>
+#include <stddef.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(int idx, unsigned int cpuid, int stateid)
+{
+	struct mt_resource_constraint const *rc = NULL;
+
+	if ((plat_mt_rm.plat_rm == NULL) || (idx < 0) ||
+	    (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_find_and_run_constraint(int idx, unsigned int cpuid,
+				     int stateid, void *priv)
+{
+	int i, 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 < 0) || (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, stateid, priv);
+		if (res != 0) {
+			return res;
+		}
+	}
+
+	for (i = idx, rc = (rm->consts + idx); *rc != NULL; i++, rc++) {
+		if (((*rc)->is_valid != NULL) &&
+		    ((*rc)->is_valid(cpuid, stateid))) {
+			if (((*rc)->run != NULL) &&
+			    ((*rc)->run(cpuid, stateid) == 0)) {
+				res = i;
+				break;
+			}
+		}
+	}
+
+	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_rm.h b/plat/mediatek/common/lpm/mt_lp_rm.h
new file mode 100644
index 0000000..39759f1
--- /dev/null
+++ b/plat/mediatek/common/lpm/mt_lp_rm.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_LP_RM_H
+#define MT_LP_RM_H
+
+#include <stdbool.h>
+
+#define MT_RM_STATUS_OK		0
+#define MT_RM_STATUS_BAD	-1
+
+enum PLAT_MT_LPM_RC_TYPE {
+	PLAT_RC_UPDATE_CONDITION,
+	PLAT_RC_UPDATE_REMAIN_IRQS
+};
+
+struct mt_resource_constraint {
+	int level;
+	int (*init)(void);
+	bool (*is_valid)(unsigned int cpu, int stateid);
+	int (*update)(int stateid, int type, const void *p);
+	int (*run)(unsigned int cpu, int stateid);
+	int (*reset)(unsigned int cpu, int stateid);
+	unsigned int (*allow)(int stateid);
+};
+
+struct mt_resource_manager {
+	int (*update)(struct mt_resource_constraint **con,
+		      int stateid, void *priv);
+	struct mt_resource_constraint **consts;
+};
+
+extern int mt_lp_rm_register(struct mt_resource_manager *rm);
+extern int mt_lp_rm_find_and_run_constraint(int idx, unsigned int cpuid,
+					    int stateid, void *priv);
+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);
+#endif /* MT_LP_RM_H */
diff --git a/plat/mediatek/mt8192/platform.mk b/plat/mediatek/mt8192/platform.mk
index a5e7ee2..9c9b233 100644
--- a/plat/mediatek/mt8192/platform.mk
+++ b/plat/mediatek/mt8192/platform.mk
@@ -8,6 +8,7 @@
 MTK_PLAT_SOC  := ${MTK_PLAT}/${PLAT}
 
 PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
+                 -I${MTK_PLAT}/common/lpm/                        \
                  -I${MTK_PLAT_SOC}/include/                       \
                  -I${MTK_PLAT_SOC}/drivers/                       \
                  -I${MTK_PLAT_SOC}/drivers/dcm                    \
@@ -42,6 +43,7 @@
                    ${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init_v2.c \
                    ${MTK_PLAT}/common/drivers/rtc/rtc_common.c           \
                    ${MTK_PLAT}/common/drivers/uart/uart.c                \
+                   ${MTK_PLAT}/common/lpm/mt_lp_rm.c                     \
                    ${MTK_PLAT}/common/mtk_plat_common.c                  \
                    ${MTK_PLAT}/common/mtk_sip_svc.c                      \
                    ${MTK_PLAT}/common/params_setup.c                     \