diff options
Diffstat (limited to 'drivers/gpu/drm/exynos')
-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 |