|
@@ -14,19 +14,19 @@
|
|
|
* GNU General Public License for more details.
|
|
|
*/
|
|
|
|
|
|
-#include <asm/dma-iommu.h>
|
|
|
-
|
|
|
#include <drm/drmP.h>
|
|
|
#include <drm/drm_crtc_helper.h>
|
|
|
#include <drm/drm_fb_helper.h>
|
|
|
#include <drm/drm_gem_cma_helper.h>
|
|
|
#include <drm/drm_of.h>
|
|
|
#include <linux/dma-mapping.h>
|
|
|
+#include <linux/dma-iommu.h>
|
|
|
#include <linux/pm_runtime.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/of_graph.h>
|
|
|
#include <linux/component.h>
|
|
|
#include <linux/console.h>
|
|
|
+#include <linux/iommu.h>
|
|
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
|
#include "rockchip_drm_fb.h"
|
|
@@ -50,28 +50,31 @@ static struct drm_driver rockchip_drm_driver;
|
|
|
int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
|
|
|
struct device *dev)
|
|
|
{
|
|
|
- struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping;
|
|
|
+ struct rockchip_drm_private *private = drm_dev->dev_private;
|
|
|
int ret;
|
|
|
|
|
|
if (!is_support_iommu)
|
|
|
return 0;
|
|
|
|
|
|
- ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
|
|
|
- if (ret)
|
|
|
+ ret = iommu_attach_device(private->domain, dev);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "Failed to attach iommu device\n");
|
|
|
return ret;
|
|
|
+ }
|
|
|
|
|
|
- dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
|
|
|
-
|
|
|
- return arm_iommu_attach_device(dev, mapping);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
|
|
|
struct device *dev)
|
|
|
{
|
|
|
+ struct rockchip_drm_private *private = drm_dev->dev_private;
|
|
|
+ struct iommu_domain *domain = private->domain;
|
|
|
+
|
|
|
if (!is_support_iommu)
|
|
|
return;
|
|
|
|
|
|
- arm_iommu_detach_device(dev);
|
|
|
+ iommu_detach_device(domain, dev);
|
|
|
}
|
|
|
|
|
|
int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
|
|
@@ -123,11 +126,46 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev,
|
|
|
priv->crtc_funcs[pipe]->disable_vblank(crtc);
|
|
|
}
|
|
|
|
|
|
+static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
|
|
|
+{
|
|
|
+ struct rockchip_drm_private *private = drm_dev->dev_private;
|
|
|
+ struct iommu_domain_geometry *geometry;
|
|
|
+ u64 start, end;
|
|
|
+
|
|
|
+ if (!is_support_iommu)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ private->domain = iommu_domain_alloc(&platform_bus_type);
|
|
|
+ if (!private->domain)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ geometry = &private->domain->geometry;
|
|
|
+ start = geometry->aperture_start;
|
|
|
+ end = geometry->aperture_end;
|
|
|
+
|
|
|
+ DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n",
|
|
|
+ start, end);
|
|
|
+ drm_mm_init(&private->mm, start, end - start + 1);
|
|
|
+ mutex_init(&private->mm_lock);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
|
|
|
+{
|
|
|
+ struct rockchip_drm_private *private = drm_dev->dev_private;
|
|
|
+
|
|
|
+ if (!is_support_iommu)
|
|
|
+ return;
|
|
|
+
|
|
|
+ drm_mm_takedown(&private->mm);
|
|
|
+ iommu_domain_free(private->domain);
|
|
|
+}
|
|
|
+
|
|
|
static int rockchip_drm_bind(struct device *dev)
|
|
|
{
|
|
|
struct drm_device *drm_dev;
|
|
|
struct rockchip_drm_private *private;
|
|
|
- struct dma_iommu_mapping *mapping = NULL;
|
|
|
int ret;
|
|
|
|
|
|
drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
|
|
@@ -151,38 +189,14 @@ static int rockchip_drm_bind(struct device *dev)
|
|
|
|
|
|
rockchip_drm_mode_config_init(drm_dev);
|
|
|
|
|
|
- dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!dev->dma_parms) {
|
|
|
- ret = -ENOMEM;
|
|
|
+ ret = rockchip_drm_init_iommu(drm_dev);
|
|
|
+ if (ret)
|
|
|
goto err_config_cleanup;
|
|
|
- }
|
|
|
-
|
|
|
- if (is_support_iommu) {
|
|
|
- /* TODO(djkurtz): fetch the mapping start/size from somewhere */
|
|
|
- mapping = arm_iommu_create_mapping(&platform_bus_type,
|
|
|
- 0x00000000,
|
|
|
- SZ_2G);
|
|
|
- if (IS_ERR(mapping)) {
|
|
|
- ret = PTR_ERR(mapping);
|
|
|
- goto err_config_cleanup;
|
|
|
- }
|
|
|
-
|
|
|
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
|
|
- if (ret)
|
|
|
- goto err_release_mapping;
|
|
|
-
|
|
|
- dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
|
|
|
-
|
|
|
- ret = arm_iommu_attach_device(dev, mapping);
|
|
|
- if (ret)
|
|
|
- goto err_release_mapping;
|
|
|
- }
|
|
|
|
|
|
/* Try to bind all sub drivers. */
|
|
|
ret = component_bind_all(dev, drm_dev);
|
|
|
if (ret)
|
|
|
- goto err_detach_device;
|
|
|
+ goto err_iommu_cleanup;
|
|
|
|
|
|
/* init kms poll for handling hpd */
|
|
|
drm_kms_helper_poll_init(drm_dev);
|
|
@@ -207,8 +221,6 @@ static int rockchip_drm_bind(struct device *dev)
|
|
|
if (ret)
|
|
|
goto err_fbdev_fini;
|
|
|
|
|
|
- if (is_support_iommu)
|
|
|
- arm_iommu_release_mapping(mapping);
|
|
|
return 0;
|
|
|
err_fbdev_fini:
|
|
|
rockchip_drm_fbdev_fini(drm_dev);
|
|
@@ -217,12 +229,8 @@ err_vblank_cleanup:
|
|
|
err_kms_helper_poll_fini:
|
|
|
drm_kms_helper_poll_fini(drm_dev);
|
|
|
component_unbind_all(dev, drm_dev);
|
|
|
-err_detach_device:
|
|
|
- if (is_support_iommu)
|
|
|
- arm_iommu_detach_device(dev);
|
|
|
-err_release_mapping:
|
|
|
- if (is_support_iommu)
|
|
|
- arm_iommu_release_mapping(mapping);
|
|
|
+err_iommu_cleanup:
|
|
|
+ rockchip_iommu_cleanup(drm_dev);
|
|
|
err_config_cleanup:
|
|
|
drm_mode_config_cleanup(drm_dev);
|
|
|
drm_dev->dev_private = NULL;
|
|
@@ -239,8 +247,7 @@ static void rockchip_drm_unbind(struct device *dev)
|
|
|
drm_vblank_cleanup(drm_dev);
|
|
|
drm_kms_helper_poll_fini(drm_dev);
|
|
|
component_unbind_all(dev, drm_dev);
|
|
|
- if (is_support_iommu)
|
|
|
- arm_iommu_detach_device(dev);
|
|
|
+ rockchip_iommu_cleanup(drm_dev);
|
|
|
drm_mode_config_cleanup(drm_dev);
|
|
|
drm_dev->dev_private = NULL;
|
|
|
drm_dev_unregister(drm_dev);
|