1 /* sunxi_drm_iommu.c
2 *
3 * Copyright (C) 2022 Allwinnertech Co., Ltd.
4 * Authors: hongyaobin <hongyaobin@allwinnertech.com>
5 *
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.
10 */
11
12
13 #include <drm/drmP.h>
14 #include <uapi/drm/sunxi_drm.h>
15
16
17 #include <linux/dma-mapping.h>
18 #include <linux/iommu.h>
19
20 #include "sunxi_drm_drv.h"
21 #include "sunxi_drm_iommu.h"
22
23 /* dram space, according to the memory mapping spec */
24 #define SUNXI_DEV_ADDR_START 0x40000000
25
configure_dma_max_seg_size(struct device * dev)26 static inline int configure_dma_max_seg_size(struct device *dev)
27 {
28 if (!dev->dma_parms)
29 dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
30 if (!dev->dma_parms)
31 return -ENOMEM;
32
33 dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
34 return 0;
35 }
36
clear_dma_max_seg_size(struct device * dev)37 static inline void clear_dma_max_seg_size(struct device *dev)
38 {
39 kfree(dev->dma_parms);
40 dev->dma_parms = NULL;
41 }
42
43 /*
44 * sunxi_drm_create_iommu_mapping - create a mapping structure
45 *
46 * @drm_dev: DRM device
47 */
sunxi_drm_create_iommu_mapping(struct drm_device * drm_dev)48 int sunxi_drm_create_iommu_mapping(struct drm_device *drm_dev)
49 {
50 struct sunxi_drm_private *priv = drm_dev->dev_private;
51
52 return __sunxi_iommu_create_mapping(priv, SUNXI_DEV_ADDR_START,
53 SZ_4G);
54 }
55
56 /*
57 * sunxi_drm_release_iommu_mapping - release iommu mapping structure
58 *
59 * @drm_dev: DRM device
60 */
sunxi_drm_release_iommu_mapping(struct drm_device * drm_dev)61 void sunxi_drm_release_iommu_mapping(struct drm_device *drm_dev)
62 {
63 struct sunxi_drm_private *priv = drm_dev->dev_private;
64
65 __sunxi_iommu_release_mapping(priv);
66 }
67
68 /*
69 * sunxi_drm_iommu_attach_device- attach device to iommu mapping
70 *
71 * @drm_dev: DRM device
72 * @subdrv_dev: device to be attach
73 *
74 * This function should be called by sub drivers to attach it to iommu
75 * mapping.
76 */
sunxi_drm_iommu_attach_device(struct drm_device * drm_dev,struct device * subdrv_dev)77 int sunxi_drm_iommu_attach_device(struct drm_device *drm_dev,
78 struct device *subdrv_dev)
79 {
80 struct sunxi_drm_private *priv = drm_dev->dev_private;
81 int ret;
82
83 if (get_dma_ops(drm_dev->dev) != get_dma_ops(subdrv_dev)) {
84 DRM_ERROR("Device %s lacks support for IOMMU\n",
85 dev_name(subdrv_dev));
86 return -EINVAL;
87 }
88
89 ret = configure_dma_max_seg_size(subdrv_dev);
90 if (ret)
91 return ret;
92
93 ret = __sunxi_iommu_attach(priv, subdrv_dev);
94 if (ret)
95 clear_dma_max_seg_size(subdrv_dev);
96
97 return 0;
98 }
99
100 /*
101 * sunxi_drm_iommu_detach_device -detach device address space mapping from device
102 *
103 * @drm_dev: DRM device
104 * @subdrv_dev: device to be detached
105 *
106 * This function should be called by sub drivers to detach it from iommu
107 * mapping
108 */
sunxi_drm_iommu_detach_device(struct drm_device * drm_dev,struct device * subdrv_dev)109 void sunxi_drm_iommu_detach_device(struct drm_device *drm_dev,
110 struct device *subdrv_dev)
111 {
112 struct sunxi_drm_private *priv = drm_dev->dev_private;
113
114 __sunxi_iommu_detach(priv, subdrv_dev);
115 clear_dma_max_seg_size(subdrv_dev);
116 }
117