drm/rockchip: support non-iommu buffer path

Some rockchip vop not support iommu, need use non-iommu
buffer for it. And if we get iommu issues, we can compare
the issues with non-iommu path, that would help the debug.

Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
This commit is contained in:
Mark Yao 2016-04-19 10:13:27 +08:00
parent 4e257d9eee
commit 2d90d47743
1 changed files with 49 additions and 21 deletions

View File

@ -36,6 +36,8 @@
#define DRIVER_MAJOR 1 #define DRIVER_MAJOR 1
#define DRIVER_MINOR 0 #define DRIVER_MINOR 0
static bool is_support_iommu = true;
/* /*
* Attach a (component) device to the shared drm dma mapping from master drm * Attach a (component) device to the shared drm dma mapping from master drm
* device. This is used by the VOPs to map GEM buffers to a common DMA * device. This is used by the VOPs to map GEM buffers to a common DMA
@ -47,6 +49,9 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping; struct dma_iommu_mapping *mapping = drm_dev->dev->archdata.mapping;
int ret; int ret;
if (!is_support_iommu)
return 0;
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret) if (ret)
return ret; return ret;
@ -59,6 +64,9 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
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)
{ {
if (!is_support_iommu)
return;
arm_iommu_detach_device(dev); arm_iommu_detach_device(dev);
} }
@ -127,7 +135,7 @@ static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev,
static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags) static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
{ {
struct rockchip_drm_private *private; struct rockchip_drm_private *private;
struct dma_iommu_mapping *mapping; struct dma_iommu_mapping *mapping = NULL;
struct device *dev = drm_dev->dev; struct device *dev = drm_dev->dev;
struct drm_connector *connector; struct drm_connector *connector;
int ret; int ret;
@ -152,24 +160,27 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
goto err_config_cleanup; goto err_config_cleanup;
} }
/* TODO(djkurtz): fetch the mapping start/size from somewhere */ if (is_support_iommu) {
mapping = arm_iommu_create_mapping(&platform_bus_type, 0x00000000, /* TODO(djkurtz): fetch the mapping start/size from somewhere */
SZ_2G); mapping = arm_iommu_create_mapping(&platform_bus_type,
if (IS_ERR(mapping)) { 0x00000000,
ret = PTR_ERR(mapping); SZ_2G);
goto err_config_cleanup; 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;
} }
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)
@ -218,7 +229,8 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
if (ret) if (ret)
goto err_vblank_cleanup; goto err_vblank_cleanup;
arm_iommu_release_mapping(mapping); if (is_support_iommu)
arm_iommu_release_mapping(mapping);
return 0; return 0;
err_vblank_cleanup: err_vblank_cleanup:
drm_vblank_cleanup(drm_dev); drm_vblank_cleanup(drm_dev);
@ -227,9 +239,11 @@ err_kms_helper_poll_fini:
err_unbind: err_unbind:
component_unbind_all(dev, drm_dev); component_unbind_all(dev, drm_dev);
err_detach_device: err_detach_device:
arm_iommu_detach_device(dev); if (is_support_iommu)
arm_iommu_detach_device(dev);
err_release_mapping: err_release_mapping:
arm_iommu_release_mapping(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;
@ -244,7 +258,8 @@ static int rockchip_drm_unload(struct drm_device *drm_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);
arm_iommu_detach_device(dev); if (is_support_iommu)
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;
@ -488,6 +503,8 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
* works as expected. * works as expected.
*/ */
for (i = 0;; i++) { for (i = 0;; i++) {
struct device_node *iommu;
port = of_parse_phandle(np, "ports", i); port = of_parse_phandle(np, "ports", i);
if (!port) if (!port)
break; break;
@ -497,6 +514,17 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
continue; continue;
} }
iommu = of_parse_phandle(port->parent, "iommus", 0);
if (!iommu || !of_device_is_available(iommu->parent)) {
dev_dbg(dev, "no iommu attached for %s, using non-iommu buffers\n",
port->parent->full_name);
/*
* if there is a crtc not support iommu, force set all
* crtc use non-iommu buffer.
*/
is_support_iommu = false;
}
component_match_add(dev, &match, compare_of, port->parent); component_match_add(dev, &match, compare_of, port->parent);
of_node_put(port); of_node_put(port);
} }