diff options
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 101 |
1 files changed, 54 insertions, 47 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index c30d649cb147..b360e6251836 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |||
@@ -14,19 +14,19 @@ | |||
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <asm/dma-iommu.h> | ||
18 | |||
19 | #include <drm/drmP.h> | 17 | #include <drm/drmP.h> |
20 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
21 | #include <drm/drm_fb_helper.h> | 19 | #include <drm/drm_fb_helper.h> |
22 | #include <drm/drm_gem_cma_helper.h> | 20 | #include <drm/drm_gem_cma_helper.h> |
23 | #include <drm/drm_of.h> | 21 | #include <drm/drm_of.h> |
24 | #include <linux/dma-mapping.h> | 22 | #include <linux/dma-mapping.h> |
23 | #include <linux/dma-iommu.h> | ||
25 | #include <linux/pm_runtime.h> | 24 | #include <linux/pm_runtime.h> |
26 | #include <linux/module.h> | 25 | #include <linux/module.h> |
27 | #include <linux/of_graph.h> | 26 | #include <linux/of_graph.h> |
28 | #include <linux/component.h> | 27 | #include <linux/component.h> |
29 | #include <linux/console.h> | 28 | #include <linux/console.h> |
29 | #include <linux/iommu.h> | ||
30 | 30 | ||
31 | #include "rockchip_drm_drv.h" | 31 | #include "rockchip_drm_drv.h" |
32 | #include "rockchip_drm_fb.h" | 32 | #include "rockchip_drm_fb.h" |
@@ -50,28 +50,31 @@ static struct drm_driver rockchip_drm_driver; | |||
50 | int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, | 50 | int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, |
51 | struct device *dev) | 51 | struct device *dev) |
52 | { | 52 | { |
53 | struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping; | 53 | struct rockchip_drm_private *private = drm_dev->dev_private; |
54 | int ret; | 54 | int ret; |
55 | 55 | ||
56 | if (!is_support_iommu) | 56 | if (!is_support_iommu) |
57 | return 0; | 57 | return 0; |
58 | 58 | ||
59 | ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); | 59 | ret = iommu_attach_device(private->domain, dev); |
60 | if (ret) | 60 | if (ret) { |
61 | dev_err(dev, "Failed to attach iommu device\n"); | ||
61 | return ret; | 62 | return ret; |
63 | } | ||
62 | 64 | ||
63 | dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); | 65 | return 0; |
64 | |||
65 | return arm_iommu_attach_device(dev, mapping); | ||
66 | } | 66 | } |
67 | 67 | ||
68 | void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, | 68 | void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, |
69 | struct device *dev) | 69 | struct device *dev) |
70 | { | 70 | { |
71 | struct rockchip_drm_private *private = drm_dev->dev_private; | ||
72 | struct iommu_domain *domain = private->domain; | ||
73 | |||
71 | if (!is_support_iommu) | 74 | if (!is_support_iommu) |
72 | return; | 75 | return; |
73 | 76 | ||
74 | arm_iommu_detach_device(dev); | 77 | iommu_detach_device(domain, dev); |
75 | } | 78 | } |
76 | 79 | ||
77 | int rockchip_register_crtc_funcs(struct drm_crtc *crtc, | 80 | int rockchip_register_crtc_funcs(struct drm_crtc *crtc, |
@@ -123,11 +126,46 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, | |||
123 | priv->crtc_funcs[pipe]->disable_vblank(crtc); | 126 | priv->crtc_funcs[pipe]->disable_vblank(crtc); |
124 | } | 127 | } |
125 | 128 | ||
129 | static int rockchip_drm_init_iommu(struct drm_device *drm_dev) | ||
130 | { | ||
131 | struct rockchip_drm_private *private = drm_dev->dev_private; | ||
132 | struct iommu_domain_geometry *geometry; | ||
133 | u64 start, end; | ||
134 | |||
135 | if (!is_support_iommu) | ||
136 | return 0; | ||
137 | |||
138 | private->domain = iommu_domain_alloc(&platform_bus_type); | ||
139 | if (!private->domain) | ||
140 | return -ENOMEM; | ||
141 | |||
142 | geometry = &private->domain->geometry; | ||
143 | start = geometry->aperture_start; | ||
144 | end = geometry->aperture_end; | ||
145 | |||
146 | DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n", | ||
147 | start, end); | ||
148 | drm_mm_init(&private->mm, start, end - start + 1); | ||
149 | mutex_init(&private->mm_lock); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static void rockchip_iommu_cleanup(struct drm_device *drm_dev) | ||
155 | { | ||
156 | struct rockchip_drm_private *private = drm_dev->dev_private; | ||
157 | |||
158 | if (!is_support_iommu) | ||
159 | return; | ||
160 | |||
161 | drm_mm_takedown(&private->mm); | ||
162 | iommu_domain_free(private->domain); | ||
163 | } | ||
164 | |||
126 | static int rockchip_drm_bind(struct device *dev) | 165 | static int rockchip_drm_bind(struct device *dev) |
127 | { | 166 | { |
128 | struct drm_device *drm_dev; | 167 | struct drm_device *drm_dev; |
129 | struct rockchip_drm_private *private; | 168 | struct rockchip_drm_private *private; |
130 | struct dma_iommu_mapping *mapping = NULL; | ||
131 | int ret; | 169 | int ret; |
132 | 170 | ||
133 | drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); | 171 | drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); |
@@ -151,38 +189,14 @@ static int rockchip_drm_bind(struct device *dev) | |||
151 | 189 | ||
152 | rockchip_drm_mode_config_init(drm_dev); | 190 | rockchip_drm_mode_config_init(drm_dev); |
153 | 191 | ||
154 | dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), | 192 | ret = rockchip_drm_init_iommu(drm_dev); |
155 | GFP_KERNEL); | 193 | if (ret) |
156 | if (!dev->dma_parms) { | ||
157 | ret = -ENOMEM; | ||
158 | goto err_config_cleanup; | 194 | goto err_config_cleanup; |
159 | } | ||
160 | |||
161 | if (is_support_iommu) { | ||
162 | /* TODO(djkurtz): fetch the mapping start/size from somewhere */ | ||
163 | mapping = arm_iommu_create_mapping(&platform_bus_type, | ||
164 | 0x00000000, | ||
165 | SZ_2G); | ||
166 | if (IS_ERR(mapping)) { | ||
167 | ret = PTR_ERR(mapping); | ||
168 | goto err_config_cleanup; | ||
169 | } | ||
170 | |||
171 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); | ||
172 | if (ret) | ||
173 | goto err_release_mapping; | ||
174 | |||
175 | dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); | ||
176 | |||
177 | ret = arm_iommu_attach_device(dev, mapping); | ||
178 | if (ret) | ||
179 | goto err_release_mapping; | ||
180 | } | ||
181 | 195 | ||
182 | /* Try to bind all sub drivers. */ | 196 | /* Try to bind all sub drivers. */ |
183 | ret = component_bind_all(dev, drm_dev); | 197 | ret = component_bind_all(dev, drm_dev); |
184 | if (ret) | 198 | if (ret) |
185 | goto err_detach_device; | 199 | goto err_iommu_cleanup; |
186 | 200 | ||
187 | /* init kms poll for handling hpd */ | 201 | /* init kms poll for handling hpd */ |
188 | drm_kms_helper_poll_init(drm_dev); | 202 | drm_kms_helper_poll_init(drm_dev); |
@@ -207,8 +221,6 @@ static int rockchip_drm_bind(struct device *dev) | |||
207 | if (ret) | 221 | if (ret) |
208 | goto err_fbdev_fini; | 222 | goto err_fbdev_fini; |
209 | 223 | ||
210 | if (is_support_iommu) | ||
211 | arm_iommu_release_mapping(mapping); | ||
212 | return 0; | 224 | return 0; |
213 | err_fbdev_fini: | 225 | err_fbdev_fini: |
214 | rockchip_drm_fbdev_fini(drm_dev); | 226 | rockchip_drm_fbdev_fini(drm_dev); |
@@ -217,12 +229,8 @@ err_vblank_cleanup: | |||
217 | err_kms_helper_poll_fini: | 229 | err_kms_helper_poll_fini: |
218 | drm_kms_helper_poll_fini(drm_dev); | 230 | drm_kms_helper_poll_fini(drm_dev); |
219 | component_unbind_all(dev, drm_dev); | 231 | component_unbind_all(dev, drm_dev); |
220 | err_detach_device: | 232 | err_iommu_cleanup: |
221 | if (is_support_iommu) | 233 | rockchip_iommu_cleanup(drm_dev); |
222 | arm_iommu_detach_device(dev); | ||
223 | err_release_mapping: | ||
224 | if (is_support_iommu) | ||
225 | arm_iommu_release_mapping(mapping); | ||
226 | err_config_cleanup: | 234 | err_config_cleanup: |
227 | drm_mode_config_cleanup(drm_dev); | 235 | drm_mode_config_cleanup(drm_dev); |
228 | drm_dev->dev_private = NULL; | 236 | drm_dev->dev_private = NULL; |
@@ -239,8 +247,7 @@ static void rockchip_drm_unbind(struct device *dev) | |||
239 | drm_vblank_cleanup(drm_dev); | 247 | drm_vblank_cleanup(drm_dev); |
240 | drm_kms_helper_poll_fini(drm_dev); | 248 | drm_kms_helper_poll_fini(drm_dev); |
241 | component_unbind_all(dev, drm_dev); | 249 | component_unbind_all(dev, drm_dev); |
242 | if (is_support_iommu) | 250 | rockchip_iommu_cleanup(drm_dev); |
243 | arm_iommu_detach_device(dev); | ||
244 | drm_mode_config_cleanup(drm_dev); | 251 | drm_mode_config_cleanup(drm_dev); |
245 | drm_dev->dev_private = NULL; | 252 | drm_dev->dev_private = NULL; |
246 | drm_dev_unregister(drm_dev); | 253 | drm_dev_unregister(drm_dev); |