Skip to content

Commit 41b1234

Browse files
Andrzej Hajdagregkh
authored andcommitted
drm/exynos/mixer: fix MIXER shadow registry synchronisation code
[ Upstream commit 6a3b45a ] 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 torvalds#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 <mihailescu2m@gmail.com> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent bde271d commit 41b1234

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>
@@ -337,15 +338,62 @@ static void mixer_cfg_vp_blend(struct mixer_context *ctx)
337338
mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
338339
}
339340

340-
static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
341+
static bool mixer_is_synced(struct mixer_context *ctx)
341342
{
342-
/* block update on vsync */
343-
mixer_reg_writemask(ctx, MXR_STATUS, enable ?
344-
MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
343+
u32 base, shadow;
345344

345+
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
346+
ctx->mxr_ver == MXR_VER_128_0_0_184)
347+
return !(mixer_reg_read(ctx, MXR_CFG) &
348+
MXR_CFG_LAYER_UPDATE_COUNT_MASK);
349+
350+
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
351+
vp_reg_read(ctx, VP_SHADOW_UPDATE))
352+
return false;
353+
354+
base = mixer_reg_read(ctx, MXR_CFG);
355+
shadow = mixer_reg_read(ctx, MXR_CFG_S);
356+
if (base != shadow)
357+
return false;
358+
359+
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
360+
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
361+
if (base != shadow)
362+
return false;
363+
364+
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
365+
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
366+
if (base != shadow)
367+
return false;
368+
369+
return true;
370+
}
371+
372+
static int mixer_wait_for_sync(struct mixer_context *ctx)
373+
{
374+
ktime_t timeout = ktime_add_us(ktime_get(), 100000);
375+
376+
while (!mixer_is_synced(ctx)) {
377+
usleep_range(1000, 2000);
378+
if (ktime_compare(ktime_get(), timeout) > 0)
379+
return -ETIMEDOUT;
380+
}
381+
return 0;
382+
}
383+
384+
static void mixer_disable_sync(struct mixer_context *ctx)
385+
{
386+
mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_SYNC_ENABLE);
387+
}
388+
389+
static void mixer_enable_sync(struct mixer_context *ctx)
390+
{
391+
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
392+
ctx->mxr_ver == MXR_VER_128_0_0_184)
393+
mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
394+
mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SYNC_ENABLE);
346395
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
347-
vp_reg_write(ctx, VP_SHADOW_UPDATE, enable ?
348-
VP_SHADOW_UPDATE_ENABLE : 0);
396+
vp_reg_write(ctx, VP_SHADOW_UPDATE, VP_SHADOW_UPDATE_ENABLE);
349397
}
350398

351399
static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
@@ -482,7 +530,6 @@ static void vp_video_buffer(struct mixer_context *ctx,
482530

483531
spin_lock_irqsave(&ctx->reg_slock, flags);
484532

485-
vp_reg_write(ctx, VP_SHADOW_UPDATE, 1);
486533
/* interlace or progressive scan mode */
487534
val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
488535
vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
@@ -537,11 +584,6 @@ static void vp_video_buffer(struct mixer_context *ctx,
537584
vp_regs_dump(ctx);
538585
}
539586

540-
static void mixer_layer_update(struct mixer_context *ctx)
541-
{
542-
mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
543-
}
544-
545587
static void mixer_graph_buffer(struct mixer_context *ctx,
546588
struct exynos_drm_plane *plane)
547589
{
@@ -618,11 +660,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
618660
mixer_cfg_layer(ctx, win, priority, true);
619661
mixer_cfg_gfx_blend(ctx, win, fb->format->has_alpha);
620662

621-
/* layer update mandatory for mixer 16.0.33.0 */
622-
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
623-
ctx->mxr_ver == MXR_VER_128_0_0_184)
624-
mixer_layer_update(ctx);
625-
626663
spin_unlock_irqrestore(&ctx->reg_slock, flags);
627664

628665
mixer_regs_dump(ctx);
@@ -687,7 +724,7 @@ static void mixer_win_reset(struct mixer_context *ctx)
687724
static irqreturn_t mixer_irq_handler(int irq, void *arg)
688725
{
689726
struct mixer_context *ctx = arg;
690-
u32 val, base, shadow;
727+
u32 val;
691728

692729
spin_lock(&ctx->reg_slock);
693730

@@ -701,26 +738,9 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
701738
val &= ~MXR_INT_STATUS_VSYNC;
702739

703740
/* interlace scan need to check shadow register */
704-
if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
705-
if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
706-
vp_reg_read(ctx, VP_SHADOW_UPDATE))
707-
goto out;
708-
709-
base = mixer_reg_read(ctx, MXR_CFG);
710-
shadow = mixer_reg_read(ctx, MXR_CFG_S);
711-
if (base != shadow)
712-
goto out;
713-
714-
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
715-
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
716-
if (base != shadow)
717-
goto out;
718-
719-
base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
720-
shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
721-
if (base != shadow)
722-
goto out;
723-
}
741+
if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)
742+
&& !mixer_is_synced(ctx))
743+
goto out;
724744

725745
drm_crtc_handle_vblank(&ctx->crtc->base);
726746
}
@@ -895,12 +915,14 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
895915

896916
static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
897917
{
898-
struct mixer_context *mixer_ctx = crtc->ctx;
918+
struct mixer_context *ctx = crtc->ctx;
899919

900-
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
920+
if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
901921
return;
902922

903-
mixer_vsync_set_update(mixer_ctx, false);
923+
if (mixer_wait_for_sync(ctx))
924+
dev_err(ctx->dev, "timeout waiting for VSYNC\n");
925+
mixer_disable_sync(ctx);
904926
}
905927

906928
static void mixer_update_plane(struct exynos_drm_crtc *crtc,
@@ -942,7 +964,7 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
942964
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
943965
return;
944966

945-
mixer_vsync_set_update(mixer_ctx, true);
967+
mixer_enable_sync(mixer_ctx);
946968
exynos_crtc_handle_event(crtc);
947969
}
948970

@@ -957,7 +979,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
957979

958980
exynos_drm_pipe_clk_enable(crtc, true);
959981

960-
mixer_vsync_set_update(ctx, false);
982+
mixer_disable_sync(ctx);
961983

962984
mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
963985

@@ -970,7 +992,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
970992

971993
mixer_commit(ctx);
972994

973-
mixer_vsync_set_update(ctx, true);
995+
mixer_enable_sync(ctx);
974996

975997
set_bit(MXR_BIT_POWERED, &ctx->flags);
976998
}

0 commit comments

Comments
 (0)