summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/exynos
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/exynos')
-rw-r--r--drivers/gpu/drm/exynos/Makefile1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.h10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu_init.c69
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu_init.h30
5 files changed, 114 insertions, 4 deletions
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 639b49e1ec0..a7c34f53212 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -9,6 +9,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
exynos_drm_plane.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
+exynosdrm-$(CONFIG_ARM_DMA_USE_IOMMU) += exynos_drm_iommu_init.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index c659fc3c05f..f727f98346d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -28,6 +28,7 @@
#include "exynos_drm_g2d.h"
#include "exynos_drm_ipp.h"
#include "exynos_drm_iommu.h"
+#include "exynos_drm_iommu_init.h"
#define DRIVER_NAME "exynos"
#define DRIVER_DESC "Samsung SoC DRM"
@@ -335,6 +336,11 @@ static int __init exynos_drm_init(void)
{
int ret, i = 0;
+ ret = exynos_drm_iommu_register(exynos_drm_subdrivers,
+ ARRAY_SIZE(exynos_drm_subdrivers));
+ if (ret < 0)
+ return ret;
+
#ifdef CONFIG_DRM_EXYNOS_HDMI
ret = exynos_platform_device_hdmi_register();
if (ret < 0)
@@ -375,6 +381,7 @@ out_ipp:
out_hdmi:
exynos_platform_device_hdmi_unregister();
#endif
+ exynos_drm_iommu_unregister();
return ret;
}
@@ -391,6 +398,7 @@ static void __exit exynos_drm_exit(void)
#ifdef CONFIG_DRM_EXYNOS_HDMI
exynos_platform_device_hdmi_unregister();
#endif
+ exynos_drm_iommu_unregister();
}
module_init(exynos_drm_init);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
index 598e60f57d4..9f6a24e1d86 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
@@ -12,6 +12,8 @@
#ifndef _EXYNOS_DRM_IOMMU_H_
#define _EXYNOS_DRM_IOMMU_H_
+#include "exynos_drm_iommu_init.h"
+
#define EXYNOS_DEV_ADDR_START 0x20000000
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
#define EXYNOS_DEV_ADDR_ORDER 0x0
@@ -32,11 +34,11 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
{
#ifdef CONFIG_ARM_DMA_USE_IOMMU
struct device *dev = drm_dev->dev;
-
- return dev->archdata.mapping ? true : false;
-#else
- return false;
+ if (dev->archdata.mapping &&
+ dev->archdata.mapping != EXYNOS_DRM_INITIAL_MAPPING_VAL)
+ return true;
#endif
+ return false;
}
#else
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu_init.c b/drivers/gpu/drm/exynos/exynos_drm_iommu_init.c
new file mode 100644
index 00000000000..3022a0cbbe5
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu_init.c
@@ -0,0 +1,69 @@
+/* exynos_drm_iommu_init.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <drmP.h>
+#include <drm/exynos_drm.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
+#include <linux/kref.h>
+
+#include <asm/dma-iommu.h>
+
+#include "exynos_drm_drv.h"
+#include "exynos_drm_iommu_init.h"
+
+static struct platform_driver **exynos_drm_subdrivers;
+static int exynos_drm_subdrivers_count;
+
+static int exynos_iommu_hook_driver(struct notifier_block *nb,
+ unsigned long val, void *p)
+{
+ struct device *dev = p;
+ int i;
+
+ switch (val) {
+ case BUS_NOTIFY_BIND_DRIVER:
+ for (i=0; i < exynos_drm_subdrivers_count; i++) {
+ if (dev->driver == &exynos_drm_subdrivers[i]->driver) {
+ dev->archdata.mapping = EXYNOS_DRM_INITIAL_MAPPING_VAL;
+ break;
+ }
+ }
+ break;
+
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ case BUS_NOTIFY_BIND_FAILED:
+ for (i=0; i < exynos_drm_subdrivers_count; i++) {
+ if (dev->driver == &exynos_drm_subdrivers[i]->driver) {
+ dev->archdata.mapping = NULL;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static struct notifier_block exynos_drm_iommu_notifier = {
+ .notifier_call = &exynos_iommu_hook_driver,
+ .priority = 100,
+};
+
+int exynos_drm_iommu_register(struct platform_driver **drivers, int count)
+{
+ exynos_drm_subdrivers = drivers;
+ exynos_drm_subdrivers_count = count;
+ return bus_register_notifier(&platform_bus_type, &exynos_drm_iommu_notifier);
+}
+
+int exynos_drm_iommu_unregister(void)
+{
+ return bus_register_notifier(&platform_bus_type, &exynos_drm_iommu_notifier);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu_init.h b/drivers/gpu/drm/exynos/exynos_drm_iommu_init.h
new file mode 100644
index 00000000000..b7a416e50be
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu_init.h
@@ -0,0 +1,30 @@
+/* exynos_drm_iommu_init.h
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _EXYNOS_DRM_IOMMU_INIT_H_
+#define _EXYNOS_DRM_IOMMU_INIT_H_
+
+#define EXYNOS_DRM_INITIAL_MAPPING_VAL ERR_PTR(-EAGAIN)
+
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+int exynos_drm_iommu_register(struct platform_driver **drivers, int count);
+int exynos_drm_iommu_unregister(void);
+#else
+static inline int exynos_drm_iommu_register(struct platform_driver **drivers, int count)
+{
+ return 0;
+}
+static inline int exynos_drm_iommu_unregister(void)
+{
+ return 0;
+}
+#endif
+
+#endif