• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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