iommu/mediatek: Add enable IOMMU SMC command for INFRA masters
authorChengci.Xu <chengci.xu@mediatek.com>
Fri, 2 Jun 2023 09:02:24 +0000 (17:02 +0800)
committerJoerg Roedel <jroedel@suse.de>
Mon, 7 Aug 2023 12:15:48 +0000 (14:15 +0200)
Prepare for MT8188. In MT8188, the register which enables IOMMU for
INFRA masters are in the secure world for security concerns, therefore we
add a SMC command for INFRA masters to enable IOMMU in ATF.

Signed-off-by: Chengci.Xu <chengci.xu@mediatek.com>
Signed-off-by: Yong Wu <yong.wu@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
Link: https://lore.kernel.org/r/20230602090227.7264-5-yong.wu@mediatek.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/mtk_iommu.c
include/soc/mediatek/smi.h

index e1146a59573283a22abeae12635596ee4cc443b1..fe3839bb14f7c043a5918d021ef01473fe3ad4c9 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2015-2016 MediaTek Inc.
  * Author: Yong Wu <yong.wu@mediatek.com>
  */
+#include <linux/arm-smccc.h>
 #include <linux/bitfield.h>
 #include <linux/bug.h>
 #include <linux/clk.h>
@@ -27,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/soc/mediatek/infracfg.h>
+#include <linux/soc/mediatek/mtk_sip_svc.h>
 #include <asm/barrier.h>
 #include <soc/mediatek/smi.h>
 
 #define PGTABLE_PA_35_EN               BIT(17)
 #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 MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask)       \
                                ((((pdata)->flags) & (mask)) == (_x))
@@ -580,6 +583,7 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev,
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        const struct mtk_iommu_iova_region *region;
        unsigned long portid_msk = 0;
+       struct arm_smccc_res res;
        int i, ret = 0;
 
        for (i = 0; i < fwspec->num_ids; ++i) {
@@ -605,17 +609,24 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev,
                else
                        larb_mmu->mmu &= ~portid_msk;
        } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA)) {
-               /* PCI dev has only one output id, enable the next writing bit for PCIe */
-               if (dev_is_pci(dev)) {
-                       if (fwspec->num_ids != 1) {
-                               dev_err(dev, "PCI dev can only have one port.\n");
-                               return -ENODEV;
+               if (MTK_IOMMU_HAS_FLAG(data->plat_data, CFG_IFA_MASTER_IN_ATF)) {
+                       arm_smccc_smc(MTK_SIP_KERNEL_IOMMU_CONTROL,
+                                     IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU,
+                                     portid_msk, enable, 0, 0, 0, 0, &res);
+                       ret = res.a0;
+               } else {
+                       /* PCI dev has only one output id, enable the next writing bit for PCIe */
+                       if (dev_is_pci(dev)) {
+                               if (fwspec->num_ids != 1) {
+                                       dev_err(dev, "PCI dev can only have one port.\n");
+                                       return -ENODEV;
+                               }
+                               portid_msk |= BIT(portid + 1);
                        }
-                       portid_msk |= BIT(portid + 1);
-               }
 
-               ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1,
-                                        (u32)portid_msk, enable ? (u32)portid_msk : 0);
+                       ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1,
+                                                (u32)portid_msk, enable ? (u32)portid_msk : 0);
+               }
                if (ret)
                        dev_err(dev, "%s iommu(%s) inframaster 0x%lx fail(%d).\n",
                                enable ? "enable" : "disable",
@@ -1330,7 +1341,8 @@ static int mtk_iommu_probe(struct platform_device *pdev)
                        dev_err_probe(dev, ret, "mm dts parse fail\n");
                        goto out_runtime_disable;
                }
-       } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA)) {
+       } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA) &&
+                  !MTK_IOMMU_HAS_FLAG(data->plat_data, CFG_IFA_MASTER_IN_ATF)) {
                p = data->plat_data->pericfg_comp_str;
                data->pericfg = syscon_regmap_lookup_by_compatible(p);
                if (IS_ERR(data->pericfg)) {
index dfd8efca5e606accf947ff3878a28791d4bd58de..000eb1cf68b7a7bb5e151d023238281ceb400c8a 100644 (file)
@@ -13,6 +13,7 @@
 
 enum iommu_atf_cmd {
        IOMMU_ATF_CMD_CONFIG_SMI_LARB,          /* For mm master to en/disable iommu */
+       IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU,       /* For infra master to enable iommu */
        IOMMU_ATF_CMD_MAX,
 };