From 47f42e3653f50ab3db71d754849a89b43a501475 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 2 Nov 2015 20:32:36 +0900 Subject: [PATCH] UPSTREAM: drm/exynos: add pm_runtime to DP Let pm_runtime handle the enabling/disabling of the device with proper refcnt instead of rely on specific flags to track the enabled state. Chnagelog v3: - revive dpms_mode to keep current dpms mode. Changelog v2: - no change (cherry picked from commit 613d3853c2aca6cfd990e8bd0b436833b6c76db6) Change-Id: Ieac8db078030f9331135ff0bc43a3a41d56d3b62 Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae Signed-off-by: Yakir Yang --- drivers/gpu/drm/exynos/exynos_dp_core.c | 51 +++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index e361d4c6692c..2223ba985a0f 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1061,6 +1061,8 @@ static void exynos_dp_bridge_enable(struct drm_bridge *bridge) if (dp->dpms_mode == DRM_MODE_DPMS_ON) return; + pm_runtime_get_sync(dp->dev); + if (dp->panel) { if (drm_panel_prepare(dp->panel)) { DRM_ERROR("failed to setup the panel\n"); @@ -1071,7 +1073,6 @@ static void exynos_dp_bridge_enable(struct drm_bridge *bridge) if (crtc->ops->clock_enable) crtc->ops->clock_enable(dp_to_crtc(dp), true); - clk_prepare_enable(dp->clock); phy_power_on(dp->phy); exynos_dp_init_dp(dp); enable_irq(dp->irq); @@ -1098,7 +1099,6 @@ static void exynos_dp_bridge_disable(struct drm_bridge *bridge) disable_irq(dp->irq); flush_work(&dp->hotplug_work); phy_power_off(dp->phy); - clk_disable_unprepare(dp->clock); if (crtc->ops->clock_enable) crtc->ops->clock_enable(dp_to_crtc(dp), false); @@ -1108,6 +1108,8 @@ static void exynos_dp_bridge_disable(struct drm_bridge *bridge) DRM_ERROR("failed to turnoff the panel\n"); } + pm_runtime_put_sync(dp->dev); + dp->dpms_mode = DRM_MODE_DPMS_OFF; } @@ -1392,6 +1394,7 @@ static int exynos_dp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *panel_node, *bridge_node, *endpoint; struct exynos_dp_device *dp; + int ret; dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), GFP_KERNEL); @@ -1420,16 +1423,57 @@ static int exynos_dp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - return component_add(&pdev->dev, &exynos_dp_ops); + pm_runtime_enable(dev); + + ret = component_add(&pdev->dev, &exynos_dp_ops); + if (ret) + goto err_disable_pm_runtime; + + return ret; + +err_disable_pm_runtime: + pm_runtime_disable(dev); + + return ret; } static int exynos_dp_remove(struct platform_device *pdev) { + pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &exynos_dp_ops); return 0; } +#ifdef CONFIG_PM +static int exynos_dp_suspend(struct device *dev) +{ + struct exynos_dp_device *dp = dev_get_drvdata(dev); + + clk_disable_unprepare(dp->clock); + + return 0; +} + +static int exynos_dp_resume(struct device *dev) +{ + struct exynos_dp_device *dp = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(dp->clock); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops exynos_dp_pm_ops = { + SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL) +}; + static const struct of_device_id exynos_dp_match[] = { { .compatible = "samsung,exynos5-dp" }, {}, @@ -1442,6 +1486,7 @@ struct platform_driver dp_driver = { .driver = { .name = "exynos-dp", .owner = THIS_MODULE, + .pm = &exynos_dp_pm_ops, .of_match_table = exynos_dp_match, }, }; -- 2.34.1