[PATCH 3/3] iommu/mediatek-v1: add mt6572 support

Roman Vivchar via B4 Relay devnull+rva333.protonmail.com at kernel.org
Wed Sep 9 07:14:07 PDT 2026


From: Roman Vivchar <rva333 at protonmail.com>

mt6572 SoC utilizes an earlier version of the IOMMU, that shares the
same v1 architecture, but has minor hardware differences compared to
mt2701.

Introduce mtk_iommu_type to distinguish between mt2701 and mt6572
variant and apply the necessary logic.

Finally, add a platform data for the mt6572 SoC.

Signed-off-by: Roman Vivchar <rva333 at protonmail.com>
---
Based on my downstream findings, this change may also support mt6582 SoC,
but I don't have the hardware to test if it actually works.
---
 drivers/iommu/mtk_iommu_v1.c | 72 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 55 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 72355f41c36a..b6f547b100d1 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -7,6 +7,7 @@
  *
  * Based on driver/iommu/mtk_iommu.c
  */
+#include <linux/bitfield.h>
 #include <linux/bug.h>
 #include <linux/clk.h>
 #include <linux/component.h>
@@ -85,6 +86,13 @@ struct dma_iommu_mapping {
 #define F_DESC_NONSEC				BIT(3)
 #define MT2701_M4U_TF_LARB(TF)			(6 - (((TF) >> 13) & 0x7))
 #define MT2701_M4U_TF_PORT(TF)			(((TF) >> 8) & 0xF)
+
+#define MT6572_MMU_INT_ID_PORT_ID		GENMASK(12, 8)
+#define MT6572_MMU_INT_ID_LARB_ID		GENMASK(14, 13)
+
+#define MT6572_M4U_TF_PORT(TF)			FIELD_GET(MT6572_MMU_INT_ID_PORT_ID, TF)
+#define MT6572_M4U_TF_LARB(TF)			(FIELD_GET(MT6572_MMU_INT_ID_LARB_ID, TF) - 1)
+
 /* MTK generation one iommu HW only support 4K size mapping */
 #define MT2701_IOMMU_PAGE_SHIFT			12
 #define MT2701_IOMMU_PAGE_SIZE			(1UL << MT2701_IOMMU_PAGE_SHIFT)
@@ -96,6 +104,11 @@ struct dma_iommu_mapping {
  */
 #define M2701_IOMMU_PGT_SIZE			SZ_4M
 
+enum mtk_iommu_type {
+	MTK_IOMMU_MT6572,
+	MTK_IOMMU_V1,
+};
+
 struct mtk_iommu_v1_suspend_reg {
 	u32			standard_axi_mode;
 	u32			dcm_dis;
@@ -116,6 +129,8 @@ struct mtk_iommu_v1_data {
 	struct mtk_smi_larb_iommu	larb_imu[MTK_LARB_NR_MAX];
 
 	struct mtk_iommu_v1_suspend_reg	reg;
+
+	enum mtk_iommu_type type;
 };
 
 struct mtk_iommu_v1_domain {
@@ -170,8 +185,12 @@ static inline int mt2701_m4u_to_port(int id)
 
 static void mtk_iommu_v1_tlb_flush_all(struct mtk_iommu_v1_data *data)
 {
-	writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
-			data->base + REG_MMU_INV_SEL);
+	u32 val = F_INVLD_EN0;
+
+	if (data->type == MTK_IOMMU_V1)
+		val |= F_INVLD_EN1;
+
+	writel_relaxed(val, data->base + REG_MMU_INV_SEL);
 	writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
 	wmb(); /* Make sure the tlb flush all done */
 }
@@ -180,25 +199,33 @@ static void mtk_iommu_v1_tlb_flush_range(struct mtk_iommu_v1_data *data,
 					 unsigned long iova, size_t size)
 {
 	int ret;
-	u32 tmp;
+	u32 tmp, val = F_INVLD_EN0;
 
-	writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
-		data->base + REG_MMU_INV_SEL);
+	if (data->type == MTK_IOMMU_V1)
+		val |= F_INVLD_EN1;
+
+	writel_relaxed(val, data->base + REG_MMU_INV_SEL);
 	writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
 		data->base + REG_MMU_INVLD_START_A);
 	writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
 		data->base + REG_MMU_INVLD_END_A);
 	writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
 
-	ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
-				tmp, tmp != 0, 10, 100000);
-	if (ret) {
-		dev_warn(data->dev,
-			 "Partial TLB flush timed out, falling back to full flush\n");
-		mtk_iommu_v1_tlb_flush_all(data);
+	if (data->type == MTK_IOMMU_V1) {
+		ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
+						tmp, tmp != 0, 10, 100000);
+		if (ret) {
+			dev_warn(data->dev,
+				 "Partial TLB flush timed out, falling back to full flush\n");
+			mtk_iommu_v1_tlb_flush_all(data);
+		}
+
+		/* Clear the CPE status */
+		writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
+	} else {
+		/* Make sure the TLB flush is done */
+		wmb();
 	}
-	/* Clear the CPE status */
-	writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
 }
 
 static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
@@ -215,8 +242,14 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
 	fault_iova &= F_MMU_FAULT_VA_MSK;
 	fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
 	regval = readl_relaxed(data->base + REG_MMU_INT_ID);
-	fault_larb = MT2701_M4U_TF_LARB(regval);
-	fault_port = MT2701_M4U_TF_PORT(regval);
+
+	if (data->type == MTK_IOMMU_V1) {
+		fault_larb = MT2701_M4U_TF_LARB(regval);
+		fault_port = MT2701_M4U_TF_PORT(regval);
+	} else {
+		fault_larb = MT6572_M4U_TF_LARB(regval);
+		fault_port = MT6572_M4U_TF_PORT(regval);
+	}
 
 	/*
 	 * MTK v1 iommu HW could not determine whether the fault is read or
@@ -539,7 +572,10 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
 		return ret;
 	}
 
-	regval = F_MMU_CTRL_COHERENT_EN | F_MMU_TF_PROTECT_SEL(2);
+	regval = F_MMU_TF_PROTECT_SEL(2);
+	if (data->type == MTK_IOMMU_V1)
+		regval |= F_MMU_CTRL_COHERENT_EN;
+
 	writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
 
 	regval = F_INT_TRANSLATION_FAULT |
@@ -588,7 +624,8 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
 };
 
 static const struct of_device_id mtk_iommu_v1_of_ids[] = {
-	{ .compatible = "mediatek,mt2701-m4u", },
+	{ .compatible = "mediatek,mt2701-m4u", .data = (void *)MTK_IOMMU_V1 },
+	{ .compatible = "mediatek,mt6572-m4u", .data = (void *)MTK_IOMMU_MT6572 },
 	{}
 };
 MODULE_DEVICE_TABLE(of, mtk_iommu_v1_of_ids);
@@ -612,6 +649,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	data->dev = dev;
+	data->type = (enum mtk_iommu_type)(uintptr_t)of_device_get_match_data(dev);
 
 	/* Protect memory. HW will access here while translation fault.*/
 	protect = devm_kcalloc(dev, 2, MTK_PROTECT_PA_ALIGN,

-- 
2.55.0





More information about the Linux-mediatek mailing list