Commit | Line | Data |
---|---|---|
0519f9a1 ID |
1 | /* exynos_drm_iommu.c |
2 | * | |
3 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | |
4 | * Author: Inki Dae <inki.dae@samsung.com> | |
5 | * | |
d81aecb5 ID |
6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. | |
0519f9a1 ID |
10 | */ |
11 | ||
4e6319cd | 12 | #include <drm/drmP.h> |
0519f9a1 ID |
13 | #include <drm/exynos_drm.h> |
14 | ||
15 | #include <linux/dma-mapping.h> | |
16 | #include <linux/iommu.h> | |
0519f9a1 ID |
17 | |
18 | #include "exynos_drm_drv.h" | |
19 | #include "exynos_drm_iommu.h" | |
20 | ||
f7c72773 MS |
21 | static 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 | ||
32 | static inline void clear_dma_max_seg_size(struct device *dev) | |
33 | { | |
34 | kfree(dev->dma_parms); | |
35 | dev->dma_parms = NULL; | |
36 | } | |
37 | ||
0519f9a1 ID |
38 | /* |
39 | * drm_create_iommu_mapping - create a mapping structure | |
40 | * | |
41 | * @drm_dev: DRM device | |
42 | */ | |
43 | int drm_create_iommu_mapping(struct drm_device *drm_dev) | |
44 | { | |
0519f9a1 | 45 | struct exynos_drm_private *priv = drm_dev->dev_private; |
0519f9a1 | 46 | |
17879a41 MS |
47 | return __exynos_iommu_create_mapping(priv, EXYNOS_DEV_ADDR_START, |
48 | EXYNOS_DEV_ADDR_SIZE); | |
0519f9a1 ID |
49 | } |
50 | ||
51 | /* | |
52 | * drm_release_iommu_mapping - release iommu mapping structure | |
53 | * | |
54 | * @drm_dev: DRM device | |
0519f9a1 ID |
55 | */ |
56 | void drm_release_iommu_mapping(struct drm_device *drm_dev) | |
57 | { | |
f43c3596 | 58 | struct exynos_drm_private *priv = drm_dev->dev_private; |
0519f9a1 | 59 | |
17879a41 | 60 | __exynos_iommu_release_mapping(priv); |
0519f9a1 ID |
61 | } |
62 | ||
63 | /* | |
64 | * drm_iommu_attach_device- attach device to iommu mapping | |
65 | * | |
66 | * @drm_dev: DRM device | |
67 | * @subdrv_dev: device to be attach | |
68 | * | |
69 | * This function should be called by sub drivers to attach it to iommu | |
70 | * mapping. | |
71 | */ | |
72 | int drm_iommu_attach_device(struct drm_device *drm_dev, | |
73 | struct device *subdrv_dev) | |
74 | { | |
f43c3596 | 75 | struct exynos_drm_private *priv = drm_dev->dev_private; |
0519f9a1 ID |
76 | int ret; |
77 | ||
c04d9eb7 MS |
78 | if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) { |
79 | DRM_ERROR("Device %s lacks support for IOMMU\n", | |
80 | dev_name(subdrv_dev)); | |
81 | return -EINVAL; | |
82 | } | |
4db7fcdf | 83 | |
f7c72773 MS |
84 | ret = configure_dma_max_seg_size(subdrv_dev); |
85 | if (ret) | |
86 | return ret; | |
0519f9a1 | 87 | |
17879a41 MS |
88 | ret = __exynos_iommu_attach(priv, subdrv_dev); |
89 | if (ret) | |
f7c72773 | 90 | clear_dma_max_seg_size(subdrv_dev); |
0519f9a1 | 91 | |
0519f9a1 ID |
92 | return 0; |
93 | } | |
94 | ||
95 | /* | |
96 | * drm_iommu_detach_device -detach device address space mapping from device | |
97 | * | |
98 | * @drm_dev: DRM device | |
99 | * @subdrv_dev: device to be detached | |
100 | * | |
101 | * This function should be called by sub drivers to detach it from iommu | |
102 | * mapping | |
103 | */ | |
104 | void drm_iommu_detach_device(struct drm_device *drm_dev, | |
105 | struct device *subdrv_dev) | |
106 | { | |
f43c3596 | 107 | struct exynos_drm_private *priv = drm_dev->dev_private; |
0519f9a1 | 108 | |
17879a41 | 109 | __exynos_iommu_detach(priv, subdrv_dev); |
f7c72773 | 110 | clear_dma_max_seg_size(subdrv_dev); |
0519f9a1 | 111 | } |