linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/8] Add mt8196 SMMU support
@ 2025-06-16  2:56 Xueqi Zhang
  2025-06-16  2:56 ` [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support Xueqi Zhang
                   ` (7 more replies)
  0 siblings, 8 replies; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

This patchset add mt8196 SMMU support.
1. Mediatek SMMU interrupt is low level active rather than the
standard edge. Process Mediatek SMMU wrapper interrupt and dump
detailed information when a translation fault occurs.
2. In some projects, Mediatek also have EL2 driver, so put the pm
operation in TFA(EL3), then all the kernel and EL2 could control
the pm. Thus implement rpm get/put function which send smc call to
TFA to get/put SMMU power.

Xueqi Zhang (8):
  dt-bindings: iommu: mediatek: Add mt8196 support
  iommu/arm-smmu-v3: Add SMMU implementation
  iommu/arm-smmu-v3: Add implementation for MT8196 MM SMMU
  iommu/arm-smmu-v3: Add implementation for MT8196 APU SMMU
  iommu/arm-smmu-v3: Add IRQ handle for smmu impl
  iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ
  iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw
  iommu/arm-smmu-v3: mediatek: Implement rpm get/put function

 .../bindings/iommu/arm,smmu-v3.yaml           |  24 +-
 drivers/iommu/arm/Kconfig                     |   7 +
 drivers/iommu/arm/arm-smmu-v3/Makefile        |   3 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c  |  16 +
 .../arm/arm-smmu-v3/arm-smmu-v3-mediatek.c    | 536 ++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  96 +++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  14 +
 7 files changed, 691 insertions(+), 5 deletions(-)
 create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c
 create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c

-- 
2.46.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  2025-06-16  4:40   ` Rob Herring (Arm)
                     ` (2 more replies)
  2025-06-16  2:56 ` [RFC PATCH 2/8] iommu/arm-smmu-v3: Add SMMU implementation Xueqi Zhang
                   ` (6 subsequent siblings)
  7 siblings, 3 replies; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

1. Mediatek has its own implementation for wrapper interrupts and
power management. Add the SoC specific compatible for MT8196
implementing arm,smmu-v3.
2. APU SMMU need wait until its power is ready, thus add a phandle
smmu-mediatek-parents to its power node.

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 .../bindings/iommu/arm,smmu-v3.yaml           | 24 ++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
index 75fcf4cb52d9..c9a99e54de69 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
@@ -20,7 +20,12 @@ properties:
   $nodename:
     pattern: "^iommu@[0-9a-f]*"
   compatible:
-    const: arm,smmu-v3
+    - description: MediaTek SoCs implementing "arm,smmu-v3"
+      items:
+        - enum:
+            - mediatek,mt8196-apu-smmu
+            - mediatek,mt8196-mm-smmu
+        - const: arm,smmu-v3
 
   reg:
     maxItems: 1
@@ -69,11 +74,28 @@ properties:
       register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
       doesn't support SMMU page1 register space.
 
+  mediatek,smmu-parents:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      A phandle to the SMMU's power node. The SMMU should wait until its power
+      is ready
+
 required:
   - compatible
   - reg
   - '#iommu-cells'
 
+allOf:
+  - if:  # for SMMU need to wait its power node
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8196-apu-smmu
+    then:
+      required:
+        - mediatek,smmu-parents
+
 additionalProperties: false
 
 examples:
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 2/8] iommu/arm-smmu-v3: Add SMMU implementation
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
  2025-06-16  2:56 ` [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  2025-06-16 21:17   ` Pranjal Shrivastava
  2025-06-16  2:56 ` [RFC PATCH 3/8] iommu/arm-smmu-v3: Add implementation for MT8196 MM SMMU Xueqi Zhang
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

Mediatek has its own implementation for wrapper interrupts and
power management.So add SMMU implementation when smmu device probe.

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 drivers/iommu/arm/Kconfig                        |  7 +++++++
 drivers/iommu/arm/arm-smmu-v3/Makefile           |  3 ++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c | 16 ++++++++++++++++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c | 13 +++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c      |  3 +++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h      |  4 ++++
 6 files changed, 45 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c
 create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c

diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
index ef42bbe07dbe..a7f98fd0f2bf 100644
--- a/drivers/iommu/arm/Kconfig
+++ b/drivers/iommu/arm/Kconfig
@@ -88,6 +88,13 @@ config ARM_SMMU_V3
 	  the ARM SMMUv3 architecture.
 
 if ARM_SMMU_V3
+config ARM_SMMU_V3_MEDIATEK
+	bool "ARM Ltd. System MMU Version 3 (SMMUv3) MediaTek Support"
+	depends on ARM_SMMU_V3 && ARCH_MEDIATEK
+	help
+	  When running on a MediaTek platform that has the custom variant
+	  of the ARM SMMUv3, this needs to be built into the SMMU driver.
+
 config ARM_SMMU_V3_SVA
 	bool "Shared Virtual Addressing support for the ARM SMMUv3"
 	select IOMMU_SVA
diff --git a/drivers/iommu/arm/arm-smmu-v3/Makefile b/drivers/iommu/arm/arm-smmu-v3/Makefile
index 493a659cc66b..0670065d6e9a 100644
--- a/drivers/iommu/arm/arm-smmu-v3/Makefile
+++ b/drivers/iommu/arm/arm-smmu-v3/Makefile
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o
-arm_smmu_v3-y := arm-smmu-v3.o
+arm_smmu_v3-y := arm-smmu-v3.o arm-smmu-v3-impl.o
 arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_IOMMUFD) += arm-smmu-v3-iommufd.o
+arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_MEDIATEK) += arm-smmu-v3-mediatek.o
 arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o
 arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c
new file mode 100644
index 000000000000..d39587b965ef
--- /dev/null
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Ning li <ning.li@mediatek.com>
+ * Author: Xueqi Zhang <xueqi.zhang@mediatek.com>
+ */
+
+#include "arm-smmu-v3.h"
+
+struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu)
+{
+#if IS_ENABLED(CONFIG_ARM_SMMU_V3_MEDIATEK)
+	smmu = arm_smmu_v3_impl_mtk_init(smmu);
+#endif
+	return smmu;
+}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
new file mode 100644
index 000000000000..381268968185
--- /dev/null
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Ning li <ning.li@mediatek.com>
+ * Author: Xueqi Zhang <xueqi.zhang@mediatek.com>
+ */
+
+#include "arm-smmu-v3.h"
+
+struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
+{
+	return NULL;
+}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 10cc6dc26b7b..d36124a6bb54 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4754,6 +4754,9 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	}
 	ioaddr = res->start;
 
+	smmu = arm_smmu_v3_impl_init(smmu);
+	if (IS_ERR(smmu))
+		return PTR_ERR(smmu);
 	/*
 	 * Don't map the IMPLEMENTATION DEFINED regions, since they may contain
 	 * the PMCG registers which are reserved by the PMU driver.
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ea41d790463e..99eeb6143c49 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -998,6 +998,10 @@ int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
 				struct arm_smmu_cmdq *cmdq, u64 *cmds, int n,
 				bool sync);
 
+struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu);
+#if IS_ENABLED(CONFIG_ARM_SMMU_V3_MEDIATEK)
+struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu);
+#endif
 #ifdef CONFIG_ARM_SMMU_V3_SVA
 bool arm_smmu_sva_supported(struct arm_smmu_device *smmu);
 void arm_smmu_sva_notifier_synchronize(void);
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 3/8] iommu/arm-smmu-v3: Add implementation for MT8196 MM SMMU
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
  2025-06-16  2:56 ` [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support Xueqi Zhang
  2025-06-16  2:56 ` [RFC PATCH 2/8] iommu/arm-smmu-v3: Add SMMU implementation Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  2025-06-16  2:56 ` [RFC PATCH 4/8] iommu/arm-smmu-v3: Add implementation for MT8196 APU SMMU Xueqi Zhang
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

Add implementation for mediatek MM SMMU.

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-mediatek.c    | 72 ++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
index 381268968185..c00ee687d839 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
@@ -4,10 +4,80 @@
  * Author: Ning li <ning.li@mediatek.com>
  * Author: Xueqi Zhang <xueqi.zhang@mediatek.com>
  */
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
 
 #include "arm-smmu-v3.h"
 
-struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
+#define MTK_SMMU_COMP_STR_LEN		64
+#define MTK_SMMU_HAS_FLAG(pdata, _x)    (!!(((pdata)->flags) & (_x)))
+
+enum mtk_smmu_type {
+	MTK_SMMU_MM,
+	MTK_SMMU_TYPE_NUM,
+};
+
+struct mtk_smmu_v3_plat {
+	enum mtk_smmu_type	smmu_type;
+	u32			flags;
+};
+
+struct mtk_smmu_v3 {
+	struct arm_smmu_device	smmu;
+	const struct mtk_smmu_v3_plat *plat_data;
+};
+
+static const struct mtk_smmu_v3_plat mt8196_data_mm = {
+	.smmu_type		= MTK_SMMU_MM,
+};
+
+struct mtk_smmu_v3_of_device_data {
+	char			compatible[MTK_SMMU_COMP_STR_LEN];
+	const void		*data;
+};
+
+static const struct mtk_smmu_v3_of_device_data mtk_smmu_v3_of_ids[] = {
+	{ .compatible = "mediatek,mt8196-mm-smmu", .data = &mt8196_data_mm},
+};
+
+static inline struct mtk_smmu_v3 *to_mtk_smmu_v3(struct arm_smmu_device *smmu)
 {
+	return container_of(smmu, struct mtk_smmu_v3, smmu);
+}
+
+static const struct mtk_smmu_v3_plat *mtk_smmu_v3_get_plat_data(const struct device_node *np)
+{
+	const struct mtk_smmu_v3_of_device_data *of_device = mtk_smmu_v3_of_ids;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mtk_smmu_v3_of_ids); i++, of_device++) {
+		if (of_device_is_compatible(np, of_device->compatible))
+			return of_device->data;
+	}
 	return NULL;
 }
