@@ -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:
@@ -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) {
@@ -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;
/*
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(+)