[PATCH 2/3] iommu/mediatek-v1: fix IOMMU device binding
Roman Vivchar via B4 Relay
devnull+rva333.protonmail.com at kernel.org
Wed Sep 9 07:14:06 PDT 2026
From: Roman Vivchar <rva333 at protonmail.com>
Currently the driver silently fails to bind devices and DRM subsystem
(which is the primary IOMMU user on MediaTek SoCs) falls back to PA mode.
Fix this by providing of_xlate callback, which lets the driver actually
bind devices and use VA mode.
The fix can be verified by reading overlay engine input address.
Before:
~ # devmem 0x14007040 32
0xBB900000
After:
~ # devmem 0x14007040 32
0x00000000
Fixes: b17336c55d89 ("iommu/mediatek: add support for mtk iommu generation one HW")
Cc: stable at vger.kernel.org
Signed-off-by: Roman Vivchar <rva333 at protonmail.com>
---
Untested on mt2701.
---
drivers/iommu/mtk_iommu_v1.c | 86 ++++++++++++++++++++------------------------
1 file changed, 39 insertions(+), 47 deletions(-)
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index ac97dd2868d4..72355f41c36a 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -413,38 +413,10 @@ static const struct iommu_ops mtk_iommu_v1_ops;
* MTK generation one iommu HW only support one iommu domain, and all the client
* sharing the same iova address space.
*/
-static int mtk_iommu_v1_create_mapping(struct device *dev,
- const struct of_phandle_args *args)
+static int mtk_iommu_v1_create_mapping(struct device *dev)
{
struct mtk_iommu_v1_data *data;
- struct platform_device *m4updev;
struct dma_iommu_mapping *mtk_mapping;
- int ret;
-
- if (args->args_count != 1) {
- dev_err(dev, "invalid #iommu-cells(%d) property for IOMMU\n",
- args->args_count);
- return -EINVAL;
- }
-
- ret = iommu_fwspec_init(dev, of_fwnode_handle(args->np));
- if (ret)
- return ret;
-
- if (!dev_iommu_priv_get(dev)) {
- /* Get the m4u device */
- m4updev = of_find_device_by_node(args->np);
- if (WARN_ON(!m4updev))
- return -EINVAL;
-
- dev_iommu_priv_set(dev, platform_get_drvdata(m4updev));
-
- put_device(&m4updev->dev);
- }
-
- ret = iommu_fwspec_add_ids(dev, args->args, 1);
- if (ret)
- return ret;
data = dev_iommu_priv_get(dev);
mtk_mapping = data->mapping;
@@ -462,27 +434,12 @@ static int mtk_iommu_v1_create_mapping(struct device *dev,
static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
{
- struct iommu_fwspec *fwspec = NULL;
- struct of_phandle_args iommu_spec;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct mtk_iommu_v1_data *data;
- int err, idx = 0, larbid, larbidx;
+ int idx, larbid, larbidx;
struct device_link *link;
struct device *larbdev;
- while (!of_parse_phandle_with_args(dev->of_node, "iommus",
- "#iommu-cells",
- idx, &iommu_spec)) {
-
- err = mtk_iommu_v1_create_mapping(dev, &iommu_spec);
- of_node_put(iommu_spec.np);
- if (err)
- return ERR_PTR(err);
-
- /* dev->iommu_fwspec might have changed */
- fwspec = dev_iommu_fwspec_get(dev);
- idx++;
- }
-
if (!fwspec)
return ERR_PTR(-ENODEV);
@@ -519,9 +476,15 @@ static void mtk_iommu_v1_probe_finalize(struct device *dev)
__maybe_unused struct mtk_iommu_v1_data *data = dev_iommu_priv_get(dev);
int err;
+ err = mtk_iommu_v1_create_mapping(dev);
+ if (err) {
+ dev_err(dev, "Can't create IOMMU mapping - DMA-OPS will not work\n");
+ return;
+ }
+
err = arm_iommu_attach_device(dev, data->mapping);
if (err)
- dev_err(dev, "Can't create IOMMU mapping - DMA-OPS will not work\n");
+ dev_err(dev, "Can't attach to IOMMU mapping - DMA-OPS will not work\n");
}
static void mtk_iommu_v1_release_device(struct device *dev)
@@ -537,6 +500,34 @@ static void mtk_iommu_v1_release_device(struct device *dev)
device_link_remove(dev, larbdev);
}
+static int mtk_iommu_v1_of_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct platform_device *m4updev;
+ int ret;
+
+ if (args->args_count != 1) {
+ dev_err(dev, "invalid #iommu-cells(%d) property for IOMMU\n",
+ args->args_count);
+ return -EINVAL;
+ }
+
+ ret = iommu_fwspec_init(dev, of_fwnode_handle(args->np));
+ if (ret)
+ return ret;
+
+ if (!dev_iommu_priv_get(dev)) {
+ m4updev = of_find_device_by_node(args->np);
+ if (WARN_ON(!m4updev))
+ return -EINVAL;
+
+ dev_iommu_priv_set(dev, platform_get_drvdata(m4updev));
+ put_device(&m4updev->dev);
+ }
+
+ return iommu_fwspec_add_ids(dev, args->args, 1);
+}
+
static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
{
u32 regval;
@@ -585,6 +576,7 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
.probe_finalize = mtk_iommu_v1_probe_finalize,
.release_device = mtk_iommu_v1_release_device,
.device_group = generic_device_group,
+ .of_xlate = mtk_iommu_v1_of_xlate,
.owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = mtk_iommu_v1_attach_device,
--
2.55.0
More information about the Linux-mediatek
mailing list