blob: 36dde9691274323dd8d268da8ec17b509bb60166 [file] [log] [blame]
Inki Dae0519f9a2012-10-20 07:53:42 -07001/* exynos_drm_iommu.c
2 *
3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 * Author: Inki Dae <inki.dae@samsung.com>
5 *
Inki Daed81aecb2012-12-18 02:30:17 +09006 * 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.
Inki Dae0519f9a2012-10-20 07:53:42 -070010 */
11
Andrzej Hajda4e6319c2016-02-24 15:15:22 +010012#include <drm/drmP.h>
Inki Dae0519f9a2012-10-20 07:53:42 -070013#include <drm/exynos_drm.h>
14
15#include <linux/dma-mapping.h>
16#include <linux/iommu.h>
17#include <linux/kref.h>
18
19#include <asm/dma-iommu.h>
20
21#include "exynos_drm_drv.h"
22#include "exynos_drm_iommu.h"
23
Marek Szyprowskif7c72772016-06-17 09:54:23 +020024static inline int configure_dma_max_seg_size(struct device *dev)
25{
26 if (!dev->dma_parms)
27 dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
28 if (!dev->dma_parms)
29 return -ENOMEM;
30
31 dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
32 return 0;
33}
34
35static inline void clear_dma_max_seg_size(struct device *dev)
36{
37 kfree(dev->dma_parms);
38 dev->dma_parms = NULL;
39}
40
Inki Dae0519f9a2012-10-20 07:53:42 -070041/*
42 * drm_create_iommu_mapping - create a mapping structure
43 *
44 * @drm_dev: DRM device
45 */
46int drm_create_iommu_mapping(struct drm_device *drm_dev)
47{
48 struct dma_iommu_mapping *mapping = NULL;
49 struct exynos_drm_private *priv = drm_dev->dev_private;
Inki Dae0519f9a2012-10-20 07:53:42 -070050
51 if (!priv->da_start)
52 priv->da_start = EXYNOS_DEV_ADDR_START;
53 if (!priv->da_space_size)
54 priv->da_space_size = EXYNOS_DEV_ADDR_SIZE;
Inki Dae0519f9a2012-10-20 07:53:42 -070055
56 mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
Marek Szyprowski68efd7d2014-02-25 13:01:09 +010057 priv->da_space_size);
58
Wei Yongjuna0e41b52012-12-10 02:11:13 -050059 if (IS_ERR(mapping))
60 return PTR_ERR(mapping);
Inki Dae0519f9a2012-10-20 07:53:42 -070061
Marek Szyprowskif43c3592016-02-29 17:50:53 +090062 priv->mapping = mapping;
Inki Dae0519f9a2012-10-20 07:53:42 -070063
64 return 0;
65}
66
67/*
68 * drm_release_iommu_mapping - release iommu mapping structure
69 *
70 * @drm_dev: DRM device
71 *
72 * if mapping->kref becomes 0 then all things related to iommu mapping
73 * will be released
74 */
75void drm_release_iommu_mapping(struct drm_device *drm_dev)
76{
Marek Szyprowskif43c3592016-02-29 17:50:53 +090077 struct exynos_drm_private *priv = drm_dev->dev_private;
Inki Dae0519f9a2012-10-20 07:53:42 -070078
Marek Szyprowskif43c3592016-02-29 17:50:53 +090079 arm_iommu_release_mapping(priv->mapping);
Inki Dae0519f9a2012-10-20 07:53:42 -070080}
81
82/*
83 * drm_iommu_attach_device- attach device to iommu mapping
84 *
85 * @drm_dev: DRM device
86 * @subdrv_dev: device to be attach
87 *
88 * This function should be called by sub drivers to attach it to iommu
89 * mapping.
90 */
91int drm_iommu_attach_device(struct drm_device *drm_dev,
92 struct device *subdrv_dev)
93{
Marek Szyprowskif43c3592016-02-29 17:50:53 +090094 struct exynos_drm_private *priv = drm_dev->dev_private;
Inki Dae0519f9a2012-10-20 07:53:42 -070095 int ret;
96
Marek Szyprowskif43c3592016-02-29 17:50:53 +090097 if (!priv->mapping)
Joonyoung Shimbf566082015-07-02 21:49:38 +090098 return 0;
Inki Dae0519f9a2012-10-20 07:53:42 -070099
Marek Szyprowskic04d9eb2016-06-17 09:54:24 +0200100 if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
101 DRM_ERROR("Device %s lacks support for IOMMU\n",
102 dev_name(subdrv_dev));
103 return -EINVAL;
104 }
Sachin Kamat4db7fcd2013-08-14 16:38:03 +0530105
Marek Szyprowskif7c72772016-06-17 09:54:23 +0200106 ret = configure_dma_max_seg_size(subdrv_dev);
107 if (ret)
108 return ret;
Inki Dae0519f9a2012-10-20 07:53:42 -0700109
Marek Szyprowski45286852015-06-03 10:26:23 +0200110 if (subdrv_dev->archdata.mapping)
111 arm_iommu_detach_device(subdrv_dev);
112
Marek Szyprowskif43c3592016-02-29 17:50:53 +0900113 ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
Inki Dae0519f9a2012-10-20 07:53:42 -0700114 if (ret < 0) {
115 DRM_DEBUG_KMS("failed iommu attach.\n");
Marek Szyprowskif7c72772016-06-17 09:54:23 +0200116 clear_dma_max_seg_size(subdrv_dev);
Inki Dae0519f9a2012-10-20 07:53:42 -0700117 return ret;
118 }
119
Inki Dae0519f9a2012-10-20 07:53:42 -0700120 return 0;
121}
122
123/*
124 * drm_iommu_detach_device -detach device address space mapping from device
125 *
126 * @drm_dev: DRM device
127 * @subdrv_dev: device to be detached
128 *
129 * This function should be called by sub drivers to detach it from iommu
130 * mapping
131 */
132void drm_iommu_detach_device(struct drm_device *drm_dev,
133 struct device *subdrv_dev)
134{
Marek Szyprowskif43c3592016-02-29 17:50:53 +0900135 struct exynos_drm_private *priv = drm_dev->dev_private;
136 struct dma_iommu_mapping *mapping = priv->mapping;
Inki Dae0519f9a2012-10-20 07:53:42 -0700137
138 if (!mapping || !mapping->domain)
139 return;
140
Joonyoung Shim4d91a852015-10-02 09:30:38 +0900141 arm_iommu_detach_device(subdrv_dev);
Marek Szyprowskif7c72772016-06-17 09:54:23 +0200142 clear_dma_max_seg_size(subdrv_dev);
Inki Dae0519f9a2012-10-20 07:53:42 -0700143}