From: Simon Glass <sjg@chromium.org> When expo is being used, it should only redraw the display when it has made changes. Add a new 'manual sync' mode which tells the video subsystem to ignore video syncs from other sources. This also disables the idle feature, since it can interfere with tests. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/video-uclass.c | 35 ++++++++++++++++++++++++ include/video.h | 10 +++++++ test/dm/video.c | 52 ++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index bf633861ef3..f8ba3abc5f4 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -65,11 +65,13 @@ struct cyclic_info; * gd->video_top and works downwards, running out of space when it hits * gd->video_bottom. * @cyc_active: true if cyclic video sync is currently registered + * @manual_sync: true if manual-sync mode is active (caller controls video sync) * @cyc: handle for cyclic-execution function, or NULL if none */ struct video_uc_priv { ulong video_ptr; bool cyc_active; + bool manual_sync; struct cyclic_info cyc; }; @@ -501,9 +503,14 @@ static void video_flush_copy(struct udevice *vid) int video_sync(struct udevice *vid, bool force) { struct video_priv *priv = dev_get_uclass_priv(vid); + struct video_uc_priv *uc_priv = uclass_get_priv(vid->uclass); struct video_ops *ops = video_get_ops(vid); int ret; + /* Skip sync if manual-sync mode is active */ + if (uc_priv->manual_sync) + return 0; + if (IS_ENABLED(CONFIG_VIDEO_COPY)) video_flush_copy(vid); @@ -622,6 +629,20 @@ int video_default_font_height(struct udevice *dev) static void video_idle(struct cyclic_info *cyc) { + struct video_uc_priv *uc_priv; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_VIDEO, &uc); + if (ret) + return; + + uc_priv = uclass_get_priv(uc); + + /* Skip sync if manual-sync mode is active */ + if (uc_priv->manual_sync) + return; + if (CONFIG_IS_ENABLED(CURSOR)) { struct udevice *cons; struct uclass *uc; @@ -809,6 +830,20 @@ __maybe_unused static int video_destroy(struct uclass *uc) return 0; } +void video_set_manual_sync(bool enable) +{ + struct video_uc_priv *uc_priv; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_VIDEO, &uc); + if (ret) + return; + + uc_priv = uclass_get_priv(uc); + uc_priv->manual_sync = enable; +} + UCLASS_DRIVER(video) = { .id = UCLASS_VIDEO, .name = "video", diff --git a/include/video.h b/include/video.h index 3ce603384dc..3f5c8cbd45a 100644 --- a/include/video.h +++ b/include/video.h @@ -543,4 +543,14 @@ static inline bool video_is_visible(void) #endif } +/** + * video_set_manual_sync() - Set manual-sync mode for video subsystem + * + * When manual-sync mode is enabled, automatic video sync operations are + * suppressed to allow the caller to control rendering timing. + * + * @enable: true to enable manual-sync mode, false to disable + */ +void video_set_manual_sync(bool enable); + #endif diff --git a/test/dm/video.c b/test/dm/video.c index 7ada4c75bf7..cee9e528689 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -1293,3 +1293,55 @@ static int dm_test_video_images(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_video_images, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Test manual-sync mode suppresses auto-sync */ +static int dm_test_video_manual_sync(struct unit_test_state *uts) +{ + struct video_priv *priv; + struct udevice *dev, *con; + + ut_assertok(select_vidconsole(uts, "vidconsole0")); + ut_assertok(video_get_nologo(uts, &dev)); + ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); + priv = dev_get_uclass_priv(dev); + + /* Write some text and verify it appears in the framebuffer */ + vidconsole_put_string(con, "Test"); + ut_asserteq(118, video_compress_fb(uts, dev, false)); + + /* Sync to copy buffer before enabling manual-sync mode */ + ut_assertok(video_sync(dev, true)); + + /* Enable manual-sync mode - sync should be suppressed */ + video_set_manual_sync(true); + + /* Clear and write new text - auto-sync should not happen */ + video_clear(dev); + vidconsole_put_string(con, "Manual Sync"); + + /* should do nothing in manual-sync mode */ + ut_assertok(video_sync(dev, false)); + + /* The copy framebuffer should still show old content */ + if (IS_ENABLED(CONFIG_VIDEO_COPY)) { + ut_assertf(memcmp(priv->fb, priv->copy_fb, priv->fb_size), + "Copy fb should not match fb in manual-sync mode"); + } + + /* + * video_sync() with force=true should still do nothing, except of + * course that without a copy framebuffer the string will be present on + * (only) framebuffer + */ + ut_assertok(video_sync(dev, true)); + if (IS_ENABLED(CONFIG_VIDEO_COPY)) { + ut_asserteq(118, video_compress_fb(uts, dev, true)); + ut_assertf(memcmp(priv->fb, priv->copy_fb, priv->fb_size), + "Copy fb should not match fb in manual-sync mode"); + } else { + ut_asserteq(183, video_compress_fb(uts, dev, true)); + } + + return 0; +} +DM_TEST(dm_test_video_manual_sync, UTF_SCAN_PDATA | UTF_SCAN_FDT); -- 2.43.0