[05/10] drm/msm/mdp5: Vote for SMMU power when performing translations
diff mbox

Message ID 1442320913-3248-6-git-send-email-sviau@codeaurora.org
State New
Headers show

Commit Message

Stephane Viau Sept. 15, 2015, 12:41 p.m. UTC
On most recent chipsets, clients need to vote for SMMU power
(regulator and clock) themselves for as long as they want the
SMMU to be on, performing translations.

This change enables (disables) the SMMU power just before
attaching (after detaching) MDP5 device to the SMMU.

Signed-off-by: Stephane Viau <sviau@codeaurora.org>
---
 Documentation/devicetree/bindings/drm/msm/mdp.txt |  3 ++
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c           | 65 +++++++++++++++++++++++
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h           |  3 ++
 3 files changed, 71 insertions(+)

Patch
diff mbox

diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt
index 0833eda..99ba764 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdp.txt
@@ -19,6 +19,9 @@  Optional properties:
 - gpus: phandle for gpu device
 - clock-names: the following clocks are optional:
   * "lut_clk"
+  * "iommu_clk"
+  * "mmagic_clk"
+- mmagic-supply: phandle for mmagic GDSC regulator used during IOMMU translation
 
 Example:
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index 61fcb41..983bd53 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -129,6 +129,54 @@  static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
 		mdp5_crtc_cancel_pending_flip(priv->crtcs[i], file);
 }
 
+static int mdp5_translation_ctrl_pwr(struct mdp5_kms *mdp5_kms, bool on)
+{
+	struct device *dev = mdp5_kms->dev->dev;
+	int ret;
+
+	if (on) {
+		if (mdp5_kms->mmagic) {
+			ret = regulator_enable(mdp5_kms->mmagic);
+			if (ret) {
+				dev_err(dev, "failed to enable mmagic GDSC: %d\n", ret);
+				return ret;
+			}
+		}
+		if (mdp5_kms->mmagic_clk) {
+			clk_prepare_enable(mdp5_kms->mmagic_clk);
+			if (ret) {
+				dev_err(dev, "failed to enable mmagic_clk\n");
+				goto undo_gdsc;
+			}
+		}
+		if (mdp5_kms->iommu_clk) {
+			ret = clk_prepare_enable(mdp5_kms->iommu_clk);
+			if (ret) {
+				dev_err(dev, "failed to enable iommu_clk\n");
+				goto undo_mmagic_clk;
+			}
+		}
+	} else {
+		if (mdp5_kms->iommu_clk)
+			clk_disable_unprepare(mdp5_kms->iommu_clk);
+		if (mdp5_kms->mmagic_clk)
+			clk_disable_unprepare(mdp5_kms->mmagic_clk);
+		if (mdp5_kms->mmagic)
+			regulator_disable(mdp5_kms->mmagic);
+	}
+
+	return 0;
+
+undo_mmagic_clk:
+	if (mdp5_kms->mmagic_clk)
+		clk_disable_unprepare(mdp5_kms->mmagic_clk);
+undo_gdsc:
+	if (mdp5_kms->mmagic)
+		regulator_disable(mdp5_kms->mmagic);
+
+	return ret;
+}
+
 static void mdp5_destroy(struct msm_kms *kms)
 {
 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
@@ -138,6 +186,7 @@  static void mdp5_destroy(struct msm_kms *kms)
 
 	if (mmu) {
 		mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports));
+		mdp5_translation_ctrl_pwr(mdp5_kms, false);
 		mmu->funcs->destroy(mmu);
 	}
 
@@ -520,6 +569,13 @@  struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 		goto fail;
 	}
 
+	mdp5_kms->mmagic = devm_regulator_get_optional(&pdev->dev, "mmagic");
+	if (IS_ERR(mdp5_kms->mmagic)) {
+		ret = PTR_ERR(mdp5_kms->mmagic);
+		DBG("failed to get mmagic GDSC regulator: %d\n", ret);
+		mdp5_kms->mmagic = NULL;
+	}
+
 	/* mandatory clocks: */
 	ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk", true);
 	if (ret)
@@ -539,6 +595,8 @@  struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 
 	/* optional clocks: */
 	get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk", false);
+	get_clk(pdev, &mdp5_kms->mmagic_clk, "mmagic_clk", false);
+	get_clk(pdev, &mdp5_kms->iommu_clk, "iommu_clk", false);
 
 	/* we need to set a default rate before enabling.  Set a safe
 	 * rate first, then figure out hw revision, and then set a
@@ -612,6 +670,13 @@  struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 			DBG("coherent hardware translation table walks is off");
 		}
 
+		ret = mdp5_translation_ctrl_pwr(mdp5_kms, true);
+		if (ret) {
+			dev_err(dev->dev, "failed to power iommu: %d\n", ret);
+			mmu->funcs->destroy(mmu);
+			goto fail;
+		}
+
 		ret = mmu->funcs->attach(mmu, iommu_ports,
 				ARRAY_SIZE(iommu_ports));
 		if (ret) {
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index 1e1a6b0..ab19d52a 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -44,12 +44,15 @@  struct mdp5_kms {
 	void __iomem *mmio, *vbif;
 
 	struct regulator *vdd;
+	struct regulator *mmagic;
 
 	struct clk *axi_clk;
 	struct clk *ahb_clk;
 	struct clk *src_clk;
 	struct clk *core_clk;
 	struct clk *lut_clk;
+	struct clk *mmagic_clk;
+	struct clk *iommu_clk;
 	struct clk *vsync_clk;
 
 	/*