summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tegra/drm.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-06-26 21:41:53 +0200
committerThierry Reding <treding@nvidia.com>2014-11-13 16:14:48 +0100
commitdf06b759f2cf4690fa9991edb1504ba39932b2bb (patch)
tree0365d27fb82b94d4569c8b86dd775838bedc5ff1 /drivers/gpu/drm/tegra/drm.c
parent1d1e6fe9b5cd9e51c0b064b60f673a973cac38ba (diff)
drm/tegra: Add IOMMU support
When an IOMMU device is available on the platform bus, allocate an IOMMU domain and attach the display controllers to it. The display controllers can then scan out non-contiguous buffers by mapping them through the IOMMU. Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/drm.c')
-rw-r--r--drivers/gpu/drm/tegra/drm.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index e1632fb03a89..6c9df794b3be 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -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;
@@ -76,6 +88,12 @@ fbdev:
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;
}
@@ -83,6 +101,7 @@ config:
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);
@@ -94,6 +113,11 @@ 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);
+ }
+
return 0;
}