summaryrefslogtreecommitdiff
path: root/drivers/iommu/rockchip-iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/rockchip-iommu.c')
-rw-r--r--drivers/iommu/rockchip-iommu.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 9d991c2d8767..6a3719e118da 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1209,6 +1209,23 @@ static int rk_iommu_remove(struct platform_device *pdev)
return 0;
}
+static void rk_iommu_shutdown(struct platform_device *pdev)
+{
+ struct rk_iommu *iommu = platform_get_drvdata(pdev);
+
+ /*
+ * Be careful not to try to shutdown an otherwise unused
+ * IOMMU, as it is likely not to be clocked, and accessing it
+ * would just block. An IOMMU without a domain is likely to be
+ * unused, so let's use this as a (weak) guard.
+ */
+ if (iommu && iommu->domain) {
+ rk_iommu_enable_stall(iommu);
+ rk_iommu_disable_paging(iommu);
+ rk_iommu_force_reset(iommu);
+ }
+}
+
static const struct of_device_id rk_iommu_dt_ids[] = {
{ .compatible = "rockchip,iommu" },
{ /* sentinel */ }
@@ -1218,6 +1235,7 @@ MODULE_DEVICE_TABLE(of, rk_iommu_dt_ids);
static struct platform_driver rk_iommu_driver = {
.probe = rk_iommu_probe,
.remove = rk_iommu_remove,
+ .shutdown = rk_iommu_shutdown,
.driver = {
.name = "rk_iommu",
.of_match_table = rk_iommu_dt_ids,