feat(mt8196): add MMinfra support
Add MMinfra support for MT8196.
Change-Id: I5504764d05fecace4f0d3981785ff1bc8ae13d00
Signed-off-by: Yidi Lin <yidilin@chromium.org>
diff --git a/plat/mediatek/drivers/mminfra/mminfra_common.h b/plat/mediatek/drivers/mminfra/mminfra_common.h
new file mode 100644
index 0000000..93820c7
--- /dev/null
+++ b/plat/mediatek/drivers/mminfra/mminfra_common.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2025, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MMINFRA_COMMON_H
+#define MMINFRA_COMMON_H
+
+#define mminfra_info(fmt, args...) INFO("[mminfra] %s: "fmt"\n", __func__, ##args)
+#define mminfra_err(fmt, args...) ERROR("[mminfra] %s: "fmt"\n", __func__, ##args)
+
+#endif
diff --git a/plat/mediatek/drivers/mminfra/mminfra_stub.c b/plat/mediatek/drivers/mminfra/mminfra_stub.c
deleted file mode 100644
index dc37280..0000000
--- a/plat/mediatek/drivers/mminfra/mminfra_stub.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2025, MediaTek Inc. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <drivers/mminfra_public.h>
-
-int mminfra_get_if_in_use(void)
-{
- return 0;
-}
-
-int mminfra_put(void)
-{
- return 0;
-}
diff --git a/plat/mediatek/drivers/mminfra/mt8196/mminfra.c b/plat/mediatek/drivers/mminfra/mt8196/mminfra.c
new file mode 100644
index 0000000..1086c75
--- /dev/null
+++ b/plat/mediatek/drivers/mminfra/mt8196/mminfra.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2025, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <drivers/mminfra_public.h>
+#include <mminfra.h>
+#include <mtk_mmap_pool.h>
+
+static const mmap_region_t mminfra_plat_mmap[] MTK_MMAP_SECTION = {
+ MAP_REGION_FLAT(MMINFRA_HW_VOTER_BASE, PAGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ {0}
+};
+DECLARE_MTK_MMAP_REGIONS(mminfra_plat_mmap);
+
+static struct mtk_mminfra_pwr_ctrl mminfra_pwr_ctrl = {
+ .hw_voter = {
+ .base = MMINFRA_HW_VOTER_BASE,
+ .set_ofs = 0x104,
+ .clr_ofs = 0x108,
+ .en_ofs = 0x100,
+ .en_shift = 0x1,
+ .done_bits = VLP_AO_RSVD6,
+ },
+ .hw_sema = {
+ .base = SPM_BASE,
+ .offset = SPM_SEMAPHORE_M1,
+ .offset_all = {
+ SPM_SEMAPHORE_M0,
+ SPM_SEMAPHORE_M1,
+ SPM_SEMAPHORE_M2,
+ SPM_SEMAPHORE_M3,
+ SPM_SEMAPHORE_M4,
+ SPM_SEMAPHORE_M5,
+ SPM_SEMAPHORE_M6,
+ SPM_SEMAPHORE_M7,
+ },
+ .set_val = SPM_SEMA_MMINFRA,
+ },
+ .active = true,
+ .ref_cnt = 0,
+};
+
+static int spm_semaphore_get(uint32_t base, uint32_t set_val)
+{
+ int cnt = SEMA_RETRY_CNT;
+ uint32_t val;
+
+ val = mmio_read_32(base);
+ if ((val & set_val) == set_val) {
+ mminfra_err("hw_sem was already got, base:0x%x=0x%x, set_val:0x%x\n",
+ base, val, set_val);
+ return -1;
+ }
+
+ while (cnt > 0) {
+ mmio_write_32(base, set_val);
+ udelay(10);
+ if ((mmio_read_32(base) & set_val) == set_val)
+ return 0;
+ cnt--;
+ }
+
+ mminfra_err("timeout! base:0x%x, set_val:0x%x\n", base, set_val);
+ return -1;
+}
+
+static int spm_semaphore_release(uint32_t base, uint32_t set_val)
+{
+ int cnt = SEMA_RETRY_CNT;
+ uint32_t val;
+
+ val = mmio_read_32(base);
+ if ((val & set_val) != set_val) {
+ mminfra_err("hw_sem was already released, base:0x%x=0x%x, set_val:0x%x\n",
+ base, val, set_val);
+ return -1;
+ }
+ do {
+ mmio_write_32(base, set_val);
+ udelay(10);
+ if (cnt-- < 0) {
+ if ((mmio_read_32(base) & set_val) != set_val)
+ return 0;
+ mminfra_err("timeout! base:0x%x, set_val:0x%x\n", base, set_val);
+ return -1;
+ }
+ } while ((mmio_read_32(base) & set_val) == set_val);
+
+ return 0;
+}
+
+static int mminfra_hw_sema_ctrl(struct mminfra_hw_sema *hw_sema, bool is_get)
+{
+ int i, ret;
+
+ if (!hw_sema)
+ return 0;
+
+ if (is_get)
+ ret = spm_semaphore_get(hw_sema->base + hw_sema->offset, hw_sema->set_val);
+ else
+ ret = spm_semaphore_release(hw_sema->base + hw_sema->offset, hw_sema->set_val);
+
+ if (ret)
+ for (i = 0; i < SPM_SEMA_MMINFRA_NR; i++)
+ mminfra_err("0x%x=0x%x\n", hw_sema->base + hw_sema->offset_all[i],
+ mmio_read_32(hw_sema->base + hw_sema->offset_all[i]));
+
+ return ret;
+}
+
+static bool is_mminfra_ready(struct mminfra_hw_voter *hw_voter)
+{
+ if (!hw_voter)
+ return false;
+
+ return !!(mmio_read_32(hw_voter->done_bits) & MMINFRA_DONE);
+}
+
+static int mminfra_hwv_power_ctrl(struct mminfra_hw_voter *hw_voter, bool is_on)
+{
+ uint32_t vote_ofs, vote_mask, vote_ack;
+ uint32_t val = 0, cnt;
+
+ vote_mask = BIT(hw_voter->en_shift);
+ vote_ofs = is_on ? hw_voter->set_ofs : hw_voter->clr_ofs;
+ vote_ack = is_on ? vote_mask : 0x0;
+
+ /* Vote on off */
+ cnt = 0;
+ do {
+ mmio_write_32(hw_voter->base + vote_ofs, vote_mask);
+ udelay(MTK_POLL_HWV_VOTE_US);
+ val = mmio_read_32(hw_voter->base + hw_voter->en_ofs);
+ if ((val & vote_mask) == vote_ack)
+ break;
+
+ if (cnt > MTK_POLL_HWV_VOTE_CNT) {
+ mminfra_err("vote mminfra timeout, is_on:%d, 0x%x=0x%x\n",
+ is_on, hw_voter->base + hw_voter->en_ofs, val);
+ return -1;
+ }
+ cnt++;
+ } while (1);
+
+ if (!is_on)
+ return 0;
+
+ /* Confirm done bits */
+ cnt = 0;
+ while (cnt < MTK_POLL_DONE_RETRY) {
+ if (is_mminfra_ready(hw_voter))
+ return 0;
+ udelay(MTK_POLL_DONE_DELAY_US);
+ cnt++;
+ }
+
+ mminfra_err("polling mminfra done timeout, 0x%x=0x%x\n",
+ hw_voter->done_bits, val);
+ return -1;
+}
+
+int mminfra_get_if_in_use(void)
+{
+ int ret, is_on = MMINFRA_RET_POWER_OFF;
+
+ if (!mminfra_pwr_ctrl.active) {
+ mminfra_err("not ready\n");
+ return MMINFRA_RET_POWER_OFF;
+ }
+
+ spin_lock(&mminfra_pwr_ctrl.lock);
+ if (mminfra_pwr_ctrl.ref_cnt > 0) {
+ mminfra_pwr_ctrl.ref_cnt++;
+ is_on = MMINFRA_RET_POWER_ON;
+ spin_unlock(&mminfra_pwr_ctrl.lock);
+ return is_on;
+ }
+
+ ret = mminfra_hw_sema_ctrl(&mminfra_pwr_ctrl.hw_sema, true);
+ if (ret)
+ goto err;
+
+ /* Check if mminfra is in use */
+ if (is_mminfra_ready(&mminfra_pwr_ctrl.hw_voter)) {
+ ret = mminfra_hwv_power_ctrl(&mminfra_pwr_ctrl.hw_voter, true);
+ if (ret) {
+ mminfra_err("vote for mminfra fail, ret=%d\n", ret);
+ goto err;
+ }
+ mminfra_pwr_ctrl.ref_cnt++;
+ is_on = MMINFRA_RET_POWER_ON;
+ } else {
+ is_on = MMINFRA_RET_POWER_OFF;
+ }
+
+ ret = mminfra_hw_sema_ctrl(&mminfra_pwr_ctrl.hw_sema, false);
+ if (ret)
+ goto err;
+ ret = is_on; /* Return power is on or off. */
+err:
+ spin_unlock(&mminfra_pwr_ctrl.lock);
+ return ret;
+}
+
+int mminfra_put(void)
+{
+ if (!mminfra_pwr_ctrl.active) {
+ mminfra_err("not ready\n");
+ return 0;
+ }
+
+ spin_lock(&mminfra_pwr_ctrl.lock);
+ mminfra_pwr_ctrl.ref_cnt--;
+ if (mminfra_pwr_ctrl.ref_cnt > 0)
+ goto out;
+
+ mminfra_hwv_power_ctrl(&mminfra_pwr_ctrl.hw_voter, false);
+out:
+ spin_unlock(&mminfra_pwr_ctrl.lock);
+ return 0;
+}
diff --git a/plat/mediatek/drivers/mminfra/mt8196/mminfra.h b/plat/mediatek/drivers/mminfra/mt8196/mminfra.h
new file mode 100644
index 0000000..fcee08c
--- /dev/null
+++ b/plat/mediatek/drivers/mminfra/mt8196/mminfra.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MMINFRA_H
+#define MMINFRA_H
+
+#include <lib/spinlock.h>
+
+#include "../mminfra_common.h"
+#include <platform_def.h>
+
+#define VLP_AO_RSVD6 (MTK_VLP_TRACER_MON_BASE + 0x918)
+#define MMINFRA_DONE (1U << 0)
+
+#define SPM_SEMA_MMINFRA (1U << 5)
+#define SPM_SEMA_MMINFRA_NR (8)
+
+#define SEMA_RETRY_CNT (500)
+
+#define SPM_SEMAPHORE_M0 (0x69C)
+#define SPM_SEMAPHORE_M1 (0x6A0)
+#define SPM_SEMAPHORE_M2 (0x6A4)
+#define SPM_SEMAPHORE_M3 (0x6A8)
+#define SPM_SEMAPHORE_M4 (0x6AC)
+#define SPM_SEMAPHORE_M5 (0x6B0)
+#define SPM_SEMAPHORE_M6 (0x6B4)
+#define SPM_SEMAPHORE_M7 (0x6B8)
+
+#define MMINFRA_HW_VOTER_BASE (0x31A80000)
+#define MTK_POLL_HWV_VOTE_US (2)
+#define MTK_POLL_HWV_VOTE_CNT (2500)
+#define MTK_POLL_DONE_DELAY_US (1)
+#define MTK_POLL_DONE_RETRY (3000)
+
+struct mminfra_hw_sema {
+ uint32_t base;
+ uint32_t offset;
+ uint32_t offset_all[SPM_SEMA_MMINFRA_NR];
+ uint32_t set_val;
+};
+
+struct mminfra_hw_voter {
+ uint32_t base;
+ uint32_t set_ofs;
+ uint32_t clr_ofs;
+ uint32_t en_ofs;
+ uint32_t en_shift;
+ uint32_t done_bits;
+};
+
+struct mtk_mminfra_pwr_ctrl {
+ spinlock_t lock;
+ struct mminfra_hw_voter hw_voter;
+ struct mminfra_hw_sema hw_sema;
+ uint32_t ref_cnt;
+ bool active;
+};
+
+#endif
diff --git a/plat/mediatek/drivers/mminfra/rules.mk b/plat/mediatek/drivers/mminfra/rules.mk
index f3a6822..cd5d607 100644
--- a/plat/mediatek/drivers/mminfra/rules.mk
+++ b/plat/mediatek/drivers/mminfra/rules.mk
@@ -8,10 +8,9 @@
MODULE := mminfra
-PLAT_INCLUDES += -I${MTK_PLAT}/include/drivers/
+PLAT_INCLUDES += -I$(MTK_PLAT)/include/drivers/
+PLAT_INCLUDES += -I$(MTK_PLAT)/drivers/mminfra/$(MTK_SOC)
-ifeq ($(MTKLIB_PATH),)
-LOCAL_SRCS-y := ${LOCAL_DIR}/mminfra_stub.c
-endif
+LOCAL_SRCS-y := $(LOCAL_DIR)/$(MTK_SOC)/mminfra.c
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/mt8196/include/platform_def.h b/plat/mediatek/mt8196/include/platform_def.h
index 363c8cc..ad0bf68 100644
--- a/plat/mediatek/mt8196/include/platform_def.h
+++ b/plat/mediatek/mt8196/include/platform_def.h
@@ -341,4 +341,10 @@
#define SSPM_CFGREG_BASE (IO_PHYS + 0x0C300000 + SSPM_REG_OFFSET)
#define SSPM_CFGREG_SIZE (0x1000)
+/*******************************************************************************
+ * MMinfra related constants
+ ******************************************************************************/
+#define MTK_VLP_TRACER_MON_BASE (IO_PHYS + 0x0c000000)
+#define MTK_VLP_TRACER_MON_REG_SIZE (0x1000)
+
#endif /* PLATFORM_DEF_H */