diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index ab02cea09f17..80c263ac081e 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -2239,7 +2239,10 @@ int mpp_dev_probe(struct mpp_dev *mpp, if (IS_ERR(mpp->iommu_info)) { dev_err(dev, "failed to attach iommu\n"); mpp->iommu_info = NULL; + } else { + mpp->iommu_info->queue = mpp->queue; } + if (mpp->hw_ops->init) { ret = mpp->hw_ops->init(mpp); if (ret) diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index d60d69970f56..e88243e78617 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -507,6 +507,9 @@ struct mpp_taskqueue { u32 core_id_max; u32 core_count; unsigned long dev_active_flags; + + /* for devices which share iommu, record last attach device */ + struct mpp_iommu_info *last_iommu_info; }; struct mpp_reset_group { @@ -547,6 +550,9 @@ struct mpp_service { /* global timing record flag */ u32 timing_en; u32 load_interval; + + /* bit mask for iommu shared */ + u32 iommu_shared_mask; }; /* diff --git a/drivers/video/rockchip/mpp/mpp_iommu.c b/drivers/video/rockchip/mpp/mpp_iommu.c index 9a3589314e0e..ff93d7f75e6c 100644 --- a/drivers/video/rockchip/mpp/mpp_iommu.c +++ b/drivers/video/rockchip/mpp/mpp_iommu.c @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_ARM_DMA_USE_IOMMU #include @@ -451,9 +452,19 @@ int mpp_iommu_detach(struct mpp_iommu_info *info) int mpp_iommu_attach(struct mpp_iommu_info *info) { + struct mpp_iommu_info *last_info; + if (!info) return 0; + /* if device changed, detach last first */ + last_info = info->queue->last_iommu_info; + if (info->shared && last_info && last_info->shared + && (info->dev != last_info->dev)) { + iommu_detach_group(last_info->domain, last_info->group); + } + info->queue->last_iommu_info = info; + if (info->domain == iommu_get_domain_for_dev(info->dev)) return 0; @@ -561,6 +572,15 @@ mpp_iommu_probe(struct device *dev) info->irq = platform_get_irq(pdev, 0); info->got_irq = (info->irq < 0) ? false : true; + /* get shared flag, if true detach */ + if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) { + struct platform_driver *drv = to_platform_driver(dev->driver); + + info->shared = drv->driver_managed_dma; + if (info->shared) + iommu_detach_group(info->domain, info->group); + } + return info; err_put_group: @@ -578,6 +598,10 @@ int mpp_iommu_remove(struct mpp_iommu_info *info) if (!info) return 0; + /* if iommu shared, ensure current device's domain, then remove correctly */ + if (info->shared) + mpp_iommu_attach(info); + iommu_group_put(info->group); platform_device_put(info->pdev); diff --git a/drivers/video/rockchip/mpp/mpp_iommu.h b/drivers/video/rockchip/mpp/mpp_iommu.h index 265f276de281..bf51e0ee4de3 100644 --- a/drivers/video/rockchip/mpp/mpp_iommu.h +++ b/drivers/video/rockchip/mpp/mpp_iommu.h @@ -102,6 +102,9 @@ struct mpp_iommu_info { int irq; int got_irq; + /* flag for mark iommu whether shared */ + bool shared; + struct mpp_taskqueue *queue; }; struct mpp_dma_session * diff --git a/drivers/video/rockchip/mpp/mpp_service.c b/drivers/video/rockchip/mpp/mpp_service.c index 882002e20097..4ae409738685 100644 --- a/drivers/video/rockchip/mpp/mpp_service.c +++ b/drivers/video/rockchip/mpp/mpp_service.c @@ -100,6 +100,9 @@ static int mpp_add_driver(struct mpp_service *srv, &srv->grf_infos[type], grf_name); + if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) + driver->driver_managed_dma = (srv->iommu_shared_mask & BIT(type)) ? true : false; + ret = platform_driver_register(driver); if (ret) return ret; @@ -444,6 +447,9 @@ static int mpp_service_probe(struct platform_device *pdev) } } + of_property_read_u32(np, "rockchip,iommu-shared-mask", + &srv->iommu_shared_mask); + ret = mpp_register_service(srv, MPP_SERVICE_NAME); if (ret) { dev_err(dev, "register %s device\n", MPP_SERVICE_NAME);