]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/host1x/dev.c
gpu: host1x: Add IOMMU support
[karo-tx-linux.git] / drivers / gpu / host1x / dev.c
index a62317af76ad7b8b90593c2fda904a102e360701..b386a0bf828abf24457c442c8153e32e77387a07 100644 (file)
@@ -27,6 +27,7 @@
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/host1x.h>
+#undef CREATE_TRACE_POINTS
 
 #include "bus.h"
 #include "dev.h"
@@ -168,16 +169,37 @@ static int host1x_probe(struct platform_device *pdev)
                return err;
        }
 
+       if (iommu_present(&platform_bus_type)) {
+               struct iommu_domain_geometry *geometry;
+               unsigned long order;
+
+               host->domain = iommu_domain_alloc(&platform_bus_type);
+               if (!host->domain)
+                       return -ENOMEM;
+
+               err = iommu_attach_device(host->domain, &pdev->dev);
+               if (err)
+                       goto fail_free_domain;
+
+               geometry = &host->domain->geometry;
+
+               order = __ffs(host->domain->pgsize_bitmap);
+               init_iova_domain(&host->iova, 1UL << order,
+                                geometry->aperture_start >> order,
+                                geometry->aperture_end >> order);
+               host->iova_end = geometry->aperture_end;
+       }
+
        err = host1x_channel_list_init(host);
        if (err) {
                dev_err(&pdev->dev, "failed to initialize channel list\n");
-               return err;
+               goto fail_detach_device;
        }
 
        err = clk_prepare_enable(host->clk);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to enable clock\n");
-               return err;
+               goto fail_detach_device;
        }
 
        err = host1x_syncpt_init(host);
@@ -206,6 +228,15 @@ fail_deinit_syncpt:
        host1x_syncpt_deinit(host);
 fail_unprepare_disable:
        clk_disable_unprepare(host->clk);
+fail_detach_device:
+       if (host->domain) {
+               put_iova_domain(&host->iova);
+               iommu_detach_device(host->domain, &pdev->dev);
+       }
+fail_free_domain:
+       if (host->domain)
+               iommu_domain_free(host->domain);
+
        return err;
 }
 
@@ -218,6 +249,12 @@ static int host1x_remove(struct platform_device *pdev)
        host1x_syncpt_deinit(host);
        clk_disable_unprepare(host->clk);
 
+       if (host->domain) {
+               put_iova_domain(&host->iova);
+               iommu_detach_device(host->domain, &pdev->dev);
+               iommu_domain_free(host->domain);
+       }
+
        return 0;
 }