Skip to content

Commit 6a3b45a

Browse files
Andrzej Hajdadaeinki
Andrzej Hajda
authored andcommitted
drm/exynos/mixer: fix MIXER shadow registry synchronisation code
MIXER on Exynos5 SoCs uses different synchronisation method than Exynos4 to update internal state (shadow registers). Apparently the driver implements it incorrectly. The rule should be as follows: - do not request updating registers until previous request was finished, ie. MXR_CFG_LAYER_UPDATE_COUNT must be 0. - before setting registers synchronisation on VSYNC should be turned off, ie. MXR_STATUS_SYNC_ENABLE should be reset, - after finishing MXR_STATUS_SYNC_ENABLE should be set again. The patch hopefully implements it correctly. Below sample kernel log from page fault caused by the bug: [ 25.670038] exynos-sysmmu 14650000.sysmmu: 14450000.mixer: PAGE FAULT occurred at 0x2247b800 [ 25.677888] ------------[ cut here ]------------ [ 25.682164] kernel BUG at ../drivers/iommu/exynos-iommu.c:450! [ 25.687971] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [ 25.693778] Modules linked in: [ 25.696816] CPU: 5 PID: 1553 Comm: fb-release_test Not tainted 5.0.0-rc7-01157-g5f86b1566bdd #136 [ 25.705646] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 25.711710] PC is at exynos_sysmmu_irq+0x1c0/0x264 [ 25.716470] LR is at lock_is_held_type+0x44/0x64 v2: added missing MXR_CFG_LAYER_UPDATE bit setting in mixer_enable_sync Reported-by: Marian Mihailescu <[email protected]> Signed-off-by: Andrzej Hajda <[email protected]> Signed-off-by: Inki Dae <[email protected]>
1 parent 9e98c67 commit 6a3b45a

File tree

1 file changed

+66
-44
lines changed

1 file changed

+66
-44
lines changed

drivers/gpu/drm/exynos/exynos_mixer.c

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "regs-vp.h"
2121

2222
#include <linux/kernel.h>
23+
#include <linux/ktime.h>
2324
#include <linux/spinlock.h>
2425
#include <linux/wait.h>
2526
#include <linux/i2c.h>
@@ -352,15 +353,62 @@ static void mixer_cfg_vp_blend(struct mixer_context *ctx, unsigned int alpha)
352353
mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
353354
}
354355

355-
static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
356+
static bool mixer_is_synced(struct mixer_context *ctx)
356357
{
357-
/* block update on vsync */
358-
mixer_reg_writemask(ctx, MXR_STATUS, enable ?
359-
MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
358+
u32 base, shadow;
360359

360+
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
361+
ctx->mxr_ver == MXR_VER_128_0_0_184)
362+
return !(mixer_reg_read(ctx, MXR_CFG) &
363+
MXR_CFG_LAYER_UPDATE_COUNT_MASK);
364+
365+
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
366+
vp_reg_read(ctx, VP_SHADOW_UPDATE))
367+
return false;
368+
369+
base = mixer_reg_read(ctx, MXR_CFG);
370+
shadow = mixer_reg_read(ctx, MXR_CFG_S);
371+
if (base != shadow)
372+
return false;
373+
374+
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
375+
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
376+
if (base != shadow)
377+
return false;
378+
379+
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
380+
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
381+
if (base != shadow)
382+
return false;
383+
384+
return true;
385+
}
386+
387+
static int mixer_wait_for_sync(struct mixer_context *ctx)
388+
{
389+
ktime_t timeout = ktime_add_us(ktime_get(), 100000);
390+
391+
while (!mixer_is_synced(ctx)) {
392+
usleep_range(1000, 2000);
393+
if (ktime_compare(ktime_get(), timeout) > 0)
394+
return -ETIMEDOUT;
395+
}
396+
return 0;
397+
}
398+
399+
static void mixer_disable_sync(struct mixer_context *ctx)
400+
{
401+
mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_SYNC_ENABLE);
402+
}
403+
404+
static void mixer_enable_sync(struct mixer_context *ctx)
405+
{
406+
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
407+
ctx->mxr_ver == MXR_VER_128_0_0_184)
408+
mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
409+
mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SYNC_ENABLE);
361410
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
362-
vp_reg_write(ctx, VP_SHADOW_UPDATE, enable ?
363-
VP_SHADOW_UPDATE_ENABLE : 0);
411+
vp_reg_write(ctx, VP_SHADOW_UPDATE, VP_SHADOW_UPDATE_ENABLE);
364412
}
365413

