diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index d0484ad0cdb13e..c243b1d7e7d55d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -936,6 +936,10 @@ snps,arcsync-cluster-id = <0x01>; /* Disable ARC core booting during Linux kernel booting for debugging purposes */ /* snps,auto-boot; */ + #stream-id-cells = <1>; + /* VPX@0 CBU master interface stream ID's for the SMMU, connected to TBU3: + TBU3 (0b11 << 10) | S_AXI_HP0_FPD Master ID (0b1010 << 6) | AXI ID (0) */ + iommus = <&smmu 0xE80>; }; app_vpx@0 { @@ -970,7 +974,7 @@ /* How many address bits the VPX master can use for DMA to system RAM */ snps,dma-bits = <0x1f>; #stream-id-cells = <0x01>; - /* Stream ID = TBU4 (0b100 << 10) | S_AXI_HP1_FPD Master ID (0b1001 << 6) | AXI ID (0) */ + /* Stream ID = TBU4 (0b100 << 10) | S_AXI_HP1_FPD Master ID (0b1001 << 6) | AXI ID (1) */ iommus = <&smmu 0x12c1>; }; }; diff --git a/drivers/remoteproc/snps_accel/accel_rproc.c b/drivers/remoteproc/snps_accel/accel_rproc.c index cafbe244c28059..de346e30a294ec 100644 --- a/drivers/remoteproc/snps_accel/accel_rproc.c +++ b/drivers/remoteproc/snps_accel/accel_rproc.c @@ -26,6 +26,12 @@ #include #endif +#if IS_ENABLED(CONFIG_IOMMU_API) +#include +/* Enable ARC CBU IOMMU bypass so that IOVA equals physical address */ +#define SNPS_ACCEL_RPROC_CBU_IOMMU_BYPASS +#endif + #include "accel_rproc.h" static int snps_accel_rproc_prepare(struct rproc *rproc) @@ -512,11 +518,55 @@ static int snps_accel_rproc_probe(struct platform_device *pdev) return ret; } +#if IS_ENABLED(CONFIG_IOMMU_API) && defined(SNPS_ACCEL_RPROC_CBU_IOMMU_BYPASS) + struct iommu_group *group = iommu_group_get(dev); + if (group) { + /* Allocate a new domain */ + struct iommu_domain *domain = iommu_domain_alloc(dev->bus); + if (!domain) { + dev_err(dev, "Failed to allocate IOMMU domain\n"); + iommu_group_put(group); + return -ENOMEM; + } + + /* Configure allocated domain as an identity domain */ + domain->type = IOMMU_DOMAIN_IDENTITY; + + /* Attach domain to the device */ + ret = iommu_attach_device(domain, dev); + if (ret) { + dev_err(dev, "Failed to attach device to identity domain, error %d\n", ret); + iommu_domain_free(domain); + iommu_group_put(group); + return ret; + } + dev_dbg(dev, "Attached to IOMMU identity domain\n"); + iommu_group_put(group); + } + else { + dev_dbg(dev, "No IOMMU found for device\n"); + } +#endif + return 0; } static int snps_accel_rproc_remove(struct platform_device *pdev) { +#if IS_ENABLED(CONFIG_IOMMU_API) && defined(SNPS_ACCEL_RPROC_CBU_IOMMU_BYPASS) + struct device *dev = &pdev->dev; + struct iommu_group *group = iommu_group_get(dev); + if (group) { + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + /* Ensure that only the allocated domain is freed */ + if (domain->type == IOMMU_DOMAIN_IDENTITY) { + iommu_detach_device(domain, dev); + iommu_domain_free(domain); + } + iommu_group_put(group); + } +#endif + return 0; }