summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/Kconfig13
-rw-r--r--drivers/video/video-uclass.c35
-rw-r--r--include/video.h40
3 files changed, 86 insertions, 2 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 73353944971..bc9c7c1d223 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -98,6 +98,19 @@ config VIDEO_COPY
To use this, your video driver must set @copy_base in
struct video_uc_plat.
+config VIDEO_DAMAGE
+ bool "Enable damage tracking of frame buffer regions"
+ help
+ On some machines (most ARM), the display frame buffer resides in
+ RAM. To make the display controller pick up screen updates, we
+ have to flush frame buffer contents from CPU caches into RAM which
+ can be a slow operation.
+
+ This feature adds damage tracking to collect information about regions
+ that received updates. When we want to sync, we then only flush
+ regions of the frame buffer that were modified before, speeding up
+ screen refreshes significantly.
+
config BACKLIGHT_PWM
bool "Generic PWM based Backlight Driver"
depends on BACKLIGHT && DM_PWM
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index c684c994b61..8e2edd7ec49 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -369,6 +369,34 @@ void video_set_default_colors(struct udevice *dev, bool invert)
priv->colour_bg = video_index_to_colour(priv, back);
}
+/* Notify about changes in the frame buffer */
+#ifdef CONFIG_VIDEO_DAMAGE
+void video_damage(struct udevice *vid, int x, int y, int width, int height)
+{
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+ int xend = x + width;
+ int yend = y + height;
+
+ if (x > priv->xsize)
+ return;
+
+ if (y > priv->ysize)
+ return;
+
+ if (xend > priv->xsize)
+ xend = priv->xsize;
+
+ if (yend > priv->ysize)
+ yend = priv->ysize;
+
+ /* Span a rectangle across all old and new damage */
+ priv->damage.xstart = min(x, priv->damage.xstart);
+ priv->damage.ystart = min(y, priv->damage.ystart);
+ priv->damage.xend = max(xend, priv->damage.xend);
+ priv->damage.yend = max(yend, priv->damage.yend);
+}
+#endif
+
/* Flush video activity to the caches */
int video_sync(struct udevice *vid, bool force)
{
@@ -402,6 +430,13 @@ int video_sync(struct udevice *vid, bool force)
#endif
priv->last_sync = get_timer(0);
+ if (IS_ENABLED(CONFIG_VIDEO_DAMAGE)) {
+ priv->damage.xstart = priv->xsize;
+ priv->damage.ystart = priv->ysize;
+ priv->damage.xend = 0;
+ priv->damage.yend = 0;
+ }
+
return 0;
}
diff --git a/include/video.h b/include/video.h
index a1f7fd7e839..7eed112e00c 100644
--- a/include/video.h
+++ b/include/video.h
@@ -85,6 +85,11 @@ enum video_format {
* @fb_size: Frame buffer size
* @copy_fb: Copy of the frame buffer to keep up to date; see struct
* video_uc_plat
+ * @damage: A bounding box of framebuffer regions updated since last sync
+ * @damage.xstart: X start position in pixels from the left
+ * @damage.ystart: Y start position in pixels from the top
+ * @damage.xend: X end position in pixels from the left
+ * @damage.xend: Y end position in pixels from the top
* @line_length: Length of each frame buffer line, in bytes. This can be
* set by the driver, but if not, the uclass will set it after
* probing
@@ -113,6 +118,12 @@ struct video_priv {
void *fb;
int fb_size;
void *copy_fb;
+ struct {
+ int xstart;
+ int ystart;
+ int xend;
+ int yend;
+ } damage;
int line_length;
u32 colour_fg;
u32 colour_bg;
@@ -259,8 +270,9 @@ int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
* @return: 0 on success, error code otherwise
*
* Some frame buffers are cached or have a secondary frame buffer. This
- * function syncs these up so that the current contents of the U-Boot frame
- * buffer are displayed to the user.
+ * function syncs the damaged parts of them up so that the current contents
+ * of the U-Boot frame buffer are displayed to the user. It clears the damage
+ * buffer.
*/
int video_sync(struct udevice *vid, bool force);
@@ -380,6 +392,30 @@ static inline int video_sync_copy_all(struct udevice *dev)
#endif
+#ifdef CONFIG_VIDEO_DAMAGE
+/**
+ * video_damage() - Notify the video subsystem about screen updates.
+ *
+ * @vid: Device to sync
+ * @x: Upper left X coordinate of the damaged rectangle
+ * @y: Upper left Y coordinate of the damaged rectangle
+ * @width: Width of the damaged rectangle
+ * @height: Height of the damaged rectangle
+ *
+ * Some frame buffers are cached or have a secondary frame buffer. This
+ * function notifies the video subsystem about rectangles that were updated
+ * within the frame buffer. They may only get written to the screen on the
+ * next call to video_sync().
+ */
+void video_damage(struct udevice *vid, int x, int y, int width, int height);
+#else
+static inline void video_damage(struct udevice *vid, int x, int y, int width,
+ int height)
+{
+ return;
+}
+#endif /* CONFIG_VIDEO_DAMAGE */
+
/**
* video_is_active() - Test if one video device it active
*