+
+struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
+{
+	struct mtk_smmu_v3 *mtk_smmu_v3;
+	struct device *dev = smmu->dev;
+	struct platform_device *parent_pdev;
+	struct device_node *parent_node;
+
+	mtk_smmu_v3 = devm_krealloc(dev, smmu, sizeof(*mtk_smmu_v3), GFP_KERNEL);
+	if (!mtk_smmu_v3)
+		return ERR_PTR(-ENOMEM);
+
+	mtk_smmu_v3->plat_data = mtk_smmu_v3_get_plat_data(dev->of_node);
+	if (!mtk_smmu_v3->plat_data) {
+		dev_err(dev, "Get platform data fail\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return &mtk_smmu_v3->smmu;
+}
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 4/8] iommu/arm-smmu-v3: Add implementation for MT8196 APU SMMU
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
                   ` (2 preceding siblings ...)
  2025-06-16  2:56 ` [RFC PATCH 3/8] iommu/arm-smmu-v3: Add implementation for MT8196 MM SMMU Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  2025-06-16  2:56 ` [RFC PATCH 5/8] iommu/arm-smmu-v3: Add IRQ handle for smmu impl Xueqi Zhang
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

Add a special implementation for mediatek APU SMMU. APU SMMU need to
wait APU SMMU's power which depends on APU driver. Therefore, add the
label mediatek,smmu-parent to point to the power device that the
smmu depends on. If the device has not finished probing, return
-EPROBE_DEFER.

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-mediatek.c    | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
index c00ee687d839..48290366e596 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
@@ -15,10 +15,12 @@
 #include "arm-smmu-v3.h"
 
 #define MTK_SMMU_COMP_STR_LEN		64
+#define SMMU_REQUIRE_PARENT		BIT(5)
 #define MTK_SMMU_HAS_FLAG(pdata, _x)    (!!(((pdata)->flags) & (_x)))
 
 enum mtk_smmu_type {
 	MTK_SMMU_MM,
+	MTK_SMMU_APU,
 	MTK_SMMU_TYPE_NUM,
 };
 
@@ -36,12 +38,18 @@ static const struct mtk_smmu_v3_plat mt8196_data_mm = {
 	.smmu_type		= MTK_SMMU_MM,
 };
 
+static const struct mtk_smmu_v3_plat mt8196_data_apu = {
+	.smmu_type		= MTK_SMMU_APU,
+	.flags			= SMMU_REQUIRE_PARENT,
+};
+
 struct mtk_smmu_v3_of_device_data {
 	char			compatible[MTK_SMMU_COMP_STR_LEN];
 	const void		*data;
 };
 
 static const struct mtk_smmu_v3_of_device_data mtk_smmu_v3_of_ids[] = {
+	{ .compatible = "mediatek,mt8196-apu-smmu", .data = &mt8196_data_apu},
 	{ .compatible = "mediatek,mt8196-mm-smmu", .data = &mt8196_data_mm},
 };
 
@@ -79,5 +87,29 @@ struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
 		return ERR_PTR(-EINVAL);
 	}
 
+	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_REQUIRE_PARENT)) {
+		parent_node = of_parse_phandle(dev->of_node, "mediatek,smmu-parent", 0);
+		if (!parent_node) {
+			dev_err(dev, "Lack its parent node.\n");
+			return ERR_PTR(-EINVAL);
+		}
+		if (!of_device_is_available(parent_node)) {
+			of_node_put(parent_node);
+			return ERR_PTR(-EINVAL);
+		}
+
+		parent_pdev = of_find_device_by_node(parent_node);
+		of_node_put(parent_node);
+		if (!parent_pdev) {
+			dev_err(dev, "Lack its parent devices.\n");
+			return ERR_PTR(-ENODEV);
+		}
+
+		if (!platform_get_drvdata(parent_pdev)) {
+			dev_err(dev, "Delay since its parent driver is not ready.\n");
+			return ERR_PTR(-EPROBE_DEFER);
+		}
+	}
+
 	return &mtk_smmu_v3->smmu;
 }
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 5/8] iommu/arm-smmu-v3: Add IRQ handle for smmu impl
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
                   ` (3 preceding siblings ...)
  2025-06-16  2:56 ` [RFC PATCH 4/8] iommu/arm-smmu-v3: Add implementation for MT8196 APU SMMU Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  2025-06-16 21:32   ` Pranjal Shrivastava
  2025-06-16  2:56 ` [RFC PATCH 6/8] iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ Xueqi Zhang
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

Add IRQ handle for smmu impl

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 ++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 8 ++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index d36124a6bb54..154417b380fa 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1954,7 +1954,8 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 			arm_smmu_decode_event(smmu, evt, &event);
 			if (arm_smmu_handle_event(smmu, evt, &event))
 				arm_smmu_dump_event(smmu, evt, &event, &rs);
-
+			if (smmu->impl && smmu->impl->smmu_evt_handler)
+				smmu->impl->smmu_evt_handler(irq, smmu, evt, &rs);
 			put_device(event.dev);
 			cond_resched();
 		}
@@ -2091,7 +2092,13 @@ static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
 
 static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
 {
+	struct arm_smmu_device *smmu = dev;
+
 	arm_smmu_gerror_handler(irq, dev);
+
+	if (smmu->impl && smmu->impl->combined_irq_handle)
+		smmu->impl->combined_irq_handle(irq, smmu);
+
 	return IRQ_WAKE_THREAD;
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 99eeb6143c49..f45c4bf84bc1 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -792,6 +792,7 @@ struct arm_smmu_device {
 
 	struct rb_root			streams;
 	struct mutex			streams_mutex;
+	const struct arm_smmu_v3_impl	*impl;
 };
 
 struct arm_smmu_stream {
@@ -998,6 +999,13 @@ int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
 				struct arm_smmu_cmdq *cmdq, u64 *cmds, int n,
 				bool sync);
 
+/* Implementation details */
+struct arm_smmu_v3_impl {
+	int (*combined_irq_handle)(int irq, struct arm_smmu_device *smmu_dev);
+	int (*smmu_evt_handler)(int irq, struct arm_smmu_device *smmu_dev,
+				u64 *evt, struct ratelimit_state *rs);
+};
+
 struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu);
 #if IS_ENABLED(CONFIG_ARM_SMMU_V3_MEDIATEK)
 struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu);
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 6/8] iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
                   ` (4 preceding siblings ...)
  2025-06-16  2:56 ` [RFC PATCH 5/8] iommu/arm-smmu-v3: Add IRQ handle for smmu impl Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  2025-06-24 11:22   ` Will Deacon
  2025-06-16  2:56 ` [RFC PATCH 7/8] iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw Xueqi Zhang
  2025-06-16  2:56 ` [RFC PATCH 8/8] iommu/arm-smmu-v3: mediatek: Implement rpm get/put function Xueqi Zhang
  7 siblings, 1 reply; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

Mediatek SMMU interrupt is low level active rather than the standard
edge.Process Mediatek SMMU wrapper interrupt and dump detailed
information when a translation fault occurs.

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-mediatek.c    | 349 +++++++++++++++++-
 1 file changed, 347 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
index 48290366e596..448166c1ca64 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
@@ -14,7 +14,122 @@
 
 #include "arm-smmu-v3.h"
 
+#include <linux/soc/mediatek/mtk_sip_svc.h>
+#include <linux/arm-smccc.h>
+
+#define SMMUWP_GLB_CTL0			(0x0)
+#define CTL0_STD_AXI_MODE_DIS		BIT(0)
+#define CTL0_MON_DIS			BIT(1)
+#define CTL0_DCM_EN			BIT(2)
+#define CTL0_WRAPPER_CK_AOEN		BIT(3)
+#define CTL0_AUTO_AXDOMAIN_EN		BIT(4)
+#define CTL0_IRQ_BUSY_EN		BIT(5)
+#define CTL0_ABT_CNT_CLR		BIT(6)
+#define CTL0_LEGACY_AXCACHE		BIT(7)
+#define CTL0_COMMIT_DIS			BIT(8)
+#define CTL0_AUTO_SLP_DIS		BIT(9)
+#define CTL0_STTSL_DIS			BIT(10)
+#define CTL0_CFG_TAB_DCM_EN		BIT(11)
+#define CTL0_CPU_PARTID_DIS		BIT(14)
+/* New bits of SMMU wrapper extension */
+#define CTL0_TCU2SLC_DCM_EN		BIT(18)
+#define CTL0_APB_DCM_EN			BIT(19)
+#define CTL0_DVM_DCM_EN			BIT(20)
+#define CTL0_CPU_TBU_PARTID_DIS		BIT(21)
+
+#define SMMUWP_IRQ_STA			(0x80)
+#define STA_TCU_GLB_INTR		BIT(0)
+#define STA_TCU_CMD_SYNC_INTR		BIT(1)
+#define STA_TCU_EVTQ_INTR		BIT(2)
+#define STA_TCU_PRI_INTR		BIT(3)
+#define STA_TCU_PMU_INTR		BIT(4)
+#define STA_TCU_RAS_CRI			BIT(5)
+#define STA_TCU_RAS_ERI			BIT(6)
+#define STA_TCU_RAS_FHI			BIT(7)
+
+#define SMMUWP_IRQ_ACK			(0x84)
+
+#define SMMUWP_IRQ_ACK_CNT		(0x88)
+#define IRQ_ACK_CNT_MSK			GENMASK(7, 0)
+
+/* SMMU non-secure interrupt pending count register, count 20 */
+#define SMMUWP_IRQ_CNTx(cnt)		(0x100 + 0x4 * (cnt))
+
+#define SMMU_TCU_CTL1_AXSLC		(0x204)
+#define AXSLC_BIT_FIELD			GENMASK(8, 4)
+#define AXSLC_CACHE			BIT(5)
+#define AXSLC_ALLOCATE			BIT(6)
+#define AXSLC_SPECULATIVE		BIT(7)
+#define AXSLC_SET			(AXSLC_CACHE | AXSLC_ALLOCATE | AXSLC_SPECULATIVE)
+#define SLC_SB_ONLY_EN			BIT(1)
+
+/* SMMU TBUx read translation fault monitor0 */
+#define SMMUWP_TBUx_RTFM0(tbu)		(0x380 + 0x100 * (tbu))
+#define RTFM0_FAULT_AXI_ID		GENMASK_ULL(19, 0)
+#define RTFM0_FAULT_DET			BIT(31)
+
+/* SMMU TBUx read translation fault monitor1 */
+#define SMMUWP_TBUx_RTFM1(tbu)		(0x384 + 0x100 * (tbu))
+#define RTFM1_FAULT_VA_35_32		GENMASK_ULL(3, 0)
+#define RTFM1_FAULT_VA_31_12		GENMASK_ULL(31, 12)
+
+/* SMMU TBUx read translation fault monitor2 */
+#define SMMUWP_TBUx_RTFM2(tbu)		(0x388 + 0x100 * (tbu))
+#define RTFM2_FAULT_SID			GENMASK_ULL(7, 0)
+#define RTFM2_FAULT_SSID		GENMASK_ULL(15, 8)
+#define RTFM2_FAULT_SSIDV		BIT(16)
+#define RTFM2_FAULT_SECSID		BIT(17)
+
+/* SMMU TBUx write translation fault monitor0 */
+#define SMMUWP_TBUx_WTFM0(tbu)		(0x390 + 0x100 * (tbu))
+#define WTFM0_FAULT_AXI_ID		GENMASK_ULL(19, 0)
+#define WTFM0_FAULT_DET			BIT(31)
+
+/* SMMU TBUx write translation fault monitor1 */
+#define SMMUWP_TBUx_WTFM1(tbu)		(0x394 + 0x100 * (tbu))
+#define WTFM1_FAULT_VA_35_32		GENMASK_ULL(3, 0)
+#define WTFM1_FAULT_VA_31_12		GENMASK_ULL(31, 12)
+
+/* SMMU TBUx write translation fault monitor2 */
+#define SMMUWP_TBUx_WTFM2(tbu)		(0x398 + 0x100 * (tbu))
+#define WTFM2_FAULT_SID			GENMASK_ULL(7, 0)
+#define WTFM2_FAULT_SSID		GENMASK_ULL(15, 8)
+#define WTFM2_FAULT_SSIDV		BIT(16)
+#define WTFM2_FAULT_SECSID		BIT(17)
+
+/* SMMU TBU Manual OG Control High Register0 */
+#define SMMUWP_TBU0_MOGH0		(0x3b4)
+#define MOGH_EN				BIT(29)
+#define MOGH_RW				BIT(28)
+
+/* SMMU translation fault TBUx */
+#define SMMUWP_TF_TBU_MSK		GENMASK(26, 24)
+#define SMMUWP_TF_TBU(tbu)		FIELD_PREP(SMMUWP_TF_TBU_MSK, tbu)
+
+#define SMMU_FAULT_RS_INTERVAL		DEFAULT_RATELIMIT_INTERVAL
+#define SMMU_FAULT_RS_BURST		(1)
+
+#define STRSEC(sec)			((sec) ? "SECURE" : "NORMAL")
+
+#define WP_OFFSET_MT8196		0x1e0000
+
 #define MTK_SMMU_COMP_STR_LEN		64
+
+#define MTK_SMMU_FAULT_IOVA(low, high) ((low) | (((u64)(high) & 0xf) << 32))
+
+#define SMMU_SUCCESS			(0)
+#define SMMU_ID_ERR			(1)
+#define SMMU_CMD_ERR			(2)
+#define SMMU_PARA_INVALID		(3)
+#define SMMU_NEED			(4)
+#define SMMU_NONEED			(5)
+
+/* plat flags: */
+#define SMMU_SKIP_PM_CLK		BIT(0)
+#define SMMU_CLK_AO_EN			BIT(1)
+#define SMMU_AXSLC_EN			BIT(2)
+#define SMMU_DIS_CPU_PARTID		BIT(3)
+#define SMMU_DIS_CPU_TBU_PARTID		BIT(4)
 #define SMMU_REQUIRE_PARENT		BIT(5)
 #define MTK_SMMU_HAS_FLAG(pdata, _x)    (!!(((pdata)->flags) & (_x)))
 
@@ -25,22 +140,30 @@ enum mtk_smmu_type {
 };
 
 struct mtk_smmu_v3_plat {
+	u32			wp_offset;
+	unsigned int		tbu_cnt;
 	enum mtk_smmu_type	smmu_type;
 	u32			flags;
 };
 
 struct mtk_smmu_v3 {
 	struct arm_smmu_device	smmu;
+	void __iomem			*wp_base;
 	const struct mtk_smmu_v3_plat *plat_data;
 };
 
 static const struct mtk_smmu_v3_plat mt8196_data_mm = {
+	.wp_offset		= WP_OFFSET_MT8196,
+	.tbu_cnt		= 3,
 	.smmu_type		= MTK_SMMU_MM,
+	.flags			= SMMU_AXSLC_EN,
 };
 
 static const struct mtk_smmu_v3_plat mt8196_data_apu = {
+	.wp_offset		= WP_OFFSET_MT8196,
+	.tbu_cnt		= 3,
 	.smmu_type		= MTK_SMMU_APU,
-	.flags			= SMMU_REQUIRE_PARENT,
+	.flags			= SMMU_AXSLC_EN | SMMU_REQUIRE_PARENT,
 };
 
 struct mtk_smmu_v3_of_device_data {
@@ -70,17 +193,228 @@ static const struct mtk_smmu_v3_plat *mtk_smmu_v3_get_plat_data(const struct dev
 	return NULL;
 }
 
+static inline void smmu_write_field(void __iomem *base,
+				    unsigned int reg,
+				    unsigned int mask,
+				    unsigned int val)
+{
+	unsigned int regval;
+
+	regval = readl_relaxed(base + reg);
+	regval = (regval & (~mask)) | val;
+	writel_relaxed(regval, base + reg);
+}
+
+static void smmu_init_wpcfg(struct arm_smmu_device *smmu)
+{
+	struct mtk_smmu_v3 *mtk_smmu_v3 = to_mtk_smmu_v3(smmu);
+	void __iomem *wp_base = mtk_smmu_v3->wp_base;
+
+	/* DCM basic setting */
+	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_DCM_EN, CTL0_DCM_EN);
+	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_CFG_TAB_DCM_EN,
+			 CTL0_CFG_TAB_DCM_EN);
+
+	smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
+			 CTL0_TCU2SLC_DCM_EN | CTL0_APB_DCM_EN |
+			 CTL0_DVM_DCM_EN,
+			 CTL0_TCU2SLC_DCM_EN | CTL0_APB_DCM_EN |
+			 CTL0_DVM_DCM_EN);
+
+	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_DIS_CPU_PARTID))
+		smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_CPU_PARTID_DIS,
+				 CTL0_CPU_PARTID_DIS);
+	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_DIS_CPU_TBU_PARTID))
+		smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
+				 CTL0_CPU_TBU_PARTID_DIS, CTL0_CPU_TBU_PARTID_DIS);
+
+	/* Used for MM_SMMMU read command overtaking */
+	if (mtk_smmu_v3->plat_data->smmu_type == MTK_SMMU_MM)
+		smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_STD_AXI_MODE_DIS,
+				 CTL0_STD_AXI_MODE_DIS);
+
+	/* Set AXSLC */
+	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_AXSLC_EN)) {
+		smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
+				 CTL0_STD_AXI_MODE_DIS, CTL0_STD_AXI_MODE_DIS);
+		smmu_write_field(wp_base, SMMU_TCU_CTL1_AXSLC, AXSLC_BIT_FIELD,
+				 AXSLC_SET);
+		smmu_write_field(wp_base, SMMU_TCU_CTL1_AXSLC, SLC_SB_ONLY_EN,
+				 SLC_SB_ONLY_EN);
+	}
+}
+
+/* Consume SMMU wrapper interrupt bit */
+static unsigned int
+smmuwp_consume_intr(void __iomem *wp_base, unsigned int irq_bit)
+{
+	unsigned int pend_cnt;
+
+	pend_cnt = readl_relaxed(wp_base + SMMUWP_IRQ_CNTx(__ffs(irq_bit)));
+	smmu_write_field(wp_base, SMMUWP_IRQ_ACK_CNT, IRQ_ACK_CNT_MSK, pend_cnt);
+	writel_relaxed(irq_bit, wp_base + SMMUWP_IRQ_ACK);
+
+	return pend_cnt;
+}
+
+/* clear translation fault mark */
+static void smmuwp_clear_tf(void __iomem *wp_base)
+{
+	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_ABT_CNT_CLR, CTL0_ABT_CNT_CLR);
+	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_ABT_CNT_CLR, 0);
+}
+
+static u32 smmuwp_fault_id(u32 axi_id, u32 tbu_id)
+{
+	u32 fault_id = (axi_id & ~SMMUWP_TF_TBU_MSK) | (SMMUWP_TF_TBU(tbu_id));
+
+	return fault_id;
+}
+
+/* Process TBU translation fault Monitor */
+static bool smmuwp_process_tf(struct arm_smmu_device *smmu)
+{
+	struct mtk_smmu_v3 *mtk_smmu_v3 = to_mtk_smmu_v3(smmu);
+	void __iomem *wp_base = mtk_smmu_v3->wp_base;
+	unsigned int sid, ssid, secsidv, ssidv;
+	u32 i, regval, va35_32, axiid, fault_id;
+	u64 fault_iova;
+	bool tf_det = false;
+
+	for (i = 0; i < mtk_smmu_v3->plat_data->tbu_cnt; i++) {
+		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM0(i));
+		if (!(regval & RTFM0_FAULT_DET))
+			goto write;
+
+		tf_det = true;
+		axiid = FIELD_GET(RTFM0_FAULT_AXI_ID, regval);
+		fault_id = smmuwp_fault_id(axiid, i);
+
+		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM1(i));
+		va35_32 = FIELD_GET(RTFM1_FAULT_VA_35_32, regval);
+		fault_iova = MTK_SMMU_FAULT_IOVA(regval & RTFM1_FAULT_VA_31_12, va35_32);
+
+		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM2(i));
+		sid = FIELD_GET(RTFM2_FAULT_SID, regval);
+		ssid = FIELD_GET(RTFM2_FAULT_SSID, regval);
+		ssidv = FIELD_GET(RTFM2_FAULT_SSIDV, regval);
+		secsidv = FIELD_GET(RTFM2_FAULT_SECSID, regval);
+		dev_err_ratelimited(smmu->dev, "TF read in %s world, TBU_id-%d-fault_id:0x%x(0x%x)\n",
+				    STRSEC(secsidv), i, fault_id, axiid);
+		dev_err_ratelimited(smmu->dev,
+				    "iova:0x%llx, sid:%d, ssid:%d, ssidv:%d, secsidv:%d\n",
+				    fault_iova, sid, ssid, ssidv, secsidv);
+
+write:
+		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM0(i));
+		if (!(regval & WTFM0_FAULT_DET))
+			continue;
+
+		tf_det = true;
+		axiid = FIELD_GET(WTFM0_FAULT_AXI_ID, regval);
+		fault_id = smmuwp_fault_id(axiid, i);
+
+		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM1(i));
+		va35_32 = FIELD_GET(WTFM1_FAULT_VA_35_32, regval);
+		fault_iova = MTK_SMMU_FAULT_IOVA(regval & RTFM1_FAULT_VA_31_12, va35_32);
+
+		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM2(i));
+		sid = FIELD_GET(WTFM2_FAULT_SID, regval);
+		ssid = FIELD_GET(WTFM2_FAULT_SSID, regval);
+		ssidv = FIELD_GET(WTFM2_FAULT_SSIDV, regval);
+		secsidv = FIELD_GET(WTFM2_FAULT_SECSID, regval);
+		dev_err_ratelimited(smmu->dev, "TF write in %s world, TBU_id-%d-fault_id:0x%x(0x%x)\n",
+				    STRSEC(secsidv), i, fault_id, axiid);
+		dev_err_ratelimited(smmu->dev,
+				    "iova:0x%llx, sid:%d, ssid:%d, ssidv:%d, secsidv:%d\n",
+				    fault_iova, sid, ssid, ssidv, secsidv);
+	}
+
+	if (!tf_det)
+		dev_info(smmu->dev, "No TF detected or has been cleaned\n");
+
+	return tf_det;
+}
+
+static int
+mtk_smmu_evt_handler(int irq, struct arm_smmu_device *smmu, u64 *evt, struct ratelimit_state *rs)
+{
+	if (!__ratelimit(rs)) {
+		smmuwp_clear_tf(smmu);
+		return 0;
+	}
+
+	smmuwp_process_tf(smmu);
+	smmuwp_clear_tf(smmu);
+
+	return 0;
+}
+
+/* Process SMMU wrapper interrupt */
+static int mtk_smmu_v3_smmuwp_irq_handler(int irq, struct arm_smmu_device *smmu)
+{
+	struct mtk_smmu_v3 *mtk_smmuv3 = to_mtk_smmu_v3(smmu);
+	void __iomem *wp_base = mtk_smmuv3->wp_base;
+	unsigned int irq_sta, pend_cnt;
+
+	irq_sta = readl_relaxed(wp_base + SMMUWP_IRQ_STA);
+	if (irq_sta == 0)
+		return 0;
+
+	if (irq_sta & STA_TCU_GLB_INTR) {
+		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_GLB_INTR);
+		dev_dbg(smmu->dev,
+			"IRQ_STA:0x%x, Non-secure TCU global interrupt detected pending_cnt: %d\n",
+			irq_sta, pend_cnt);
+	}
+
+	if (irq_sta & STA_TCU_CMD_SYNC_INTR) {
+		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_CMD_SYNC_INTR);
+		dev_dbg(smmu->dev,
+			"IRQ_STA:0x%x, Non-secure TCU CMD_SYNC interrupt detected pending_cnt: %d\n",
+			irq_sta, pend_cnt);
+	}
+
+	if (irq_sta & STA_TCU_EVTQ_INTR) {
+		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_EVTQ_INTR);
+		dev_dbg(smmu->dev,
+			"IRQ_STA:0x%x, Non-secure TCU EVTQ interrupt detected pending_cnt: %d\n",
+			irq_sta, pend_cnt);
+	}
+
+	if (irq_sta & STA_TCU_PRI_INTR) {
+		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_PRI_INTR);
+		dev_dbg(smmu->dev, "IRQ_STA:0x%x, TCU PRI interrupt detected pending_cnt: %d\n",
+			irq_sta, pend_cnt);
+	}
+
+	if (irq_sta & STA_TCU_PMU_INTR) {
+		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_PMU_INTR);
+		dev_dbg(smmu->dev, "IRQ_STA:0x%x, TCU PMU interrupt detected pending_cnt: %d\n",
+			irq_sta, pend_cnt);
+	}
+
+	return 0;
+}
+
+static const struct arm_smmu_v3_impl mtk_smmu_v3_impl = {
+	.combined_irq_handle = mtk_smmu_v3_smmuwp_irq_handler,
+	.smmu_evt_handler = mtk_smmu_evt_handler,
+};
+
 struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
 {
 	struct mtk_smmu_v3 *mtk_smmu_v3;
 	struct device *dev = smmu->dev;
-	struct platform_device *parent_pdev;
+	struct platform_device *pdev = to_platform_device(dev), *parent_pdev;
+	struct resource *res, wp_res;
 	struct device_node *parent_node;
 
 	mtk_smmu_v3 = devm_krealloc(dev, smmu, sizeof(*mtk_smmu_v3), GFP_KERNEL);
 	if (!mtk_smmu_v3)
 		return ERR_PTR(-ENOMEM);
 
+	mtk_smmu_v3->smmu.impl = &mtk_smmu_v3_impl;
 	mtk_smmu_v3->plat_data = mtk_smmu_v3_get_plat_data(dev->of_node);
 	if (!mtk_smmu_v3->plat_data) {
 		dev_err(dev, "Get platform data fail\n");
@@ -111,5 +445,16 @@ struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
 		}
 	}
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return ERR_PTR(-EINVAL);
+	wp_res = DEFINE_RES_MEM(res->start + mtk_smmu_v3->plat_data->wp_offset,  SZ_4K);
+	mtk_smmu_v3->wp_base = devm_ioremap_resource(dev, &wp_res);
+	if (IS_ERR(mtk_smmu_v3->wp_base))
+		return mtk_smmu_v3->wp_base;
+
+	mtk_smmu_pm_get(dev, mtk_smmu_v3->plat_data->smmu_type);
+	smmu_init_wpcfg(smmu);
+	mtk_smmu_pm_put(dev, mtk_smmu_v3->plat_data->smmu_type);
 	return &mtk_smmu_v3->smmu;
 }
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 7/8] iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
                   ` (5 preceding siblings ...)
  2025-06-16  2:56 ` [RFC PATCH 6/8] iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  2025-06-16 20:54   ` Pranjal Shrivastava
  2025-06-16  2:56 ` [RFC PATCH 8/8] iommu/arm-smmu-v3: mediatek: Implement rpm get/put function Xueqi Zhang
  7 siblings, 1 reply; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

