Merge tag 'tags/renesas-dt-du-for-v3.19' into drm/next/adv7511-base
[cascardo/linux.git] / drivers / gpu / drm / tegra / drm.c
index 59736bb..e549afe 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/host1x.h>
+#include <linux/iommu.h>
 
 #include "drm.h"
 #include "gem.h"
@@ -33,6 +34,17 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
        if (!tegra)
                return -ENOMEM;
 
+       if (iommu_present(&platform_bus_type)) {
+               tegra->domain = iommu_domain_alloc(&platform_bus_type);
+               if (IS_ERR(tegra->domain)) {
+                       err = PTR_ERR(tegra->domain);
+                       goto free;
+               }
+
+               DRM_DEBUG("IOMMU context initialized\n");
+               drm_mm_init(&tegra->mm, 0, SZ_2G);
+       }
+
        mutex_init(&tegra->clients_lock);
        INIT_LIST_HEAD(&tegra->clients);
        drm->dev_private = tegra;
@@ -42,13 +54,13 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 
        err = tegra_drm_fb_prepare(drm);
        if (err < 0)
-               return err;
+               goto config;
 
        drm_kms_helper_poll_init(drm);
 
        err = host1x_device_init(device);
        if (err < 0)
-               return err;
+               goto fbdev;
 
        /*
         * We don't use the drm_irq_install() helpers provided by the DRM
@@ -59,18 +71,37 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 
        err = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (err < 0)
-               return err;
+               goto device;
 
        err = tegra_drm_fb_init(drm);
        if (err < 0)
-               return err;
+               goto vblank;
 
        return 0;
+
+vblank:
+       drm_vblank_cleanup(drm);
+device:
+       host1x_device_exit(device);
+fbdev:
+       drm_kms_helper_poll_fini(drm);
+       tegra_drm_fb_free(drm);
+config:
+       drm_mode_config_cleanup(drm);
+
+       if (tegra->domain) {
+               iommu_domain_free(tegra->domain);
+               drm_mm_takedown(&tegra->mm);
+       }
+free:
+       kfree(tegra);
+       return err;
 }
 
 static int tegra_drm_unload(struct drm_device *drm)
 {
        struct host1x_device *device = to_host1x_device(drm->dev);
+       struct tegra_drm *tegra = drm->dev_private;
        int err;
 
        drm_kms_helper_poll_fini(drm);
@@ -82,6 +113,13 @@ static int tegra_drm_unload(struct drm_device *drm)
        if (err < 0)
                return err;
 
+       if (tegra->domain) {
+               iommu_domain_free(tegra->domain);
+               drm_mm_takedown(&tegra->mm);
+       }
+
+       kfree(tegra);
+
        return 0;
 }