Commit db43fd16 authored by Prathyush K's avatar Prathyush K Committed by Inki Dae

drm/exynos: clear windows in mixer dpms off

When mixer is turned off, we disable the clocks which will stop
the dma. Now if we remove the current framebuffer, we cannot
disable the overlay but the current framebuffer will still be freed.
When mixer resumes, the dma will continue from where it left off
and will throw a PAGE FAULT since the memory was freed.

This patch fixes the above problem by disabling the mixer windows
before disabling the mixer clocks. It also keeps track of which
windows were currently active by setting the 'resume' flag. When
mixer resumes, the window with a resume flag set is enabled again.

Now if a current fb is removed when mixer is off, mixer_win_disable
will set the 'resume' flag of that window to zero and return.
So when mixer resumes, that window will not be resumed.
Signed-off-by: default avatarPrathyush K <prathyush.k@samsung.com>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
parent 01ce113c
...@@ -60,6 +60,8 @@ struct hdmi_win_data { ...@@ -60,6 +60,8 @@ struct hdmi_win_data {
unsigned int mode_width; unsigned int mode_width;
unsigned int mode_height; unsigned int mode_height;
unsigned int scan_flags; unsigned int scan_flags;
bool enabled;
bool resume;
}; };
struct mixer_resources { struct mixer_resources {
...@@ -688,60 +690,6 @@ static int mixer_iommu_on(void *ctx, bool enable) ...@@ -688,60 +690,6 @@ static int mixer_iommu_on(void *ctx, bool enable)
return 0; 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) static int mixer_enable_vblank(void *ctx, int pipe)
{ {
struct mixer_context *mixer_ctx = ctx; struct mixer_context *mixer_ctx = ctx;
...@@ -769,27 +717,6 @@ static void mixer_disable_vblank(void *ctx) ...@@ -769,27 +717,6 @@ static void mixer_disable_vblank(void *ctx)
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); 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, static void mixer_win_mode_set(void *ctx,
struct exynos_drm_overlay *overlay) struct exynos_drm_overlay *overlay)
{ {
...@@ -856,6 +783,8 @@ static void mixer_win_commit(void *ctx, int win) ...@@ -856,6 +783,8 @@ static void mixer_win_commit(void *ctx, int win)
vp_video_buffer(mixer_ctx, win); vp_video_buffer(mixer_ctx, win);
else else
mixer_graph_buffer(mixer_ctx, win); mixer_graph_buffer(mixer_ctx, win);
mixer_ctx->win_data[win].enabled = true;
} }
static void mixer_win_disable(void *ctx, int win) static void mixer_win_disable(void *ctx, int win)
...@@ -866,6 +795,14 @@ 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); 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); spin_lock_irqsave(&res->reg_slock, flags);
mixer_vsync_set_update(mixer_ctx, false); mixer_vsync_set_update(mixer_ctx, false);
...@@ -873,6 +810,8 @@ static void mixer_win_disable(void *ctx, int win) ...@@ -873,6 +810,8 @@ static void mixer_win_disable(void *ctx, int win)
mixer_vsync_set_update(mixer_ctx, true); mixer_vsync_set_update(mixer_ctx, true);
spin_unlock_irqrestore(&res->reg_slock, flags); spin_unlock_irqrestore(&res->reg_slock, flags);
mixer_ctx->win_data[win].enabled = false;
} }
static void mixer_wait_for_vblank(void *ctx) static void mixer_wait_for_vblank(void *ctx)
...@@ -898,6 +837,110 @@ 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"); 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 = { static struct exynos_mixer_ops mixer_ops = {
/* manager */ /* manager */
.iommu_on = mixer_iommu_on, .iommu_on = mixer_iommu_on,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment