diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index acbab7494de4..3c16222b8890 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -26,6 +26,47 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev, return 0; } +/* + * Get and enable the IOMMU clocks so that we can make + * sure they stay on the entire duration so that we can + * safely change the pagetable from the GPU + */ +static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + struct device *dev; + struct property *prop; + const char *name; + int i = 0; + + if (WARN_ON(!pdev)) + return; + + dev = &pdev->dev; + + iommu->nr_clocks = + of_property_count_strings(dev->of_node, "clock-names"); + + if (iommu->nr_clocks < 0) { + iommu->nr_clocks = 0; + return; + } + + if (WARN_ON(iommu->nr_clocks > ARRAY_SIZE(iommu->clocks))) + iommu->nr_clocks = ARRAY_SIZE(iommu->clocks); + + of_property_for_each_string(dev->of_node, "clock-names", prop, name) { + if (i == iommu->nr_clocks) + break; + + iommu->clocks[i] = clk_get(dev, name); + if (iommu->clocks[i]) + clk_prepare_enable(iommu->clocks[i]); + + i++; + } +} + static int _attach_iommu_device(struct msm_mmu *mmu, struct iommu_domain *domain, const char **names, int cnt) { @@ -58,7 +99,11 @@ static int _attach_iommu_device(struct msm_mmu *mmu, if (!pdev) continue; + _get_iommu_clocks(mmu, + of_find_device_by_node(node->parent)); + mmu->dev = &pdev->dev; + return iommu_attach_device(domain, mmu->dev); } } @@ -128,6 +173,19 @@ static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names, } static void msm_iommu_detach(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + int i; + + iommu_detach_device(iommu->domain, mmu->dev); + + for (i = 0; i < iommu->nr_clocks; i++) { + if (iommu->clocks[i]) + clk_disable(iommu->clocks[i]); + } +} + +static void msm_iommu_detach_dynamic(struct msm_mmu *mmu) { struct msm_iommu *iommu = to_msm_iommu(mmu); iommu_detach_device(iommu->domain, mmu->dev); @@ -216,7 +274,7 @@ static const struct msm_mmu_funcs funcs = { static const struct msm_mmu_funcs dynamic_funcs = { .attach = msm_iommu_attach_dynamic, - .detach = msm_iommu_detach, + .detach = msm_iommu_detach_dynamic, .map = msm_iommu_map, .unmap = msm_iommu_unmap, .destroy = msm_iommu_destroy, diff --git a/drivers/gpu/drm/msm/msm_iommu.h b/drivers/gpu/drm/msm/msm_iommu.h index bfb75015efbc..d005cfb9758f 100644 --- a/drivers/gpu/drm/msm/msm_iommu.h +++ b/drivers/gpu/drm/msm/msm_iommu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,6 +22,9 @@ struct msm_iommu { phys_addr_t ttbr0; uint32_t contextidr; bool allow_dynamic; + + struct clk *clocks[5]; + int nr_clocks; }; #define to_msm_iommu(x) container_of(x, struct msm_iommu, base)