366414
static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
@@ -498,7 +546,6 @@ static void vp_video_buffer(struct mixer_context *ctx,
498546

499547
spin_lock_irqsave(&ctx->reg_slock, flags);
500548

501-
vp_reg_write(ctx, VP_SHADOW_UPDATE, 1);
502549
/* interlace or progressive scan mode */
503550
val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
504551
vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
@@ -553,11 +600,6 @@ static void vp_video_buffer(struct mixer_context *ctx,
553600
vp_regs_dump(ctx);
554601
}
555602

556-
static void mixer_layer_update(struct mixer_context *ctx)
557-
{
558-
mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
559-
}
560-
561603
static void mixer_graph_buffer(struct mixer_context *ctx,
562604
struct exynos_drm_plane *plane)
563605
{
@@ -640,11 +682,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
640682
mixer_cfg_layer(ctx, win, priority, true);
641683
mixer_cfg_gfx_blend(ctx, win, pixel_alpha, state->base.alpha);
642684

643-
/* layer update mandatory for mixer 16.0.33.0 */
644-
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
645-
ctx->mxr_ver == MXR_VER_128_0_0_184)
646-
mixer_layer_update(ctx);
647-
648685
spin_unlock_irqrestore(&ctx->reg_slock, flags);
649686

650687
mixer_regs_dump(ctx);
@@ -709,7 +746,7 @@ static void mixer_win_reset(struct mixer_context *ctx)
709746
static irqreturn_t mixer_irq_handler(int irq, void *arg)
710747
{
711748
struct mixer_context *ctx = arg;
712-
u32 val, base, shadow;
749+
u32 val;
713750

714751
spin_lock(&ctx->reg_slock);
715752

@@ -723,26 +760,9 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
723760
val &= ~MXR_INT_STATUS_VSYNC;
724761

725762
/* interlace scan need to check shadow register */
726-
if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
727-
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
728-
vp_reg_read(ctx, VP_SHADOW_UPDATE))
729-
goto out;
730-
731-
base = mixer_reg_read(ctx, MXR_CFG);
732-
shadow = mixer_reg_read(ctx, MXR_CFG_S);
733-
if (base != shadow)
734-
goto out;
735-
736-
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
737-
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
738-
if (base != shadow)
739-
goto out;
740-
741-
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
742-
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
743-
if (base != shadow)
744-
goto out;
745-
}
763+
if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)
764+
&& !mixer_is_synced(ctx))
765+
goto out;
746766

747767
drm_crtc_handle_vblank(&ctx->crtc->base);
748768
}
@@ -917,12 +937,14 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
917937

918938
static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
919939
{
920-
struct mixer_context *mixer_ctx = crtc->ctx;
940+
struct mixer_context *ctx = crtc->ctx;
921941

922-
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
942+
if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
923943
return;
924944

925-
mixer_vsync_set_update(mixer_ctx, false);
945+
if (mixer_wait_for_sync(ctx))
946+
dev_err(ctx->dev, "timeout waiting for VSYNC\n");
947+
mixer_disable_sync(ctx);
926948
}
927949

928950
static void mixer_update_plane(struct exynos_drm_crtc *crtc,
@@ -964,7 +986,7 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
964986
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
965987
return;
966988

967-
mixer_vsync_set_update(mixer_ctx, true);
989+
mixer_enable_sync(mixer_ctx);
968990
exynos_crtc_handle_event(crtc);
969991
}
970992

@@ -979,7 +1001,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
9791001

9801002
exynos_drm_pipe_clk_enable(crtc, true);
9811003

982-
mixer_vsync_set_update(ctx, false);
1004+
mixer_disable_sync(ctx);
9831005

9841006
mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
9851007

@@ -992,7 +1014,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
9921014

9931015
mixer_commit(ctx);
9941016

995-
mixer_vsync_set_update(ctx, true);
1017+
mixer_enable_sync(ctx);
9961018

9971019
set_bit(MXR_BIT_POWERED, &ctx->flags);
9981020
}

0 commit comments

Comments
 (0)