Commit 1aa5ca6e authored by Shunqian Zheng's avatar Shunqian Zheng Committed by Mark Yao

drm/rockchip: Use common IOMMU API to attach devices

Rockchip DRM used the arm special API, arm_iommu_*(), to attach
iommu for ARM32 SoCs. This patch convert to common iommu API
so it would support ARM64 like RK3399.

Since previous patch added support for direct IOMMU address space
management, there is no need to use DMA API anymore and this patch wires
things to use the new method.
Signed-off-by: default avatarShunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: default avatarTomasz Figa <tfiga@chromium.org>
Signed-off-by: default avatarMark Yao <mark.yao@rock-chips.com>
parent 38f993b7
...@@ -14,19 +14,19 @@ ...@@ -14,19 +14,19 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <asm/dma-iommu.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dma-iommu.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/iommu.h>
#include "rockchip_drm_drv.h" #include "rockchip_drm_drv.h"
#include "rockchip_drm_fb.h" #include "rockchip_drm_fb.h"
...@@ -50,28 +50,31 @@ static struct drm_driver rockchip_drm_driver; ...@@ -50,28 +50,31 @@ static struct drm_driver rockchip_drm_driver;
int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct device *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; int ret;
if (!is_support_iommu) if (!is_support_iommu)
return 0; return 0;
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); ret = iommu_attach_device(private->domain, dev);
if (ret) if (ret) {
dev_err(dev, "Failed to attach iommu device\n");
return ret; return ret;
}
dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); return 0;
return arm_iommu_attach_device(dev, mapping);
} }
void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev) struct device *dev)
{ {
struct rockchip_drm_private *private = drm_dev->dev_private;
struct iommu_domain *domain = private->domain;
if (!is_support_iommu) if (!is_support_iommu)
return; return;
arm_iommu_detach_device(dev); iommu_detach_device(domain, dev);
} }
int rockchip_register_crtc_funcs(struct drm_crtc *crtc, int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
...@@ -123,11 +126,46 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, ...@@ -123,11 +126,46 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev,
priv->crtc_funcs[pipe]->disable_vblank(crtc); 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) static int rockchip_drm_bind(struct device *dev)
{ {
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct rockchip_drm_private *private; struct rockchip_drm_private *private;
struct dma_iommu_mapping *mapping = NULL;
int ret; int ret;
drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
...@@ -151,38 +189,14 @@ static int rockchip_drm_bind(struct device *dev) ...@@ -151,38 +189,14 @@ static int rockchip_drm_bind(struct device *dev)
rockchip_drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev);
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), ret = rockchip_drm_init_iommu(drm_dev);
GFP_KERNEL); if (ret)
if (!dev->dma_parms) {
ret = -ENOMEM;
goto err_config_cleanup; 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. */ /* Try to bind all sub drivers. */
ret = component_bind_all(dev, drm_dev); ret = component_bind_all(dev, drm_dev);
if (ret) if (ret)
goto err_detach_device; goto err_iommu_cleanup;
/* init kms poll for handling hpd */ /* init kms poll for handling hpd */
drm_kms_helper_poll_init(drm_dev); drm_kms_helper_poll_init(drm_dev);
...@@ -207,8 +221,6 @@ static int rockchip_drm_bind(struct device *dev) ...@@ -207,8 +221,6 @@ static int rockchip_drm_bind(struct device *dev)
if (ret) if (ret)
goto err_fbdev_fini; goto err_fbdev_fini;
if (is_support_iommu)
arm_iommu_release_mapping(mapping);
return 0; return 0;
err_fbdev_fini: err_fbdev_fini:
rockchip_drm_fbdev_fini(drm_dev); rockchip_drm_fbdev_fini(drm_dev);
...@@ -217,12 +229,8 @@ static int rockchip_drm_bind(struct device *dev) ...@@ -217,12 +229,8 @@ static int rockchip_drm_bind(struct device *dev)
err_kms_helper_poll_fini: err_kms_helper_poll_fini:
drm_kms_helper_poll_fini(drm_dev); drm_kms_helper_poll_fini(drm_dev);
component_unbind_all(dev, drm_dev); component_unbind_all(dev, drm_dev);
err_detach_device: err_iommu_cleanup:
if (is_support_iommu) rockchip_iommu_cleanup(drm_dev);
arm_iommu_detach_device(dev);
err_release_mapping:
if (is_support_iommu)
arm_iommu_release_mapping(mapping);
err_config_cleanup: err_config_cleanup:
drm_mode_config_cleanup(drm_dev); drm_mode_config_cleanup(drm_dev);
drm_dev->dev_private = NULL; drm_dev->dev_private = NULL;
...@@ -239,8 +247,7 @@ static void rockchip_drm_unbind(struct device *dev) ...@@ -239,8 +247,7 @@ static void rockchip_drm_unbind(struct device *dev)
drm_vblank_cleanup(drm_dev); drm_vblank_cleanup(drm_dev);
drm_kms_helper_poll_fini(drm_dev); drm_kms_helper_poll_fini(drm_dev);
component_unbind_all(dev, drm_dev); component_unbind_all(dev, drm_dev);
if (is_support_iommu) rockchip_iommu_cleanup(drm_dev);
arm_iommu_detach_device(dev);
drm_mode_config_cleanup(drm_dev); drm_mode_config_cleanup(drm_dev);
drm_dev->dev_private = NULL; drm_dev->dev_private = NULL;
drm_dev_unregister(drm_dev); drm_dev_unregister(drm_dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment