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(+)
@@ -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",
@@ -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
@@ -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);