diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index ca83139cd309..b6a737d196ae 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -158,7 +158,8 @@ static void fimd_dpms(struct device *subdrv_dev, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - pm_runtime_put_sync(subdrv_dev); + if (!ctx->suspended) + pm_runtime_put_sync(subdrv_dev); break; default: DRM_DEBUG_KMS("unspecified mode %d\n", mode); @@ -734,6 +735,46 @@ static void fimd_clear_win(struct fimd_context *ctx, int win) writel(val, ctx->regs + SHADOWCON); } +static int fimd_power_on(struct fimd_context *ctx, bool enable) +{ + struct exynos_drm_subdrv *subdrv = &ctx->subdrv; + struct device *dev = subdrv->manager.dev; + + DRM_DEBUG_KMS("%s\n", __FILE__); + + if (enable != false && enable != true) + return -EINVAL; + + if (enable) { + int ret; + + ret = clk_enable(ctx->bus_clk); + if (ret < 0) + return ret; + + ret = clk_enable(ctx->lcd_clk); + if (ret < 0) { + clk_disable(ctx->bus_clk); + return ret; + } + + ctx->suspended = false; + + /* if vblank was enabled status, enable it again. */ + if (test_and_clear_bit(0, &ctx->irq_flags)) + fimd_enable_vblank(dev); + + fimd_apply(dev); + } else { + clk_disable(ctx->lcd_clk); + clk_disable(ctx->bus_clk); + + ctx->suspended = true; + } + + return 0; +} + static int __devinit fimd_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -911,39 +952,30 @@ out: #ifdef CONFIG_PM_SLEEP static int fimd_suspend(struct device *dev) { - int ret; + struct fimd_context *ctx = get_fimd_context(dev); if (pm_runtime_suspended(dev)) return 0; - ret = pm_runtime_suspend(dev); - if (ret < 0) - return ret; - - return 0; + /* + * do not use pm_runtime_suspend(). if pm_runtime_suspend() is + * called here, an error would be returned by that interface + * because the usage_count of pm runtime is more than 1. + */ + return fimd_power_on(ctx, false); } static int fimd_resume(struct device *dev) { - int ret; + struct fimd_context *ctx = get_fimd_context(dev); - ret = pm_runtime_resume(dev); - if (ret < 0) { - DRM_ERROR("failed to resume runtime pm.\n"); - return ret; - } - - pm_runtime_disable(dev); - - ret = pm_runtime_set_active(dev); - if (ret < 0) { - DRM_ERROR("failed to active runtime pm.\n"); - pm_runtime_enable(dev); - pm_runtime_suspend(dev); - return ret; - } - - pm_runtime_enable(dev); + /* + * if entered to sleep when lcd panel was on, the usage_count + * of pm runtime would still be 1 so in this case, fimd driver + * should be on directly not drawing on pm runtime interface. + */ + if (!pm_runtime_suspended(dev)) + return fimd_power_on(ctx, true); return 0; } @@ -956,39 +988,16 @@ static int fimd_runtime_suspend(struct device *dev) DRM_DEBUG_KMS("%s\n", __FILE__); - clk_disable(ctx->lcd_clk); - clk_disable(ctx->bus_clk); - - ctx->suspended = true; - return 0; + return fimd_power_on(ctx, false); } static int fimd_runtime_resume(struct device *dev) { struct fimd_context *ctx = get_fimd_context(dev); - int ret; DRM_DEBUG_KMS("%s\n", __FILE__); - ret = clk_enable(ctx->bus_clk); - if (ret < 0) - return ret; - - ret = clk_enable(ctx->lcd_clk); - if (ret < 0) { - clk_disable(ctx->bus_clk); - return ret; - } - - ctx->suspended = false; - - /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) - fimd_enable_vblank(dev); - - fimd_apply(dev); - - return 0; + return fimd_power_on(ctx, true); } #endif