drm/exynos: clear windows in mixer dpms off
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / exynos / exynos_mixer.c
index b20c063d0b084380ce122d2be7bee1e351020a82..6c2c49912f1316a4bbec907d22631e05a23c23a2 100644 (file)
@@ -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,