1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
/* exynos_drm_iommu.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Authoer: Inki Dae <inki.dae@samsung.com>
*
* 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_H_
#define _EXYNOS_DRM_IOMMU_H_
#define EXYNOS_DEV_ADDR_START 0x20000000
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
#ifdef CONFIG_DRM_EXYNOS_IOMMU
#if defined(CONFIG_ARM_DMA_USE_IOMMU)
#include <asm/dma-iommu.h>
static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
unsigned long start, unsigned long size)
{
priv->mapping = arm_iommu_create_mapping(&platform_bus_type, start,
size);
return IS_ERR(priv->mapping);
}
static inline void
__exynos_iommu_release_mapping(struct exynos_drm_private *priv)
{
arm_iommu_release_mapping(priv->mapping);
}
static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
struct device *dev)
{
if (dev->archdata.mapping)
arm_iommu_detach_device(dev);
return arm_iommu_attach_device(dev, priv->mapping);
}
static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
struct device *dev)
{
arm_iommu_detach_device(dev);
}
#elif defined(CONFIG_IOMMU_DMA)
#include <linux/dma-iommu.h>
static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
unsigned long start, unsigned long size)
{
struct iommu_domain *domain;
int ret;
domain = iommu_domain_alloc(priv->dma_dev->bus);
if (!domain)
return -ENOMEM;
ret = iommu_get_dma_cookie(domain);
if (ret)
goto free_domain;
ret = iommu_dma_init_domain(domain, start, size, NULL);
if (ret)
goto put_cookie;
priv->mapping = domain;
return 0;
put_cookie:
iommu_put_dma_cookie(domain);
free_domain:
iommu_domain_free(domain);
return ret;
}
static inline void __exynos_iommu_release_mapping(struct exynos_drm_private *priv)
{
struct iommu_domain *domain = priv->mapping;
iommu_put_dma_cookie(domain);
iommu_domain_free(domain);
priv->mapping = NULL;
}
static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
struct device *dev)
{
struct iommu_domain *domain = priv->mapping;
return iommu_attach_device(domain, dev);
}
static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
struct device *dev)
{
struct iommu_domain *domain = priv->mapping;
iommu_detach_device(domain, dev);
}
#else
#error Unsupported architecture and IOMMU/DMA-mapping glue code
#endif
int drm_create_iommu_mapping(struct drm_device *drm_dev);
void drm_release_iommu_mapping(struct drm_device *drm_dev);
int drm_iommu_attach_device(struct drm_device *drm_dev,
struct device *subdrv_dev);
void drm_iommu_detach_device(struct drm_device *dev_dev,
struct device *subdrv_dev);
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
{
struct exynos_drm_private *priv = drm_dev->dev_private;
return priv->mapping ? true : false;
}
#else
static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
{
return 0;
}
static inline void drm_release_iommu_mapping(struct drm_device *drm_dev)
{
}
static inline int drm_iommu_attach_device(struct drm_device *drm_dev,
struct device *subdrv_dev)
{
return 0;
}
static inline void drm_iommu_detach_device(struct drm_device *drm_dev,
struct device *subdrv_dev)
{
}
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
{
return false;
}
#endif
#endif
|