Invoke rpm operation before accessing the SMMU hw.

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 84 ++++++++++++++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  3 +
 2 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 154417b380fa..88912b0f8132 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -122,6 +122,22 @@ static void parse_driver_options(struct arm_smmu_device *smmu)
 	} while (arm_smmu_options[++i].opt);
 }
 
+static int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
+{
+	if (smmu && smmu->impl && smmu->impl->smmu_power_get)
+		return smmu->impl->smmu_power_get(smmu);
+
+	return 0;
+}
+
+static int arm_smmu_rpm_put(struct arm_smmu_device *smmu)
+{
+	if (smmu && smmu->impl && smmu->impl->smmu_power_put)
+		return smmu->impl->smmu_power_put(smmu);
+
+	return 0;
+}
+
 /* Low-level queue manipulation functions */
 static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n)
 {
@@ -2082,23 +2098,35 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
 static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
 {
 	struct arm_smmu_device *smmu = dev;
+	int ret;
+
+	ret = arm_smmu_rpm_get(smmu);
+	if (ret)
+		return IRQ_NONE;
 
 	arm_smmu_evtq_thread(irq, dev);
 	if (smmu->features & ARM_SMMU_FEAT_PRI)
 		arm_smmu_priq_thread(irq, dev);
 
+	arm_smmu_rpm_put(smmu);
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
 {
 	struct arm_smmu_device *smmu = dev;
+	int ret;
+
+	ret = arm_smmu_rpm_get(smmu);
+	if (ret)
+		return IRQ_WAKE_THREAD;
 
 	arm_smmu_gerror_handler(irq, dev);
 
 	if (smmu->impl && smmu->impl->combined_irq_handle)
 		smmu->impl->combined_irq_handle(irq, smmu);
 
+	arm_smmu_rpm_put(smmu);
 	return IRQ_WAKE_THREAD;
 }
 
@@ -2255,6 +2283,11 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	struct arm_smmu_domain *smmu_domain = cookie;
 	struct arm_smmu_device *smmu = smmu_domain->smmu;
 	struct arm_smmu_cmdq_ent cmd;
+	int ret;
+
+	ret = arm_smmu_rpm_get(smmu);
+	if (ret)
+		return;
 
 	/*
 	 * NOTE: when io-pgtable is in non-strict mode, we may get here with
@@ -2271,6 +2304,8 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
 	}
 	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+
+	arm_smmu_rpm_put(smmu);
 }
 
 static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
@@ -2353,6 +2388,11 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
 			.leaf	= leaf,
 		},
 	};
+	int ret;
+
+	ret = arm_smmu_rpm_get(smmu_domain->smmu);
+	if (ret)
+		return;
 
 	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
 		cmd.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
@@ -2378,6 +2418,8 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
 	 * zapped an entire table.
 	 */
 	arm_smmu_atc_inv_domain(smmu_domain, iova, size);
+
+	arm_smmu_rpm_put(smmu_domain->smmu);
 }
 
 void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
@@ -2392,8 +2434,15 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
 			.leaf	= leaf,
 		},
 	};
+	int ret;
+
+	ret = arm_smmu_rpm_get(smmu_domain->smmu);
+	if (ret)
+		return;
 
 	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
+
+	arm_smmu_rpm_put(smmu_domain->smmu);
 }
 
 static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
@@ -3038,6 +3087,12 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	} else if (arm_smmu_ssids_in_use(&master->cd_table))
 		return -EBUSY;
 
+	ret = arm_smmu_rpm_get(smmu);
+	if (ret) {
+		dev_info(smmu->dev, "[%s] power_status:%d\n", __func__, ret);
+		return -EBUSY;
+	}
+
 	/*
 	 * Prevent arm_smmu_share_asid() from trying to change the ASID
 	 * of either the old or new domain while we are working on it.
@@ -3049,6 +3104,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	ret = arm_smmu_attach_prepare(&state, domain);
 	if (ret) {
 		mutex_unlock(&arm_smmu_asid_lock);
+		arm_smmu_rpm_put(smmu);
 		return ret;
 	}
 
@@ -3074,6 +3130,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 
 	arm_smmu_attach_commit(&state);
 	mutex_unlock(&arm_smmu_asid_lock);
+	arm_smmu_rpm_put(smmu);
 	return 0;
 }
 
@@ -3216,7 +3273,13 @@ static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
 		.old_domain = iommu_get_domain_for_dev(dev),
 		.ssid = IOMMU_NO_PASID,
 	};
+	int ret;
 
+	ret = arm_smmu_rpm_get(master->smmu);
+	if (ret) {
+		dev_info(master->smmu->dev, "[%s] power_status:%d\n", __func__, ret);
+		return;
+	}
 	/*
 	 * Do not allow any ASID to be changed while are working on the STE,
 	 * otherwise we could miss invalidations.
@@ -3244,7 +3307,7 @@ static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
 	arm_smmu_install_ste_for_dev(master, ste);
 	arm_smmu_attach_commit(&state);
 	mutex_unlock(&arm_smmu_asid_lock);
-
+	arm_smmu_rpm_put(master->smmu);
 	/*
 	 * This has to be done after removing the master from the
 	 * arm_smmu_domain->devices to avoid races updating the same context
@@ -4799,10 +4862,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		if (irq > 0)
 			smmu->gerr_irq = irq;
 	}
+
+	ret = arm_smmu_rpm_get(smmu);
+	if (ret) {
+		dev_info(smmu->dev, "[%s] power_status fail:%d\n", __func__, ret);
+		return ret;
+	}
+
 	/* Probe the h/w */
 	ret = arm_smmu_device_hw_probe(smmu);
 	if (ret)
