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

From: Stephane Viau
Date: Tue Sep 15 2015 - 08:43:46 EST


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@xxxxxxxxxxxxxx>
---
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(+)

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;

/*
--
Qualcomm Innovation Center, Inc.

The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/