]> Gentwo Git Trees - linux/.git/commitdiff
iommu/mediatek: Add a flag DL_WITH_MULTI_LARB
authorZhengnan Chen <zhengnan.chen@mediatek.com>
Sat, 18 Oct 2025 13:26:11 +0000 (21:26 +0800)
committerJoerg Roedel <joerg.roedel@amd.com>
Mon, 27 Oct 2025 12:42:49 +0000 (13:42 +0100)
Add DL_WITH_MULTI_LARB flag to support the HW which connect with
multiple larbs. Prepare for mt8189. In mt8189, the display connect
with larb1 and larb2 at the same time. Thus, we should add link
between disp-dev with these two larbs.

Signed-off-by: Zhengnan Chen <zhengnan.chen@mediatek.com>
Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
Reviewed-by: Yong Wu <yong.wu@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
drivers/iommu/mtk_iommu.c

index 0e0285348d2b8ec4e197eef5d99e7c9071a44b77..7af47c59b10bd6d56066fb11f17b7f7f0160618e 100644 (file)
 #define TF_PORT_TO_ADDR_MT8173         BIT(18)
 #define INT_ID_PORT_WIDTH_6            BIT(19)
 #define CFG_IFA_MASTER_IN_ATF          BIT(20)
+#define DL_WITH_MULTI_LARB             BIT(21)
 
 #define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask)       \
                                ((((pdata)->flags) & (mask)) == (_x))
@@ -865,6 +866,7 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev)
        struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
        struct device_link *link;
        struct device *larbdev;
+       unsigned long larbid_msk = 0;
        unsigned int larbid, larbidx, i;
 
        if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
@@ -872,30 +874,50 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev)
 
        /*
         * Link the consumer device with the smi-larb device(supplier).
-        * The device that connects with each a larb is a independent HW.
-        * All the ports in each a device should be in the same larbs.
+        * w/DL_WITH_MULTI_LARB: the master may connect with multi larbs,
+        * we should create device link with each larb.
+        * w/o DL_WITH_MULTI_LARB: the master must connect with one larb,
+        * otherwise fail.
         */
        larbid = MTK_M4U_TO_LARB(fwspec->ids[0]);
        if (larbid >= MTK_LARB_NR_MAX)
                return ERR_PTR(-EINVAL);
 
+       larbid_msk |= BIT(larbid);
+
        for (i = 1; i < fwspec->num_ids; i++) {
                larbidx = MTK_M4U_TO_LARB(fwspec->ids[i]);
-               if (larbid != larbidx) {
+               if (MTK_IOMMU_HAS_FLAG(data->plat_data, DL_WITH_MULTI_LARB)) {
+                       larbid_msk |= BIT(larbidx);
+               } else if (larbid != larbidx) {
                        dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n",
                                larbid, larbidx);
                        return ERR_PTR(-EINVAL);
                }
        }
-       larbdev = data->larb_imu[larbid].dev;
-       if (!larbdev)
-               return ERR_PTR(-EINVAL);
 
-       link = device_link_add(dev, larbdev,
-                              DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
-       if (!link)
-               dev_err(dev, "Unable to link %s\n", dev_name(larbdev));
+       for_each_set_bit(larbid, &larbid_msk, 32) {
+               larbdev = data->larb_imu[larbid].dev;
+               if (!larbdev)
+                       return ERR_PTR(-EINVAL);
+
+               link = device_link_add(dev, larbdev,
+                                      DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
+               if (!link) {
+                       dev_err(dev, "Unable to link %s\n", dev_name(larbdev));
+                       goto link_remove;
+               }
+       }
+
        return &data->iommu;
+
+link_remove:
+       for_each_set_bit(i, &larbid_msk, larbid) {
+               larbdev = data->larb_imu[i].dev;
+               device_link_remove(dev, larbdev);
+       }
+
+       return ERR_PTR(-ENODEV);
 }
 
 static void mtk_iommu_release_device(struct device *dev)
@@ -903,11 +925,19 @@ static void mtk_iommu_release_device(struct device *dev)
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct mtk_iommu_data *data;
        struct device *larbdev;
-       unsigned int larbid;
+       unsigned int larbid, i;
+       unsigned long larbid_msk = 0;
 
        data = dev_iommu_priv_get(dev);
-       if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
-               larbid = MTK_M4U_TO_LARB(fwspec->ids[0]);
+       if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
+               return;
+
+       for (i = 0; i < fwspec->num_ids; i++) {
+               larbid = MTK_M4U_TO_LARB(fwspec->ids[i]);
+               larbid_msk |= BIT(larbid);
+       }
+
+       for_each_set_bit(larbid, &larbid_msk, 32) {
                larbdev = data->larb_imu[larbid].dev;
                device_link_remove(dev, larbdev);
        }