-		return ret;
+		goto err_pm_put;
 
 	/* Initialise in-memory data structures */
 	ret = arm_smmu_init_structures(smmu);
@@ -4840,6 +4910,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	arm_smmu_device_disable(smmu);
 err_free_iopf:
 	iopf_queue_free(smmu->evtq.iopf);
+err_pm_put:
+	arm_smmu_rpm_put(smmu);
 	return ret;
 }
 
@@ -4857,8 +4929,16 @@ static void arm_smmu_device_remove(struct platform_device *pdev)
 static void arm_smmu_device_shutdown(struct platform_device *pdev)
 {
 	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+	int ret;
 
+	ret = arm_smmu_rpm_get(smmu);
+	if (ret) {
+		dev_info(smmu->dev, "[%s] power_status:%d\n", __func__, ret);
+		return;
+	}
 	arm_smmu_device_disable(smmu);
+
+	arm_smmu_rpm_put(smmu);
 }
 
 static const struct of_device_id arm_smmu_of_match[] = {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f45c4bf84bc1..cd96ff9cbc54 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -792,6 +792,7 @@ struct arm_smmu_device {
 
 	struct rb_root			streams;
 	struct mutex			streams_mutex;
+
 	const struct arm_smmu_v3_impl	*impl;
 };
 
@@ -1004,6 +1005,8 @@ struct arm_smmu_v3_impl {
 	int (*combined_irq_handle)(int irq, struct arm_smmu_device *smmu_dev);
 	int (*smmu_evt_handler)(int irq, struct arm_smmu_device *smmu_dev,
 				u64 *evt, struct ratelimit_state *rs);
+	int (*smmu_power_get)(struct arm_smmu_device *smmu);
+	int (*smmu_power_put)(struct arm_smmu_device *smmu);
 };
 
 struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu);
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 8/8] iommu/arm-smmu-v3: mediatek: Implement rpm get/put function
  2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
                   ` (6 preceding siblings ...)
  2025-06-16  2:56 ` [RFC PATCH 7/8] iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw Xueqi Zhang
