diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index b20c063d0b084380ce122d2be7bee1e351020a82..6c2c49912f1316a4bbec907d22631e05a23c23a2 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -60,6 +60,8 @@ struct hdmi_win_data { unsigned int mode_width; unsigned int mode_height; unsigned int scan_flags; + bool enabled; + bool resume; }; struct mixer_resources { @@ -688,60 +690,6 @@ static int mixer_iommu_on(void *ctx, bool enable) return 0; } -static void mixer_poweron(struct mixer_context *ctx) -{ - struct mixer_resources *res = &ctx->mixer_res; - - DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - - mutex_lock(&ctx->mixer_mutex); - if (ctx->powered) { - mutex_unlock(&ctx->mixer_mutex); - return; - } - ctx->powered = true; - mutex_unlock(&ctx->mixer_mutex); - - pm_runtime_get_sync(ctx->dev); - - clk_enable(res->mixer); - if (ctx->vp_enabled) { - clk_enable(res->vp); - clk_enable(res->sclk_mixer); - } - - mixer_reg_write(res, MXR_INT_EN, ctx->int_en); - mixer_win_reset(ctx); -} - -static void mixer_poweroff(struct mixer_context *ctx) -{ - struct mixer_resources *res = &ctx->mixer_res; - - DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - - mutex_lock(&ctx->mixer_mutex); - if (!ctx->powered) - goto out; - mutex_unlock(&ctx->mixer_mutex); - - ctx->int_en = mixer_reg_read(res, MXR_INT_EN); - - clk_disable(res->mixer); - if (ctx->vp_enabled) { - clk_disable(res->vp); - clk_disable(res->sclk_mixer); - } - - pm_runtime_put_sync(ctx->dev); - - mutex_lock(&ctx->mixer_mutex); - ctx->powered = false; - -out: - mutex_unlock(&ctx->mixer_mutex); -} - static int mixer_enable_vblank(void *ctx, int pipe) { struct mixer_context *mixer_ctx = ctx; @@ -769,27 +717,6 @@ static void mixer_disable_vblank(void *ctx) mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } -static void mixer_dpms(void *ctx, int mode) -{ - struct mixer_context *mixer_ctx = ctx; - - DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - - switch (mode) { - case DRM_MODE_DPMS_ON: - mixer_poweron(mixer_ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - mixer_poweroff(mixer_ctx); - break; - default: - DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); - break; - } -} - static void mixer_win_mode_set(void *ctx, struct exynos_drm_overlay *overlay) { @@ -856,6 +783,8 @@ static void mixer_win_commit(void *ctx, int win) vp_video_buffer(mixer_ctx, win); else mixer_graph_buffer(mixer_ctx, win); + + mixer_ctx->win_data[win].enabled = true; } static void mixer_win_disable(void *ctx, int win) @@ -866,6 +795,14 @@ static void mixer_win_disable(void *ctx, int win) DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); + mutex_lock(&mixer_ctx->mixer_mutex); + if (!mixer_ctx->powered) { + mutex_unlock(&mixer_ctx->mixer_mutex); + mixer_ctx->win_data[win].resume = false; + return; + } + mutex_unlock(&mixer_ctx->mixer_mutex); + spin_lock_irqsave(&res->reg_slock, flags); mixer_vsync_set_update(mixer_ctx, false); @@ -873,6 +810,8 @@ static void mixer_win_disable(void *ctx, int win) mixer_vsync_set_update(mixer_ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); + + mixer_ctx->win_data[win].enabled = false; } static void mixer_wait_for_vblank(void *ctx) @@ -898,6 +837,110 @@ static void mixer_wait_for_vblank(void *ctx) DRM_DEBUG_KMS("vblank wait timed out.\n"); } +static void mixer_window_suspend(struct mixer_context *ctx) +{ + struct hdmi_win_data *win_data; + int i; + + for (i = 0; i < MIXER_WIN_NR; i++) { + win_data = &ctx->win_data[i]; + win_data->resume = win_data->enabled; + mixer_win_disable(ctx, i); + } + mixer_wait_for_vblank(ctx); +} + +static void mixer_window_resume(struct mixer_context *ctx) +{ + struct hdmi_win_data *win_data; + int i; + + for (i = 0; i < MIXER_WIN_NR; i++) { + win_data = &ctx->win_data[i]; + win_data->enabled = win_data->resume; + win_data->resume = false; + } +} + +static void mixer_poweron(struct mixer_context *ctx) +{ + struct mixer_resources *res = &ctx->mixer_res; + + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); + + mutex_lock(&ctx->mixer_mutex); + if (ctx->powered) { + mutex_unlock(&ctx->mixer_mutex); + return; + } + ctx->powered = true; + mutex_unlock(&ctx->mixer_mutex); + + pm_runtime_get_sync(ctx->dev); + + clk_enable(res->mixer); + if (ctx->vp_enabled) { + clk_enable(res->vp); + clk_enable(res->sclk_mixer); + } + + mixer_reg_write(res, MXR_INT_EN, ctx->int_en); + mixer_win_reset(ctx); + + mixer_window_resume(ctx); +} + +static void mixer_poweroff(struct mixer_context *ctx) +{ + struct mixer_resources *res = &ctx->mixer_res; + + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); + + mutex_lock(&ctx->mixer_mutex); + if (!ctx->powered) + goto out; + mutex_unlock(&ctx->mixer_mutex); + + mixer_window_suspend(ctx); + + ctx->int_en = mixer_reg_read(res, MXR_INT_EN); + + clk_disable(res->mixer); + if (ctx->vp_enabled) { + clk_disable(res->vp); + clk_disable(res->sclk_mixer); + } + + pm_runtime_put_sync(ctx->dev); + + mutex_lock(&ctx->mixer_mutex); + ctx->powered = false; + +out: + mutex_unlock(&ctx->mixer_mutex); +} + +static void mixer_dpms(void *ctx, int mode) +{ + struct mixer_context *mixer_ctx = ctx; + + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); + + switch (mode) { + case DRM_MODE_DPMS_ON: + mixer_poweron(mixer_ctx); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + mixer_poweroff(mixer_ctx); + break; + default: + DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); + break; + } +} + static struct exynos_mixer_ops mixer_ops = { /* manager */ .iommu_on = mixer_iommu_on,