summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2013-08-08 11:18:32 +0200
committerChanho Park <chanho61.park@samsung.com>2014-11-18 11:44:05 +0900
commitacd0b1469fd1f714ef8b29c809b757d2081ea9a2 (patch)
tree9e02123d55940cd1be85eb143dc4f8639c59f4da /drivers
parent442a1c7602381e0c59f4b03df76ea29fbb7454ea (diff)
downloadlinux-3.10-acd0b1469fd1f714ef8b29c809b757d2081ea9a2.tar.gz
linux-3.10-acd0b1469fd1f714ef8b29c809b757d2081ea9a2.tar.bz2
linux-3.10-acd0b1469fd1f714ef8b29c809b757d2081ea9a2.zip
drm/exynos: add support for separate iommu mapping management by drm driver
This patch adds support for a single, shared iommu domain (mapping and address space) management for all Exynos DRM subdrivers. The registered high priority notifier ensures that IOMMU driver will not create default domains for all devices which will be handled by Exynos DRM subdrivers. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Diffstat (limited to 'drivers')
-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