]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
video: Use cyclic to handle video sync
authorSimon Glass <sjg@chromium.org>
Wed, 31 Jul 2024 14:44:10 +0000 (08:44 -0600)
committerAnatolij Gustschin <agust@denx.de>
Wed, 31 Jul 2024 14:54:09 +0000 (16:54 +0200)
At present U-Boot flushes the cache after every character written to
the display. This makes the command-line slower, to the point that
pasting in long strings can fail.

Add a cyclic function to sync the display every 10ms. Enable this by
default.

Allow much longer times for sandbox, since the SDL display is quite
slow.

Avoid size growth if the feature is disabled by making the new init and
destroy functions dependent on CYCLIC being enabled.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/video/Kconfig
drivers/video/video-uclass.c

index 7808ae7919e073fa125a488ce5e8fc5cc2b9e14a..6e79694fd192bed12bd01853bcb0d15df40dfcad 100644 (file)
@@ -7,6 +7,7 @@ menu "Graphics support"
 config VIDEO
        bool "Enable driver model support for LCD/video"
        depends on DM
+       imply CYCLIC
        help
          This enables driver model for LCD and video devices. These support
          a bitmap display of various sizes and depths which can be drawn on
@@ -14,6 +15,11 @@ config VIDEO
          option compiles in the video uclass and routes all LCD/video access
          through this.
 
+         If CYCLIC is enabled (which it is by default), the cyclic subsystem
+         is used to flush pending output to the display periodically, rather
+         than this happening with every chunk of output. This allows for more
+         efficient operation and faster display output.
+
 if VIDEO
 
 config VIDEO_FONT_4X6
@@ -232,6 +238,35 @@ config NO_FB_CLEAR
          loads takes over the screen.  This, for example, can be used to
          keep splash image on screen until grub graphical boot menu starts.
 
+config VIDEO_SYNC_MS
+       int "Video-sync period in milliseconds for foreground processing"
+       default 300 if SANDBOX
+       default 100
+       help
+         This sets the requested, maximum time before a video sync will take
+         place, in milliseconds. Note that the time between video syncs
+         may be longer than this, since syncs only happen when the video system
+         is used, e.g. by outputting a character to the console.
+
+         It may also be shorter, since the video uclass will automatically
+         force a sync in certain situations.
+
+         Many video-output systems require a sync operation before any output
+         is visible. This may flush the CPU cache or perhaps copy the
+         display contents to a hardware framebuffer. Without this, change to
+         the video may never be displayed.
+
+config VIDEO_SYNC_CYCLIC_MS
+       int "Video-sync period in milliseconds for cyclic processing"
+       depends on CYCLIC
+       default 100 if SANDBOX
+       default 10
+       help
+         This sets the frequency of cyclic video syncs. The cyclic system is
+         used to ensure that when U-Boot is idle, it syncs the video. This
+         improves the responsiveness of the command line to new characters
+         being entered.
+
 config PANEL
        bool "Enable panel uclass support"
        default y
index a95b5f199dcddef9acc44a25e9335e7451824473..a5aa8dd52954af81df9adb44111ccd8b523d0e64 100644 (file)
@@ -8,6 +8,7 @@
 #include <bloblist.h>
 #include <console.h>
 #include <cpu_func.h>
+#include <cyclic.h>
 #include <dm.h>
 #include <log.h>
 #include <malloc.h>
@@ -52,6 +53,8 @@
  */
 DECLARE_GLOBAL_DATA_PTR;
 
+struct cyclic_info;
+
 /**
  * struct video_uc_priv - Information for the video uclass
  *
@@ -60,9 +63,12 @@ DECLARE_GLOBAL_DATA_PTR;
  *     available address to use for a device's framebuffer. It starts at
  *     gd->video_top and works downwards, running out of space when it hits
  *     gd->video_bottom.
+ * @cyc: handle for cyclic-execution function, or NULL if none
  */
 struct video_uc_priv {
        ulong video_ptr;
+       bool cyc_active;
+       struct cyclic_info cyc;
 };
 
 /** struct vid_rgb - Describes a video colour */
@@ -359,6 +365,10 @@ int video_sync(struct udevice *vid, bool force)
                        return ret;
        }
 
+       if (CONFIG_IS_ENABLED(CYCLIC) && !force &&
+           get_timer(priv->last_sync) < CONFIG_VIDEO_SYNC_MS)
+               return 0;
+
        /*
         * flush_dcache_range() is declared in common.h but it seems that some
         * architectures do not actually implement it. Is there a way to find
@@ -371,11 +381,10 @@ int video_sync(struct udevice *vid, bool force)
                                         CONFIG_SYS_CACHELINE_SIZE));
        }
 #elif defined(CONFIG_VIDEO_SANDBOX_SDL)
-       if (force || get_timer(priv->last_sync) > 100) {
-               sandbox_sdl_sync(priv->fb);
-               priv->last_sync = get_timer(0);
-       }
+       sandbox_sdl_sync(priv->fb);
 #endif
+       priv->last_sync = get_timer(0);
+
        return 0;
 }
 
@@ -524,10 +533,16 @@ int video_default_font_height(struct udevice *dev)
        return vc_priv->y_charsize;
 }
 
+static void video_idle(struct cyclic_info *cyc)
+{
+       video_sync_all();
+}
+
 /* Set up the display ready for use */
 static int video_post_probe(struct udevice *dev)
 {
        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+       struct video_uc_priv *uc_priv = uclass_get_priv(dev->uclass);
        struct video_priv *priv = dev_get_uclass_priv(dev);
        char name[30], drv[15], *str;
        const char *drv_name = drv;
@@ -618,6 +633,16 @@ static int video_post_probe(struct udevice *dev)
                }
        }
 
+       /* register cyclic as soon as the first video device is probed */
+       if (CONFIG_IS_ENABLED(CYCLIC) && (gd->flags && GD_FLG_RELOC) &&
+           !uc_priv->cyc_active) {
+               uint ms = CONFIG_IF_ENABLED_INT(CYCLIC, VIDEO_SYNC_CYCLIC_MS);
+
+               cyclic_register(&uc_priv->cyc, video_idle, ms * 1000,
+                               "video_init");
+               uc_priv->cyc_active = true;
+       }
+
        return 0;
 };
 
@@ -657,6 +682,18 @@ static int video_post_bind(struct udevice *dev)
        return 0;
 }
 
+__maybe_unused static int video_destroy(struct uclass *uc)
+{
+       struct video_uc_priv *uc_priv = uclass_get_priv(uc);
+
+       if (uc_priv->cyc_active) {
+               cyclic_unregister(&uc_priv->cyc);
+               uc_priv->cyc_active = false;
+       }
+
+       return 0;
+}
+
 UCLASS_DRIVER(video) = {
        .id             = UCLASS_VIDEO,
        .name           = "video",
@@ -666,4 +703,5 @@ UCLASS_DRIVER(video) = {
        .priv_auto      = sizeof(struct video_uc_priv),
        .per_device_auto        = sizeof(struct video_priv),
        .per_device_plat_auto   = sizeof(struct video_uc_plat),
+       CONFIG_IS_ENABLED(CYCLIC, (.destroy = video_destroy, ))
 };