summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 9c08b82ecc3e..ea61ebbe6ee0 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -19,6 +19,7 @@
#include <linux/bitops.h>
#include <linux/msi.h>
#include <linux/dma-mapping.h>
+#include <linux/dma-map-ops.h>
#include <linux/acpi.h>
#include <linux/iommu.h>
#include <linux/io.h>
@@ -138,14 +139,56 @@ static int fsl_mc_dma_configure(struct device *dev)
struct device *dma_dev = dev;
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
u32 input_id = mc_dev->icid;
+ struct iommu_fwspec *fwspec;
+ const struct iommu_ops *iommu_ops;
+ int ret;
+
+ /* Skip DMA setup for devices that are not DMA masters */
+ if (dev->type == &fsl_mc_bus_dpmcp_type ||
+ dev->type == &fsl_mc_bus_dpbp_type ||
+ dev->type == &fsl_mc_bus_dpcon_type ||
+ dev->type == &fsl_mc_bus_dpio_type)
+ return 0;
while (dev_is_fsl_mc(dma_dev))
dma_dev = dma_dev->parent;
+
+#if 0
if (dev_of_node(dma_dev))
return of_dma_configure_id(dev, dma_dev->of_node, 0, &input_id);
return acpi_dma_configure_id(dev, DEV_DMA_COHERENT, &input_id);
+#else
+ fwspec = dev_iommu_fwspec_get(dma_dev);
+ if (!fwspec)
+ return -ENODEV;
+ iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode);
+ if (!iommu_ops)
+ return -ENODEV;
+
+ ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops);
+ if (ret)
+ return ret;
+
+ ret = iommu_fwspec_add_ids(dev, &input_id, 1);
+ if (ret) {
+ iommu_fwspec_free(dev);
+ return ret;
+ }
+
+ if (!device_iommu_mapped(dev)) {
+ ret = iommu_probe_device(dev);
+ if (ret) {
+ iommu_fwspec_free(dev);
+ return ret;
+ }
+ }
+
+ arch_setup_dma_ops(dev, 0, *dma_dev->dma_mask + 1, iommu_ops, true);
+
+ return 0;
+#endif
}
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,