diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2013-08-08 11:18:32 +0200 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-18 11:44:05 +0900 |
commit | acd0b1469fd1f714ef8b29c809b757d2081ea9a2 (patch) | |
tree | 9e02123d55940cd1be85eb143dc4f8639c59f4da /drivers | |
parent | 442a1c7602381e0c59f4b03df76ea29fbb7454ea (diff) | |
download | linux-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/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_iommu.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_iommu_init.c | 69 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_iommu_init.h | 30 |
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 |