feat(mt8188): add IOMMU enable control in SiP service

Add SiP service for multimedia & infra master to enable/disable
MM & INFRA IOMMU in secure world

TEST=build pass
BUG=b:236339614

Signed-off-by: Chengci Xu <chengci.xu@mediatek.corp-partner.google.com>
Change-Id: I4eb1fda6044cf2cb6c22c005cb2fa550906b71e9
diff --git a/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.c b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.c
new file mode 100644
index 0000000..1d6863f
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mtk_iommu_plat.h>
+#include <mtk_mmap_pool.h>
+#include <platform_def.h>
+
+/* mm iommu */
+#define SMI_L0_ID		(0)
+#define SMI_L1_ID		(1)
+#define SMI_L2_ID		(2)
+#define SMI_L3_ID		(3)
+#define SMI_L4_ID		(4)
+#define SMI_L5_ID		(5)
+#define SMI_L6_ID		(6)
+#define SMI_L7_ID		(7)
+#define SMI_L9_ID		(8)
+#define SMI_L10_ID		(9)
+#define SMI_L11A_ID		(10)
+#define SMI_L11B_ID		(11)
+#define SMI_L11C_ID		(12)
+#define SMI_L12_ID		(13)
+#define SMI_L13_ID		(14)
+#define SMI_L14_ID		(15)
+#define SMI_L15_ID		(16)
+#define SMI_L16A_ID		(17)
+#define SMI_L16B_ID		(18)
+#define SMI_L17A_ID		(19)
+#define SMI_L17B_ID		(20)
+#define SMI_L19_ID		(21)
+#define SMI_L21_ID		(22)
+#define SMI_L23_ID		(23)
+#define SMI_L27_ID		(24)
+#define SMI_L28_ID		(25)
+
+/* infra iommu */
+#define PERI_MST_PROT		(0x710)
+#define PERICFG_AO_IOMMU_1	(0x714)
+#define MMU_DEV_PCIE_0		(0)
+#define IFR_CFG_GROUP_NUM	(1)
+
+static struct mtk_smi_larb_config mt8188_larb_cfg[SMI_LARB_NUM] = {
+	[SMI_L0_ID] = LARB_CFG_ENTRY(SMI_LARB_0_BASE, 7, 0),
+	[SMI_L1_ID] = LARB_CFG_ENTRY(SMI_LARB_1_BASE, 7, 0),
+	[SMI_L2_ID] = LARB_CFG_ENTRY(SMI_LARB_2_BASE, 5, 0),
+	[SMI_L3_ID] = LARB_CFG_ENTRY(SMI_LARB_3_BASE, 7, 0),
+	[SMI_L4_ID] = LARB_CFG_ENTRY(SMI_LARB_4_BASE, 7, 0),
+	[SMI_L5_ID] = LARB_CFG_ENTRY(SMI_LARB_5_BASE, 8, 0),
+	[SMI_L6_ID] = LARB_CFG_ENTRY(SMI_LARB_6_BASE, 4, 0),
+	[SMI_L7_ID] = LARB_CFG_ENTRY(SMI_LARB_7_BASE, 3, 0),
+	[SMI_L9_ID] = LARB_CFG_ENTRY(SMI_LARB_9_BASE, 25, 0),
+	[SMI_L10_ID] = LARB_CFG_ENTRY(SMI_LARB_10_BASE, 20, 0),
+	[SMI_L11A_ID] = LARB_CFG_ENTRY(SMI_LARB_11A_BASE, 30, 0),
+	[SMI_L11B_ID] = LARB_CFG_ENTRY(SMI_LARB_11B_BASE, 30, 0),
+	[SMI_L11C_ID] = LARB_CFG_ENTRY(SMI_LARB_11C_BASE, 30, 0),
+	[SMI_L12_ID] = LARB_CFG_ENTRY(SMI_LARB_12_BASE, 16, 0),
+	[SMI_L13_ID] = LARB_CFG_ENTRY(SMI_LARB_13_BASE, 24, 0),
+	[SMI_L14_ID] = LARB_CFG_ENTRY(SMI_LARB_14_BASE, 23, 0),
+	[SMI_L15_ID] = LARB_CFG_ENTRY(SMI_LARB_15_BASE, 19, 0),
+	[SMI_L16A_ID] = LARB_CFG_ENTRY(SMI_LARB_16A_BASE, 17, 0),
+	[SMI_L16B_ID] = LARB_CFG_ENTRY(SMI_LARB_16B_BASE, 17, 0),
+	[SMI_L17A_ID] = LARB_CFG_ENTRY(SMI_LARB_17A_BASE, 7, 0),
+	[SMI_L17B_ID] = LARB_CFG_ENTRY(SMI_LARB_17B_BASE, 7, 0),
+	/* venc nbm ports (5/6/11/15/16/17) to sram */
+	[SMI_L19_ID] = LARB_CFG_ENTRY_WITH_PATH(SMI_LARB_19_BASE, 27, 0, 0x38860),
+	[SMI_L21_ID] = LARB_CFG_ENTRY(SMI_LARB_21_BASE, 11, 0),
+	[SMI_L23_ID] = LARB_CFG_ENTRY(SMI_LARB_23_BASE, 9, 0),
+	[SMI_L27_ID] = LARB_CFG_ENTRY(SMI_LARB_27_BASE, 4, 0),
+	[SMI_L28_ID] = LARB_CFG_ENTRY(SMI_LARB_28_BASE, 0, 0),
+};
+
+static bool is_protected;
+
+static uint32_t mt8188_ifr_mst_cfg_base[IFR_CFG_GROUP_NUM] = {
+	PERICFG_AO_BASE,
+};
+static uint32_t mt8188_ifr_mst_cfg_offs[IFR_CFG_GROUP_NUM] = {
+	PERICFG_AO_IOMMU_1,
+};
+static struct mtk_ifr_mst_config mt8188_ifr_mst_cfg[MMU_DEV_NUM] = {
+	[MMU_DEV_PCIE_0] = IFR_MST_CFG_ENTRY(0, 18),
+};
+
+struct mtk_smi_larb_config *g_larb_cfg = &mt8188_larb_cfg[0];
+struct mtk_ifr_mst_config *g_ifr_mst_cfg = &mt8188_ifr_mst_cfg[0];
+uint32_t *g_ifr_mst_cfg_base = &mt8188_ifr_mst_cfg_base[0];
+uint32_t *g_ifr_mst_cfg_offs = &mt8188_ifr_mst_cfg_offs[0];
+
+/* Protect infra iommu enable setting registers as secure access. */
+void mtk_infra_iommu_enable_protect(void)
+{
+	if (!is_protected) {
+		mmio_write_32(PERICFG_AO_BASE + PERI_MST_PROT, 0xffffffff);
+		is_protected = true;
+	}
+}
diff --git a/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.h b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.h
new file mode 100644
index 0000000..a59e0c7
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IOMMU_PLAT_H
+#define IOMMU_PLAT_H
+
+#include <mtk_iommu_priv.h>
+
+/* mm iommu */
+#define SMI_LARB_NUM	(26)
+extern struct mtk_smi_larb_config *g_larb_cfg;
+
+/* infra iommu */
+#define MMU_DEV_NUM	(1)
+extern struct mtk_ifr_mst_config *g_ifr_mst_cfg;
+extern uint32_t *g_ifr_mst_cfg_base;
+extern uint32_t *g_ifr_mst_cfg_offs;
+
+extern void mtk_infra_iommu_enable_protect(void);
+
+#endif /* IOMMU_PLAT_H */
diff --git a/plat/mediatek/drivers/iommu/mtk_iommu_priv.h b/plat/mediatek/drivers/iommu/mtk_iommu_priv.h
new file mode 100644
index 0000000..3404d31
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mtk_iommu_priv.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IOMMU_PRIV_H
+#define IOMMU_PRIV_H
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mtk_sip_svc.h>
+
+#define LARB_CFG_ENTRY(bs, p_nr, dom)			\
+	{ .base = (bs), .port_nr = (p_nr),		\
+	  .dom_id = (dom), .to_sram = 0, }
+
+#define LARB_CFG_ENTRY_WITH_PATH(bs, p_nr, dom, sram)	\
+	{ .base = (bs), .port_nr = (p_nr),		\
+	  .dom_id = (dom), .to_sram = (sram), }
+
+#define IFR_MST_CFG_ENTRY(idx, bit)	\
+	{ .cfg_addr_idx = (idx), .r_mmu_en_bit = (bit), }
+
+enum IOMMU_ATF_CMD {
+	IOMMU_ATF_CMD_CONFIG_SMI_LARB,		/* For mm master to enable iommu */
+	IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU,	/* For infra master to enable iommu */
+	IOMMU_ATF_CMD_COUNT,
+};
+
+struct mtk_smi_larb_config {
+	uint32_t base;
+	uint32_t port_nr;
+	uint32_t dom_id;
+	uint32_t to_sram;
+	uint32_t sec_en_msk;
+};
+
+struct mtk_ifr_mst_config {
+	uint8_t cfg_addr_idx;
+	uint8_t r_mmu_en_bit;
+};
+
+#endif	/* IOMMU_PRIV_H */
diff --git a/plat/mediatek/drivers/iommu/mtk_iommu_smc.c b/plat/mediatek/drivers/iommu/mtk_iommu_smc.c
new file mode 100644
index 0000000..9762d0b
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mtk_iommu_smc.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <mtk_iommu_plat.h>
+
+/* defination */
+/* smi larb */
+#define SMI_LARB_NON_SEC_CON(port)	(0x380 + ((port) << 2))
+#define PATH_SEL_MASK			(0xf0000) /* to sram (INT) */
+#define SMI_LARB_SEC_CON_INT(port)	(0xf00 + ((port) << 2))
+#define SMI_LARB_SEC_CON(port)		(0xf80 + ((port) << 2))
+#define MMU_MASK			BIT(0)
+#define MMU_EN(en)			((!!(en)) << 0)
+#define SEC_MASK			BIT(1)
+#define SEC_EN(en)			((!!(en)) << 1)
+#define DOMAIN_MASK			(0x1f << 4)
+#define SMI_MMU_EN(port)		(0x1 << (port))
+
+/* infra master */
+#define IFR_CFG_MMU_EN_MSK(r_bit)	(0x3 << (r_bit))
+
+/* smi larb configure */
+/*
+ * If multimedia security config is enabled, the SMI config register must be
+ * configurated in security world.
+ * And the SRAM path is also configurated here to enhance security.
+ */
+static void mtk_smi_larb_port_config_to_sram(
+				const struct mtk_smi_larb_config *larb,
+				uint32_t port_id)
+{
+	mmio_clrbits_32(larb->base + SMI_LARB_SEC_CON_INT(port_id),
+			MMU_MASK | SEC_MASK | DOMAIN_MASK);
+
+	mmio_setbits_32(larb->base + SMI_LARB_NON_SEC_CON(port_id),
+			PATH_SEL_MASK);
+}
+
+static void mtk_smi_port_config(const struct mtk_smi_larb_config *larb,
+				uint32_t port_id, uint8_t mmu_en, uint8_t sec_en)
+{
+	mmio_clrsetbits_32(larb->base + SMI_LARB_SEC_CON(port_id),
+			   MMU_MASK | SEC_MASK | DOMAIN_MASK,
+			   MMU_EN(mmu_en) | SEC_EN(sec_en));
+}
+
+static int mtk_smi_larb_port_config_sec(uint32_t larb_id, uint32_t mmu_en_msk)
+{
+	uint32_t port_id, port_nr;
+	const struct mtk_smi_larb_config *larb;
+	uint32_t to_sram;
+	uint8_t mmu_en;
+
+	if (larb_id >= SMI_LARB_NUM) {
+		return MTK_SIP_E_INVALID_PARAM;
+	}
+
+	larb = &g_larb_cfg[larb_id];
+	port_nr = larb->port_nr;
+	to_sram = larb->to_sram;
+
+	for (port_id = 0; port_id < port_nr; port_id++) {
+		if ((to_sram & BIT(port_id)) > 0U) {
+			mtk_smi_larb_port_config_to_sram(larb, port_id);
+			continue;
+		}
+		mmu_en = !!(mmu_en_msk & SMI_MMU_EN(port_id));
+		mtk_smi_port_config(larb, port_id, mmu_en, 0);
+	}
+
+	return MTK_SIP_E_SUCCESS;
+}
+
+static int mtk_infra_master_config_sec(uint32_t dev_id, uint32_t enable)
+{
+	const struct mtk_ifr_mst_config *ifr_cfg;
+	uint32_t reg_addr;
+
+	mtk_infra_iommu_enable_protect();
+
+	if (dev_id >= MMU_DEV_NUM) {
+		return MTK_SIP_E_NOT_SUPPORTED;
+	}
+
+	ifr_cfg = &g_ifr_mst_cfg[dev_id];
+	reg_addr = g_ifr_mst_cfg_base[(ifr_cfg->cfg_addr_idx)] +
+		   g_ifr_mst_cfg_offs[(ifr_cfg->cfg_addr_idx)];
+
+	if (enable > 0U) {
+		mmio_setbits_32(reg_addr, IFR_CFG_MMU_EN_MSK(ifr_cfg->r_mmu_en_bit));
+	} else {
+		mmio_clrbits_32(reg_addr, IFR_CFG_MMU_EN_MSK(ifr_cfg->r_mmu_en_bit));
+	}
+
+	return MTK_SIP_E_SUCCESS;
+}
+
+static u_register_t mtk_iommu_handler(u_register_t x1, u_register_t x2,
+				      u_register_t x3, u_register_t x4,
+				      void *handle, struct smccc_res *smccc_ret)
+{
+	uint32_t cmd_id = x1, mdl_id = x2, val = x3;
+	int ret = MTK_SIP_E_NOT_SUPPORTED;
+
+	(void)x4;
+	(void)handle;
+
+	switch (cmd_id) {
+	case IOMMU_ATF_CMD_CONFIG_SMI_LARB:
+		ret = mtk_smi_larb_port_config_sec(mdl_id, val);
+		break;
+	case IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU:
+		ret = mtk_infra_master_config_sec(mdl_id, val);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+DECLARE_SMC_HANDLER(MTK_SIP_IOMMU_CONTROL, mtk_iommu_handler);
diff --git a/plat/mediatek/drivers/iommu/rules.mk b/plat/mediatek/drivers/iommu/rules.mk
new file mode 100644
index 0000000..5490f41
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/rules.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_iommu
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_iommu_smc.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtk_iommu_plat.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/include/mt8188/platform_def.h b/plat/mediatek/include/mt8188/platform_def.h
index 15ea5b6..fa8cd41 100644
--- a/plat/mediatek/include/mt8188/platform_def.h
+++ b/plat/mediatek/include/mt8188/platform_def.h
@@ -26,6 +26,12 @@
 #define UART_BAUDRATE	(115200)
 
 /*******************************************************************************
+ * Infra IOMMU related constants
+ ******************************************************************************/
+#define PERICFG_AO_BASE		(IO_PHYS + 0x01003000)
+#define PERICFG_AO_REG_SIZE	(0x1000)
+
+/*******************************************************************************
  * GIC-600 & interrupt handling related constants
  ******************************************************************************/
 /* Base MTK_platform compatible GIC memory map */
@@ -42,6 +48,37 @@
 #define CIRQ_SPI_START		(96)
 
 /*******************************************************************************
+ * MM IOMMU & SMI related constants
+ ******************************************************************************/
+#define SMI_LARB_0_BASE		(IO_PHYS + 0x0c022000)
+#define SMI_LARB_1_BASE		(IO_PHYS + 0x0c023000)
+#define SMI_LARB_2_BASE		(IO_PHYS + 0x0c102000)
+#define SMI_LARB_3_BASE		(IO_PHYS + 0x0c103000)
+#define SMI_LARB_4_BASE		(IO_PHYS + 0x04013000)
+#define SMI_LARB_5_BASE		(IO_PHYS + 0x04f02000)
+#define SMI_LARB_6_BASE		(IO_PHYS + 0x04f03000)
+#define SMI_LARB_7_BASE		(IO_PHYS + 0x04e04000)
+#define SMI_LARB_9_BASE		(IO_PHYS + 0x05001000)
+#define SMI_LARB_10_BASE	(IO_PHYS + 0x05120000)
+#define SMI_LARB_11A_BASE	(IO_PHYS + 0x05230000)
+#define SMI_LARB_11B_BASE	(IO_PHYS + 0x05530000)
+#define SMI_LARB_11C_BASE	(IO_PHYS + 0x05630000)
+#define SMI_LARB_12_BASE	(IO_PHYS + 0x05340000)
+#define SMI_LARB_13_BASE	(IO_PHYS + 0x06001000)
+#define SMI_LARB_14_BASE	(IO_PHYS + 0x06002000)
+#define SMI_LARB_15_BASE	(IO_PHYS + 0x05140000)
+#define SMI_LARB_16A_BASE	(IO_PHYS + 0x06008000)
+#define SMI_LARB_16B_BASE	(IO_PHYS + 0x0600a000)
+#define SMI_LARB_17A_BASE	(IO_PHYS + 0x06009000)
+#define SMI_LARB_17B_BASE	(IO_PHYS + 0x0600b000)
+#define SMI_LARB_19_BASE	(IO_PHYS + 0x0a010000)
+#define SMI_LARB_21_BASE	(IO_PHYS + 0x0802e000)
+#define SMI_LARB_23_BASE	(IO_PHYS + 0x0800d000)
+#define SMI_LARB_27_BASE	(IO_PHYS + 0x07201000)
+#define SMI_LARB_28_BASE	(IO_PHYS + 0x00000000)
+#define SMI_LARB_REG_RNG_SIZE	(0x1000)
+
+/*******************************************************************************
  * DP related constants
  ******************************************************************************/
 #define EDP_SEC_BASE		(IO_PHYS + 0x0C504000)
diff --git a/plat/mediatek/include/mtk_sip_def.h b/plat/mediatek/include/mtk_sip_def.h
index 37734ea..d760101 100644
--- a/plat/mediatek/include/mtk_sip_def.h
+++ b/plat/mediatek/include/mtk_sip_def.h
@@ -11,6 +11,7 @@
 #define MTK_SIP_SMC_FROM_NS_EL1_TABLE(_func) \
 	_func(MTK_SIP_KERNEL_TIME_SYNC, 0x202) \
 	_func(MTK_SIP_VCORE_CONTROL, 0x506) \
+	_func(MTK_SIP_IOMMU_CONTROL, 0x514) \
 	_func(MTK_SIP_APUSYS_CONTROL, 0x51E) \
 	_func(MTK_SIP_DP_CONTROL, 0x523) \
 	_func(MTK_SIP_KERNEL_GIC_OP, 0x526)
diff --git a/plat/mediatek/mt8188/platform.mk b/plat/mediatek/mt8188/platform.mk
index 61b61db..8ba66da 100644
--- a/plat/mediatek/mt8188/platform.mk
+++ b/plat/mediatek/mt8188/platform.mk
@@ -25,6 +25,7 @@
 MODULES-y += $(MTK_PLAT)/drivers/cirq
 MODULES-y += $(MTK_PLAT)/drivers/dp
 MODULES-y += $(MTK_PLAT)/drivers/gic600
+MODULES-y += $(MTK_PLAT)/drivers/iommu
 MODULES-y += $(MTK_PLAT)/drivers/timer
 
 PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \