diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c index 9c34d7824988654ab2f8366741724da8ac18b82a..f2a0db7a8a031d7ee308139e71aca8b47663663b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c @@ -31,6 +31,10 @@ struct msm_mdss { struct regulator *vdd; + struct clk *ahb_clk; + struct clk *axi_clk; + struct clk *vsync_clk; + struct { volatile unsigned long enabled_mask; struct irq_domain *domain; @@ -140,6 +144,51 @@ static int mdss_irq_domain_init(struct msm_mdss *mdss) return 0; } +int msm_mdss_enable(struct msm_mdss *mdss) +{ + DBG(""); + + clk_prepare_enable(mdss->ahb_clk); + if (mdss->axi_clk) + clk_prepare_enable(mdss->axi_clk); + if (mdss->vsync_clk) + clk_prepare_enable(mdss->vsync_clk); + + return 0; +} + +int msm_mdss_disable(struct msm_mdss *mdss) +{ + DBG(""); + + if (mdss->vsync_clk) + clk_disable_unprepare(mdss->vsync_clk); + if (mdss->axi_clk) + clk_disable_unprepare(mdss->axi_clk); + clk_disable_unprepare(mdss->ahb_clk); + + return 0; +} + +static int msm_mdss_get_clocks(struct msm_mdss *mdss) +{ + struct platform_device *pdev = to_platform_device(mdss->dev->dev); + + mdss->ahb_clk = msm_clk_get(pdev, "iface"); + if (IS_ERR(mdss->ahb_clk)) + mdss->ahb_clk = NULL; + + mdss->axi_clk = msm_clk_get(pdev, "bus"); + if (IS_ERR(mdss->axi_clk)) + mdss->axi_clk = NULL; + + mdss->vsync_clk = msm_clk_get(pdev, "vsync"); + if (IS_ERR(mdss->vsync_clk)) + mdss->vsync_clk = NULL; + + return 0; +} + void msm_mdss_destroy(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; @@ -153,8 +202,6 @@ void msm_mdss_destroy(struct drm_device *dev) regulator_disable(mdss->vdd); - pm_runtime_put_sync(dev->dev); - pm_runtime_disable(dev->dev); } @@ -190,6 +237,12 @@ int msm_mdss_init(struct drm_device *dev) goto fail; } + ret = msm_mdss_get_clocks(mdss); + if (ret) { + dev_err(dev->dev, "failed to get clocks: %d\n", ret); + goto fail; + } + /* Regulator to enable GDSCs in downstream kernels */ mdss->vdd = devm_regulator_get(dev->dev, "vdd"); if (IS_ERR(mdss->vdd)) { @@ -221,12 +274,6 @@ int msm_mdss_init(struct drm_device *dev) pm_runtime_enable(dev->dev); - /* - * TODO: This is needed as the MDSS GDSC is only tied to MDSS's power - * domain. Remove this once runtime PM is adapted for all the devices. - */ - pm_runtime_get_sync(dev->dev); - return 0; fail_irq: regulator_disable(mdss->vdd); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f49f6ac5585c4ff7aabf1ecf7fe3c9d61a4de4ee..a19c393f7e45ef2199576fb4db7b1d5913e1f3b6 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -879,8 +879,37 @@ static int msm_pm_resume(struct device *dev) } #endif +#ifdef CONFIG_PM +static int msm_runtime_suspend(struct device *dev) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev->dev_private; + + DBG(""); + + if (priv->mdss) + return msm_mdss_disable(priv->mdss); + + return 0; +} + +static int msm_runtime_resume(struct device *dev) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev->dev_private; + + DBG(""); + + if (priv->mdss) + return msm_mdss_enable(priv->mdss); + + return 0; +} +#endif + static const struct dev_pm_ops msm_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume) + SET_RUNTIME_PM_OPS(msm_runtime_suspend, msm_runtime_resume, NULL) }; /* diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index a8f2ba5e5f077a923224a82cca7c2e014d869f92..17d5824417ad32a0fbddaf94069a0bb453c8403c 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -99,5 +99,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); int msm_mdss_init(struct drm_device *dev); void msm_mdss_destroy(struct drm_device *dev); +int msm_mdss_enable(struct msm_mdss *mdss); +int msm_mdss_disable(struct msm_mdss *mdss); #endif /* __MSM_KMS_H__ */