summaryrefslogtreecommitdiff
path: root/drivers/video/video-uclass.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/video-uclass.c')
-rw-r--r--drivers/video/video-uclass.c193
1 files changed, 110 insertions, 83 deletions
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index c684c994b61..503cdb9f025 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -171,7 +171,7 @@ int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
struct video_priv *priv = dev_get_uclass_priv(dev);
void *start, *line;
int pixels = xend - xstart;
- int row, i, ret;
+ int row, i;
start = priv->fb + ystart * priv->line_length;
start += xstart * VNBYTES(priv->bpix);
@@ -210,9 +210,8 @@ int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
}
line += priv->line_length;
}
- ret = video_sync_copy(dev, start, line);
- if (ret)
- return ret;
+
+ video_damage(dev, xstart, ystart, xend - xstart, yend - ystart);
return 0;
}
@@ -233,7 +232,6 @@ int video_reserve_from_bloblist(struct video_handoff *ho)
int video_fill(struct udevice *dev, u32 colour)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
- int ret;
switch (priv->bpix) {
case VIDEO_BPP16:
@@ -260,9 +258,8 @@ int video_fill(struct udevice *dev, u32 colour)
memset(priv->fb, colour, priv->fb_size);
break;
}
- ret = video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
- if (ret)
- return ret;
+
+ video_damage(dev, 0, 0, priv->xsize, priv->ysize);
return video_sync(dev, false);
}
@@ -369,6 +366,95 @@ 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
+
+static void video_flush_dcache(struct udevice *vid, bool use_copy)
+{
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+ ulong fb = use_copy ? (ulong)priv->copy_fb : (ulong)priv->fb;
+ uint cacheline_size = 32;
+
+#ifdef CONFIG_SYS_CACHELINE_SIZE
+ cacheline_size = CONFIG_SYS_CACHELINE_SIZE;
+#endif
+
+ if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
+ return;
+
+ if (!priv->flush_dcache)
+ return;
+
+ if (!IS_ENABLED(CONFIG_VIDEO_DAMAGE)) {
+ flush_dcache_range(fb, ALIGN(fb + priv->fb_size,
+ cacheline_size));
+
+ return;
+ }
+
+ if (priv->damage.xend && priv->damage.yend) {
+ int lstart = priv->damage.xstart * VNBYTES(priv->bpix);
+ int lend = priv->damage.xend * VNBYTES(priv->bpix);
+ int y;
+
+ for (y = priv->damage.ystart; y < priv->damage.yend; y++) {
+ ulong start = fb + (y * priv->line_length) + lstart;
+ ulong end = start + lend - lstart;
+
+ start = ALIGN_DOWN(start, cacheline_size);
+ end = ALIGN(end, cacheline_size);
+
+ flush_dcache_range(start, end);
+ }
+ }
+}
+
+static void video_flush_copy(struct udevice *vid)
+{
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+
+ if (!priv->copy_fb)
+ return;
+
+ if (priv->damage.xend && priv->damage.yend) {
+ int lstart = priv->damage.xstart * VNBYTES(priv->bpix);
+ int lend = priv->damage.xend * VNBYTES(priv->bpix);
+ int y;
+
+ for (y = priv->damage.ystart; y < priv->damage.yend; y++) {
+ ulong offset = (y * priv->line_length) + lstart;
+ ulong len = lend - lstart;
+
+ memcpy(priv->copy_fb + offset, priv->fb + offset, len);
+ }
+ }
+}
+
/* Flush video activity to the caches */
int video_sync(struct udevice *vid, bool force)
{
@@ -376,6 +462,9 @@ int video_sync(struct udevice *vid, bool force)
struct video_ops *ops = video_get_ops(vid);
int ret;
+ if (IS_ENABLED(CONFIG_VIDEO_COPY))
+ video_flush_copy(vid);
+
if (ops && ops->video_sync) {
ret = ops->video_sync(vid);
if (ret)
@@ -386,22 +475,23 @@ int video_sync(struct udevice *vid, bool 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
- * out whether it exists? For now, ARM is safe.
- */
-#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
- if (priv->flush_dcache) {
- flush_dcache_range((ulong)priv->fb,
- ALIGN((ulong)priv->fb + priv->fb_size,
- CONFIG_SYS_CACHELINE_SIZE));
- }
-#elif defined(CONFIG_VIDEO_SANDBOX_SDL)
+ video_flush_dcache(vid, false);
+
+ if (IS_ENABLED(CONFIG_VIDEO_COPY))
+ video_flush_dcache(vid, true);
+
+#if defined(CONFIG_VIDEO_SANDBOX_SDL)
sandbox_sdl_sync(priv->fb);
#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;
}
@@ -453,69 +543,6 @@ int video_get_ysize(struct udevice *dev)
return priv->ysize;
}
-#ifdef CONFIG_VIDEO_COPY
-int video_sync_copy(struct udevice *dev, void *from, void *to)
-{
- struct video_priv *priv = dev_get_uclass_priv(dev);
-
- if (priv->copy_fb) {
- long offset, size;
-
- /* Find the offset of the first byte to copy */
- if ((ulong)to > (ulong)from) {
- size = to - from;
- offset = from - priv->fb;
- } else {
- size = from - to;
- offset = to - priv->fb;
- }
-
- /*
- * Allow a bit of leeway for valid requests somewhere near the
- * frame buffer
- */
- if (offset < -priv->fb_size || offset > 2 * priv->fb_size) {
-#ifdef DEBUG
- char str[120];
-
- snprintf(str, sizeof(str),
- "[** FAULT sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
- priv->fb, from, to, offset);
- console_puts_select_stderr(true, str);
-#endif
- return -EFAULT;
- }
-
- /*
- * Silently crop the memcpy. This allows callers to avoid doing
- * this themselves. It is common for the end pointer to go a
- * few lines after the end of the frame buffer, since most of
- * the update algorithms terminate a line after their last write
- */
- if (offset + size > priv->fb_size) {
- size = priv->fb_size - offset;
- } else if (offset < 0) {
- size += offset;
- offset = 0;
- }
-
- memcpy(priv->copy_fb + offset, priv->fb + offset, size);
- }
-
- return 0;
-}
-
-int video_sync_copy_all(struct udevice *dev)
-{
- struct video_priv *priv = dev_get_uclass_priv(dev);
-
- video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
-
- return 0;
-}
-
-#endif
-
#define SPLASH_DECL(_name) \
extern u8 __splash_ ## _name ## _begin[]; \
extern u8 __splash_ ## _name ## _end[]