@ 2025-06-16  2:56 ` Xueqi Zhang
  7 siblings, 0 replies; 17+ messages in thread
From: Xueqi Zhang @ 2025-06-16  2:56 UTC (permalink / raw)
  To: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, Ning li, linux-mediatek,
	linux-kernel, linux-arm-kernel, devicetree, iommu, Xueqi Zhang

In some projects, we also have EL2 driver, so we put the pm operation
in TFA(EL3), then all the kernel and EL2 could control the pm.
Implement rpm get/put function which send smc call to ATF to get/put
SMMU power.

Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-mediatek.c    | 78 +++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
index 448166c1ca64..38c995e90469 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
@@ -397,9 +397,87 @@ static int mtk_smmu_v3_smmuwp_irq_handler(int irq, struct arm_smmu_device *smmu)
 	return 0;
 }
 
+/*
+ * SMMU TF-A SMC cmd format:
+ * sec[11:11] + smmu_type[10:8] + cmd_id[7:0]
+ */
+#define SMMU_ATF_SET_CMD(smmu_type, sec, cmd_id) \
+	((cmd_id) | ((smmu_type) << 8) | ((sec) << 11))
+
+enum smmu_atf_cmd {
+	SMMU_SECURE_PM_GET,
+	SMMU_SECURE_PM_PUT,
+	SMMU_CMD_NUM
+};
+
+/*
+ * a0/in0 = MTK_IOMMU_SECURE_CONTROL(IOMMU SMC ID)
+ * a1/in1 = SMMU TF-A SMC cmd (sec + smmu_type + cmd_id)
+ * a2/in2 ~ a7/in7: user defined
+ */
+static int mtk_smmu_atf_call(u32 smmu_type, unsigned long cmd,
+			     unsigned long in2, unsigned long in3, unsigned long in4,
+			     unsigned long in5, unsigned long in6, unsigned long in7)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(MTK_SIP_KERNEL_IOMMU_CONTROL, cmd, in2, in3, in4, in5, in6, in7, &res);
+
+	return res.a0;
+}
+
+static int mtk_smmu_atf_call_common(u32 smmu_type, unsigned long cmd_id)
+{
+	unsigned long cmd = SMMU_ATF_SET_CMD(smmu_type, 1, cmd_id);
+
+	return mtk_smmu_atf_call(smmu_type, cmd, 0, 0, 0, 0, 0, 0);
+}
+
+static int mtk_smmu_pm_get(struct device *dev, uint32_t smmu_type)
+{
+	int ret;
+
+	ret = mtk_smmu_atf_call_common(smmu_type, SMMU_SECURE_PM_GET);
+	if (ret) {
+		dev_dbg(dev, "%s, smc call fail. ret:%d, type:%u\n", __func__, ret, smmu_type);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int mtk_smmu_pm_put(struct device *dev, uint32_t smmu_type)
+{
+	int ret;
+
+	ret = mtk_smmu_atf_call_common(smmu_type, SMMU_SECURE_PM_PUT);
+	if (ret) {
+		dev_dbg(dev, "%s, smc call fail:%d, type:%u\n", __func__, ret, smmu_type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mtk_smmu_power_get(struct arm_smmu_device *smmu)
+{
+	struct mtk_smmu_v3 *mtk_smmuv3 = to_mtk_smmu_v3(smmu);
+	const struct mtk_smmu_v3_plat *plat_data = mtk_smmuv3->plat_data;
+
+	return mtk_smmu_pm_get(smmu->dev, plat_data->smmu_type);
+}
+
+static int mtk_smmu_power_put(struct arm_smmu_device *smmu)
+{
+	struct mtk_smmu_v3 *mtk_smmuv3 = to_mtk_smmu_v3(smmu);
+	const struct mtk_smmu_v3_plat *plat_data = mtk_smmuv3->plat_data;
+
+	return mtk_smmu_pm_put(smmu->dev, plat_data->smmu_type);
+}
+
 static const struct arm_smmu_v3_impl mtk_smmu_v3_impl = {
 	.combined_irq_handle = mtk_smmu_v3_smmuwp_irq_handler,
 	.smmu_evt_handler = mtk_smmu_evt_handler,
+	.smmu_power_get = mtk_smmu_power_get,
+	.smmu_power_put = mtk_smmu_power_put,
 };
 
 struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support
  2025-06-16  2:56 ` [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support Xueqi Zhang
@ 2025-06-16  4:40   ` Rob Herring (Arm)
  2025-06-16 14:27   ` Rob Herring
  2025-06-17  6:28   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 17+ messages in thread
From: Rob Herring (Arm) @ 2025-06-16  4:40 UTC (permalink / raw)
  To: Xueqi Zhang
  Cc: Yong Wu, linux-mediatek, linux-kernel, linux-arm-kernel,
	Krzysztof Kozlowski, Robin Murphy, Joerg Roedel,
	AngeloGioacchino Del Regno, Will Deacon,
	Project_Global_Chrome_Upstream_Group, Conor Dooley,
	Matthias Brugger, iommu, devicetree, Ning li


On Mon, 16 Jun 2025 10:56:07 +0800, Xueqi Zhang wrote:
> 1. Mediatek has its own implementation for wrapper interrupts and
> power management. Add the SoC specific compatible for MT8196
> implementing arm,smmu-v3.
> 2. APU SMMU need wait until its power is ready, thus add a phandle
> smmu-mediatek-parents to its power node.
> 
> Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> ---
>  .../bindings/iommu/arm,smmu-v3.yaml           | 24 ++++++++++++++++++-
>  1 file changed, 23 insertions(+), 1 deletion(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml: ignoring, error in schema: properties: compatible
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml: properties:compatible: [{'description': 'MediaTek SoCs implementing "arm,smmu-v3"', 'items': [{'enum': ['mediatek,mt8196-apu-smmu', 'mediatek,mt8196-mm-smmu']}, {'const': 'arm,smmu-v3'}]}] is not of type 'object', 'boolean'
	from schema $id: http://json-schema.org/draft-07/schema#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml: properties:compatible: [{'description': 'MediaTek SoCs implementing "arm,smmu-v3"', 'items': [{'enum': ['mediatek,mt8196-apu-smmu', 'mediatek,mt8196-mm-smmu']}, {'const': 'arm,smmu-v3'}]}] is not of type 'object', 'boolean'
	from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
Documentation/devicetree/bindings/iommu/arm,smmu-v3.example.dtb: /example-0/iommu@2b400000: failed to match any schema with compatible: ['arm,smmu-v3']

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250616025628.25454-2-xueqi.zhang@mediatek.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support
  2025-06-16  2:56 ` [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support Xueqi Zhang
  2025-06-16  4:40   ` Rob Herring (Arm)
@ 2025-06-16 14:27   ` Rob Herring
  2025-06-17  6:28   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 17+ messages in thread
From: Rob Herring @ 2025-06-16 14:27 UTC (permalink / raw)
  To: Xueqi Zhang
  Cc: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Project_Global_Chrome_Upstream_Group,
	Ning li, linux-mediatek, linux-kernel, linux-arm-kernel,
	devicetree, iommu

On Mon, Jun 16, 2025 at 10:56:07AM +0800, Xueqi Zhang wrote:
> 1. Mediatek has its own implementation for wrapper interrupts and
> power management. Add the SoC specific compatible for MT8196
> implementing arm,smmu-v3.
> 2. APU SMMU need wait until its power is ready, thus add a phandle
> smmu-mediatek-parents to its power node.
> 
> Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> ---
>  .../bindings/iommu/arm,smmu-v3.yaml           | 24 ++++++++++++++++++-
>  1 file changed, 23 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> index 75fcf4cb52d9..c9a99e54de69 100644
> --- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> @@ -20,7 +20,12 @@ properties:
>    $nodename:
>      pattern: "^iommu@[0-9a-f]*"
>    compatible:
> -    const: arm,smmu-v3
> +    - description: MediaTek SoCs implementing "arm,smmu-v3"
> +      items:
> +        - enum:
> +            - mediatek,mt8196-apu-smmu
> +            - mediatek,mt8196-mm-smmu
> +        - const: arm,smmu-v3
>  
>    reg:
>      maxItems: 1
> @@ -69,11 +74,28 @@ properties:
>        register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
>        doesn't support SMMU page1 register space.
>  
> +  mediatek,smmu-parents:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      A phandle to the SMMU's power node. The SMMU should wait until its power
> +      is ready

What's wrong with the power-domains binding? Don't add vendor specific 
properties to a common IP block.

Rob

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 7/8] iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw
  2025-06-16  2:56 ` [RFC PATCH 7/8] iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw Xueqi Zhang
@ 2025-06-16 20:54   ` Pranjal Shrivastava
  0 siblings, 0 replies; 17+ messages in thread
From: Pranjal Shrivastava @ 2025-06-16 20:54 UTC (permalink / raw)
  To: Xueqi Zhang
  Cc: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Project_Global_Chrome_Upstream_Group,
	Ning li, linux-mediatek, linux-kernel, linux-arm-kernel,
	devicetree, iommu

On Mon, Jun 16, 2025 at 10:56:13AM +0800, Xueqi Zhang wrote:

Hi Xueqi,

> Invoke rpm operation before accessing the SMMU hw.
> 
> Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 84 ++++++++++++++++++++-
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  3 +
>  2 files changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 154417b380fa..88912b0f8132 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -122,6 +122,22 @@ static void parse_driver_options(struct arm_smmu_device *smmu)
>  	} while (arm_smmu_options[++i].opt);
>  }
>  
> +static int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
> +{
> +	if (smmu && smmu->impl && smmu->impl->smmu_power_get)
> +		return smmu->impl->smmu_power_get(smmu);
> +
> +	return 0;
> +}
> +
> +static int arm_smmu_rpm_put(struct arm_smmu_device *smmu)
> +{
> +	if (smmu && smmu->impl && smmu->impl->smmu_power_put)
> +		return smmu->impl->smmu_power_put(smmu);
> +
> +	return 0;
> +}
> +

I've been working on enabling PM runtime for arm-smmu-v3 for a while, 
I just posted the RFCv3 for that series [1]. I see that you need some
implementation specific rpm calls too, I think it would be nice if we
could align on this?

Perhaps, you could rebase this on top of my series OR we can collaborate
for the runtime PM series where you can contribute only the rpm patches
from this series to handle your implmentation? 
Let me know what you think! 

>  /* Low-level queue manipulation functions */
>  static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n)
>  {
> @@ -2082,23 +2098,35 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>  static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
>  {
>  	struct arm_smmu_device *smmu = dev;
> +	int ret;
> +
> +	ret = arm_smmu_rpm_get(smmu);
> +	if (ret)
> +		return IRQ_NONE;
>  
>  	arm_smmu_evtq_thread(irq, dev);
>  	if (smmu->features & ARM_SMMU_FEAT_PRI)
>  		arm_smmu_priq_thread(irq, dev);
>  
> +	arm_smmu_rpm_put(smmu);
>  	return IRQ_HANDLED;
>  }
>  
>  static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
>  {
> +
> +	ret = arm_smmu_rpm_get(smmu);
> +	if (ret)
> +		return IRQ_WAKE_THREAD;
>  
>  	arm_smmu_gerror_handler(irq, dev);
>  
>  	if (smmu->impl && smmu->impl->combined_irq_handle)
>  		smmu->impl->combined_irq_handle(irq, smmu);
>  
> +	arm_smmu_rpm_put(smmu);
>  	return IRQ_WAKE_THREAD;
>  }
>  
> @@ -2255,6 +2283,11 @@ static void arm_smmu_tlb_inv_context(void *cookie)
>  	struct arm_smmu_domain *smmu_domain = cookie;
>  	struct arm_smmu_device *smmu = smmu_domain->smmu;
>  	struct arm_smmu_cmdq_ent cmd;
> +	int ret;
> +
> +	ret = arm_smmu_rpm_get(smmu);
> +	if (ret)
> +		return;
>  
>  	/*
>  	 * NOTE: when io-pgtable is in non-strict mode, we may get here with
> @@ -2271,6 +2304,8 @@ static void arm_smmu_tlb_inv_context(void *cookie)
>  		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
>  	}
>  	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
> +
> +	arm_smmu_rpm_put(smmu);
>  }
>  
>  static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
> @@ -2353,6 +2388,11 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
>  			.leaf	= leaf,
>  		},
>  	};
> +	int ret;
> +
> +	ret = arm_smmu_rpm_get(smmu_domain->smmu);
> +	if (ret)
> +		return;

I'm afraid we aren't going for a hard rpm_get in such functions in our
design as per the the discussions in the rpm series[1]. It would be 
great if you could review that too and drop some comments there, I'd be
happy to understand and collaborate to meet your requirements as well :)

[...]

>  static const struct of_device_id arm_smmu_of_match[] = {
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index f45c4bf84bc1..cd96ff9cbc54 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -792,6 +792,7 @@ struct arm_smmu_device {
>  
>  	struct rb_root			streams;
>  	struct mutex			streams_mutex;
> +
>  	const struct arm_smmu_v3_impl	*impl;
>  };
>  
> @@ -1004,6 +1005,8 @@ struct arm_smmu_v3_impl {
>  	int (*combined_irq_handle)(int irq, struct arm_smmu_device *smmu_dev);
>  	int (*smmu_evt_handler)(int irq, struct arm_smmu_device *smmu_dev,
>  				u64 *evt, struct ratelimit_state *rs);
> +	int (*smmu_power_get)(struct arm_smmu_device *smmu);
> +	int (*smmu_power_put)(struct arm_smmu_device *smmu);
>  };
>  
>  struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu);
> -- 
> 2.46.0
> 

Thanks,
Praan

[1] https://lore.kernel.org/all/20250616203149.2649118-1-praan@google.com/

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/8] iommu/arm-smmu-v3: Add SMMU implementation
  2025-06-16  2:56 ` [RFC PATCH 2/8] iommu/arm-smmu-v3: Add SMMU implementation Xueqi Zhang
@ 2025-06-16 21:17   ` Pranjal Shrivastava
  0 siblings, 0 replies; 17+ messages in thread
From: Pranjal Shrivastava @ 2025-06-16 21:17 UTC (permalink / raw)
  To: Xueqi Zhang
  Cc: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Project_Global_Chrome_Upstream_Group,
	Ning li, linux-mediatek, linux-kernel, linux-arm-kernel,
	devicetree, iommu

On Mon, Jun 16, 2025 at 10:56:08AM +0800, Xueqi Zhang wrote:
> Mediatek has its own implementation for wrapper interrupts and
> power management.So add SMMU implementation when smmu device probe.
> 
> Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> ---
>  drivers/iommu/arm/Kconfig                        |  7 +++++++
>  drivers/iommu/arm/arm-smmu-v3/Makefile           |  3 ++-
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c | 16 ++++++++++++++++
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c | 13 +++++++++++++
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c      |  3 +++
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h      |  4 ++++
>  6 files changed, 45 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c
>  create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> 
> diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
> index ef42bbe07dbe..a7f98fd0f2bf 100644
> --- a/drivers/iommu/arm/Kconfig
> +++ b/drivers/iommu/arm/Kconfig
> @@ -88,6 +88,13 @@ config ARM_SMMU_V3
>  	  the ARM SMMUv3 architecture.
>  
>  if ARM_SMMU_V3
> +config ARM_SMMU_V3_MEDIATEK
> +	bool "ARM Ltd. System MMU Version 3 (SMMUv3) MediaTek Support"
> +	depends on ARM_SMMU_V3 && ARCH_MEDIATEK
> +	help
> +	  When running on a MediaTek platform that has the custom variant
> +	  of the ARM SMMUv3, this needs to be built into the SMMU driver.
> +
>  config ARM_SMMU_V3_SVA
>  	bool "Shared Virtual Addressing support for the ARM SMMUv3"
>  	select IOMMU_SVA
> diff --git a/drivers/iommu/arm/arm-smmu-v3/Makefile b/drivers/iommu/arm/arm-smmu-v3/Makefile
> index 493a659cc66b..0670065d6e9a 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/Makefile
> +++ b/drivers/iommu/arm/arm-smmu-v3/Makefile
> @@ -1,7 +1,8 @@
>  # SPDX-License-Identifier: GPL-2.0
>  obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o
> -arm_smmu_v3-y := arm-smmu-v3.o
> +arm_smmu_v3-y := arm-smmu-v3.o arm-smmu-v3-impl.o
>  arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_IOMMUFD) += arm-smmu-v3-iommufd.o
> +arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_MEDIATEK) += arm-smmu-v3-mediatek.o
>  arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o
>  arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o
>  
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c
> new file mode 100644
> index 000000000000..d39587b965ef
> --- /dev/null
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-impl.c
> @@ -0,0 +1,16 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2025 MediaTek Inc.
> + * Author: Ning li <ning.li@mediatek.com>
> + * Author: Xueqi Zhang <xueqi.zhang@mediatek.com>
> + */
> +
> +#include "arm-smmu-v3.h"
> +
> +struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu)
> +{
> +#if IS_ENABLED(CONFIG_ARM_SMMU_V3_MEDIATEK)
> +	smmu = arm_smmu_v3_impl_mtk_init(smmu);
> +#endif
> +	return smmu;
> +}
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> new file mode 100644
> index 000000000000..381268968185
> --- /dev/null
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> @@ -0,0 +1,13 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2025 MediaTek Inc.
> + * Author: Ning li <ning.li@mediatek.com>
> + * Author: Xueqi Zhang <xueqi.zhang@mediatek.com>
> + */
> +
> +#include "arm-smmu-v3.h"
> +
> +struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu)
> +{
> +	return NULL;
> +}
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 10cc6dc26b7b..d36124a6bb54 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -4754,6 +4754,9 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  	}
>  	ioaddr = res->start;
>  
> +	smmu = arm_smmu_v3_impl_init(smmu);
> +	if (IS_ERR(smmu))
> +		return PTR_ERR(smmu);

I'd suggest adding ops to struct arm_smmu_impl_ops and use them. Please
see how Nvidia's implementation makes use of `arm_smmu_impl_probe`,
maybe we could improve that function to handle mtk smmu as well.

>  	/*
>  	 * Don't map the IMPLEMENTATION DEFINED regions, since they may contain
>  	 * the PMCG registers which are reserved by the PMU driver.
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index ea41d790463e..99eeb6143c49 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -998,6 +998,10 @@ int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
>  				struct arm_smmu_cmdq *cmdq, u64 *cmds, int n,
>  				bool sync);
>  
> +struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu);
> +#if IS_ENABLED(CONFIG_ARM_SMMU_V3_MEDIATEK)
> +struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu);
> +#endif

We'd prefer to avoid implementation-specific #if CONFIG_* across the
driver as much as possible.

>  #ifdef CONFIG_ARM_SMMU_V3_SVA
>  bool arm_smmu_sva_supported(struct arm_smmu_device *smmu);
>  void arm_smmu_sva_notifier_synchronize(void);
> -- 
> 2.46.0

Thanks,
Praan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 5/8] iommu/arm-smmu-v3: Add IRQ handle for smmu impl
  2025-06-16  2:56 ` [RFC PATCH 5/8] iommu/arm-smmu-v3: Add IRQ handle for smmu impl Xueqi Zhang
@ 2025-06-16 21:32   ` Pranjal Shrivastava
  0 siblings, 0 replies; 17+ messages in thread
From: Pranjal Shrivastava @ 2025-06-16 21:32 UTC (permalink / raw)
  To: Xueqi Zhang
  Cc: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Project_Global_Chrome_Upstream_Group,
	Ning li, linux-mediatek, linux-kernel, linux-arm-kernel,
	devicetree, iommu

On Mon, Jun 16, 2025 at 10:56:11AM +0800, Xueqi Zhang wrote:
> Add IRQ handle for smmu impl
> 
> Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 ++++++++-
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 8 ++++++++
>  2 files changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index d36124a6bb54..154417b380fa 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -1954,7 +1954,8 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>  			arm_smmu_decode_event(smmu, evt, &event);
>  			if (arm_smmu_handle_event(smmu, evt, &event))
>  				arm_smmu_dump_event(smmu, evt, &event, &rs);
> -
> +			if (smmu->impl && smmu->impl->smmu_evt_handler)
> +				smmu->impl->smmu_evt_handler(irq, smmu, evt, &rs);
>  			put_device(event.dev);
>  			cond_resched();
>  		}
> @@ -2091,7 +2092,13 @@ static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
>  
>  static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
>  {
> +	struct arm_smmu_device *smmu = dev;
> +
>  	arm_smmu_gerror_handler(irq, dev);
> +
> +	if (smmu->impl && smmu->impl->combined_irq_handle)
> +		smmu->impl->combined_irq_handle(irq, smmu);
> +
>  	return IRQ_WAKE_THREAD;
>  }
>  
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index 99eeb6143c49..f45c4bf84bc1 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -792,6 +792,7 @@ struct arm_smmu_device {
>  
>  	struct rb_root			streams;
>  	struct mutex			streams_mutex;
> +	const struct arm_smmu_v3_impl	*impl;
>  };
>  
>  struct arm_smmu_stream {
> @@ -998,6 +999,13 @@ int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
>  				struct arm_smmu_cmdq *cmdq, u64 *cmds, int n,
>  				bool sync);
>  
> +/* Implementation details */
> +struct arm_smmu_v3_impl {
> +	int (*combined_irq_handle)(int irq, struct arm_smmu_device *smmu_dev);
> +	int (*smmu_evt_handler)(int irq, struct arm_smmu_device *smmu_dev,
> +				u64 *evt, struct ratelimit_state *rs);
> +};

Let's add these to the exisiting struct arm_smmu_impl_ops and invoke
them like:

	if (smmu->impl && smmu->impl_ops->combined_irq_handle)
		smmu->impl_ops->combined_irq_handle(irq, smmu);

Or maybe we could merge the existing impl_dev and impl_ops into a single
structure.

> +
>  struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu);
>  #if IS_ENABLED(CONFIG_ARM_SMMU_V3_MEDIATEK)
>  struct arm_smmu_device *arm_smmu_v3_impl_mtk_init(struct arm_smmu_device *smmu);
> -- 
> 2.46.0
> 
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support
  2025-06-16  2:56 ` [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support Xueqi Zhang
  2025-06-16  4:40   ` Rob Herring (Arm)
  2025-06-16 14:27   ` Rob Herring
@ 2025-06-17  6:28   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 17+ messages in thread
From: Krzysztof Kozlowski @ 2025-06-17  6:28 UTC (permalink / raw)
  To: Xueqi Zhang
  Cc: Yong Wu, Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Project_Global_Chrome_Upstream_Group,
	Ning li, linux-mediatek, linux-kernel, linux-arm-kernel,
	devicetree, iommu

On Mon, Jun 16, 2025 at 10:56:07AM GMT, Xueqi Zhang wrote:
> 1. Mediatek has its own implementation for wrapper interrupts and
> power management. Add the SoC specific compatible for MT8196
> implementing arm,smmu-v3.
> 2. APU SMMU need wait until its power is ready, thus add a phandle
> smmu-mediatek-parents to its power node.
> 
> Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> ---
>  .../bindings/iommu/arm,smmu-v3.yaml           | 24 ++++++++++++++++++-
>  1 file changed, 23 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> index 75fcf4cb52d9..c9a99e54de69 100644
> --- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.yaml
> @@ -20,7 +20,12 @@ properties:
>    $nodename:
>      pattern: "^iommu@[0-9a-f]*"
>    compatible:
> -    const: arm,smmu-v3
> +    - description: MediaTek SoCs implementing "arm,smmu-v3"
> +      items:
> +        - enum:
> +            - mediatek,mt8196-apu-smmu
> +            - mediatek,mt8196-mm-smmu
> +        - const: arm,smmu-v3

You just broke every existing user, so this was not tested.

Limited review follows - test your patches first.

>  
>    reg:
>      maxItems: 1
> @@ -69,11 +74,28 @@ properties:
>        register access with page 0 offsets. Set for Cavium ThunderX2 silicon that
>        doesn't support SMMU page1 register space.
>  
> +  mediatek,smmu-parents:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      A phandle to the SMMU's power node. The SMMU should wait until its power
> +      is ready

No, power domains express power relationship. Or some other existing
properties or simply parent-child relationships.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 6/8] iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ
  2025-06-16  2:56 ` [RFC PATCH 6/8] iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ Xueqi Zhang
@ 2025-06-24 11:22   ` Will Deacon
  2025-06-25 16:54     ` Marc Zyngier
  0 siblings, 1 reply; 17+ messages in thread
From: Will Deacon @ 2025-06-24 11:22 UTC (permalink / raw)
  To: Xueqi Zhang
  Cc: Yong Wu, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Project_Global_Chrome_Upstream_Group,
	Ning li, linux-mediatek, linux-kernel, linux-arm-kernel,
	devicetree, iommu, maz

[+Marc for irqchip question at the end]

On Mon, Jun 16, 2025 at 10:56:12AM +0800, Xueqi Zhang wrote:
> Mediatek SMMU interrupt is low level active rather than the standard
> edge.Process Mediatek SMMU wrapper interrupt and dump detailed
> information when a translation fault occurs.
> 
> Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> ---
>  .../arm/arm-smmu-v3/arm-smmu-v3-mediatek.c    | 349 +++++++++++++++++-
>  1 file changed, 347 insertions(+), 2 deletions(-)

I think this probably needs splitting in two parts so that the low-level
IRQ handling is separate from the fault diagnostic reporting.

> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> index 48290366e596..448166c1ca64 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> @@ -14,7 +14,122 @@
>  
>  #include "arm-smmu-v3.h"
>  
> +#include <linux/soc/mediatek/mtk_sip_svc.h>
> +#include <linux/arm-smccc.h>
> +
> +#define SMMUWP_GLB_CTL0			(0x0)
> +#define CTL0_STD_AXI_MODE_DIS		BIT(0)
> +#define CTL0_MON_DIS			BIT(1)
> +#define CTL0_DCM_EN			BIT(2)
> +#define CTL0_WRAPPER_CK_AOEN		BIT(3)
> +#define CTL0_AUTO_AXDOMAIN_EN		BIT(4)
> +#define CTL0_IRQ_BUSY_EN		BIT(5)
> +#define CTL0_ABT_CNT_CLR		BIT(6)
> +#define CTL0_LEGACY_AXCACHE		BIT(7)
> +#define CTL0_COMMIT_DIS			BIT(8)
> +#define CTL0_AUTO_SLP_DIS		BIT(9)
> +#define CTL0_STTSL_DIS			BIT(10)
> +#define CTL0_CFG_TAB_DCM_EN		BIT(11)
> +#define CTL0_CPU_PARTID_DIS		BIT(14)
> +/* New bits of SMMU wrapper extension */
> +#define CTL0_TCU2SLC_DCM_EN		BIT(18)
> +#define CTL0_APB_DCM_EN			BIT(19)
> +#define CTL0_DVM_DCM_EN			BIT(20)
> +#define CTL0_CPU_TBU_PARTID_DIS		BIT(21)
> +
> +#define SMMUWP_IRQ_STA			(0x80)
> +#define STA_TCU_GLB_INTR		BIT(0)
> +#define STA_TCU_CMD_SYNC_INTR		BIT(1)
> +#define STA_TCU_EVTQ_INTR		BIT(2)
> +#define STA_TCU_PRI_INTR		BIT(3)
> +#define STA_TCU_PMU_INTR		BIT(4)
> +#define STA_TCU_RAS_CRI			BIT(5)
> +#define STA_TCU_RAS_ERI			BIT(6)
> +#define STA_TCU_RAS_FHI			BIT(7)
> +
> +#define SMMUWP_IRQ_ACK			(0x84)
> +
> +#define SMMUWP_IRQ_ACK_CNT		(0x88)
> +#define IRQ_ACK_CNT_MSK			GENMASK(7, 0)
> +
> +/* SMMU non-secure interrupt pending count register, count 20 */
> +#define SMMUWP_IRQ_CNTx(cnt)		(0x100 + 0x4 * (cnt))
> +
> +#define SMMU_TCU_CTL1_AXSLC		(0x204)
> +#define AXSLC_BIT_FIELD			GENMASK(8, 4)
> +#define AXSLC_CACHE			BIT(5)
> +#define AXSLC_ALLOCATE			BIT(6)
> +#define AXSLC_SPECULATIVE		BIT(7)
> +#define AXSLC_SET			(AXSLC_CACHE | AXSLC_ALLOCATE | AXSLC_SPECULATIVE)
> +#define SLC_SB_ONLY_EN			BIT(1)
> +
> +/* SMMU TBUx read translation fault monitor0 */
> +#define SMMUWP_TBUx_RTFM0(tbu)		(0x380 + 0x100 * (tbu))
> +#define RTFM0_FAULT_AXI_ID		GENMASK_ULL(19, 0)
> +#define RTFM0_FAULT_DET			BIT(31)
> +
> +/* SMMU TBUx read translation fault monitor1 */
> +#define SMMUWP_TBUx_RTFM1(tbu)		(0x384 + 0x100 * (tbu))
> +#define RTFM1_FAULT_VA_35_32		GENMASK_ULL(3, 0)
> +#define RTFM1_FAULT_VA_31_12		GENMASK_ULL(31, 12)
> +
> +/* SMMU TBUx read translation fault monitor2 */
> +#define SMMUWP_TBUx_RTFM2(tbu)		(0x388 + 0x100 * (tbu))
> +#define RTFM2_FAULT_SID			GENMASK_ULL(7, 0)
> +#define RTFM2_FAULT_SSID		GENMASK_ULL(15, 8)
> +#define RTFM2_FAULT_SSIDV		BIT(16)
> +#define RTFM2_FAULT_SECSID		BIT(17)
> +
> +/* SMMU TBUx write translation fault monitor0 */
> +#define SMMUWP_TBUx_WTFM0(tbu)		(0x390 + 0x100 * (tbu))
> +#define WTFM0_FAULT_AXI_ID		GENMASK_ULL(19, 0)
> +#define WTFM0_FAULT_DET			BIT(31)
> +
> +/* SMMU TBUx write translation fault monitor1 */
> +#define SMMUWP_TBUx_WTFM1(tbu)		(0x394 + 0x100 * (tbu))
> +#define WTFM1_FAULT_VA_35_32		GENMASK_ULL(3, 0)
> +#define WTFM1_FAULT_VA_31_12		GENMASK_ULL(31, 12)
> +
> +/* SMMU TBUx write translation fault monitor2 */
> +#define SMMUWP_TBUx_WTFM2(tbu)		(0x398 + 0x100 * (tbu))
> +#define WTFM2_FAULT_SID			GENMASK_ULL(7, 0)
> +#define WTFM2_FAULT_SSID		GENMASK_ULL(15, 8)
> +#define WTFM2_FAULT_SSIDV		BIT(16)
> +#define WTFM2_FAULT_SECSID		BIT(17)
> +
> +/* SMMU TBU Manual OG Control High Register0 */
> +#define SMMUWP_TBU0_MOGH0		(0x3b4)
> +#define MOGH_EN				BIT(29)
> +#define MOGH_RW				BIT(28)
> +
> +/* SMMU translation fault TBUx */
> +#define SMMUWP_TF_TBU_MSK		GENMASK(26, 24)
> +#define SMMUWP_TF_TBU(tbu)		FIELD_PREP(SMMUWP_TF_TBU_MSK, tbu)
> +
> +#define SMMU_FAULT_RS_INTERVAL		DEFAULT_RATELIMIT_INTERVAL
> +#define SMMU_FAULT_RS_BURST		(1)
> +
> +#define STRSEC(sec)			((sec) ? "SECURE" : "NORMAL")
> +
> +#define WP_OFFSET_MT8196		0x1e0000
> +
>  #define MTK_SMMU_COMP_STR_LEN		64
> +
> +#define MTK_SMMU_FAULT_IOVA(low, high) ((low) | (((u64)(high) & 0xf) << 32))
> +
> +#define SMMU_SUCCESS			(0)
> +#define SMMU_ID_ERR			(1)
> +#define SMMU_CMD_ERR			(2)
> +#define SMMU_PARA_INVALID		(3)
> +#define SMMU_NEED			(4)
> +#define SMMU_NONEED			(5)
> +
> +/* plat flags: */
> +#define SMMU_SKIP_PM_CLK		BIT(0)
> +#define SMMU_CLK_AO_EN			BIT(1)
> +#define SMMU_AXSLC_EN			BIT(2)
> +#define SMMU_DIS_CPU_PARTID		BIT(3)
> +#define SMMU_DIS_CPU_TBU_PARTID		BIT(4)
>  #define SMMU_REQUIRE_PARENT		BIT(5)
>  #define MTK_SMMU_HAS_FLAG(pdata, _x)    (!!(((pdata)->flags) & (_x)))
>  
> @@ -25,22 +140,30 @@ enum mtk_smmu_type {
>  };
>  
>  struct mtk_smmu_v3_plat {
> +	u32			wp_offset;
> +	unsigned int		tbu_cnt;
>  	enum mtk_smmu_type	smmu_type;
>  	u32			flags;
>  };
>  
>  struct mtk_smmu_v3 {
>  	struct arm_smmu_device	smmu;
> +	void __iomem			*wp_base;
>  	const struct mtk_smmu_v3_plat *plat_data;
>  };
>  
>  static const struct mtk_smmu_v3_plat mt8196_data_mm = {
> +	.wp_offset		= WP_OFFSET_MT8196,
> +	.tbu_cnt		= 3,
>  	.smmu_type		= MTK_SMMU_MM,
> +	.flags			= SMMU_AXSLC_EN,
>  };
>  
>  static const struct mtk_smmu_v3_plat mt8196_data_apu = {
> +	.wp_offset		= WP_OFFSET_MT8196,
> +	.tbu_cnt		= 3,
>  	.smmu_type		= MTK_SMMU_APU,
> -	.flags			= SMMU_REQUIRE_PARENT,
> +	.flags			= SMMU_AXSLC_EN | SMMU_REQUIRE_PARENT,
>  };
>  
>  struct mtk_smmu_v3_of_device_data {
> @@ -70,17 +193,228 @@ static const struct mtk_smmu_v3_plat *mtk_smmu_v3_get_plat_data(const struct dev
>  	return NULL;
>  }
>  
> +static inline void smmu_write_field(void __iomem *base,
> +				    unsigned int reg,
> +				    unsigned int mask,
> +				    unsigned int val)
> +{
> +	unsigned int regval;
> +
> +	regval = readl_relaxed(base + reg);
> +	regval = (regval & (~mask)) | val;
> +	writel_relaxed(regval, base + reg);
> +}
> +
> +static void smmu_init_wpcfg(struct arm_smmu_device *smmu)
> +{
> +	struct mtk_smmu_v3 *mtk_smmu_v3 = to_mtk_smmu_v3(smmu);
> +	void __iomem *wp_base = mtk_smmu_v3->wp_base;
> +
> +	/* DCM basic setting */
> +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_DCM_EN, CTL0_DCM_EN);
> +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_CFG_TAB_DCM_EN,
> +			 CTL0_CFG_TAB_DCM_EN);
> +
> +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
> +			 CTL0_TCU2SLC_DCM_EN | CTL0_APB_DCM_EN |
> +			 CTL0_DVM_DCM_EN,
> +			 CTL0_TCU2SLC_DCM_EN | CTL0_APB_DCM_EN |
> +			 CTL0_DVM_DCM_EN);
> +
> +	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_DIS_CPU_PARTID))
> +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_CPU_PARTID_DIS,
> +				 CTL0_CPU_PARTID_DIS);
> +	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_DIS_CPU_TBU_PARTID))
> +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
> +				 CTL0_CPU_TBU_PARTID_DIS, CTL0_CPU_TBU_PARTID_DIS);
> +
> +	/* Used for MM_SMMMU read command overtaking */
> +	if (mtk_smmu_v3->plat_data->smmu_type == MTK_SMMU_MM)
> +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_STD_AXI_MODE_DIS,
> +				 CTL0_STD_AXI_MODE_DIS);
> +
> +	/* Set AXSLC */
> +	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_AXSLC_EN)) {
> +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
> +				 CTL0_STD_AXI_MODE_DIS, CTL0_STD_AXI_MODE_DIS);
> +		smmu_write_field(wp_base, SMMU_TCU_CTL1_AXSLC, AXSLC_BIT_FIELD,
> +				 AXSLC_SET);
> +		smmu_write_field(wp_base, SMMU_TCU_CTL1_AXSLC, SLC_SB_ONLY_EN,
> +				 SLC_SB_ONLY_EN);
> +	}
> +}
> +
> +/* Consume SMMU wrapper interrupt bit */
> +static unsigned int
> +smmuwp_consume_intr(void __iomem *wp_base, unsigned int irq_bit)
> +{
> +	unsigned int pend_cnt;
> +
> +	pend_cnt = readl_relaxed(wp_base + SMMUWP_IRQ_CNTx(__ffs(irq_bit)));
> +	smmu_write_field(wp_base, SMMUWP_IRQ_ACK_CNT, IRQ_ACK_CNT_MSK, pend_cnt);
> +	writel_relaxed(irq_bit, wp_base + SMMUWP_IRQ_ACK);
> +
> +	return pend_cnt;
> +}
> +
> +/* clear translation fault mark */
> +static void smmuwp_clear_tf(void __iomem *wp_base)
> +{
> +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_ABT_CNT_CLR, CTL0_ABT_CNT_CLR);
> +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_ABT_CNT_CLR, 0);
> +}
> +
> +static u32 smmuwp_fault_id(u32 axi_id, u32 tbu_id)
> +{
> +	u32 fault_id = (axi_id & ~SMMUWP_TF_TBU_MSK) | (SMMUWP_TF_TBU(tbu_id));
> +
> +	return fault_id;
> +}
> +
> +/* Process TBU translation fault Monitor */
> +static bool smmuwp_process_tf(struct arm_smmu_device *smmu)
> +{
> +	struct mtk_smmu_v3 *mtk_smmu_v3 = to_mtk_smmu_v3(smmu);
> +	void __iomem *wp_base = mtk_smmu_v3->wp_base;
> +	unsigned int sid, ssid, secsidv, ssidv;
> +	u32 i, regval, va35_32, axiid, fault_id;
> +	u64 fault_iova;
> +	bool tf_det = false;
> +
> +	for (i = 0; i < mtk_smmu_v3->plat_data->tbu_cnt; i++) {
> +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM0(i));
> +		if (!(regval & RTFM0_FAULT_DET))
> +			goto write;
> +
> +		tf_det = true;
> +		axiid = FIELD_GET(RTFM0_FAULT_AXI_ID, regval);
> +		fault_id = smmuwp_fault_id(axiid, i);
> +
> +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM1(i));
> +		va35_32 = FIELD_GET(RTFM1_FAULT_VA_35_32, regval);
> +		fault_iova = MTK_SMMU_FAULT_IOVA(regval & RTFM1_FAULT_VA_31_12, va35_32);
> +
> +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM2(i));
> +		sid = FIELD_GET(RTFM2_FAULT_SID, regval);
> +		ssid = FIELD_GET(RTFM2_FAULT_SSID, regval);

We already print a bunch of this stuff in arm_smmu_dump_event() now that
Pranjal has improved the logic. I don't see the value in printing the
same information twice, so we should trim down the extra diagnostics here
so that (a) the information is distinct from that provided by the core
driuver code and (b) it's relevant to Linux (e.g. there's no need to
print information about secure transactions).

The core driver code should also print some delimiters around the
implementation-defined data as well. Out of curiosity, is the TBU
monitor part of Arm's IP or is this additional hardware from MTK?

> +		ssidv = FIELD_GET(RTFM2_FAULT_SSIDV, regval);
> +		secsidv = FIELD_GET(RTFM2_FAULT_SECSID, regval);
> +		dev_err_ratelimited(smmu->dev, "TF read in %s world, TBU_id-%d-fault_id:0x%x(0x%x)\n",
> +				    STRSEC(secsidv), i, fault_id, axiid);
> +		dev_err_ratelimited(smmu->dev,
> +				    "iova:0x%llx, sid:%d, ssid:%d, ssidv:%d, secsidv:%d\n",
> +				    fault_iova, sid, ssid, ssidv, secsidv);
> +
> +write:
> +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM0(i));
> +		if (!(regval & WTFM0_FAULT_DET))
> +			continue;
> +
> +		tf_det = true;
> +		axiid = FIELD_GET(WTFM0_FAULT_AXI_ID, regval);
> +		fault_id = smmuwp_fault_id(axiid, i);
> +
> +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM1(i));
> +		va35_32 = FIELD_GET(WTFM1_FAULT_VA_35_32, regval);
> +		fault_iova = MTK_SMMU_FAULT_IOVA(regval & RTFM1_FAULT_VA_31_12, va35_32);
> +
> +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM2(i));
> +		sid = FIELD_GET(WTFM2_FAULT_SID, regval);
> +		ssid = FIELD_GET(WTFM2_FAULT_SSID, regval);
> +		ssidv = FIELD_GET(WTFM2_FAULT_SSIDV, regval);
> +		secsidv = FIELD_GET(WTFM2_FAULT_SECSID, regval);
> +		dev_err_ratelimited(smmu->dev, "TF write in %s world, TBU_id-%d-fault_id:0x%x(0x%x)\n",
> +				    STRSEC(secsidv), i, fault_id, axiid);
> +		dev_err_ratelimited(smmu->dev,
> +				    "iova:0x%llx, sid:%d, ssid:%d, ssidv:%d, secsidv:%d\n",
> +				    fault_iova, sid, ssid, ssidv, secsidv);

nit: but I don't think we should use the _ratelimited() prints here as it
could end up with random lines being dropped.

> +/* Process SMMU wrapper interrupt */
> +static int mtk_smmu_v3_smmuwp_irq_handler(int irq, struct arm_smmu_device *smmu)
> +{
> +	struct mtk_smmu_v3 *mtk_smmuv3 = to_mtk_smmu_v3(smmu);
> +	void __iomem *wp_base = mtk_smmuv3->wp_base;
> +	unsigned int irq_sta, pend_cnt;
> +
> +	irq_sta = readl_relaxed(wp_base + SMMUWP_IRQ_STA);
> +	if (irq_sta == 0)
> +		return 0;
> +
> +	if (irq_sta & STA_TCU_GLB_INTR) {
> +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_GLB_INTR);
> +		dev_dbg(smmu->dev,
> +			"IRQ_STA:0x%x, Non-secure TCU global interrupt detected pending_cnt: %d\n",
> +			irq_sta, pend_cnt);
> +	}
> +
> +	if (irq_sta & STA_TCU_CMD_SYNC_INTR) {
> +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_CMD_SYNC_INTR);
> +		dev_dbg(smmu->dev,
> +			"IRQ_STA:0x%x, Non-secure TCU CMD_SYNC interrupt detected pending_cnt: %d\n",
> +			irq_sta, pend_cnt);
> +	}
> +
> +	if (irq_sta & STA_TCU_EVTQ_INTR) {
> +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_EVTQ_INTR);
> +		dev_dbg(smmu->dev,
> +			"IRQ_STA:0x%x, Non-secure TCU EVTQ interrupt detected pending_cnt: %d\n",
> +			irq_sta, pend_cnt);
> +	}
> +
> +	if (irq_sta & STA_TCU_PRI_INTR) {
> +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_PRI_INTR);
> +		dev_dbg(smmu->dev, "IRQ_STA:0x%x, TCU PRI interrupt detected pending_cnt: %d\n",
> +			irq_sta, pend_cnt);
> +	}
> +
> +	if (irq_sta & STA_TCU_PMU_INTR) {
> +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_PMU_INTR);
> +		dev_dbg(smmu->dev, "IRQ_STA:0x%x, TCU PMU interrupt detected pending_cnt: %d\n",
> +			irq_sta, pend_cnt);
> +	}
> +
> +	return 0;
> +}

Hrm. I wonder whether this would be better off treated as a chained irqchip
rather than hiding the logic inside the SMMU driver? It effectively looks
like a demuxer to me.

Will

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 6/8] iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ
  2025-06-24 11:22   ` Will Deacon
@ 2025-06-25 16:54     ` Marc Zyngier
  0 siblings, 0 replies; 17+ messages in thread
From: Marc Zyngier @ 2025-06-25 16:54 UTC (permalink / raw)
  To: Will Deacon
  Cc: Xueqi Zhang, Yong Wu, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Project_Global_Chrome_Upstream_Group,
	Ning li, linux-mediatek, linux-kernel, linux-arm-kernel,
	devicetree, iommu

On Tue, 24 Jun 2025 12:22:00 +0100,
Will Deacon <will@kernel.org> wrote:
> 
> [+Marc for irqchip question at the end]
> 
> On Mon, Jun 16, 2025 at 10:56:12AM +0800, Xueqi Zhang wrote:
> > Mediatek SMMU interrupt is low level active rather than the standard
> > edge.Process Mediatek SMMU wrapper interrupt and dump detailed
> > information when a translation fault occurs.
> > 
> > Signed-off-by: Xueqi Zhang <xueqi.zhang@mediatek.com>
> > ---
> >  .../arm/arm-smmu-v3/arm-smmu-v3-mediatek.c    | 349 +++++++++++++++++-
> >  1 file changed, 347 insertions(+), 2 deletions(-)
> 
> I think this probably needs splitting in two parts so that the low-level
> IRQ handling is separate from the fault diagnostic reporting.
> 
> > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> > index 48290366e596..448166c1ca64 100644
> > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-mediatek.c
> > @@ -14,7 +14,122 @@
> >  
> >  #include "arm-smmu-v3.h"
> >  
> > +#include <linux/soc/mediatek/mtk_sip_svc.h>
> > +#include <linux/arm-smccc.h>
> > +
> > +#define SMMUWP_GLB_CTL0			(0x0)
> > +#define CTL0_STD_AXI_MODE_DIS		BIT(0)
> > +#define CTL0_MON_DIS			BIT(1)
> > +#define CTL0_DCM_EN			BIT(2)
> > +#define CTL0_WRAPPER_CK_AOEN		BIT(3)
> > +#define CTL0_AUTO_AXDOMAIN_EN		BIT(4)
> > +#define CTL0_IRQ_BUSY_EN		BIT(5)
> > +#define CTL0_ABT_CNT_CLR		BIT(6)
> > +#define CTL0_LEGACY_AXCACHE		BIT(7)
> > +#define CTL0_COMMIT_DIS			BIT(8)
> > +#define CTL0_AUTO_SLP_DIS		BIT(9)
> > +#define CTL0_STTSL_DIS			BIT(10)
> > +#define CTL0_CFG_TAB_DCM_EN		BIT(11)
> > +#define CTL0_CPU_PARTID_DIS		BIT(14)
> > +/* New bits of SMMU wrapper extension */
> > +#define CTL0_TCU2SLC_DCM_EN		BIT(18)
> > +#define CTL0_APB_DCM_EN			BIT(19)
> > +#define CTL0_DVM_DCM_EN			BIT(20)
> > +#define CTL0_CPU_TBU_PARTID_DIS		BIT(21)
> > +
> > +#define SMMUWP_IRQ_STA			(0x80)
> > +#define STA_TCU_GLB_INTR		BIT(0)
> > +#define STA_TCU_CMD_SYNC_INTR		BIT(1)
> > +#define STA_TCU_EVTQ_INTR		BIT(2)
> > +#define STA_TCU_PRI_INTR		BIT(3)
> > +#define STA_TCU_PMU_INTR		BIT(4)
> > +#define STA_TCU_RAS_CRI			BIT(5)
> > +#define STA_TCU_RAS_ERI			BIT(6)
> > +#define STA_TCU_RAS_FHI			BIT(7)
> > +
> > +#define SMMUWP_IRQ_ACK			(0x84)
> > +
> > +#define SMMUWP_IRQ_ACK_CNT		(0x88)
> > +#define IRQ_ACK_CNT_MSK			GENMASK(7, 0)
> > +
> > +/* SMMU non-secure interrupt pending count register, count 20 */
> > +#define SMMUWP_IRQ_CNTx(cnt)		(0x100 + 0x4 * (cnt))
> > +
> > +#define SMMU_TCU_CTL1_AXSLC		(0x204)
> > +#define AXSLC_BIT_FIELD			GENMASK(8, 4)
> > +#define AXSLC_CACHE			BIT(5)
> > +#define AXSLC_ALLOCATE			BIT(6)
> > +#define AXSLC_SPECULATIVE		BIT(7)
> > +#define AXSLC_SET			(AXSLC_CACHE | AXSLC_ALLOCATE | AXSLC_SPECULATIVE)
> > +#define SLC_SB_ONLY_EN			BIT(1)
> > +
> > +/* SMMU TBUx read translation fault monitor0 */
> > +#define SMMUWP_TBUx_RTFM0(tbu)		(0x380 + 0x100 * (tbu))
> > +#define RTFM0_FAULT_AXI_ID		GENMASK_ULL(19, 0)
> > +#define RTFM0_FAULT_DET			BIT(31)
> > +
> > +/* SMMU TBUx read translation fault monitor1 */
> > +#define SMMUWP_TBUx_RTFM1(tbu)		(0x384 + 0x100 * (tbu))
> > +#define RTFM1_FAULT_VA_35_32		GENMASK_ULL(3, 0)
> > +#define RTFM1_FAULT_VA_31_12		GENMASK_ULL(31, 12)
> > +
> > +/* SMMU TBUx read translation fault monitor2 */
> > +#define SMMUWP_TBUx_RTFM2(tbu)		(0x388 + 0x100 * (tbu))
> > +#define RTFM2_FAULT_SID			GENMASK_ULL(7, 0)
> > +#define RTFM2_FAULT_SSID		GENMASK_ULL(15, 8)
> > +#define RTFM2_FAULT_SSIDV		BIT(16)
> > +#define RTFM2_FAULT_SECSID		BIT(17)
> > +
> > +/* SMMU TBUx write translation fault monitor0 */
> > +#define SMMUWP_TBUx_WTFM0(tbu)		(0x390 + 0x100 * (tbu))
> > +#define WTFM0_FAULT_AXI_ID		GENMASK_ULL(19, 0)
> > +#define WTFM0_FAULT_DET			BIT(31)
> > +
> > +/* SMMU TBUx write translation fault monitor1 */
> > +#define SMMUWP_TBUx_WTFM1(tbu)		(0x394 + 0x100 * (tbu))
> > +#define WTFM1_FAULT_VA_35_32		GENMASK_ULL(3, 0)
> > +#define WTFM1_FAULT_VA_31_12		GENMASK_ULL(31, 12)
> > +
> > +/* SMMU TBUx write translation fault monitor2 */
> > +#define SMMUWP_TBUx_WTFM2(tbu)		(0x398 + 0x100 * (tbu))
> > +#define WTFM2_FAULT_SID			GENMASK_ULL(7, 0)
> > +#define WTFM2_FAULT_SSID		GENMASK_ULL(15, 8)
> > +#define WTFM2_FAULT_SSIDV		BIT(16)
> > +#define WTFM2_FAULT_SECSID		BIT(17)
> > +
> > +/* SMMU TBU Manual OG Control High Register0 */
> > +#define SMMUWP_TBU0_MOGH0		(0x3b4)
> > +#define MOGH_EN				BIT(29)
> > +#define MOGH_RW				BIT(28)
> > +
> > +/* SMMU translation fault TBUx */
> > +#define SMMUWP_TF_TBU_MSK		GENMASK(26, 24)
> > +#define SMMUWP_TF_TBU(tbu)		FIELD_PREP(SMMUWP_TF_TBU_MSK, tbu)
> > +
> > +#define SMMU_FAULT_RS_INTERVAL		DEFAULT_RATELIMIT_INTERVAL
> > +#define SMMU_FAULT_RS_BURST		(1)
> > +
> > +#define STRSEC(sec)			((sec) ? "SECURE" : "NORMAL")
> > +
> > +#define WP_OFFSET_MT8196		0x1e0000
> > +
> >  #define MTK_SMMU_COMP_STR_LEN		64
> > +
> > +#define MTK_SMMU_FAULT_IOVA(low, high) ((low) | (((u64)(high) & 0xf) << 32))
> > +
> > +#define SMMU_SUCCESS			(0)
> > +#define SMMU_ID_ERR			(1)
> > +#define SMMU_CMD_ERR			(2)
> > +#define SMMU_PARA_INVALID		(3)
> > +#define SMMU_NEED			(4)
> > +#define SMMU_NONEED			(5)
> > +
> > +/* plat flags: */
> > +#define SMMU_SKIP_PM_CLK		BIT(0)
> > +#define SMMU_CLK_AO_EN			BIT(1)
> > +#define SMMU_AXSLC_EN			BIT(2)
> > +#define SMMU_DIS_CPU_PARTID		BIT(3)
> > +#define SMMU_DIS_CPU_TBU_PARTID		BIT(4)
> >  #define SMMU_REQUIRE_PARENT		BIT(5)
> >  #define MTK_SMMU_HAS_FLAG(pdata, _x)    (!!(((pdata)->flags) & (_x)))
> >  
> > @@ -25,22 +140,30 @@ enum mtk_smmu_type {
> >  };
> >  
> >  struct mtk_smmu_v3_plat {
> > +	u32			wp_offset;
> > +	unsigned int		tbu_cnt;
> >  	enum mtk_smmu_type	smmu_type;
> >  	u32			flags;
> >  };
> >  
> >  struct mtk_smmu_v3 {
> >  	struct arm_smmu_device	smmu;
> > +	void __iomem			*wp_base;
> >  	const struct mtk_smmu_v3_plat *plat_data;
> >  };
> >  
> >  static const struct mtk_smmu_v3_plat mt8196_data_mm = {
> > +	.wp_offset		= WP_OFFSET_MT8196,
> > +	.tbu_cnt		= 3,
> >  	.smmu_type		= MTK_SMMU_MM,
> > +	.flags			= SMMU_AXSLC_EN,
> >  };
> >  
> >  static const struct mtk_smmu_v3_plat mt8196_data_apu = {
> > +	.wp_offset		= WP_OFFSET_MT8196,
> > +	.tbu_cnt		= 3,
> >  	.smmu_type		= MTK_SMMU_APU,
> > -	.flags			= SMMU_REQUIRE_PARENT,
> > +	.flags			= SMMU_AXSLC_EN | SMMU_REQUIRE_PARENT,
> >  };
> >  
> >  struct mtk_smmu_v3_of_device_data {
> > @@ -70,17 +193,228 @@ static const struct mtk_smmu_v3_plat *mtk_smmu_v3_get_plat_data(const struct dev
> >  	return NULL;
> >  }
> >  
> > +static inline void smmu_write_field(void __iomem *base,
> > +				    unsigned int reg,
> > +				    unsigned int mask,
> > +				    unsigned int val)
> > +{
> > +	unsigned int regval;
> > +
> > +	regval = readl_relaxed(base + reg);
> > +	regval = (regval & (~mask)) | val;
> > +	writel_relaxed(regval, base + reg);
> > +}
> > +
> > +static void smmu_init_wpcfg(struct arm_smmu_device *smmu)
> > +{
> > +	struct mtk_smmu_v3 *mtk_smmu_v3 = to_mtk_smmu_v3(smmu);
> > +	void __iomem *wp_base = mtk_smmu_v3->wp_base;
> > +
> > +	/* DCM basic setting */
> > +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_DCM_EN, CTL0_DCM_EN);
> > +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_CFG_TAB_DCM_EN,
> > +			 CTL0_CFG_TAB_DCM_EN);
> > +
> > +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
> > +			 CTL0_TCU2SLC_DCM_EN | CTL0_APB_DCM_EN |
> > +			 CTL0_DVM_DCM_EN,
> > +			 CTL0_TCU2SLC_DCM_EN | CTL0_APB_DCM_EN |
> > +			 CTL0_DVM_DCM_EN);
> > +
> > +	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_DIS_CPU_PARTID))
> > +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_CPU_PARTID_DIS,
> > +				 CTL0_CPU_PARTID_DIS);
> > +	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_DIS_CPU_TBU_PARTID))
> > +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
> > +				 CTL0_CPU_TBU_PARTID_DIS, CTL0_CPU_TBU_PARTID_DIS);
> > +
> > +	/* Used for MM_SMMMU read command overtaking */
> > +	if (mtk_smmu_v3->plat_data->smmu_type == MTK_SMMU_MM)
> > +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_STD_AXI_MODE_DIS,
> > +				 CTL0_STD_AXI_MODE_DIS);
> > +
> > +	/* Set AXSLC */
> > +	if (MTK_SMMU_HAS_FLAG(mtk_smmu_v3->plat_data, SMMU_AXSLC_EN)) {
> > +		smmu_write_field(wp_base, SMMUWP_GLB_CTL0,
> > +				 CTL0_STD_AXI_MODE_DIS, CTL0_STD_AXI_MODE_DIS);
> > +		smmu_write_field(wp_base, SMMU_TCU_CTL1_AXSLC, AXSLC_BIT_FIELD,
> > +				 AXSLC_SET);
> > +		smmu_write_field(wp_base, SMMU_TCU_CTL1_AXSLC, SLC_SB_ONLY_EN,
> > +				 SLC_SB_ONLY_EN);
> > +	}
> > +}
> > +
> > +/* Consume SMMU wrapper interrupt bit */
> > +static unsigned int
> > +smmuwp_consume_intr(void __iomem *wp_base, unsigned int irq_bit)
> > +{
> > +	unsigned int pend_cnt;
> > +
> > +	pend_cnt = readl_relaxed(wp_base + SMMUWP_IRQ_CNTx(__ffs(irq_bit)));
> > +	smmu_write_field(wp_base, SMMUWP_IRQ_ACK_CNT, IRQ_ACK_CNT_MSK, pend_cnt);
> > +	writel_relaxed(irq_bit, wp_base + SMMUWP_IRQ_ACK);
> > +
> > +	return pend_cnt;
> > +}
> > +
> > +/* clear translation fault mark */
> > +static void smmuwp_clear_tf(void __iomem *wp_base)
> > +{
> > +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_ABT_CNT_CLR, CTL0_ABT_CNT_CLR);
> > +	smmu_write_field(wp_base, SMMUWP_GLB_CTL0, CTL0_ABT_CNT_CLR, 0);
> > +}
> > +
> > +static u32 smmuwp_fault_id(u32 axi_id, u32 tbu_id)
> > +{
> > +	u32 fault_id = (axi_id & ~SMMUWP_TF_TBU_MSK) | (SMMUWP_TF_TBU(tbu_id));
> > +
> > +	return fault_id;
> > +}
> > +
> > +/* Process TBU translation fault Monitor */
> > +static bool smmuwp_process_tf(struct arm_smmu_device *smmu)
> > +{
> > +	struct mtk_smmu_v3 *mtk_smmu_v3 = to_mtk_smmu_v3(smmu);
> > +	void __iomem *wp_base = mtk_smmu_v3->wp_base;
> > +	unsigned int sid, ssid, secsidv, ssidv;
> > +	u32 i, regval, va35_32, axiid, fault_id;
> > +	u64 fault_iova;
> > +	bool tf_det = false;
> > +
> > +	for (i = 0; i < mtk_smmu_v3->plat_data->tbu_cnt; i++) {
> > +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM0(i));
> > +		if (!(regval & RTFM0_FAULT_DET))
> > +			goto write;
> > +
> > +		tf_det = true;
> > +		axiid = FIELD_GET(RTFM0_FAULT_AXI_ID, regval);
> > +		fault_id = smmuwp_fault_id(axiid, i);
> > +
> > +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM1(i));
> > +		va35_32 = FIELD_GET(RTFM1_FAULT_VA_35_32, regval);
> > +		fault_iova = MTK_SMMU_FAULT_IOVA(regval & RTFM1_FAULT_VA_31_12, va35_32);
> > +
> > +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_RTFM2(i));
> > +		sid = FIELD_GET(RTFM2_FAULT_SID, regval);
> > +		ssid = FIELD_GET(RTFM2_FAULT_SSID, regval);
> 
> We already print a bunch of this stuff in arm_smmu_dump_event() now that
> Pranjal has improved the logic. I don't see the value in printing the
> same information twice, so we should trim down the extra diagnostics here
> so that (a) the information is distinct from that provided by the core
> driuver code and (b) it's relevant to Linux (e.g. there's no need to
> print information about secure transactions).
> 
> The core driver code should also print some delimiters around the
> implementation-defined data as well. Out of curiosity, is the TBU
> monitor part of Arm's IP or is this additional hardware from MTK?
> 
> > +		ssidv = FIELD_GET(RTFM2_FAULT_SSIDV, regval);
> > +		secsidv = FIELD_GET(RTFM2_FAULT_SECSID, regval);
> > +		dev_err_ratelimited(smmu->dev, "TF read in %s world, TBU_id-%d-fault_id:0x%x(0x%x)\n",
> > +				    STRSEC(secsidv), i, fault_id, axiid);
> > +		dev_err_ratelimited(smmu->dev,
> > +				    "iova:0x%llx, sid:%d, ssid:%d, ssidv:%d, secsidv:%d\n",
> > +				    fault_iova, sid, ssid, ssidv, secsidv);
> > +
> > +write:
> > +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM0(i));
> > +		if (!(regval & WTFM0_FAULT_DET))
> > +			continue;
> > +
> > +		tf_det = true;
> > +		axiid = FIELD_GET(WTFM0_FAULT_AXI_ID, regval);
> > +		fault_id = smmuwp_fault_id(axiid, i);
> > +
> > +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM1(i));
> > +		va35_32 = FIELD_GET(WTFM1_FAULT_VA_35_32, regval);
> > +		fault_iova = MTK_SMMU_FAULT_IOVA(regval & RTFM1_FAULT_VA_31_12, va35_32);
> > +
> > +		regval = readl_relaxed(wp_base + SMMUWP_TBUx_WTFM2(i));
> > +		sid = FIELD_GET(WTFM2_FAULT_SID, regval);
> > +		ssid = FIELD_GET(WTFM2_FAULT_SSID, regval);
> > +		ssidv = FIELD_GET(WTFM2_FAULT_SSIDV, regval);
> > +		secsidv = FIELD_GET(WTFM2_FAULT_SECSID, regval);
> > +		dev_err_ratelimited(smmu->dev, "TF write in %s world, TBU_id-%d-fault_id:0x%x(0x%x)\n",
> > +				    STRSEC(secsidv), i, fault_id, axiid);
> > +		dev_err_ratelimited(smmu->dev,
> > +				    "iova:0x%llx, sid:%d, ssid:%d, ssidv:%d, secsidv:%d\n",
> > +				    fault_iova, sid, ssid, ssidv, secsidv);
> 
> nit: but I don't think we should use the _ratelimited() prints here as it
> could end up with random lines being dropped.
> 
> > +/* Process SMMU wrapper interrupt */
> > +static int mtk_smmu_v3_smmuwp_irq_handler(int irq, struct arm_smmu_device *smmu)
> > +{
> > +	struct mtk_smmu_v3 *mtk_smmuv3 = to_mtk_smmu_v3(smmu);
> > +	void __iomem *wp_base = mtk_smmuv3->wp_base;
> > +	unsigned int irq_sta, pend_cnt;
> > +
> > +	irq_sta = readl_relaxed(wp_base + SMMUWP_IRQ_STA);
> > +	if (irq_sta == 0)
> > +		return 0;
> > +
> > +	if (irq_sta & STA_TCU_GLB_INTR) {
> > +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_GLB_INTR);
> > +		dev_dbg(smmu->dev,
> > +			"IRQ_STA:0x%x, Non-secure TCU global interrupt detected pending_cnt: %d\n",
> > +			irq_sta, pend_cnt);
> > +	}
> > +
> > +	if (irq_sta & STA_TCU_CMD_SYNC_INTR) {
> > +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_CMD_SYNC_INTR);
> > +		dev_dbg(smmu->dev,
> > +			"IRQ_STA:0x%x, Non-secure TCU CMD_SYNC interrupt detected pending_cnt: %d\n",
> > +			irq_sta, pend_cnt);
> > +	}
> > +
> > +	if (irq_sta & STA_TCU_EVTQ_INTR) {
> > +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_EVTQ_INTR);
> > +		dev_dbg(smmu->dev,
> > +			"IRQ_STA:0x%x, Non-secure TCU EVTQ interrupt detected pending_cnt: %d\n",
> > +			irq_sta, pend_cnt);
> > +	}
> > +
> > +	if (irq_sta & STA_TCU_PRI_INTR) {
> > +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_PRI_INTR);
> > +		dev_dbg(smmu->dev, "IRQ_STA:0x%x, TCU PRI interrupt detected pending_cnt: %d\n",
> > +			irq_sta, pend_cnt);
> > +	}
> > +
> > +	if (irq_sta & STA_TCU_PMU_INTR) {
> > +		pend_cnt = smmuwp_consume_intr(wp_base, STA_TCU_PMU_INTR);
> > +		dev_dbg(smmu->dev, "IRQ_STA:0x%x, TCU PMU interrupt detected pending_cnt: %d\n",
> > +			irq_sta, pend_cnt);
> > +	}
> > +
> > +	return 0;
> > +}
> 
> Hrm. I wonder whether this would be better off treated as a chained irqchip
> rather than hiding the logic inside the SMMU driver? It effectively looks
> like a demuxer to me.

Yeah, that's effectively what this is.

However, it isn't clear this has the basic mask/unmask logic that we'd
expect for an irqchip, and I doubt you'd want the irqchip to pry into
the SMMU code for that to mask/unmask the individual interrupt
sources.

The other thing is that I don't see any actual handling here.
smmuwp_consume_intr() ACKs the interrupt, and that's it. I'm not even
sure why this code exists at all (but I haven't read the series, TBH).

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2025-06-25 16:54 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-16  2:56 [RFC PATCH 0/8] Add mt8196 SMMU support Xueqi Zhang
2025-06-16  2:56 ` [RFC PATCH 1/8] dt-bindings: iommu: mediatek: Add mt8196 support Xueqi Zhang
2025-06-16  4:40   ` Rob Herring (Arm)
2025-06-16 14:27   ` Rob Herring
2025-06-17  6:28   ` Krzysztof Kozlowski
2025-06-16  2:56 ` [RFC PATCH 2/8] iommu/arm-smmu-v3: Add SMMU implementation Xueqi Zhang
2025-06-16 21:17   ` Pranjal Shrivastava
2025-06-16  2:56 ` [RFC PATCH 3/8] iommu/arm-smmu-v3: Add implementation for MT8196 MM SMMU Xueqi Zhang
2025-06-16  2:56 ` [RFC PATCH 4/8] iommu/arm-smmu-v3: Add implementation for MT8196 APU SMMU Xueqi Zhang
2025-06-16  2:56 ` [RFC PATCH 5/8] iommu/arm-smmu-v3: Add IRQ handle for smmu impl Xueqi Zhang
2025-06-16 21:32   ` Pranjal Shrivastava
2025-06-16  2:56 ` [RFC PATCH 6/8] iommu/arm-smmu-v3: mediatek: Add wrapper handle for IRQ Xueqi Zhang
2025-06-24 11:22   ` Will Deacon
2025-06-25 16:54     ` Marc Zyngier
2025-06-16  2:56 ` [RFC PATCH 7/8] iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw Xueqi Zhang
2025-06-16 20:54   ` Pranjal Shrivastava
2025-06-16  2:56 ` [RFC PATCH 8/8] iommu/arm-smmu-v3: mediatek: Implement rpm get/put function Xueqi Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).