diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index 3253506d26a7..e44376d89750 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -64,6 +64,17 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
 static DECLARE_WORK(splash_work_redraw_vc, splash_callback_redraw_vc);
 
 
+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 DECLARE_DELAYED_WORK(splash_dwork_animation, splash_callback_animation);
+
+
 
 
 /*
@@ -117,17 +128,45 @@ static bool is_fb_compatible(struct fb_info *info)
  */
 void bootsplash_render_full(struct fb_info *info)
 {
+	bool is_update = false;
+
 	mutex_lock(&splash_global.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_global.splash_fb == info)
+		is_update = true;
+
+
+	if (!is_update) {
+		/* Check whether we actually support this FB. */
+		splash_global.splash_fb = NULL;
+
+		if (!is_fb_compatible(info))
+			goto out;
 
-	bootsplash_do_render_background(info);
+		/* Draw the background only once */
+		bootsplash_do_render_background(info);
 
-	bootsplash_do_render_pictures(info);
+		/* Mark this FB as last seen */
+		splash_global.splash_fb = info;
+	}
+
+
+	bootsplash_do_render_pictures(info, is_update);
 
 	bootsplash_do_render_flush(info);
 
+	bootsplash_do_step_animations();
+
+	/* Schedule update for animated splash screens */
+	if (splash_global.header->frame_ms > 0)
+		queue_delayed_work(splash_global.wq,
+				   &splash_dwork_animation,
+				   msecs_to_jiffies(
+					splash_global.header->frame_ms));
+
 out:
 	mutex_unlock(&splash_global.data_lock);
 }
@@ -201,8 +240,14 @@ void bootsplash_enable(void)
 	spin_unlock_irqrestore(&splash_global.state_lock, flags);
 
 
-	if (!was_enabled)
+	if (!was_enabled) {
+		/* Force a full redraw when the splash is re-activated */
+		mutex_lock(&splash_global.data_lock);
+		splash_global.splash_fb = NULL;
+		mutex_unlock(&splash_global.data_lock);
+
 		queue_work(splash_global.wq, &splash_work_redraw_vc);
+	}
 }
 
 
@@ -281,6 +326,13 @@ 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_global.data_lock);
+	splash_global.splash_fb = NULL;
+	mutex_unlock(&splash_global.data_lock);
+
 	if (bootsplash_would_render_now())
 		queue_work(splash_global.wq, &splash_work_redraw_vc);
 
diff --git a/drivers/video/fbdev/core/bootsplash_file.h b/drivers/video/fbdev/core/bootsplash_file.h
index 59a084a05171..367d55888ab4 100644
--- a/drivers/video/fbdev/core/bootsplash_file.h
+++ b/drivers/video/fbdev/core/bootsplash_file.h
@@ -74,7 +74,14 @@ struct splash_file_header {
 	u16 num_blobs;
 	u8 num_pics;
 
-	u8 padding[103];
+	/* 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.
+	 */
+	u16 frame_ms;
+
+	u8 padding[101];
 } __attribute__((__packed__));
 
 
@@ -108,7 +115,22 @@ struct splash_pic_header {
 	 */
 	u8 corner_offset;
 
-	u8 padding[9];
+
+	/* Animation type.
+	 *  0 - off
+	 *  1 - forward loop
+	 */
+	u8 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)
+	 */
+	u8 anim_loop;
+
+	u8 padding[7];
 } __attribute__((__packed__));
 
 
@@ -137,6 +159,11 @@ struct splash_blob_header {
  * Enums for on-disk types
  */
 
+enum splash_anim_type {
+	SPLASH_ANIM_NONE = 0,
+	SPLASH_ANIM_LOOP_FORWARD = 1,
+};
+
 enum splash_corner {
 	SPLASH_CORNER_CENTER = 0,
 	SPLASH_CORNER_TOP_LEFT = 1,
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
index 791591d10d6b..ba63f3eb99ec 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
@@ -40,6 +40,8 @@ struct splash_pic_priv {
 
 	struct splash_blob_priv *blobs;
 	u16 blobs_loaded;
+
+	u16 anim_nextframe;
 };
 
 
@@ -98,8 +100,9 @@ extern struct splash_priv splash_global;
  */
 
 void bootsplash_do_render_background(struct fb_info *info);
-void bootsplash_do_render_pictures(struct fb_info *info);
+void bootsplash_do_render_pictures(struct fb_info *info, bool is_update);
 void bootsplash_do_render_flush(struct fb_info *info);
+void bootsplash_do_step_animations(void);
 
 
 void bootsplash_free_locked(void);
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
index 2f983a74664c..da171cc961a4 100644
--- a/drivers/video/fbdev/core/bootsplash_load.c
+++ b/drivers/video/fbdev/core/bootsplash_load.c
@@ -67,6 +67,7 @@ void bootsplash_free_locked(void)
 
 int bootsplash_activate_buf(char *buf, long buflen)
 {
+	bool have_anim = false;
 	unsigned int i;
 	char *walker;
 
@@ -141,6 +142,13 @@ int bootsplash_activate_buf(char *buf, long buflen)
 			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));
@@ -213,6 +221,7 @@ int bootsplash_activate_buf(char *buf, long buflen)
 	/* Walk over pictures and ensure all blob slots are filled */
 	for (i = 0; i < splash_global.header->num_pics; i++) {
 		struct splash_pic_priv *pp = &splash_global.pics[i];
+		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",
@@ -220,9 +229,24 @@ int bootsplash_activate_buf(char *buf, long buflen)
 
 			goto err;
 		}
+
+		if (ph->num_blobs < 2 || ph->anim_loop > pp->blobs_loaded)
+			/* Nothing to animate or loading error */
+			ph->anim_type = SPLASH_ANIM_NONE;
+		else if (ph->anim_type)
+			have_anim = true;
 	}
 
 
+	/* Disable animation timer if there is nothing to animate */
+	if (!have_anim)
+		splash_global.header->frame_ms = 0;
+
+	/* Enforce minimum delay between frames */
+	if (splash_global.header->frame_ms > 0
+	    && splash_global.header->frame_ms < 20)
+		splash_global.header->frame_ms = 20;
+
 	/* Force a full redraw when the splash is re-activated */
 	splash_global.splash_fb = NULL;
 
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 444233583f6f..b3667a0f067b 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -151,7 +151,7 @@ void bootsplash_do_render_background(struct fb_info *info)
 }
 
 
-void bootsplash_do_render_pictures(struct fb_info *info)
+void bootsplash_do_render_pictures(struct fb_info *info, bool is_update)
 {
 	unsigned int i;
 
@@ -167,7 +167,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;
@@ -274,3 +278,23 @@ void bootsplash_do_render_flush(struct fb_info *info)
 		info->fbops->fb_copyarea(info, &area);
 	}
 }
+
+
+void bootsplash_do_step_animations(void)
+{
+	unsigned int i;
+
+	/* Step every animation once */
+	for (i = 0; i < splash_global.header->num_pics; i++) {
+		struct splash_pic_priv *pp = &splash_global.pics[i];
+
+		if (pp->blobs_loaded < 1)
+			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;
+		}
+	}
+}
