summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurentiu Tudor <laurentiu.tudor@nxp.com>2020-02-13 11:59:12 +0200
committerRussell King <rmk+kernel@armlinux.org.uk>2021-02-15 14:01:58 +0000
commit590858e9b845bb2fdb39c75d09a722fa75173446 (patch)
tree13ec0330c14cb91dd573fc4e7e56ff219e70223c
parentcd56abe0ce83fdc1f95c5e76cbd6dad297d23094 (diff)
bus: fsl-mc: add custom .dma_configure implementation
The devices on this bus are not discovered by way of device tree but by queries to the firmware. It makes little sense to trick the generic of layer into thinking that these devices are of related so that we can get our dma configuration. Instead of doing that, add our custom dma configuration implementation. Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
-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,