aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/Kconfig2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.c77
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.h91
5 files changed, 126 insertions, 53 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 1c7e14cf2781..83f61c513b7e 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -11,7 +11,7 @@ if DRM_EXYNOS
11 11
12config DRM_EXYNOS_IOMMU 12config DRM_EXYNOS_IOMMU
13 bool 13 bool
14 depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU 14 depends on EXYNOS_IOMMU
15 default y 15 default y
16 16
17comment "CRTCs" 17comment "CRTCs"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 13d28d4229e2..877d2efa28e2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -159,12 +159,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
159 DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n", 159 DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
160 dev_name(private->dma_dev)); 160 dev_name(private->dma_dev));
161 161
162 /* 162 /* create common IOMMU mapping for all devices attached to Exynos DRM */
163 * create mapping to manage iommu table and set a pointer to iommu
164 * mapping structure to iommu_mapping of private data.
165 * also this iommu_mapping can be used to check if iommu is supported
166 * or not.
167 */
168 ret = drm_create_iommu_mapping(dev); 163 ret = drm_create_iommu_mapping(dev);
169 if (ret < 0) { 164 if (ret < 0) {
170 DRM_ERROR("failed to create iommu mapping.\n"); 165 DRM_ERROR("failed to create iommu mapping.\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index cc33ec9296e7..b39d521f093d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -224,8 +224,6 @@ struct exynos_drm_private {
224 struct drm_property *plane_zpos_property; 224 struct drm_property *plane_zpos_property;
225 225
226 struct device *dma_dev; 226 struct device *dma_dev;
227 unsigned long da_start;
228 unsigned long da_space_size;
229 void *mapping; 227 void *mapping;
230 228
231 unsigned int pipe; 229 unsigned int pipe;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
index 7ca09ee19656..0f373702414e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
@@ -14,13 +14,27 @@
14 14
15#include <linux/dma-mapping.h> 15#include <linux/dma-mapping.h>
16#include <linux/iommu.h> 16#include <linux/iommu.h>
17#include <linux/kref.h>
18
19#include <asm/dma-iommu.h>
20 17
21#include "exynos_drm_drv.h" 18#include "exynos_drm_drv.h"
22#include "exynos_drm_iommu.h" 19#include "exynos_drm_iommu.h"
23 20
21static inline int configure_dma_max_seg_size(struct device *dev)
22{
23 if (!dev->dma_parms)
24 dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
25 if (!dev->dma_parms)
26 return -ENOMEM;
27
28 dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
29 return 0;
30}
31
32static inline void clear_dma_max_seg_size(struct device *dev)
33{
34 kfree(dev->dma_parms);
35 dev->dma_parms = NULL;
36}
37
24/* 38/*
25 * drm_create_iommu_mapping - create a mapping structure 39 * drm_create_iommu_mapping - create a mapping structure
26 * 40 *
@@ -28,38 +42,22 @@
28 */ 42 */
29int drm_create_iommu_mapping(struct drm_device *drm_dev) 43int drm_create_iommu_mapping(struct drm_device *drm_dev)
30{ 44{
31 struct dma_iommu_mapping *mapping = NULL;
32 struct exynos_drm_private *priv = drm_dev->dev_private; 45 struct exynos_drm_private *priv = drm_dev->dev_private;
33 46
34 if (!priv->da_start) 47 return __exynos_iommu_create_mapping(priv, EXYNOS_DEV_ADDR_START,
35 priv->da_start = EXYNOS_DEV_ADDR_START; 48 EXYNOS_DEV_ADDR_SIZE);
36 if (!priv->da_space_size)
37 priv->da_space_size = EXYNOS_DEV_ADDR_SIZE;
38
39 mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
40 priv->da_space_size);
41
42 if (IS_ERR(mapping))
43 return PTR_ERR(mapping);
44
45 priv->mapping = mapping;
46
47 return 0;
48} 49}
49 50
50/* 51/*
51 * drm_release_iommu_mapping - release iommu mapping structure 52 * drm_release_iommu_mapping - release iommu mapping structure
52 * 53 *
53 * @drm_dev: DRM device 54 * @drm_dev: DRM device
54 *
55 * if mapping->kref becomes 0 then all things related to iommu mapping
56 * will be released
57 */ 55 */
58void drm_release_iommu_mapping(struct drm_device *drm_dev) 56void drm_release_iommu_mapping(struct drm_device *drm_dev)
59{ 57{
60 struct exynos_drm_private *priv = drm_dev->dev_private; 58 struct exynos_drm_private *priv = drm_dev->dev_private;
61 59
62 arm_iommu_release_mapping(priv->mapping); 60 __exynos_iommu_release_mapping(priv);
63} 61}
64 62
65/* 63/*
@@ -77,25 +75,19 @@ int drm_iommu_attach_device(struct drm_device *drm_dev,
77 struct exynos_drm_private *priv = drm_dev->dev_private; 75 struct exynos_drm_private *priv = drm_dev->dev_private;
78 int ret; 76 int ret;
79 77
80 if (!priv->mapping) 78 if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
81 return 0; 79 DRM_ERROR("Device %s lacks support for IOMMU\n",
82 80 dev_name(subdrv_dev));
83 subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev, 81 return -EINVAL;
84 sizeof(*subdrv_dev->dma_parms), 82 }
85 GFP_KERNEL);
86 if (!subdrv_dev->dma_parms)
87 return -ENOMEM;
88
89 dma_set_max_seg_size(subdrv_dev, 0xffffffffu);
90
91 if (subdrv_dev->archdata.mapping)
92 arm_iommu_detach_device(subdrv_dev);
93 83
94 ret = arm_iommu_attach_device(subdrv_dev, priv->mapping); 84 ret = configure_dma_max_seg_size(subdrv_dev);
95 if (ret < 0) { 85 if (ret)
96 DRM_DEBUG_KMS("failed iommu attach.\n");
97 return ret; 86 return ret;
98 } 87
88 ret = __exynos_iommu_attach(priv, subdrv_dev);
89 if (ret)
90 clear_dma_max_seg_size(subdrv_dev);
99 91
100 return 0; 92 return 0;
101} 93}
@@ -113,10 +105,7 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
113 struct device *subdrv_dev) 105 struct device *subdrv_dev)
114{ 106{
115 struct exynos_drm_private *priv = drm_dev->dev_private; 107 struct exynos_drm_private *priv = drm_dev->dev_private;
116 struct dma_iommu_mapping *mapping = priv->mapping;
117
118 if (!mapping || !mapping->domain)
119 return;
120 108
121 arm_iommu_detach_device(subdrv_dev); 109 __exynos_iommu_detach(priv, subdrv_dev);
110 clear_dma_max_seg_size(subdrv_dev);
122} 111}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
index 5ffebe02ee4d..c8de4913fdbe 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
@@ -17,6 +17,97 @@
17 17
18#ifdef CONFIG_DRM_EXYNOS_IOMMU 18#ifdef CONFIG_DRM_EXYNOS_IOMMU
19 19
20#if defined(CONFIG_ARM_DMA_USE_IOMMU)
21#include <asm/dma-iommu.h>
22
23static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
24 unsigned long start, unsigned long size)
25{
26 priv->mapping = arm_iommu_create_mapping(&platform_bus_type, start,
27 size);
28 return IS_ERR(priv->mapping);
29}
30
31static inline void
32__exynos_iommu_release_mapping(struct exynos_drm_private *priv)
33{
34 arm_iommu_release_mapping(priv->mapping);
35}
36
37static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
38 struct device *dev)
39{
40 if (dev->archdata.mapping)
41 arm_iommu_detach_device(dev);
42
43 return arm_iommu_attach_device(dev, priv->mapping);
44}
45
46static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
47 struct device *dev)
48{
49 arm_iommu_detach_device(dev);
50}
51
52#elif defined(CONFIG_IOMMU_DMA)
53#include <linux/dma-iommu.h>
54
55static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
56 unsigned long start, unsigned long size)
57{
58 struct iommu_domain *domain;
59 int ret;
60
61 domain = iommu_domain_alloc(priv->dma_dev->bus);
62 if (!domain)
63 return -ENOMEM;
64
65 ret = iommu_get_dma_cookie(domain);
66 if (ret)
67 goto free_domain;
68
69 ret = iommu_dma_init_domain(domain, start, size);
70 if (ret)
71 goto put_cookie;
72
73 priv->mapping = domain;
74 return 0;
75
76put_cookie:
77 iommu_put_dma_cookie(domain);
78free_domain:
79 iommu_domain_free(domain);
80 return ret;
81}
82
83static inline void __exynos_iommu_release_mapping(struct exynos_drm_private *priv)
84{
85 struct iommu_domain *domain = priv->mapping;
86
87 iommu_put_dma_cookie(domain);
88 iommu_domain_free(domain);
89 priv->mapping = NULL;
90}
91
92static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
93 struct device *dev)
94{
95 struct iommu_domain *domain = priv->mapping;
96
97 return iommu_attach_device(domain, dev);
98}
99
100static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
101 struct device *dev)
102{
103 struct iommu_domain *domain = priv->mapping;
104
105 iommu_detach_device(domain, dev);
106}
107#else
108#error Unsupported architecture and IOMMU/DMA-mapping glue code
109#endif
110
20int drm_create_iommu_mapping(struct drm_device *drm_dev); 111int drm_create_iommu_mapping(struct drm_device *drm_dev);
21 112
22void drm_release_iommu_mapping(struct drm_device *drm_dev); 113void drm_release_iommu_mapping(struct drm_device *drm_dev);