summarylogtreecommitdiffstats
path: root/0505-bootsplash.patch
diff options
context:
space:
mode:
Diffstat (limited to '0505-bootsplash.patch')
-rw-r--r--0505-bootsplash.patch327
1 files changed, 327 insertions, 0 deletions
diff --git a/0505-bootsplash.patch b/0505-bootsplash.patch
new file mode 100644
index 00000000000..2785c5e6527
--- /dev/null
+++ b/0505-bootsplash.patch
@@ -0,0 +1,327 @@
+diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
+index 815b007f81ca..c8642142cfea 100644
+--- a/drivers/video/fbdev/core/bootsplash.c
++++ b/drivers/video/fbdev/core/bootsplash.c
+@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
+ console_unlock();
+ }
+
++static void splash_callback_animation(struct work_struct *ignored)
++{
++ if (bootsplash_would_render_now()) {
++ /* This will also re-schedule this delayed worker */
++ splash_callback_redraw_vc(ignored);
++ }
++}
++
+
+ static bool is_fb_compatible(const struct fb_info *info)
+ {
+@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info)
+ */
+ void bootsplash_render_full(struct fb_info *info)
+ {
++ bool is_update = false;
++
+ mutex_lock(&splash_state.data_lock);
+
+- if (!is_fb_compatible(info))
+- goto out;
++ /*
++ * If we've painted on this FB recently, we don't have to do
++ * the sanity checks and background drawing again.
++ */
++ if (splash_state.splash_fb == info)
++ is_update = true;
++
++
++ if (!is_update) {
++ /* Check whether we actually support this FB. */
++ splash_state.splash_fb = NULL;
++
++ if (!is_fb_compatible(info))
++ goto out;
++
++ /* Draw the background only once */
++ bootsplash_do_render_background(info, splash_state.file);
+
+- bootsplash_do_render_background(info, splash_state.file);
++ /* Mark this FB as last seen */
++ splash_state.splash_fb = info;
++ }
+
+- bootsplash_do_render_pictures(info, splash_state.file);
++ bootsplash_do_render_pictures(info, splash_state.file, is_update);
+
+ bootsplash_do_render_flush(info);
+
++ bootsplash_do_step_animations(splash_state.file);
++
++ /* Schedule update for animated splash screens */
++ if (splash_state.file->frame_ms > 0)
++ schedule_delayed_work(&splash_state.dwork_animation,
++ msecs_to_jiffies(
++ splash_state.file->frame_ms));
++
+ out:
+ mutex_unlock(&splash_state.data_lock);
+ }
+@@ -169,8 +204,14 @@ void bootsplash_enable(void)
+
+ was_enabled = test_and_set_bit(0, &splash_state.enabled);
+
+- if (!was_enabled)
++ if (!was_enabled) {
++ /* Force a full redraw when the splash is re-activated */
++ mutex_lock(&splash_state.data_lock);
++ splash_state.splash_fb = NULL;
++ mutex_unlock(&splash_state.data_lock);
++
+ schedule_work(&splash_state.work_redraw_vc);
++ }
+ }
+
+
+@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev);
+ */
+ static int splash_resume(struct device *device)
+ {
++ /*
++ * Force full redraw on resume since we've probably lost the
++ * framebuffer's contents meanwhile
++ */
++ mutex_lock(&splash_state.data_lock);
++ splash_state.splash_fb = NULL;
++ mutex_unlock(&splash_state.data_lock);
++
+ if (bootsplash_would_render_now())
+ schedule_work(&splash_state.work_redraw_vc);
+
+@@ -235,6 +284,7 @@ static int splash_resume(struct device *device)
+
+ static int splash_suspend(struct device *device)
+ {
++ cancel_delayed_work_sync(&splash_state.dwork_animation);
+ cancel_work_sync(&splash_state.work_redraw_vc);
+
+ return 0;
+@@ -296,6 +346,8 @@ void bootsplash_init(void)
+ set_bit(0, &splash_state.enabled);
+
+ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
++ INIT_DELAYED_WORK(&splash_state.dwork_animation,
++ splash_callback_animation);
+
+
+ if (!splash_state.bootfile || !strlen(splash_state.bootfile))
+diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
+index 0acb383aa4e3..b3a74835d90f 100644
+--- a/drivers/video/fbdev/core/bootsplash_internal.h
++++ b/drivers/video/fbdev/core/bootsplash_internal.h
+@@ -37,6 +37,8 @@ struct splash_pic_priv {
+
+ struct splash_blob_priv *blobs;
+ u16 blobs_loaded;
++
++ u16 anim_nextframe;
+ };
+
+
+@@ -45,6 +47,12 @@ struct splash_file_priv {
+ const struct splash_file_header *header;
+
+ struct splash_pic_priv *pics;
++
++ /*
++ * A local copy of the frame delay in the header.
++ * We modify it to keep the code simple.
++ */
++ u16 frame_ms;
+ };
+
+
+@@ -71,6 +79,7 @@ struct splash_priv {
+ struct platform_device *splash_device;
+
+ struct work_struct work_redraw_vc;
++ struct delayed_work dwork_animation;
+
+ /* Splash data structures including lock for everything below */
+ struct mutex data_lock;
+@@ -88,8 +97,10 @@ struct splash_priv {
+ void bootsplash_do_render_background(struct fb_info *info,
+ const struct splash_file_priv *fp);
+ void bootsplash_do_render_pictures(struct fb_info *info,
+- const struct splash_file_priv *fp);
++ const struct splash_file_priv *fp,
++ bool is_update);
+ void bootsplash_do_render_flush(struct fb_info *info);
++void bootsplash_do_step_animations(struct splash_file_priv *fp);
+
+
+ void bootsplash_free_file(struct splash_file_priv *fp);
+diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
+index fd807571ab7d..1f661b2d4cc9 100644
+--- a/drivers/video/fbdev/core/bootsplash_load.c
++++ b/drivers/video/fbdev/core/bootsplash_load.c
+@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
+ {
+ const struct firmware *fw;
+ struct splash_file_priv *fp;
++ bool have_anim = false;
+ unsigned int i;
+ const u8 *walker;
+
+@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
+ goto err;
+ }
+
++ if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) {
++ pr_warn("Picture %u: Unsupported animation type %u.\n",
++ i, ph->anim_type);
++
++ ph->anim_type = SPLASH_ANIM_NONE;
++ }
++
+ pp->pic_header = ph;
+ pp->blobs = vzalloc(ph->num_blobs
+ * sizeof(struct splash_blob_priv));
+@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
+ /* Walk over pictures and ensure all blob slots are filled */
+ for (i = 0; i < fp->header->num_pics; i++) {
+ struct splash_pic_priv *pp = &fp->pics[i];
++ const struct splash_pic_header *ph = pp->pic_header;
+
+ if (pp->blobs_loaded != pp->pic_header->num_blobs) {
+ pr_err("Picture %u doesn't have all blob slots filled.\n",
+@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
+
+ goto err;
+ }
++
++ if (ph->anim_type
++ && ph->num_blobs > 1
++ && ph->anim_loop < pp->blobs_loaded)
++ have_anim = true;
+ }
+
++ if (!have_anim)
++ /* Disable animation timer if there is nothing to animate */
++ fp->frame_ms = 0;
++ else
++ /* Enforce minimum delay between frames */
++ fp->frame_ms = max((u16)20, fp->header->frame_ms);
++
+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
+ fw->size,
+ fp->header->num_pics,
+diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
+index 07e3a4eab811..76033606ca8a 100644
+--- a/drivers/video/fbdev/core/bootsplash_render.c
++++ b/drivers/video/fbdev/core/bootsplash_render.c
+@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info,
+
+
+ void bootsplash_do_render_pictures(struct fb_info *info,
+- const struct splash_file_priv *fp)
++ const struct splash_file_priv *fp,
++ bool is_update)
+ {
+ unsigned int i;
+
+@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
+ if (pp->blobs_loaded < 1)
+ continue;
+
+- bp = &pp->blobs[0];
++ /* Skip static pictures when refreshing animations */
++ if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
++ continue;
++
++ bp = &pp->blobs[pp->anim_nextframe];
+
+ if (!bp || bp->blob_header->type != 0)
+ continue;
+@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info)
+ info->fbops->fb_copyarea(info, &area);
+ }
+ }
++
++
++void bootsplash_do_step_animations(struct splash_file_priv *fp)
++{
++ unsigned int i;
++
++ /* Step every animation once */
++ for (i = 0; i < fp->header->num_pics; i++) {
++ struct splash_pic_priv *pp = &fp->pics[i];
++
++ if (pp->blobs_loaded < 2
++ || pp->pic_header->anim_loop > pp->blobs_loaded)
++ continue;
++
++ if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) {
++ pp->anim_nextframe++;
++ if (pp->anim_nextframe >= pp->pic_header->num_blobs)
++ pp->anim_nextframe = pp->pic_header->anim_loop;
++ }
++ }
++}
+diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
+index 71cedcc68933..b3af0a3c6487 100644
+--- a/include/uapi/linux/bootsplash_file.h
++++ b/include/uapi/linux/bootsplash_file.h
+@@ -77,7 +77,17 @@ struct splash_file_header {
+ uint16_t num_blobs;
+ uint8_t num_pics;
+
+- uint8_t padding[103];
++ uint8_t unused_1;
++
++ /*
++ * Milliseconds to wait before painting the next frame in
++ * an animation.
++ * This is actually a minimum, as the system is allowed to
++ * stall for longer between frames.
++ */
++ uint16_t frame_ms;
++
++ uint8_t padding[100];
+ } __attribute__((__packed__));
+
+
+@@ -116,7 +126,23 @@ struct splash_pic_header {
+ */
+ uint16_t position_offset;
+
+- uint8_t padding[24];
++ /*
++ * Animation type.
++ * 0 - off
++ * 1 - forward loop
++ */
++ uint8_t anim_type;
++
++ /*
++ * Animation loop point.
++ * Actual meaning depends on animation type:
++ * Type 0 - Unused
++ * 1 - Frame at which to restart the forward loop
++ * (allowing for "intro" frames)
++ */
++ uint8_t anim_loop;
++
++ uint8_t padding[22];
+ } __attribute__((__packed__));
+
+
+@@ -158,4 +184,9 @@ enum splash_position {
+ SPLASH_POS_FLAG_CORNER = 0x10,
+ };
+
++enum splash_anim_type {
++ SPLASH_ANIM_NONE = 0,
++ SPLASH_ANIM_LOOP_FORWARD = 1,
++};
++
+ #endif