summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO12
-rw-r--r--0003-bootsplash.patch746
-rw-r--r--0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch53
-rw-r--r--0004-bootsplash.patch669
-rw-r--r--0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch328
-rw-r--r--0005-bootsplash.patch66
-rw-r--r--0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch27
-rw-r--r--0006-bootsplash.patch923
-rw-r--r--0007-bootsplash.patch838
-rw-r--r--0008-bootsplash.patch128
-rw-r--r--0009-bootsplash.patch245
-rw-r--r--0010-bootsplash.patch342
-rw-r--r--0011-bootsplash.patch99
-rw-r--r--0012-bootsplash.patch363
-rw-r--r--0013-bootsplash.patch146
-rw-r--r--0014-bootsplash.patch530
-rw-r--r--0015-bootsplash.patch407
-rw-r--r--0016-bootsplash.patch129
-rw-r--r--0017-bootsplash.patch511
-rw-r--r--0018-bootsplash.patch102
-rw-r--r--PKGBUILD12
21 files changed, 3130 insertions, 3546 deletions
diff --git a/.SRCINFO b/.SRCINFO
index a7547a2743f..e0a3b45ae08 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -18,8 +18,9 @@ pkgbase = linux-bootsplash
source = enable_additional_cpu_optimizations-20190714.tar.gz::https://github.com/graysky2/kernel_gcc_patch/archive/20190714.tar.gz
source = 0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch
source = 0002-ZEN-Add-CONFIG-for-unprivileged_userns_clone.patch
- source = 0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch
- source = 0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch
+ source = 0003-bootsplash.patch
+ source = 0004-bootsplash.patch
+ source = 0005-bootsplash.patch
source = 0006-bootsplash.patch
source = 0007-bootsplash.patch
source = 0008-bootsplash.patch
@@ -30,13 +31,10 @@ pkgbase = linux-bootsplash
source = 0013-bootsplash.patch
source = 0014-bootsplash.patch
source = 0015-bootsplash.patch
- source = 0016-bootsplash.patch
- source = 0017-bootsplash.patch
- source = 0018-bootsplash.patch
source = ajax-loader.gif
validpgpkeys = ABAF11C65A2970B130ABE3C479BE3E4300411886
validpgpkeys = 647F28654894E3BD457199BE38DBBDC86092693E
- sha256sums = b6f02a4b306ca5cd314d72615bfc2650166969613135da202630e6c4e1b5d4e6
+ sha256sums = 0c2a831f993dc8a8a8e1ca4186b467de72ff173c6f5855e2aab70f6f7fb033f9
sha256sums = SKIP
sha256sums = 1c4d5500a3b4995035c2e940fc0ad2a2dae7be047c8eb20c097444e348258f87
sha256sums = ae2e95db94ef7176207c690224169594d49445e04249d2499e9d2fbc117a0b21
@@ -44,8 +42,6 @@ pkgbase = linux-bootsplash
sha256sums = ad6344badc91ad0630caacde83f7f9b97276f80d26a20619a87952be65492c65
sha256sums = f1abc13a8d859fbf6350040e45d7f04ad551a6d39f113ba96fbbd820118c0e36
sha256sums = 91fafa76bf9cb32159ac7f22191b3589278b91e65bc4505cf2fc6013b8037bf3
- sha256sums = 63e4378e69e2f23ed87af32a4951477a6d82d4ac0de2295db46502c8120da9d9
- sha256sums = fc96300831506965383ef30bc46b72735dc45bb97dea2ccb8b9450c005d2f020
sha256sums = ef926edbd866d95464eb86f7565de572eb97ecfa0369d3b2e078016a0e71a871
sha256sums = a504f6cf84094e08eaa3cc5b28440261797bf4f06f04993ee46a20628ff2b53c
sha256sums = e096b127a5208f56d368d2cb938933454d7200d70c86b763aa22c38e0ddb8717
diff --git a/0003-bootsplash.patch b/0003-bootsplash.patch
new file mode 100644
index 00000000000..924f23f33ce
--- /dev/null
+++ b/0003-bootsplash.patch
@@ -0,0 +1,746 @@
+diff --git a/MAINTAINERS b/MAINTAINERS
+index a74227ad082e..b5633b56391e 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -2705,6 +2705,14 @@ S: Supported
+ F: drivers/net/bonding/
+ F: include/uapi/linux/if_bonding.h
+
++BOOTSPLASH
++M: Max Staudt <mstaudt@suse.de>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/core/bootsplash*.*
++F: drivers/video/fbdev/core/dummycon.c
++F: include/linux/bootsplash.h
++
+ BPF (Safe dynamic programs and tools)
+ M: Alexei Starovoitov <ast@kernel.org>
+ M: Daniel Borkmann <daniel@iogearbox.net>
+diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
+index 7f1f1fbcef9e..f3ff976266fe 100644
+--- a/drivers/video/console/Kconfig
++++ b/drivers/video/console/Kconfig
+@@ -151,6 +151,30 @@ config FRAMEBUFFER_CONSOLE_ROTATION
+ such that other users of the framebuffer will remain normally
+ oriented.
+
++config BOOTSPLASH
++ bool "Bootup splash screen"
++ depends on FRAMEBUFFER_CONSOLE
++ ---help---
++ This option enables the Linux bootsplash screen.
++
++ The bootsplash is a full-screen logo or animation indicating a
++ booting system. It replaces the classic scrolling text with a
++ graphical alternative, similar to other systems.
++
++ Since this is technically implemented as a hook on top of fbcon,
++ it can only work if the FRAMEBUFFER_CONSOLE is enabled and a
++ framebuffer driver is active. Thus, to get a text-free boot,
++ the system needs to boot with vesafb, efifb, or similar.
++
++ Once built into the kernel, the bootsplash needs to be enabled
++ with bootsplash.enabled=1 and a splash file needs to be supplied.
++
++ Further documentation can be found in:
++ Documentation/fb/bootsplash.txt
++
++ If unsure, say N.
++ This is typically used by distributors and system integrators.
++
+ config STI_CONSOLE
+ bool "STI text console"
+ depends on PARISC
+diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
+index 73493bbd7a15..66895321928e 100644
+--- a/drivers/video/fbdev/core/Makefile
++++ b/drivers/video/fbdev/core/Makefile
+@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
+ obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
+ obj-$(CONFIG_FB_SVGALIB) += svgalib.o
+ obj-$(CONFIG_FB_DDC) += fb_ddc.o
++
++obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
++ dummyblit.o
+diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
+new file mode 100644
+index 000000000000..e449755af268
+--- /dev/null
++++ b/drivers/video/fbdev/core/bootsplash.c
+@@ -0,0 +1,294 @@
++/*
++ * Kernel based bootsplash.
++ *
++ * (Main file: Glue code, workers, timer, PM, kernel and userland API)
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * SPDX-License-Identifier: GPL-2.0
++ */
++
++#define pr_fmt(fmt) "bootsplash: " fmt
++
++
++#include <linux/atomic.h>
++#include <linux/bootsplash.h>
++#include <linux/console.h>
++#include <linux/device.h> /* dev_warn() */
++#include <linux/fb.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/jiffies.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/selection.h> /* console_blanked */
++#include <linux/stringify.h>
++#include <linux/types.h>
++#include <linux/vmalloc.h>
++#include <linux/vt_kern.h>
++#include <linux/workqueue.h>
++
++#include "bootsplash_internal.h"
++
++
++/*
++ * We only have one splash screen, so let's keep a single
++ * instance of the internal state.
++ */
++static struct splash_priv splash_state;
++
++
++static void splash_callback_redraw_vc(struct work_struct *ignored)
++{
++ if (console_blanked)
++ return;
++
++ console_lock();
++ if (vc_cons[fg_console].d)
++ update_screen(vc_cons[fg_console].d);
++ console_unlock();
++}
++
++
++static bool is_fb_compatible(const struct fb_info *info)
++{
++ if (!(info->flags & FBINFO_BE_MATH)
++ != !fb_be_math((struct fb_info *)info)) {
++ dev_warn(info->device,
++ "Can't draw on foreign endianness framebuffer.\n");
++
++ return false;
++ }
++
++ if (info->flags & FBINFO_MISC_TILEBLITTING) {
++ dev_warn(info->device,
++ "Can't draw splash on tiling framebuffer.\n");
++
++ return false;
++ }
++
++ if (info->fix.type != FB_TYPE_PACKED_PIXELS
++ || (info->fix.visual != FB_VISUAL_TRUECOLOR
++ && info->fix.visual != FB_VISUAL_DIRECTCOLOR)) {
++ dev_warn(info->device,
++ "Can't draw splash on non-packed or non-truecolor framebuffer.\n");
++
++ dev_warn(info->device,
++ " type: %u visual: %u\n",
++ info->fix.type, info->fix.visual);
++
++ return false;
++ }
++
++ if (info->var.bits_per_pixel != 16
++ && info->var.bits_per_pixel != 24
++ && info->var.bits_per_pixel != 32) {
++ dev_warn(info->device,
++ "We only support drawing on framebuffers with 16, 24, or 32 bpp, not %d.\n",
++ info->var.bits_per_pixel);
++
++ return false;
++ }
++
++ return true;
++}
++
++
++/*
++ * Called by fbcon_switch() when an instance is activated or refreshed.
++ */
++void bootsplash_render_full(struct fb_info *info)
++{
++ if (!is_fb_compatible(info))
++ return;
++
++ bootsplash_do_render_background(info);
++}
++
++
++/*
++ * External status enquiry and on/off switch
++ */
++bool bootsplash_would_render_now(void)
++{
++ return !oops_in_progress
++ && !console_blanked
++ && bootsplash_is_enabled();
++}
++
++bool bootsplash_is_enabled(void)
++{
++ bool was_enabled;
++
++ /* Make sure we have the newest state */
++ smp_rmb();
++
++ was_enabled = test_bit(0, &splash_state.enabled);
++
++ return was_enabled;
++}
++
++void bootsplash_disable(void)
++{
++ int was_enabled;
++
++ was_enabled = test_and_clear_bit(0, &splash_state.enabled);
++
++ if (was_enabled) {
++ if (oops_in_progress) {
++ /* Redraw screen now so we can see a panic */
++ if (vc_cons[fg_console].d)
++ update_screen(vc_cons[fg_console].d);
++ } else {
++ /* No urgency, redraw at next opportunity */
++ schedule_work(&splash_state.work_redraw_vc);
++ }
++ }
++}
++
++void bootsplash_enable(void)
++{
++ bool was_enabled;
++
++ if (oops_in_progress)
++ return;
++
++ was_enabled = test_and_set_bit(0, &splash_state.enabled);
++
++ if (!was_enabled)
++ schedule_work(&splash_state.work_redraw_vc);
++}
++
++
++/*
++ * Userland API via platform device in sysfs
++ */
++static ssize_t splash_show_enabled(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%d\n", bootsplash_is_enabled());
++}
++
++static ssize_t splash_store_enabled(struct device *device,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ bool enable;
++ int err;
++
++ if (!buf || !count)
++ return -EFAULT;
++
++ err = kstrtobool(buf, &enable);
++ if (err)
++ return err;
++
++ if (enable)
++ bootsplash_enable();
++ else
++ bootsplash_disable();
++
++ return count;
++}
++
++static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
++
++
++static struct attribute *splash_dev_attrs[] = {
++ &dev_attr_enabled.attr,
++ NULL
++};
++
++ATTRIBUTE_GROUPS(splash_dev);
++
++
++
++
++/*
++ * Power management fixup via platform device
++ *
++ * When the system is woken from sleep or restored after hibernating, we
++ * cannot expect the screen contents to still be present in video RAM.
++ * Thus, we have to redraw the splash if we're currently active.
++ */
++static int splash_resume(struct device *device)
++{
++ if (bootsplash_would_render_now())
++ schedule_work(&splash_state.work_redraw_vc);
++
++ return 0;
++}
++
++static int splash_suspend(struct device *device)
++{
++ cancel_work_sync(&splash_state.work_redraw_vc);
++
++ return 0;
++}
++
++
++static const struct dev_pm_ops splash_pm_ops = {
++ .thaw = splash_resume,
++ .restore = splash_resume,
++ .resume = splash_resume,
++ .suspend = splash_suspend,
++ .freeze = splash_suspend,
++};
++
++static struct platform_driver splash_driver = {
++ .driver = {
++ .name = "bootsplash",
++ .pm = &splash_pm_ops,
++ },
++};
++
++
++/*
++ * Main init
++ */
++void bootsplash_init(void)
++{
++ int ret;
++
++ /* Initialized already? */
++ if (splash_state.splash_device)
++ return;
++
++
++ /* Register platform device to export user API */
++ ret = platform_driver_register(&splash_driver);
++ if (ret) {
++ pr_err("platform_driver_register() failed: %d\n", ret);
++ goto err;
++ }
++
++ splash_state.splash_device
++ = platform_device_alloc("bootsplash", 0);
++
++ if (!splash_state.splash_device)
++ goto err_driver;
++
++ splash_state.splash_device->dev.groups = splash_dev_groups;
++
++ ret = platform_device_add(splash_state.splash_device);
++ if (ret) {
++ pr_err("platform_device_add() failed: %d\n", ret);
++ goto err_device;
++ }
++
++
++ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
++
++ return;
++
++err_device:
++ platform_device_put(splash_state.splash_device);
++ splash_state.splash_device = NULL;
++err_driver:
++ platform_driver_unregister(&splash_driver);
++err:
++ pr_err("Failed to initialize.\n");
++}
+diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
+new file mode 100644
+index 000000000000..b11da5cb90bf
+--- /dev/null
++++ b/drivers/video/fbdev/core/bootsplash_internal.h
+@@ -0,0 +1,55 @@
++/*
++ * Kernel based bootsplash.
++ *
++ * (Internal data structures used at runtime)
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * SPDX-License-Identifier: GPL-2.0
++ */
++
++#ifndef __BOOTSPLASH_INTERNAL_H
++#define __BOOTSPLASH_INTERNAL_H
++
++
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/kernel.h>
++#include <linux/mutex.h>
++#include <linux/spinlock.h>
++
++
++/*
++ * Runtime types
++ */
++struct splash_priv {
++ /*
++ * Enabled/disabled state, to be used with atomic bit operations.
++ * Bit 0: 0 = Splash hidden
++ * 1 = Splash shown
++ *
++ * Note: fbcon.c uses this twice, by calling
++ * bootsplash_would_render_now() in set_blitting_type() and
++ * in fbcon_switch().
++ * This is racy, but eventually consistent: Turning the
++ * splash on/off will cause a redraw, which calls
++ * fbcon_switch(), which calls set_blitting_type().
++ * So the last on/off toggle will make things consistent.
++ */
++ unsigned long enabled;
++
++ /* Our gateway to userland via sysfs */
++ struct platform_device *splash_device;
++
++ struct work_struct work_redraw_vc;
++};
++
++
++
++/*
++ * Rendering functions
++ */
++void bootsplash_do_render_background(struct fb_info *info);
++
++#endif
+diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
+new file mode 100644
+index 000000000000..4d7e0117f653
+--- /dev/null
++++ b/drivers/video/fbdev/core/bootsplash_render.c
+@@ -0,0 +1,93 @@
++/*
++ * Kernel based bootsplash.
++ *
++ * (Rendering functions)
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * SPDX-License-Identifier: GPL-2.0
++ */
++
++#define pr_fmt(fmt) "bootsplash: " fmt
++
++
++#include <linux/bootsplash.h>
++#include <linux/fb.h>
++#include <linux/kernel.h>
++#include <linux/printk.h>
++#include <linux/types.h>
++
++#include "bootsplash_internal.h"
++
++
++
++
++/*
++ * Rendering: Internal drawing routines
++ */
++
++
++/*
++ * Pack pixel into target format and do Big/Little Endian handling.
++ * This would be a good place to handle endianness conversion if necessary.
++ */
++static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
++ u8 red, u8 green, u8 blue)
++{
++ u32 dstpix;
++
++ /* Quantize pixel */
++ red = red >> (8 - dst_var->red.length);
++ green = green >> (8 - dst_var->green.length);
++ blue = blue >> (8 - dst_var->blue.length);
++
++ /* Pack pixel */
++ dstpix = red << (dst_var->red.offset)
++ | green << (dst_var->green.offset)
++ | blue << (dst_var->blue.offset);
++
++ /*
++ * Move packed pixel to the beginning of the memory cell,
++ * so we can memcpy() it out easily
++ */
++#ifdef __BIG_ENDIAN
++ switch (dst_var->bits_per_pixel) {
++ case 16:
++ dstpix <<= 16;
++ break;
++ case 24:
++ dstpix <<= 8;
++ break;
++ case 32:
++ break;
++ }
++#else
++ /* This is intrinsically unnecessary on Little Endian */
++#endif
++
++ return dstpix;
++}
++
++
++void bootsplash_do_render_background(struct fb_info *info)
++{
++ unsigned int x, y;
++ u32 dstpix;
++ u32 dst_octpp = info->var.bits_per_pixel / 8;
++
++ dstpix = pack_pixel(&info->var,
++ 0,
++ 0,
++ 0);
++
++ for (y = 0; y < info->var.yres_virtual; y++) {
++ u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
++
++ for (x = 0; x < info->var.xres_virtual; x++) {
++ memcpy(dstline, &dstpix, dst_octpp);
++
++ dstline += dst_octpp;
++ }
++ }
++}
+diff --git a/drivers/video/fbdev/core/dummyblit.c b/drivers/video/fbdev/core/dummyblit.c
+new file mode 100644
+index 000000000000..8c22ff92ce24
+--- /dev/null
++++ b/drivers/video/fbdev/core/dummyblit.c
+@@ -0,0 +1,89 @@
++/*
++ * linux/drivers/video/fbdev/core/dummyblit.c -- Dummy Blitting Operation
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * These functions are used in place of blitblit/tileblit to suppress
++ * fbcon's text output while a splash is shown.
++ *
++ * Only suppressing actual rendering keeps the text buffer in the VC layer
++ * intact and makes it easy to switch back from the bootsplash to a full
++ * text console with a simple redraw (with the original functions in place).
++ *
++ * Based on linux/drivers/video/fbdev/core/bitblit.c
++ * and linux/drivers/video/fbdev/core/tileblit.c
++ *
++ * SPDX-License-Identifier: GPL-2.0
++ */
++
++#include <linux/module.h>
++#include <linux/fb.h>
++#include <linux/vt_kern.h>
++#include <linux/console.h>
++#include <asm/types.h>
++#include "fbcon.h"
++
++static void dummy_bmove(struct vc_data *vc, struct fb_info *info, int sy,
++ int sx, int dy, int dx, int height, int width)
++{
++ ;
++}
++
++static void dummy_clear(struct vc_data *vc, struct fb_info *info, int sy,
++ int sx, int height, int width)
++{
++ ;
++}
++
++static void dummy_putcs(struct vc_data *vc, struct fb_info *info,
++ const unsigned short *s, int count, int yy, int xx,
++ int fg, int bg)
++{
++ ;
++}
++
++static void dummy_clear_margins(struct vc_data *vc, struct fb_info *info,
++ int color, int bottom_only)
++{
++ ;
++}
++
++static void dummy_cursor(struct vc_data *vc, struct fb_info *info, int mode,
++ int softback_lines, int fg, int bg)
++{
++ ;
++}
++
++static int dummy_update_start(struct fb_info *info)
++{
++ /*
++ * Copied from bitblit.c and tileblit.c
++ *
++ * As of Linux 4.12, nobody seems to care about our return value.
++ */
++ struct fbcon_ops *ops = info->fbcon_par;
++ int err;
++
++ err = fb_pan_display(info, &ops->var);
++ ops->var.xoffset = info->var.xoffset;
++ ops->var.yoffset = info->var.yoffset;
++ ops->var.vmode = info->var.vmode;
++ return err;
++}
++
++void fbcon_set_dummyops(struct fbcon_ops *ops)
++{
++ ops->bmove = dummy_bmove;
++ ops->clear = dummy_clear;
++ ops->putcs = dummy_putcs;
++ ops->clear_margins = dummy_clear_margins;
++ ops->cursor = dummy_cursor;
++ ops->update_start = dummy_update_start;
++ ops->rotate_font = NULL;
++}
++EXPORT_SYMBOL_GPL(fbcon_set_dummyops);
++
++MODULE_AUTHOR("Max Staudt <mstaudt@suse.de>");
++MODULE_DESCRIPTION("Dummy Blitting Operation");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
+index 04612f938bab..9a39a6fcfe98 100644
+--- a/drivers/video/fbdev/core/fbcon.c
++++ b/drivers/video/fbdev/core/fbcon.c
+@@ -80,6 +80,7 @@
+ #include <asm/irq.h>
+
+ #include "fbcon.h"
++#include <linux/bootsplash.h>
+
+ #ifdef FBCONDEBUG
+ # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
+@@ -542,6 +543,8 @@ static int do_fbcon_takeover(int show_logo)
+ for (i = first_fb_vc; i <= last_fb_vc; i++)
+ con2fb_map[i] = info_idx;
+
++ bootsplash_init();
++
+ err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
+ fbcon_is_default);
+
+@@ -661,6 +664,9 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
+ else {
+ fbcon_set_rotation(info);
+ fbcon_set_bitops(ops);
++
++ if (bootsplash_would_render_now())
++ fbcon_set_dummyops(ops);
+ }
+ }
+
+@@ -683,6 +689,19 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
+ ops->p = &fb_display[vc->vc_num];
+ fbcon_set_rotation(info);
+ fbcon_set_bitops(ops);
++
++ /*
++ * Note:
++ * This is *eventually correct*.
++ * Setting the fbcon operations and drawing the splash happen at
++ * different points in time. If the splash is enabled/disabled
++ * in between, then bootsplash_{en,dis}able will schedule a
++ * redraw, which will again render the splash (or not) and set
++ * the correct fbcon ops.
++ * The last run will then be the right one.
++ */
++ if (bootsplash_would_render_now())
++ fbcon_set_dummyops(ops);
+ }
+
+ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
+@@ -2184,6 +2203,9 @@ static int fbcon_switch(struct vc_data *vc)
+ info = registered_fb[con2fb_map[vc->vc_num]];
+ ops = info->fbcon_par;
+
++ if (bootsplash_would_render_now())
++ bootsplash_render_full(info);
++
+ if (softback_top) {
+ if (softback_lines)
+ fbcon_set_origin(vc);
+diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
+index 18f3ac144237..45f94347fe5e 100644
+--- a/drivers/video/fbdev/core/fbcon.h
++++ b/drivers/video/fbdev/core/fbcon.h
+@@ -214,6 +214,11 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
+ #define SCROLL_REDRAW 0x004
+ #define SCROLL_PAN_REDRAW 0x005
+
++#ifdef CONFIG_BOOTSPLASH
++extern void fbcon_set_dummyops(struct fbcon_ops *ops);
++#else /* CONFIG_BOOTSPLASH */
++#define fbcon_set_dummyops(x)
++#endif /* CONFIG_BOOTSPLASH */
+ #ifdef CONFIG_FB_TILEBLITTING
+ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
+ #endif
+diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
+new file mode 100644
+index 000000000000..c6dd0b43180d
+--- /dev/null
++++ b/include/linux/bootsplash.h
+@@ -0,0 +1,43 @@
++/*
++ * Kernel based bootsplash.
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * SPDX-License-Identifier: GPL-2.0
++ */
++
++#ifndef __LINUX_BOOTSPLASH_H
++#define __LINUX_BOOTSPLASH_H
++
++#include <linux/fb.h>
++
++
++#ifdef CONFIG_BOOTSPLASH
++
++extern void bootsplash_render_full(struct fb_info *info);
++
++extern bool bootsplash_would_render_now(void);
++
++extern bool bootsplash_is_enabled(void);
++extern void bootsplash_disable(void);
++extern void bootsplash_enable(void);
++
++extern void bootsplash_init(void);
++
++#else /* CONFIG_BOOTSPLASH */
++
++#define bootsplash_render_full(x)
++
++#define bootsplash_would_render_now() (false)
++
++#define bootsplash_is_enabled() (false)
++#define bootsplash_disable()
++#define bootsplash_enable()
++
++#define bootsplash_init()
++
++#endif /* CONFIG_BOOTSPLASH */
++
++
++#endif
diff --git a/0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch b/0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch
deleted file mode 100644
index 59d743decca..00000000000
--- a/0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From f6f6b798c7330d7851fee4bbe835c3954886fc3f Mon Sep 17 00:00:00 2001
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Wed, 3 Jul 2019 11:10:49 +0300
-Subject: [PATCH 3/4] iwlwifi: mvm: disable TX-AMSDU on older NICs
-
-On older NICs, we occasionally see issues with A-MSDU support,
-where the commands in the FIFO get confused and then we see an
-assert EDC because the next command in the FIFO isn't TX.
-
-We've tried to isolate this issue and understand where it comes
-from, but haven't found any errors in building the A-MSDU in
-software.
-
-At least for now, disable A-MSDU support on older hardware so
-that users can use it again without fearing the assert.
-
-This fixes https://bugzilla.kernel.org/show_bug.cgi?id=203315.
-
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
-Acked-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
-index fdbabca0280e..3a076e5e319f 100644
---- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
-+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
-@@ -468,7 +468,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
- ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
- ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);
- ieee80211_hw_set(hw, STA_MMPDU_TXQ);
-- ieee80211_hw_set(hw, TX_AMSDU);
-+ /*
-+ * On older devices, enabling TX A-MSDU occasionally leads to
-+ * something getting messed up, the command read from the FIFO
-+ * gets out of sync and isn't a TX command, so that we have an
-+ * assert EDC.
-+ *
-+ * It's not clear where the bug is, but since we didn't used to
-+ * support A-MSDU until moving the mac80211 iTXQs, just leave it
-+ * for older devices. We also don't see this issue on any newer
-+ * devices.
-+ */
-+ if (mvm->cfg->device_family >= IWL_DEVICE_FAMILY_9000)
-+ ieee80211_hw_set(hw, TX_AMSDU);
- ieee80211_hw_set(hw, TX_FRAG_LIST);
-
- if (iwl_mvm_has_tlc_offload(mvm)) {
---
-2.22.0
-
diff --git a/0004-bootsplash.patch b/0004-bootsplash.patch
new file mode 100644
index 00000000000..92d62caa703
--- /dev/null
+++ b/0004-bootsplash.patch
@@ -0,0 +1,669 @@
+diff --git a/MAINTAINERS b/MAINTAINERS
+index b5633b56391e..5c237445761e 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -2712,6 +2712,7 @@ S: Maintained
+ F: drivers/video/fbdev/core/bootsplash*.*
+ F: drivers/video/fbdev/core/dummycon.c
+ F: include/linux/bootsplash.h
++F: include/uapi/linux/bootsplash_file.h
+
+ BPF (Safe dynamic programs and tools)
+ M: Alexei Starovoitov <ast@kernel.org>
+diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
+index 66895321928e..6a8d1bab8a01 100644
+--- a/drivers/video/fbdev/core/Makefile
++++ b/drivers/video/fbdev/core/Makefile
+@@ -31,4 +31,4 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o
+ obj-$(CONFIG_FB_DDC) += fb_ddc.o
+
+ obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
+- dummyblit.o
++ bootsplash_load.o dummyblit.o
+diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
+index e449755af268..843c5400fefc 100644
+--- a/drivers/video/fbdev/core/bootsplash.c
++++ b/drivers/video/fbdev/core/bootsplash.c
+@@ -32,6 +32,7 @@
+ #include <linux/workqueue.h>
+
+ #include "bootsplash_internal.h"
++#include "uapi/linux/bootsplash_file.h"
+
+
+ /*
+@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info)
+ */
+ void bootsplash_render_full(struct fb_info *info)
+ {
++ mutex_lock(&splash_state.data_lock);
++
+ if (!is_fb_compatible(info))
+- return;
++ goto out;
++
++ bootsplash_do_render_background(info, splash_state.file);
++
++ bootsplash_do_render_pictures(info, splash_state.file);
+
+- bootsplash_do_render_background(info);
++out:
++ mutex_unlock(&splash_state.data_lock);
+ }
+
+
+@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void)
+ {
+ return !oops_in_progress
+ && !console_blanked
++ && splash_state.file
+ && bootsplash_is_enabled();
+ }
+
+@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = {
+ void bootsplash_init(void)
+ {
+ int ret;
++ struct splash_file_priv *fp;
+
+ /* Initialized already? */
+ if (splash_state.splash_device)
+@@ -280,8 +290,26 @@ void bootsplash_init(void)
+ }
+
+
++ mutex_init(&splash_state.data_lock);
++ set_bit(0, &splash_state.enabled);
++
+ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
+
++
++ if (!splash_state.bootfile || !strlen(splash_state.bootfile))
++ return;
++
++ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
++ splash_state.bootfile);
++
++ if (!fp)
++ goto err;
++
++ mutex_lock(&splash_state.data_lock);
++ splash_state.splash_fb = NULL;
++ splash_state.file = fp;
++ mutex_unlock(&splash_state.data_lock);
++
+ return;
+
+ err_device:
+@@ -292,3 +320,7 @@ void bootsplash_init(void)
+ err:
+ pr_err("Failed to initialize.\n");
+ }
++
++
++module_param_named(bootfile, splash_state.bootfile, charp, 0444);
++MODULE_PARM_DESC(bootfile, "Bootsplash file to load on boot");
+diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
+index b11da5cb90bf..71e2a27ac0b8 100644
+--- a/drivers/video/fbdev/core/bootsplash_internal.h
++++ b/drivers/video/fbdev/core/bootsplash_internal.h
+@@ -15,15 +15,43 @@
+
+ #include <linux/types.h>
+ #include <linux/fb.h>
++#include <linux/firmware.h>
+ #include <linux/kernel.h>
+ #include <linux/mutex.h>
+ #include <linux/spinlock.h>
+
++#include "uapi/linux/bootsplash_file.h"
++
+
+ /*
+ * Runtime types
+ */
++struct splash_blob_priv {
++ struct splash_blob_header *blob_header;
++ const void *data;
++};
++
++
++struct splash_pic_priv {
++ const struct splash_pic_header *pic_header;
++
++ struct splash_blob_priv *blobs;
++ u16 blobs_loaded;
++};
++
++
++struct splash_file_priv {
++ const struct firmware *fw;
++ const struct splash_file_header *header;
++
++ struct splash_pic_priv *pics;
++};
++
++
+ struct splash_priv {
++ /* Bootup and runtime state */
++ char *bootfile;
++
+ /*
+ * Enabled/disabled state, to be used with atomic bit operations.
+ * Bit 0: 0 = Splash hidden
+@@ -43,6 +71,13 @@ struct splash_priv {
+ struct platform_device *splash_device;
+
+ struct work_struct work_redraw_vc;
++
++ /* Splash data structures including lock for everything below */
++ struct mutex data_lock;
++
++ struct fb_info *splash_fb;
++
++ struct splash_file_priv *file;
+ };
+
+
+@@ -50,6 +85,14 @@ struct splash_priv {
+ /*
+ * Rendering functions
+ */
+-void bootsplash_do_render_background(struct fb_info *info);
++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);
++
++
++void bootsplash_free_file(struct splash_file_priv *fp);
++struct splash_file_priv *bootsplash_load_firmware(struct device *device,
++ const char *path);
+
+ #endif
+diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
+new file mode 100644
+index 000000000000..fd807571ab7d
+--- /dev/null
++++ b/drivers/video/fbdev/core/bootsplash_load.c
+@@ -0,0 +1,225 @@
++/*
++ * Kernel based bootsplash.
++ *
++ * (Loading and freeing functions)
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * SPDX-License-Identifier: GPL-2.0
++ */
++
++#define pr_fmt(fmt) "bootsplash: " fmt
++
++
++#include <linux/bootsplash.h>
++#include <linux/fb.h>
++#include <linux/firmware.h>
++#include <linux/kernel.h>
++#include <linux/mutex.h>
++#include <linux/printk.h>
++#include <linux/types.h>
++#include <linux/vmalloc.h>
++
++#include "bootsplash_internal.h"
++#include "uapi/linux/bootsplash_file.h"
++
++
++
++
++/*
++ * Free all vmalloc()'d resources describing a splash file.
++ */
++void bootsplash_free_file(struct splash_file_priv *fp)
++{
++ if (!fp)
++ return;
++
++ if (fp->pics) {
++ unsigned int i;
++
++ for (i = 0; i < fp->header->num_pics; i++) {
++ struct splash_pic_priv *pp = &fp->pics[i];
++
++ if (pp->blobs)
++ vfree(pp->blobs);
++ }
++
++ vfree(fp->pics);
++ }
++
++ release_firmware(fp->fw);
++ vfree(fp);
++}
++
++
++
++
++/*
++ * Load a splash screen from a "firmware" file.
++ *
++ * Parsing, and sanity checks.
++ */
++#ifdef __BIG_ENDIAN
++ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_BE
++#else
++ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_LE
++#endif
++
++struct splash_file_priv *bootsplash_load_firmware(struct device *device,
++ const char *path)
++{
++ const struct firmware *fw;
++ struct splash_file_priv *fp;
++ unsigned int i;
++ const u8 *walker;
++
++ if (request_firmware(&fw, path, device))
++ return NULL;
++
++ if (fw->size < sizeof(struct splash_file_header)
++ || memcmp(fw->data, BOOTSPLASH_MAGIC, sizeof(fp->header->id))) {
++ pr_err("Not a bootsplash file.\n");
++
++ release_firmware(fw);
++ return NULL;
++ }
++
++ fp = vzalloc(sizeof(struct splash_file_priv));
++ if (!fp) {
++ release_firmware(fw);
++ return NULL;
++ }
++
++ pr_info("Loading splash file (%li bytes)\n", fw->size);
++
++ fp->fw = fw;
++ fp->header = (struct splash_file_header *)fw->data;
++
++ /* Sanity checks */
++ if (fp->header->version != BOOTSPLASH_VERSION) {
++ pr_err("Loaded v%d file, but we only support version %d\n",
++ fp->header->version,
++ BOOTSPLASH_VERSION);
++
++ goto err;
++ }
++
++ if (fw->size < sizeof(struct splash_file_header)
++ + fp->header->num_pics
++ * sizeof(struct splash_pic_header)
++ + fp->header->num_blobs
++ * sizeof(struct splash_blob_header)) {
++ pr_err("File incomplete.\n");
++
++ goto err;
++ }
++
++ /* Read picture headers */
++ if (fp->header->num_pics) {
++ fp->pics = vzalloc(fp->header->num_pics
++ * sizeof(struct splash_pic_priv));
++ if (!fp->pics)
++ goto err;
++ }
++
++ walker = fw->data + sizeof(struct splash_file_header);
++ for (i = 0; i < fp->header->num_pics; i++) {
++ struct splash_pic_priv *pp = &fp->pics[i];
++ struct splash_pic_header *ph = (void *)walker;
++
++ pr_debug("Picture %u: Size %ux%u\n", i, ph->width, ph->height);
++
++ if (ph->num_blobs < 1) {
++ pr_err("Picture %u: Zero blobs? Aborting load.\n", i);
++ goto err;
++ }
++
++ pp->pic_header = ph;
++ pp->blobs = vzalloc(ph->num_blobs
++ * sizeof(struct splash_blob_priv));
++ if (!pp->blobs)
++ goto err;
++
++ walker += sizeof(struct splash_pic_header);
++ }
++
++ /* Read blob headers */
++ for (i = 0; i < fp->header->num_blobs; i++) {
++ struct splash_blob_header *bh = (void *)walker;
++ struct splash_pic_priv *pp;
++
++ if (walker + sizeof(struct splash_blob_header)
++ > fw->data + fw->size)
++ goto err;
++
++ walker += sizeof(struct splash_blob_header);
++
++ if (walker + bh->length > fw->data + fw->size)
++ goto err;
++
++ if (bh->picture_id >= fp->header->num_pics)
++ goto nextblob;
++
++ pp = &fp->pics[bh->picture_id];
++
++ pr_debug("Blob %u, pic %u, blobs_loaded %u, num_blobs %u.\n",
++ i, bh->picture_id,
++ pp->blobs_loaded, pp->pic_header->num_blobs);
++
++ if (pp->blobs_loaded >= pp->pic_header->num_blobs)
++ goto nextblob;
++
++ switch (bh->type) {
++ case 0:
++ /* Raw 24-bit packed pixels */
++ if (bh->length != pp->pic_header->width
++ * pp->pic_header->height * 3) {
++ pr_err("Blob %u, type 1: Length doesn't match picture.\n",
++ i);
++
++ goto err;
++ }
++ break;
++ default:
++ pr_warn("Blob %u, unknown type %u.\n", i, bh->type);
++ goto nextblob;
++ }
++
++ pp->blobs[pp->blobs_loaded].blob_header = bh;
++ pp->blobs[pp->blobs_loaded].data = walker;
++ pp->blobs_loaded++;
++
++nextblob:
++ walker += bh->length;
++ if (bh->length % 16)
++ walker += 16 - (bh->length % 16);
++ }
++
++ if (walker != fw->data + fw->size)
++ pr_warn("Trailing data in splash file.\n");
++
++ /* 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];
++
++ if (pp->blobs_loaded != pp->pic_header->num_blobs) {
++ pr_err("Picture %u doesn't have all blob slots filled.\n",
++ i);
++
++ goto err;
++ }
++ }
++
++ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
++ fw->size,
++ fp->header->num_pics,
++ fp->header->num_blobs);
++
++ return fp;
++
++
++err:
++ bootsplash_free_file(fp);
++ return NULL;
++}
+diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
+index 4d7e0117f653..2ae36949d0e3 100644
+--- a/drivers/video/fbdev/core/bootsplash_render.c
++++ b/drivers/video/fbdev/core/bootsplash_render.c
+@@ -19,6 +19,7 @@
+ #include <linux/types.h>
+
+ #include "bootsplash_internal.h"
++#include "uapi/linux/bootsplash_file.h"
+
+
+
+@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
+ }
+
+
+-void bootsplash_do_render_background(struct fb_info *info)
++/*
++ * Copy from source and blend into the destination picture.
++ * Currently assumes that the source picture is 24bpp.
++ * Currently assumes that the destination is <= 32bpp.
++ */
++static int splash_convert_to_fb(u8 *dst,
++ const struct fb_var_screeninfo *dst_var,
++ unsigned int dst_stride,
++ unsigned int dst_xoff,
++ unsigned int dst_yoff,
++ const u8 *src,
++ unsigned int src_width,
++ unsigned int src_height)
++{
++ unsigned int x, y;
++ unsigned int src_stride = 3 * src_width; /* Assume 24bpp packed */
++ u32 dst_octpp = dst_var->bits_per_pixel / 8;
++
++ dst_xoff += dst_var->xoffset;
++ dst_yoff += dst_var->yoffset;
++
++ /* Copy with stride and pixel size adjustment */
++ for (y = 0;
++ y < src_height && y + dst_yoff < dst_var->yres_virtual;
++ y++) {
++ const u8 *srcline = src + (y * src_stride);
++ u8 *dstline = dst + ((y + dst_yoff) * dst_stride)
++ + (dst_xoff * dst_octpp);
++
++ for (x = 0;
++ x < src_width && x + dst_xoff < dst_var->xres_virtual;
++ x++) {
++ u8 red, green, blue;
++ u32 dstpix;
++
++ /* Read pixel */
++ red = *srcline++;
++ green = *srcline++;
++ blue = *srcline++;
++
++ /* Write pixel */
++ dstpix = pack_pixel(dst_var, red, green, blue);
++ memcpy(dstline, &dstpix, dst_octpp);
++
++ dstline += dst_octpp;
++ }
++ }
++
++ return 0;
++}
++
++
++void bootsplash_do_render_background(struct fb_info *info,
++ const struct splash_file_priv *fp)
+ {
+ unsigned int x, y;
+ u32 dstpix;
+ u32 dst_octpp = info->var.bits_per_pixel / 8;
+
+ dstpix = pack_pixel(&info->var,
+- 0,
+- 0,
+- 0);
++ fp->header->bg_red,
++ fp->header->bg_green,
++ fp->header->bg_blue);
+
+ for (y = 0; y < info->var.yres_virtual; y++) {
+ u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
+@@ -91,3 +145,44 @@ void bootsplash_do_render_background(struct fb_info *info)
+ }
+ }
+ }
++
++
++void bootsplash_do_render_pictures(struct fb_info *info,
++ const struct splash_file_priv *fp)
++{
++ unsigned int i;
++
++ for (i = 0; i < fp->header->num_pics; i++) {
++ struct splash_blob_priv *bp;
++ struct splash_pic_priv *pp = &fp->pics[i];
++ long dst_xoff, dst_yoff;
++
++ if (pp->blobs_loaded < 1)
++ continue;
++
++ bp = &pp->blobs[0];
++
++ if (!bp || bp->blob_header->type != 0)
++ continue;
++
++ dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
++ dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
++
++ if (dst_xoff < 0
++ || dst_yoff < 0
++ || dst_xoff + pp->pic_header->width > info->var.xres
++ || dst_yoff + pp->pic_header->height > info->var.yres) {
++ pr_info_once("Picture %u is out of bounds at current resolution: %dx%d\n"
++ "(this will only be printed once every reboot)\n",
++ i, info->var.xres, info->var.yres);
++
++ continue;
++ }
++
++ /* Draw next splash frame */
++ splash_convert_to_fb(info->screen_buffer, &info->var,
++ info->fix.line_length, dst_xoff, dst_yoff,
++ bp->data,
++ pp->pic_header->width, pp->pic_header->height);
++ }
++}
+diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
+new file mode 100644
+index 000000000000..89dc9cca8f0c
+--- /dev/null
++++ b/include/uapi/linux/bootsplash_file.h
+@@ -0,0 +1,118 @@
++/*
++ * Kernel based bootsplash.
++ *
++ * (File format)
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
++ */
++
++#ifndef __BOOTSPLASH_FILE_H
++#define __BOOTSPLASH_FILE_H
++
++
++#define BOOTSPLASH_VERSION 55561
++
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++
++
++/*
++ * On-disk types
++ *
++ * A splash file consists of:
++ * - One single 'struct splash_file_header'
++ * - An array of 'struct splash_pic_header'
++ * - An array of raw data blocks, each padded to 16 bytes and
++ * preceded by a 'struct splash_blob_header'
++ *
++ * A single-frame splash may look like this:
++ *
++ * +--------------------+
++ * | |
++ * | splash_file_header |
++ * | -> num_blobs = 1 |
++ * | -> num_pics = 1 |
++ * | |
++ * +--------------------+
++ * | |
++ * | splash_pic_header |
++ * | |
++ * +--------------------+
++ * | |
++ * | splash_blob_header |
++ * | -> type = 0 |
++ * | -> picture_id = 0 |
++ * | |
++ * | (raw RGB data) |
++ * | (pad to 16 bytes) |
++ * | |
++ * +--------------------+
++ *
++ * All multi-byte values are stored on disk in the native format
++ * expected by the system the file will be used on.
++ */
++#define BOOTSPLASH_MAGIC_BE "Linux bootsplash"
++#define BOOTSPLASH_MAGIC_LE "hsalpstoob xuniL"
++
++struct splash_file_header {
++ uint8_t id[16]; /* "Linux bootsplash" (no trailing NUL) */
++
++ /* Splash file format version to avoid clashes */
++ uint16_t version;
++
++ /* The background color */
++ uint8_t bg_red;
++ uint8_t bg_green;
++ uint8_t bg_blue;
++ uint8_t bg_reserved;
++
++ /*
++ * Number of pic/blobs so we can allocate memory for internal
++ * structures ahead of time when reading the file
++ */
++ uint16_t num_blobs;
++ uint8_t num_pics;
++
++ uint8_t padding[103];
++} __attribute__((__packed__));
++
++
++struct splash_pic_header {
++ uint16_t width;
++ uint16_t height;
++
++ /*
++ * Number of data packages associated with this picture.
++ * Currently, the only use for more than 1 is for animations.
++ */
++ uint8_t num_blobs;
++
++ uint8_t padding[27];
++} __attribute__((__packed__));
++
++
++struct splash_blob_header {
++ /* Length of the data block in bytes. */
++ uint32_t length;
++
++ /*
++ * Type of the contents.
++ * 0 - Raw RGB data.
++ */
++ uint16_t type;
++
++ /*
++ * Picture this blob is associated with.
++ * Blobs will be added to a picture in the order they are
++ * found in the file.
++ */
++ uint8_t picture_id;
++
++ uint8_t padding[9];
++} __attribute__((__packed__));
++
++#endif
diff --git a/0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch b/0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch
deleted file mode 100644
index 67a9c762ccc..00000000000
--- a/0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch
+++ /dev/null
@@ -1,328 +0,0 @@
-From e7cae1276332a8d1a94e1e0e272c8b9209bdd83f Mon Sep 17 00:00:00 2001
-From: Haim Dreyfuss <haim.dreyfuss@intel.com>
-Date: Wed, 27 Feb 2019 16:43:45 +0200
-Subject: [PATCH 4/6] iwlwifi: Add support for SAR South Korea limitation
-
-South Korea is adding a more strict SAR limit called "Limb SAR".
-Currently, WGDS SAR offset group 3 is not used (not mapped to any country).
-In order to be able to comply with South Korea new restriction:
-- OEM will use WGDS SAR offset group 3 to South Korea limitation.
-- OEM will change WGDS revision to 1 (currently latest revision is 0)
- to notify that Korea Limb SAR applied.
-- Driver will read the WGDS table and pass the values to FW (as usual)
-- Driver will pass to FW an indication that Korea Limb SAR is applied
- in case table revision is 1.
-
-Signed-off-by: Haim Dreyfuss <haim.dreyfuss@intel.com>
-Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
----
- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 28 ++++++----
- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 5 +-
- .../net/wireless/intel/iwlwifi/fw/api/power.h | 12 ++++
- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 +
- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 55 ++++++++++++++-----
- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 +
- 6 files changed, 76 insertions(+), 28 deletions(-)
-
-diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
-index 405038ce98d6..7573af2d88ce 100644
---- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
-+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
-@@ -97,7 +97,7 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
-
- union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
- union acpi_object *data,
-- int data_size)
-+ int data_size, int *tbl_rev)
- {
- int i;
- union acpi_object *wifi_pkg;
-@@ -113,16 +113,19 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
- /*
- * We need at least two packages, one for the revision and one
- * for the data itself. Also check that the revision is valid
-- * (i.e. it is an integer set to 0).
-+ * (i.e. it is an integer smaller than 2, as we currently support only
-+ * 2 revisions).
- */
- if (data->type != ACPI_TYPE_PACKAGE ||
- data->package.count < 2 ||
- data->package.elements[0].type != ACPI_TYPE_INTEGER ||
-- data->package.elements[0].integer.value != 0) {
-+ data->package.elements[0].integer.value > 1) {
- IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n");
- return ERR_PTR(-EINVAL);
- }
-
-+ *tbl_rev = data->package.elements[0].integer.value;
-+
- /* loop through all the packages to find the one for WiFi */
- for (i = 1; i < data->package.count; i++) {
- union acpi_object *domain;
-@@ -151,14 +154,15 @@ int iwl_acpi_get_mcc(struct device *dev, char *mcc)
- {
- union acpi_object *wifi_pkg, *data;
- u32 mcc_val;
-- int ret;
-+ int ret, tbl_rev;
-
- data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
- if (IS_ERR(data))
- return PTR_ERR(data);
-
-- wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE);
-- if (IS_ERR(wifi_pkg)) {
-+ wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE,
-+ &tbl_rev);
-+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
- ret = PTR_ERR(wifi_pkg);
- goto out_free;
- }
-@@ -185,6 +189,7 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev)
- {
- union acpi_object *data, *wifi_pkg;
- u64 dflt_pwr_limit;
-+ int tbl_rev;
-
- data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
- if (IS_ERR(data)) {
-@@ -193,8 +198,8 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev)
- }
-
- wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
-- ACPI_SPLC_WIFI_DATA_SIZE);
-- if (IS_ERR(wifi_pkg) ||
-+ ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
-+ if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
- wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
- dflt_pwr_limit = 0;
- goto out_free;
-@@ -211,14 +216,15 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
- int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk)
- {
- union acpi_object *wifi_pkg, *data;
-- int ret;
-+ int ret, tbl_rev;
-
- data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD);
- if (IS_ERR(data))
- return PTR_ERR(data);
-
-- wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE);
-- if (IS_ERR(wifi_pkg)) {
-+ wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE,
-+ &tbl_rev);
-+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
- ret = PTR_ERR(wifi_pkg);
- goto out_free;
- }
-diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
-index f5704e16643f..991a23450999 100644
---- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
-+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
-@@ -97,7 +97,7 @@
- void *iwl_acpi_get_object(struct device *dev, acpi_string method);
- union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
- union acpi_object *data,
-- int data_size);
-+ int data_size, int *tbl_rev);
-
- /**
- * iwl_acpi_get_mcc - read MCC from ACPI, if available
-@@ -131,7 +131,8 @@ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method)
-
- static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
- union acpi_object *data,
-- int data_size)
-+ int data_size,
-+ int *tbl_rev)
- {
- return ERR_PTR(-ENOENT);
- }
-diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
-index 01f003c6cff9..f195db398bed 100644
---- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
-+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
-@@ -419,14 +419,26 @@ struct iwl_per_chain_offset_group {
- struct iwl_per_chain_offset hb;
- } __packed; /* PER_CHAIN_LIMIT_OFFSET_GROUP_S_VER_1 */
-
-+/**
-+ * struct iwl_geo_tx_power_profile_cmd_v1 - struct for GEO_TX_POWER_LIMIT cmd.
-+ * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
-+ * @table: offset profile per band.
-+ */
-+struct iwl_geo_tx_power_profiles_cmd_v1 {
-+ __le32 ops;
-+ struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES];
-+} __packed; /* GEO_TX_POWER_LIMIT_VER_1 */
-+
- /**
- * struct iwl_geo_tx_power_profile_cmd - struct for GEO_TX_POWER_LIMIT cmd.
- * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
- * @table: offset profile per band.
-+ * @table_revision: BIOS table revision.
- */
- struct iwl_geo_tx_power_profiles_cmd {
- __le32 ops;
- struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES];
-+ __le32 table_revision;
- } __packed; /* GEO_TX_POWER_LIMIT */
-
- /**
-diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
-index de9243d30135..a74f34a8dffb 100644
---- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
-+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
-@@ -286,6 +286,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
- * SCAN_OFFLOAD_PROFILES_QUERY_RSP_S.
- * @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of
- * STA_CONTEXT_DOT11AX_API_S
-+ * @IWL_UCODE_TLV_CAPA_SAR_TABLE_VER: This ucode supports different sar
-+ * version tables.
- *
- * @NUM_IWL_UCODE_TLV_API: number of bits used
- */
-@@ -318,6 +320,7 @@ enum iwl_ucode_tlv_api {
- IWL_UCODE_TLV_API_MBSSID_HE = (__force iwl_ucode_tlv_api_t)52,
- IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE = (__force iwl_ucode_tlv_api_t)53,
- IWL_UCODE_TLV_API_FTM_RTT_ACCURACY = (__force iwl_ucode_tlv_api_t)54,
-+ IWL_UCODE_TLV_API_SAR_TABLE_VER = (__force iwl_ucode_tlv_api_t)55,
-
- NUM_IWL_UCODE_TLV_API
- #ifdef __CHECKER__
-diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
-index 559f6df1a74d..8a3e542c47b2 100644
---- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
-+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
-@@ -682,15 +682,15 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm)
- {
- union acpi_object *wifi_pkg, *table, *data;
- bool enabled;
-- int ret;
-+ int ret, tbl_rev;
-
- data = iwl_acpi_get_object(mvm->dev, ACPI_WRDS_METHOD);
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
-- ACPI_WRDS_WIFI_DATA_SIZE);
-- if (IS_ERR(wifi_pkg)) {
-+ ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev);
-+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
- ret = PTR_ERR(wifi_pkg);
- goto out_free;
- }
-@@ -719,15 +719,15 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
- {
- union acpi_object *wifi_pkg, *data;
- bool enabled;
-- int i, n_profiles, ret;
-+ int i, n_profiles, ret, tbl_rev;
-
- data = iwl_acpi_get_object(mvm->dev, ACPI_EWRD_METHOD);
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
-- ACPI_EWRD_WIFI_DATA_SIZE);
-- if (IS_ERR(wifi_pkg)) {
-+ ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev);
-+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
- ret = PTR_ERR(wifi_pkg);
- goto out_free;
- }
-@@ -778,7 +778,7 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
- static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
- {
- union acpi_object *wifi_pkg, *data;
-- int i, j, ret;
-+ int i, j, ret, tbl_rev;
- int idx = 1;
-
- data = iwl_acpi_get_object(mvm->dev, ACPI_WGDS_METHOD);
-@@ -786,12 +786,13 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
- return PTR_ERR(data);
-
- wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
-- ACPI_WGDS_WIFI_DATA_SIZE);
-- if (IS_ERR(wifi_pkg)) {
-+ ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev);
-+ if (IS_ERR(wifi_pkg) || tbl_rev > 1) {
- ret = PTR_ERR(wifi_pkg);
- goto out_free;
- }
-
-+ mvm->geo_rev = tbl_rev;
- for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) {
- for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) {
- union acpi_object *entry;
-@@ -878,15 +879,29 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
- {
- struct iwl_geo_tx_power_profiles_resp *resp;
- int ret;
-+ u16 len;
-+ void *data;
-+ struct iwl_geo_tx_power_profiles_cmd geo_cmd;
-+ struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1;
-+ struct iwl_host_cmd cmd;
-+
-+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
-+ geo_cmd.ops =
-+ cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
-+ len = sizeof(geo_cmd);
-+ data = &geo_cmd;
-+ } else {
-+ geo_cmd_v1.ops =
-+ cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
-+ len = sizeof(geo_cmd_v1);
-+ data = &geo_cmd_v1;
-+ }
-
-- struct iwl_geo_tx_power_profiles_cmd geo_cmd = {
-- .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE),
-- };
-- struct iwl_host_cmd cmd = {
-+ cmd = (struct iwl_host_cmd){
- .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
-- .len = { sizeof(geo_cmd), },
-+ .len = { len, },
- .flags = CMD_WANT_SKB,
-- .data = { &geo_cmd },
-+ .data = { data },
- };
-
- ret = iwl_mvm_send_cmd(mvm, &cmd);
-@@ -956,6 +971,16 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
- i, j, value[1], value[2], value[0]);
- }
- }
-+
-+ cmd.table_revision = cpu_to_le32(mvm->geo_rev);
-+
-+ if (!fw_has_api(&mvm->fw->ucode_capa,
-+ IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
-+ return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0,
-+ sizeof(struct iwl_geo_tx_power_profiles_cmd_v1),
-+ &cmd);
-+ }
-+
- return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, sizeof(cmd), &cmd);
- }
-
-diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
-index 88af1f0ba3f0..ed8fc9a9204c 100644
---- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
-+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
-@@ -1184,6 +1184,7 @@ struct iwl_mvm {
- #ifdef CONFIG_ACPI
- struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM];
- struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES];
-+ u32 geo_rev;
- #endif
- };
-
---
-2.22.0
-
diff --git a/0005-bootsplash.patch b/0005-bootsplash.patch
new file mode 100644
index 00000000000..216953762e2
--- /dev/null
+++ b/0005-bootsplash.patch
@@ -0,0 +1,66 @@
+diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
+index 843c5400fefc..815b007f81ca 100644
+--- a/drivers/video/fbdev/core/bootsplash.c
++++ b/drivers/video/fbdev/core/bootsplash.c
+@@ -112,6 +112,8 @@ void bootsplash_render_full(struct fb_info *info)
+
+ bootsplash_do_render_pictures(info, splash_state.file);
+
++ bootsplash_do_render_flush(info);
++
+ out:
+ mutex_unlock(&splash_state.data_lock);
+ }
+diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
+index 71e2a27ac0b8..0acb383aa4e3 100644
+--- a/drivers/video/fbdev/core/bootsplash_internal.h
++++ b/drivers/video/fbdev/core/bootsplash_internal.h
+@@ -89,6 +89,7 @@ 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);
++void bootsplash_do_render_flush(struct fb_info *info);
+
+
+ void bootsplash_free_file(struct splash_file_priv *fp);
+diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
+index 2ae36949d0e3..8c09c306ff67 100644
+--- a/drivers/video/fbdev/core/bootsplash_render.c
++++ b/drivers/video/fbdev/core/bootsplash_render.c
+@@ -186,3 +186,36 @@ void bootsplash_do_render_pictures(struct fb_info *info,
+ pp->pic_header->width, pp->pic_header->height);
+ }
+ }
++
++
++void bootsplash_do_render_flush(struct fb_info *info)
++{
++ /*
++ * FB drivers using deferred_io (such as Xen) need to sync the
++ * screen after modifying its contents. When the FB is mmap()ed
++ * from userspace, this happens via a dirty pages callback, but
++ * when modifying the FB from the kernel, there is no such thing.
++ *
++ * So let's issue a fake fb_copyarea (copying the FB onto itself)
++ * to trick the FB driver into syncing the screen.
++ *
++ * A few DRM drivers' FB implementations are broken by not using
++ * deferred_io when they really should - we match on the known
++ * bad ones manually for now.
++ */
++ if (info->fbdefio
++ || !strcmp(info->fix.id, "astdrmfb")
++ || !strcmp(info->fix.id, "cirrusdrmfb")
++ || !strcmp(info->fix.id, "mgadrmfb")) {
++ struct fb_copyarea area;
++
++ area.dx = 0;
++ area.dy = 0;
++ area.width = info->var.xres;
++ area.height = info->var.yres;
++ area.sx = 0;
++ area.sy = 0;
++
++ info->fbops->fb_copyarea(info, &area);
++ }
++}
diff --git a/0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch b/0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch
deleted file mode 100644
index 1c617f6121d..00000000000
--- a/0005-netfilter-nf_tables-fix-module-autoload-for-redir.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 103abca5ff3ca4db4d8f6c21626fa597fe122a03 Mon Sep 17 00:00:00 2001
-From: Christian Hesse <mail@eworm.de>
-Date: Thu, 11 Jul 2019 01:31:12 +0200
-Subject: [PATCH 5/6] netfilter: nf_tables: fix module autoload for redir
-
-Fix expression for autoloading.
-
-Fixes: 5142967ab524 ("netfilter: nf_tables: fix module autoload with inet family")
-Signed-off-by: Christian Hesse <mail@eworm.de>
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
- net/netfilter/nft_redir.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c
-index 8487eeff5c0e..43eeb1f609f1 100644
---- a/net/netfilter/nft_redir.c
-+++ b/net/netfilter/nft_redir.c
-@@ -291,4 +291,4 @@ module_exit(nft_redir_module_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
--MODULE_ALIAS_NFT_EXPR("nat");
-+MODULE_ALIAS_NFT_EXPR("redir");
---
-2.22.0
-
diff --git a/0006-bootsplash.patch b/0006-bootsplash.patch
index 924f23f33ce..7eb54aff7e0 100644
--- a/0006-bootsplash.patch
+++ b/0006-bootsplash.patch
@@ -1,746 +1,215 @@
-diff --git a/MAINTAINERS b/MAINTAINERS
-index a74227ad082e..b5633b56391e 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -2705,6 +2705,14 @@ S: Supported
- F: drivers/net/bonding/
- F: include/uapi/linux/if_bonding.h
+diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
+index 8c09c306ff67..07e3a4eab811 100644
+--- a/drivers/video/fbdev/core/bootsplash_render.c
++++ b/drivers/video/fbdev/core/bootsplash_render.c
+@@ -155,6 +155,7 @@ void bootsplash_do_render_pictures(struct fb_info *info,
+ for (i = 0; i < fp->header->num_pics; i++) {
+ struct splash_blob_priv *bp;
+ struct splash_pic_priv *pp = &fp->pics[i];
++ const struct splash_pic_header *ph = pp->pic_header;
+ long dst_xoff, dst_yoff;
-+BOOTSPLASH
-+M: Max Staudt <mstaudt@suse.de>
-+L: linux-fbdev@vger.kernel.org
-+S: Maintained
-+F: drivers/video/fbdev/core/bootsplash*.*
-+F: drivers/video/fbdev/core/dummycon.c
-+F: include/linux/bootsplash.h
-+
- BPF (Safe dynamic programs and tools)
- M: Alexei Starovoitov <ast@kernel.org>
- M: Daniel Borkmann <daniel@iogearbox.net>
-diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
-index 7f1f1fbcef9e..f3ff976266fe 100644
---- a/drivers/video/console/Kconfig
-+++ b/drivers/video/console/Kconfig
-@@ -151,6 +151,30 @@ config FRAMEBUFFER_CONSOLE_ROTATION
- such that other users of the framebuffer will remain normally
- oriented.
+ if (pp->blobs_loaded < 1)
+@@ -165,8 +166,139 @@ void bootsplash_do_render_pictures(struct fb_info *info,
+ if (!bp || bp->blob_header->type != 0)
+ continue;
-+config BOOTSPLASH
-+ bool "Bootup splash screen"
-+ depends on FRAMEBUFFER_CONSOLE
-+ ---help---
-+ This option enables the Linux bootsplash screen.
-+
-+ The bootsplash is a full-screen logo or animation indicating a
-+ booting system. It replaces the classic scrolling text with a
-+ graphical alternative, similar to other systems.
-+
-+ Since this is technically implemented as a hook on top of fbcon,
-+ it can only work if the FRAMEBUFFER_CONSOLE is enabled and a
-+ framebuffer driver is active. Thus, to get a text-free boot,
-+ the system needs to boot with vesafb, efifb, or similar.
-+
-+ Once built into the kernel, the bootsplash needs to be enabled
-+ with bootsplash.enabled=1 and a splash file needs to be supplied.
-+
-+ Further documentation can be found in:
-+ Documentation/fb/bootsplash.txt
-+
-+ If unsure, say N.
-+ This is typically used by distributors and system integrators.
-+
- config STI_CONSOLE
- bool "STI text console"
- depends on PARISC
-diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
-index 73493bbd7a15..66895321928e 100644
---- a/drivers/video/fbdev/core/Makefile
-+++ b/drivers/video/fbdev/core/Makefile
-@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
- obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
- obj-$(CONFIG_FB_SVGALIB) += svgalib.o
- obj-$(CONFIG_FB_DDC) += fb_ddc.o
-+
-+obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
-+ dummyblit.o
-diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
-new file mode 100644
-index 000000000000..e449755af268
---- /dev/null
-+++ b/drivers/video/fbdev/core/bootsplash.c
-@@ -0,0 +1,294 @@
-+/*
-+ * Kernel based bootsplash.
-+ *
-+ * (Main file: Glue code, workers, timer, PM, kernel and userland API)
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * SPDX-License-Identifier: GPL-2.0
-+ */
-+
-+#define pr_fmt(fmt) "bootsplash: " fmt
-+
-+
-+#include <linux/atomic.h>
-+#include <linux/bootsplash.h>
-+#include <linux/console.h>
-+#include <linux/device.h> /* dev_warn() */
-+#include <linux/fb.h>
-+#include <linux/fs.h>
-+#include <linux/kernel.h>
-+#include <linux/jiffies.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/selection.h> /* console_blanked */
-+#include <linux/stringify.h>
-+#include <linux/types.h>
-+#include <linux/vmalloc.h>
-+#include <linux/vt_kern.h>
-+#include <linux/workqueue.h>
-+
-+#include "bootsplash_internal.h"
-+
-+
-+/*
-+ * We only have one splash screen, so let's keep a single
-+ * instance of the internal state.
-+ */
-+static struct splash_priv splash_state;
-+
-+
-+static void splash_callback_redraw_vc(struct work_struct *ignored)
-+{
-+ if (console_blanked)
-+ return;
-+
-+ console_lock();
-+ if (vc_cons[fg_console].d)
-+ update_screen(vc_cons[fg_console].d);
-+ console_unlock();
-+}
-+
-+
-+static bool is_fb_compatible(const struct fb_info *info)
-+{
-+ if (!(info->flags & FBINFO_BE_MATH)
-+ != !fb_be_math((struct fb_info *)info)) {
-+ dev_warn(info->device,
-+ "Can't draw on foreign endianness framebuffer.\n");
-+
-+ return false;
-+ }
-+
-+ if (info->flags & FBINFO_MISC_TILEBLITTING) {
-+ dev_warn(info->device,
-+ "Can't draw splash on tiling framebuffer.\n");
-+
-+ return false;
-+ }
-+
-+ if (info->fix.type != FB_TYPE_PACKED_PIXELS
-+ || (info->fix.visual != FB_VISUAL_TRUECOLOR
-+ && info->fix.visual != FB_VISUAL_DIRECTCOLOR)) {
-+ dev_warn(info->device,
-+ "Can't draw splash on non-packed or non-truecolor framebuffer.\n");
-+
-+ dev_warn(info->device,
-+ " type: %u visual: %u\n",
-+ info->fix.type, info->fix.visual);
-+
-+ return false;
-+ }
-+
-+ if (info->var.bits_per_pixel != 16
-+ && info->var.bits_per_pixel != 24
-+ && info->var.bits_per_pixel != 32) {
-+ dev_warn(info->device,
-+ "We only support drawing on framebuffers with 16, 24, or 32 bpp, not %d.\n",
-+ info->var.bits_per_pixel);
-+
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+
-+/*
-+ * Called by fbcon_switch() when an instance is activated or refreshed.
-+ */
-+void bootsplash_render_full(struct fb_info *info)
-+{
-+ if (!is_fb_compatible(info))
-+ return;
-+
-+ bootsplash_do_render_background(info);
-+}
-+
-+
-+/*
-+ * External status enquiry and on/off switch
-+ */
-+bool bootsplash_would_render_now(void)
-+{
-+ return !oops_in_progress
-+ && !console_blanked
-+ && bootsplash_is_enabled();
-+}
-+
-+bool bootsplash_is_enabled(void)
-+{
-+ bool was_enabled;
-+
-+ /* Make sure we have the newest state */
-+ smp_rmb();
-+
-+ was_enabled = test_bit(0, &splash_state.enabled);
-+
-+ return was_enabled;
-+}
-+
-+void bootsplash_disable(void)
-+{
-+ int was_enabled;
-+
-+ was_enabled = test_and_clear_bit(0, &splash_state.enabled);
-+
-+ if (was_enabled) {
-+ if (oops_in_progress) {
-+ /* Redraw screen now so we can see a panic */
-+ if (vc_cons[fg_console].d)
-+ update_screen(vc_cons[fg_console].d);
-+ } else {
-+ /* No urgency, redraw at next opportunity */
-+ schedule_work(&splash_state.work_redraw_vc);
+- dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
+- dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
++ switch (ph->position) {
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_LEFT:
++ dst_xoff = 0;
++ dst_yoff = 0;
++
++ dst_xoff += ph->position_offset;
++ dst_yoff += ph->position_offset;
++ break;
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = 0;
++
++ dst_yoff += ph->position_offset;
++ break;
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_RIGHT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_yoff = 0;
++
++ dst_xoff -= ph->position_offset;
++ dst_yoff += ph->position_offset;
++ break;
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_RIGHT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff -= ph->position_offset;
++ break;
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_RIGHT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++
++ dst_xoff -= ph->position_offset;
++ dst_yoff -= ph->position_offset;
++ break;
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++
++ dst_yoff -= ph->position_offset;
++ break;
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_LEFT:
++ dst_xoff = 0 + ph->position_offset;
++ dst_yoff = info->var.yres - pp->pic_header->height
++ - ph->position_offset;
++ break;
++ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_LEFT:
++ dst_xoff = 0;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff += ph->position_offset;
++ break;
++
++ case SPLASH_CORNER_TOP_LEFT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff -= ph->position_offset;
++ dst_yoff -= ph->position_offset;
++ break;
++ case SPLASH_CORNER_TOP:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_yoff -= ph->position_offset;
++ break;
++ case SPLASH_CORNER_TOP_RIGHT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff += ph->position_offset;
++ dst_yoff -= ph->position_offset;
++ break;
++ case SPLASH_CORNER_RIGHT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff += ph->position_offset;
++ break;
++ case SPLASH_CORNER_BOTTOM_RIGHT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff += ph->position_offset;
++ dst_yoff += ph->position_offset;
++ break;
++ case SPLASH_CORNER_BOTTOM:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_yoff += ph->position_offset;
++ break;
++ case SPLASH_CORNER_BOTTOM_LEFT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff -= ph->position_offset;
++ dst_yoff += ph->position_offset;
++ break;
++ case SPLASH_CORNER_LEFT:
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++
++ dst_xoff -= ph->position_offset;
++ break;
++
++ default:
++ /* As a fallback, center the picture. */
++ dst_xoff = info->var.xres - pp->pic_header->width;
++ dst_xoff /= 2;
++ dst_yoff = info->var.yres - pp->pic_header->height;
++ dst_yoff /= 2;
++ break;
+ }
-+ }
-+}
-+
-+void bootsplash_enable(void)
-+{
-+ bool was_enabled;
-+
-+ if (oops_in_progress)
-+ return;
-+
-+ was_enabled = test_and_set_bit(0, &splash_state.enabled);
-+
-+ if (!was_enabled)
-+ schedule_work(&splash_state.work_redraw_vc);
-+}
-+
-+
-+/*
-+ * Userland API via platform device in sysfs
-+ */
-+static ssize_t splash_show_enabled(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ return sprintf(buf, "%d\n", bootsplash_is_enabled());
-+}
-+
-+static ssize_t splash_store_enabled(struct device *device,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ bool enable;
-+ int err;
-+
-+ if (!buf || !count)
-+ return -EFAULT;
-+
-+ err = kstrtobool(buf, &enable);
-+ if (err)
-+ return err;
-+
-+ if (enable)
-+ bootsplash_enable();
-+ else
-+ bootsplash_disable();
-+
-+ return count;
-+}
-+
-+static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
-+
-+
-+static struct attribute *splash_dev_attrs[] = {
-+ &dev_attr_enabled.attr,
-+ NULL
-+};
-+
-+ATTRIBUTE_GROUPS(splash_dev);
-+
-+
-+
-+
-+/*
-+ * Power management fixup via platform device
-+ *
-+ * When the system is woken from sleep or restored after hibernating, we
-+ * cannot expect the screen contents to still be present in video RAM.
-+ * Thus, we have to redraw the splash if we're currently active.
-+ */
-+static int splash_resume(struct device *device)
-+{
-+ if (bootsplash_would_render_now())
-+ schedule_work(&splash_state.work_redraw_vc);
-+
-+ return 0;
-+}
-+
-+static int splash_suspend(struct device *device)
-+{
-+ cancel_work_sync(&splash_state.work_redraw_vc);
-+
-+ return 0;
-+}
-+
-+
-+static const struct dev_pm_ops splash_pm_ops = {
-+ .thaw = splash_resume,
-+ .restore = splash_resume,
-+ .resume = splash_resume,
-+ .suspend = splash_suspend,
-+ .freeze = splash_suspend,
-+};
-+
-+static struct platform_driver splash_driver = {
-+ .driver = {
-+ .name = "bootsplash",
-+ .pm = &splash_pm_ops,
-+ },
-+};
-+
-+
-+/*
-+ * Main init
-+ */
-+void bootsplash_init(void)
-+{
-+ int ret;
-+
-+ /* Initialized already? */
-+ if (splash_state.splash_device)
-+ return;
-+
-+
-+ /* Register platform device to export user API */
-+ ret = platform_driver_register(&splash_driver);
-+ if (ret) {
-+ pr_err("platform_driver_register() failed: %d\n", ret);
-+ goto err;
-+ }
-+
-+ splash_state.splash_device
-+ = platform_device_alloc("bootsplash", 0);
-+
-+ if (!splash_state.splash_device)
-+ goto err_driver;
-+
-+ splash_state.splash_device->dev.groups = splash_dev_groups;
-+
-+ ret = platform_device_add(splash_state.splash_device);
-+ if (ret) {
-+ pr_err("platform_device_add() failed: %d\n", ret);
-+ goto err_device;
-+ }
-+
-+
-+ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
-+
-+ return;
-+
-+err_device:
-+ platform_device_put(splash_state.splash_device);
-+ splash_state.splash_device = NULL;
-+err_driver:
-+ platform_driver_unregister(&splash_driver);
-+err:
-+ pr_err("Failed to initialize.\n");
-+}
-diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
-new file mode 100644
-index 000000000000..b11da5cb90bf
---- /dev/null
-+++ b/drivers/video/fbdev/core/bootsplash_internal.h
-@@ -0,0 +1,55 @@
-+/*
-+ * Kernel based bootsplash.
-+ *
-+ * (Internal data structures used at runtime)
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * SPDX-License-Identifier: GPL-2.0
-+ */
-+
-+#ifndef __BOOTSPLASH_INTERNAL_H
-+#define __BOOTSPLASH_INTERNAL_H
-+
-+
-+#include <linux/types.h>
-+#include <linux/fb.h>
-+#include <linux/kernel.h>
-+#include <linux/mutex.h>
-+#include <linux/spinlock.h>
-+
-+
-+/*
-+ * Runtime types
-+ */
-+struct splash_priv {
+
+ if (dst_xoff < 0
+ || dst_yoff < 0
+diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
+index 89dc9cca8f0c..71cedcc68933 100644
+--- a/include/uapi/linux/bootsplash_file.h
++++ b/include/uapi/linux/bootsplash_file.h
+@@ -91,7 +91,32 @@ struct splash_pic_header {
+ */
+ uint8_t num_blobs;
+
+- uint8_t padding[27];
+ /*
-+ * Enabled/disabled state, to be used with atomic bit operations.
-+ * Bit 0: 0 = Splash hidden
-+ * 1 = Splash shown
++ * Corner to move the picture to / from.
++ * 0x00 - Top left
++ * 0x01 - Top
++ * 0x02 - Top right
++ * 0x03 - Right
++ * 0x04 - Bottom right
++ * 0x05 - Bottom
++ * 0x06 - Bottom left
++ * 0x07 - Left
+ *
-+ * Note: fbcon.c uses this twice, by calling
-+ * bootsplash_would_render_now() in set_blitting_type() and
-+ * in fbcon_switch().
-+ * This is racy, but eventually consistent: Turning the
-+ * splash on/off will cause a redraw, which calls
-+ * fbcon_switch(), which calls set_blitting_type().
-+ * So the last on/off toggle will make things consistent.
-+ */
-+ unsigned long enabled;
-+
-+ /* Our gateway to userland via sysfs */
-+ struct platform_device *splash_device;
-+
-+ struct work_struct work_redraw_vc;
-+};
-+
-+
-+
-+/*
-+ * Rendering functions
-+ */
-+void bootsplash_do_render_background(struct fb_info *info);
-+
-+#endif
-diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
-new file mode 100644
-index 000000000000..4d7e0117f653
---- /dev/null
-+++ b/drivers/video/fbdev/core/bootsplash_render.c
-@@ -0,0 +1,93 @@
-+/*
-+ * Kernel based bootsplash.
-+ *
-+ * (Rendering functions)
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * SPDX-License-Identifier: GPL-2.0
-+ */
-+
-+#define pr_fmt(fmt) "bootsplash: " fmt
-+
-+
-+#include <linux/bootsplash.h>
-+#include <linux/fb.h>
-+#include <linux/kernel.h>
-+#include <linux/printk.h>
-+#include <linux/types.h>
-+
-+#include "bootsplash_internal.h"
-+
-+
-+
-+
-+/*
-+ * Rendering: Internal drawing routines
-+ */
-+
-+
-+/*
-+ * Pack pixel into target format and do Big/Little Endian handling.
-+ * This would be a good place to handle endianness conversion if necessary.
-+ */
-+static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
-+ u8 red, u8 green, u8 blue)
-+{
-+ u32 dstpix;
-+
-+ /* Quantize pixel */
-+ red = red >> (8 - dst_var->red.length);
-+ green = green >> (8 - dst_var->green.length);
-+ blue = blue >> (8 - dst_var->blue.length);
-+
-+ /* Pack pixel */
-+ dstpix = red << (dst_var->red.offset)
-+ | green << (dst_var->green.offset)
-+ | blue << (dst_var->blue.offset);
-+
-+ /*
-+ * Move packed pixel to the beginning of the memory cell,
-+ * so we can memcpy() it out easily
++ * Flags:
++ * 0x10 - Calculate offset from the corner towards the center,
++ * rather than from the center towards the corner
+ */
-+#ifdef __BIG_ENDIAN
-+ switch (dst_var->bits_per_pixel) {
-+ case 16:
-+ dstpix <<= 16;
-+ break;
-+ case 24:
-+ dstpix <<= 8;
-+ break;
-+ case 32:
-+ break;
-+ }
-+#else
-+ /* This is intrinsically unnecessary on Little Endian */
-+#endif
-+
-+ return dstpix;
-+}
-+
-+
-+void bootsplash_do_render_background(struct fb_info *info)
-+{
-+ unsigned int x, y;
-+ u32 dstpix;
-+ u32 dst_octpp = info->var.bits_per_pixel / 8;
-+
-+ dstpix = pack_pixel(&info->var,
-+ 0,
-+ 0,
-+ 0);
-+
-+ for (y = 0; y < info->var.yres_virtual; y++) {
-+ u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
-+
-+ for (x = 0; x < info->var.xres_virtual; x++) {
-+ memcpy(dstline, &dstpix, dst_octpp);
-+
-+ dstline += dst_octpp;
-+ }
-+ }
-+}
-diff --git a/drivers/video/fbdev/core/dummyblit.c b/drivers/video/fbdev/core/dummyblit.c
-new file mode 100644
-index 000000000000..8c22ff92ce24
---- /dev/null
-+++ b/drivers/video/fbdev/core/dummyblit.c
-@@ -0,0 +1,89 @@
-+/*
-+ * linux/drivers/video/fbdev/core/dummyblit.c -- Dummy Blitting Operation
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * These functions are used in place of blitblit/tileblit to suppress
-+ * fbcon's text output while a splash is shown.
-+ *
-+ * Only suppressing actual rendering keeps the text buffer in the VC layer
-+ * intact and makes it easy to switch back from the bootsplash to a full
-+ * text console with a simple redraw (with the original functions in place).
-+ *
-+ * Based on linux/drivers/video/fbdev/core/bitblit.c
-+ * and linux/drivers/video/fbdev/core/tileblit.c
-+ *
-+ * SPDX-License-Identifier: GPL-2.0
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/fb.h>
-+#include <linux/vt_kern.h>
-+#include <linux/console.h>
-+#include <asm/types.h>
-+#include "fbcon.h"
++ uint8_t position;
+
-+static void dummy_bmove(struct vc_data *vc, struct fb_info *info, int sy,
-+ int sx, int dy, int dx, int height, int width)
-+{
-+ ;
-+}
-+
-+static void dummy_clear(struct vc_data *vc, struct fb_info *info, int sy,
-+ int sx, int height, int width)
-+{
-+ ;
-+}
-+
-+static void dummy_putcs(struct vc_data *vc, struct fb_info *info,
-+ const unsigned short *s, int count, int yy, int xx,
-+ int fg, int bg)
-+{
-+ ;
-+}
-+
-+static void dummy_clear_margins(struct vc_data *vc, struct fb_info *info,
-+ int color, int bottom_only)
-+{
-+ ;
-+}
-+
-+static void dummy_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-+ int softback_lines, int fg, int bg)
-+{
-+ ;
-+}
-+
-+static int dummy_update_start(struct fb_info *info)
-+{
+ /*
-+ * Copied from bitblit.c and tileblit.c
-+ *
-+ * As of Linux 4.12, nobody seems to care about our return value.
++ * Pixel offset from the selected position.
++ * Example: If the picture is in the top right corner, it will
++ * be placed position_offset pixels from the top and
++ * position_offset pixels from the right margin.
+ */
-+ struct fbcon_ops *ops = info->fbcon_par;
-+ int err;
++ uint16_t position_offset;
+
-+ err = fb_pan_display(info, &ops->var);
-+ ops->var.xoffset = info->var.xoffset;
-+ ops->var.yoffset = info->var.yoffset;
-+ ops->var.vmode = info->var.vmode;
-+ return err;
-+}
-+
-+void fbcon_set_dummyops(struct fbcon_ops *ops)
-+{
-+ ops->bmove = dummy_bmove;
-+ ops->clear = dummy_clear;
-+ ops->putcs = dummy_putcs;
-+ ops->clear_margins = dummy_clear_margins;
-+ ops->cursor = dummy_cursor;
-+ ops->update_start = dummy_update_start;
-+ ops->rotate_font = NULL;
-+}
-+EXPORT_SYMBOL_GPL(fbcon_set_dummyops);
-+
-+MODULE_AUTHOR("Max Staudt <mstaudt@suse.de>");
-+MODULE_DESCRIPTION("Dummy Blitting Operation");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
-index 04612f938bab..9a39a6fcfe98 100644
---- a/drivers/video/fbdev/core/fbcon.c
-+++ b/drivers/video/fbdev/core/fbcon.c
-@@ -80,6 +80,7 @@
- #include <asm/irq.h>
++ uint8_t padding[24];
+ } __attribute__((__packed__));
- #include "fbcon.h"
-+#include <linux/bootsplash.h>
- #ifdef FBCONDEBUG
- # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
-@@ -542,6 +543,8 @@ static int do_fbcon_takeover(int show_logo)
- for (i = first_fb_vc; i <= last_fb_vc; i++)
- con2fb_map[i] = info_idx;
+@@ -115,4 +140,22 @@ struct splash_blob_header {
+ uint8_t padding[9];
+ } __attribute__((__packed__));
-+ bootsplash_init();
+
- err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
- fbcon_is_default);
-
-@@ -661,6 +664,9 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
- else {
- fbcon_set_rotation(info);
- fbcon_set_bitops(ops);
-+
-+ if (bootsplash_would_render_now())
-+ fbcon_set_dummyops(ops);
- }
- }
-
-@@ -683,6 +689,19 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
- ops->p = &fb_display[vc->vc_num];
- fbcon_set_rotation(info);
- fbcon_set_bitops(ops);
+
-+ /*
-+ * Note:
-+ * This is *eventually correct*.
-+ * Setting the fbcon operations and drawing the splash happen at
-+ * different points in time. If the splash is enabled/disabled
-+ * in between, then bootsplash_{en,dis}able will schedule a
-+ * redraw, which will again render the splash (or not) and set
-+ * the correct fbcon ops.
-+ * The last run will then be the right one.
-+ */
-+ if (bootsplash_would_render_now())
-+ fbcon_set_dummyops(ops);
- }
-
- static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
-@@ -2184,6 +2203,9 @@ static int fbcon_switch(struct vc_data *vc)
- info = registered_fb[con2fb_map[vc->vc_num]];
- ops = info->fbcon_par;
-
-+ if (bootsplash_would_render_now())
-+ bootsplash_render_full(info);
+
- if (softback_top) {
- if (softback_lines)
- fbcon_set_origin(vc);
-diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
-index 18f3ac144237..45f94347fe5e 100644
---- a/drivers/video/fbdev/core/fbcon.h
-+++ b/drivers/video/fbdev/core/fbcon.h
-@@ -214,6 +214,11 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
- #define SCROLL_REDRAW 0x004
- #define SCROLL_PAN_REDRAW 0x005
-
-+#ifdef CONFIG_BOOTSPLASH
-+extern void fbcon_set_dummyops(struct fbcon_ops *ops);
-+#else /* CONFIG_BOOTSPLASH */
-+#define fbcon_set_dummyops(x)
-+#endif /* CONFIG_BOOTSPLASH */
- #ifdef CONFIG_FB_TILEBLITTING
- extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
- #endif
-diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
-new file mode 100644
-index 000000000000..c6dd0b43180d
---- /dev/null
-+++ b/include/linux/bootsplash.h
-@@ -0,0 +1,43 @@
+/*
-+ * Kernel based bootsplash.
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * SPDX-License-Identifier: GPL-2.0
++ * Enums for on-disk types
+ */
++enum splash_position {
++ SPLASH_CORNER_TOP_LEFT = 0,
++ SPLASH_CORNER_TOP = 1,
++ SPLASH_CORNER_TOP_RIGHT = 2,
++ SPLASH_CORNER_RIGHT = 3,
++ SPLASH_CORNER_BOTTOM_RIGHT = 4,
++ SPLASH_CORNER_BOTTOM = 5,
++ SPLASH_CORNER_BOTTOM_LEFT = 6,
++ SPLASH_CORNER_LEFT = 7,
++ SPLASH_POS_FLAG_CORNER = 0x10,
++};
+
-+#ifndef __LINUX_BOOTSPLASH_H
-+#define __LINUX_BOOTSPLASH_H
-+
-+#include <linux/fb.h>
-+
-+
-+#ifdef CONFIG_BOOTSPLASH
-+
-+extern void bootsplash_render_full(struct fb_info *info);
-+
-+extern bool bootsplash_would_render_now(void);
-+
-+extern bool bootsplash_is_enabled(void);
-+extern void bootsplash_disable(void);
-+extern void bootsplash_enable(void);
-+
-+extern void bootsplash_init(void);
-+
-+#else /* CONFIG_BOOTSPLASH */
-+
-+#define bootsplash_render_full(x)
-+
-+#define bootsplash_would_render_now() (false)
-+
-+#define bootsplash_is_enabled() (false)
-+#define bootsplash_disable()
-+#define bootsplash_enable()
-+
-+#define bootsplash_init()
-+
-+#endif /* CONFIG_BOOTSPLASH */
-+
-+
-+#endif
+ #endif
diff --git a/0007-bootsplash.patch b/0007-bootsplash.patch
index 92d62caa703..2785c5e6527 100644
--- a/0007-bootsplash.patch
+++ b/0007-bootsplash.patch
@@ -1,669 +1,327 @@
-diff --git a/MAINTAINERS b/MAINTAINERS
-index b5633b56391e..5c237445761e 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -2712,6 +2712,7 @@ S: Maintained
- F: drivers/video/fbdev/core/bootsplash*.*
- F: drivers/video/fbdev/core/dummycon.c
- F: include/linux/bootsplash.h
-+F: include/uapi/linux/bootsplash_file.h
-
- BPF (Safe dynamic programs and tools)
- M: Alexei Starovoitov <ast@kernel.org>
-diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
-index 66895321928e..6a8d1bab8a01 100644
---- a/drivers/video/fbdev/core/Makefile
-+++ b/drivers/video/fbdev/core/Makefile
-@@ -31,4 +31,4 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o
- obj-$(CONFIG_FB_DDC) += fb_ddc.o
-
- obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
-- dummyblit.o
-+ bootsplash_load.o dummyblit.o
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
-index e449755af268..843c5400fefc 100644
+index 815b007f81ca..c8642142cfea 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
-@@ -32,6 +32,7 @@
- #include <linux/workqueue.h>
-
- #include "bootsplash_internal.h"
-+#include "uapi/linux/bootsplash_file.h"
+@@ -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);
++ }
++}
++
- /*
-@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info)
+ 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)
{
-+ mutex_lock(&splash_state.data_lock);
++ bool is_update = false;
+
- if (!is_fb_compatible(info))
-- return;
-+ goto out;
+ 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;
+
-+ bootsplash_do_render_background(info, splash_state.file);
+
-+ bootsplash_do_render_pictures(info, splash_state.file);
++ 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);
-+out:
-+ mutex_unlock(&splash_state.data_lock);
- }
+- 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);
-@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void)
- {
- return !oops_in_progress
- && !console_blanked
-+ && splash_state.file
- && bootsplash_is_enabled();
- }
+ bootsplash_do_render_flush(info);
-@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = {
- void bootsplash_init(void)
- {
- int ret;
-+ struct splash_file_priv *fp;
++ 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)
- /* Initialized already? */
- if (splash_state.splash_device)
-@@ -280,8 +290,26 @@ void bootsplash_init(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);
++ }
+ }
-+ mutex_init(&splash_state.data_lock);
-+ set_bit(0, &splash_state.enabled);
-+
- INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
-+
-+ if (!splash_state.bootfile || !strlen(splash_state.bootfile))
-+ return;
-+
-+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
-+ splash_state.bootfile);
-+
-+ if (!fp)
-+ goto err;
-+
+@@ -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;
-+ splash_state.file = fp;
+ mutex_unlock(&splash_state.data_lock);
+
- return;
+ if (bootsplash_would_render_now())
+ schedule_work(&splash_state.work_redraw_vc);
- err_device:
-@@ -292,3 +320,7 @@ void bootsplash_init(void)
- err:
- pr_err("Failed to initialize.\n");
- }
-+
-+
-+module_param_named(bootfile, splash_state.bootfile, charp, 0444);
-+MODULE_PARM_DESC(bootfile, "Bootsplash file to load on boot");
+@@ -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 b11da5cb90bf..71e2a27ac0b8 100644
+index 0acb383aa4e3..b3a74835d90f 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
-@@ -15,15 +15,43 @@
-
- #include <linux/types.h>
- #include <linux/fb.h>
-+#include <linux/firmware.h>
- #include <linux/kernel.h>
- #include <linux/mutex.h>
- #include <linux/spinlock.h>
+@@ -37,6 +37,8 @@ struct splash_pic_priv {
-+#include "uapi/linux/bootsplash_file.h"
+ struct splash_blob_priv *blobs;
+ u16 blobs_loaded;
+
++ u16 anim_nextframe;
+ };
- /*
- * Runtime types
- */
-+struct splash_blob_priv {
-+ struct splash_blob_header *blob_header;
-+ const void *data;
-+};
-+
-+
-+struct splash_pic_priv {
-+ const struct splash_pic_header *pic_header;
-+
-+ struct splash_blob_priv *blobs;
-+ u16 blobs_loaded;
-+};
-+
-+
-+struct splash_file_priv {
-+ const struct firmware *fw;
-+ const struct splash_file_header *header;
-+
-+ struct splash_pic_priv *pics;
-+};
-+
-+
- struct splash_priv {
-+ /* Bootup and runtime state */
-+ char *bootfile;
+
+@@ -45,6 +47,12 @@ struct splash_file_priv {
+ const struct splash_file_header *header;
+
+ struct splash_pic_priv *pics;
+
- /*
- * Enabled/disabled state, to be used with atomic bit operations.
- * Bit 0: 0 = Splash hidden
-@@ -43,6 +71,13 @@ struct splash_priv {
++ /*
++ * 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;
-+
-+ /* Splash data structures including lock for everything below */
-+ struct mutex data_lock;
-+
-+ struct fb_info *splash_fb;
-+
-+ struct splash_file_priv *file;
- };
++ 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);
-@@ -50,6 +85,14 @@ struct splash_priv {
- /*
- * Rendering functions
- */
--void bootsplash_do_render_background(struct fb_info *info);
-+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);
-+
-+
-+void bootsplash_free_file(struct splash_file_priv *fp);
-+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
-+ const char *path);
- #endif
+ 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
-new file mode 100644
-index 000000000000..fd807571ab7d
---- /dev/null
+index fd807571ab7d..1f661b2d4cc9 100644
+--- a/drivers/video/fbdev/core/bootsplash_load.c
+++ b/drivers/video/fbdev/core/bootsplash_load.c
-@@ -0,0 +1,225 @@
-+/*
-+ * Kernel based bootsplash.
-+ *
-+ * (Loading and freeing functions)
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * SPDX-License-Identifier: GPL-2.0
-+ */
-+
-+#define pr_fmt(fmt) "bootsplash: " fmt
-+
-+
-+#include <linux/bootsplash.h>
-+#include <linux/fb.h>
-+#include <linux/firmware.h>
-+#include <linux/kernel.h>
-+#include <linux/mutex.h>
-+#include <linux/printk.h>
-+#include <linux/types.h>
-+#include <linux/vmalloc.h>
-+
-+#include "bootsplash_internal.h"
-+#include "uapi/linux/bootsplash_file.h"
-+
-+
-+
-+
-+/*
-+ * Free all vmalloc()'d resources describing a splash file.
-+ */
-+void bootsplash_free_file(struct splash_file_priv *fp)
-+{
-+ if (!fp)
-+ return;
-+
-+ if (fp->pics) {
-+ unsigned int i;
-+
-+ for (i = 0; i < fp->header->num_pics; i++) {
-+ struct splash_pic_priv *pp = &fp->pics[i];
-+
-+ if (pp->blobs)
-+ vfree(pp->blobs);
-+ }
-+
-+ vfree(fp->pics);
-+ }
-+
-+ release_firmware(fp->fw);
-+ vfree(fp);
-+}
-+
-+
-+
-+
-+/*
-+ * Load a splash screen from a "firmware" file.
-+ *
-+ * Parsing, and sanity checks.
-+ */
-+#ifdef __BIG_ENDIAN
-+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_BE
-+#else
-+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_LE
-+#endif
-+
-+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
-+ const char *path)
-+{
-+ const struct firmware *fw;
-+ struct splash_file_priv *fp;
-+ unsigned int i;
-+ const u8 *walker;
-+
-+ if (request_firmware(&fw, path, device))
-+ return NULL;
-+
-+ if (fw->size < sizeof(struct splash_file_header)
-+ || memcmp(fw->data, BOOTSPLASH_MAGIC, sizeof(fp->header->id))) {
-+ pr_err("Not a bootsplash file.\n");
-+
-+ release_firmware(fw);
-+ return NULL;
-+ }
-+
-+ fp = vzalloc(sizeof(struct splash_file_priv));
-+ if (!fp) {
-+ release_firmware(fw);
-+ return NULL;
-+ }
-+
-+ pr_info("Loading splash file (%li bytes)\n", fw->size);
-+
-+ fp->fw = fw;
-+ fp->header = (struct splash_file_header *)fw->data;
-+
-+ /* Sanity checks */
-+ if (fp->header->version != BOOTSPLASH_VERSION) {
-+ pr_err("Loaded v%d file, but we only support version %d\n",
-+ fp->header->version,
-+ BOOTSPLASH_VERSION);
-+
-+ goto err;
-+ }
-+
-+ if (fw->size < sizeof(struct splash_file_header)
-+ + fp->header->num_pics
-+ * sizeof(struct splash_pic_header)
-+ + fp->header->num_blobs
-+ * sizeof(struct splash_blob_header)) {
-+ pr_err("File incomplete.\n");
-+
-+ goto err;
-+ }
-+
-+ /* Read picture headers */
-+ if (fp->header->num_pics) {
-+ fp->pics = vzalloc(fp->header->num_pics
-+ * sizeof(struct splash_pic_priv));
-+ if (!fp->pics)
-+ goto err;
-+ }
-+
-+ walker = fw->data + sizeof(struct splash_file_header);
-+ for (i = 0; i < fp->header->num_pics; i++) {
-+ struct splash_pic_priv *pp = &fp->pics[i];
-+ struct splash_pic_header *ph = (void *)walker;
-+
-+ pr_debug("Picture %u: Size %ux%u\n", i, ph->width, ph->height);
-+
-+ if (ph->num_blobs < 1) {
-+ pr_err("Picture %u: Zero blobs? Aborting load.\n", i);
-+ goto err;
-+ }
-+
-+ pp->pic_header = ph;
-+ pp->blobs = vzalloc(ph->num_blobs
-+ * sizeof(struct splash_blob_priv));
-+ if (!pp->blobs)
-+ goto err;
-+
-+ walker += sizeof(struct splash_pic_header);
-+ }
-+
-+ /* Read blob headers */
-+ for (i = 0; i < fp->header->num_blobs; i++) {
-+ struct splash_blob_header *bh = (void *)walker;
-+ struct splash_pic_priv *pp;
-+
-+ if (walker + sizeof(struct splash_blob_header)
-+ > fw->data + fw->size)
-+ goto err;
-+
-+ walker += sizeof(struct splash_blob_header);
-+
-+ if (walker + bh->length > fw->data + fw->size)
-+ goto err;
-+
-+ if (bh->picture_id >= fp->header->num_pics)
-+ goto nextblob;
-+
-+ pp = &fp->pics[bh->picture_id];
-+
-+ pr_debug("Blob %u, pic %u, blobs_loaded %u, num_blobs %u.\n",
-+ i, bh->picture_id,
-+ pp->blobs_loaded, pp->pic_header->num_blobs);
-+
-+ if (pp->blobs_loaded >= pp->pic_header->num_blobs)
-+ goto nextblob;
-+
-+ switch (bh->type) {
-+ case 0:
-+ /* Raw 24-bit packed pixels */
-+ if (bh->length != pp->pic_header->width
-+ * pp->pic_header->height * 3) {
-+ pr_err("Blob %u, type 1: Length doesn't match picture.\n",
-+ i);
-+
-+ goto err;
-+ }
-+ break;
-+ default:
-+ pr_warn("Blob %u, unknown type %u.\n", i, bh->type);
-+ goto nextblob;
-+ }
-+
-+ pp->blobs[pp->blobs_loaded].blob_header = bh;
-+ pp->blobs[pp->blobs_loaded].data = walker;
-+ pp->blobs_loaded++;
-+
-+nextblob:
-+ walker += bh->length;
-+ if (bh->length % 16)
-+ walker += 16 - (bh->length % 16);
-+ }
-+
-+ if (walker != fw->data + fw->size)
-+ pr_warn("Trailing data in splash file.\n");
-+
-+ /* 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];
-+
-+ if (pp->blobs_loaded != pp->pic_header->num_blobs) {
-+ pr_err("Picture %u doesn't have all blob slots filled.\n",
-+ i);
+@@ -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);
+
-+ goto err;
++ ph->anim_type = SPLASH_ANIM_NONE;
+ }
-+ }
-+
-+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
-+ fw->size,
-+ fp->header->num_pics,
-+ fp->header->num_blobs);
-+
-+ return fp;
+
+ 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;
+ }
+
-+err:
-+ bootsplash_free_file(fp);
-+ return NULL;
-+}
++ 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 4d7e0117f653..2ae36949d0e3 100644
+index 07e3a4eab811..76033606ca8a 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
-@@ -19,6 +19,7 @@
- #include <linux/types.h>
-
- #include "bootsplash_internal.h"
-+#include "uapi/linux/bootsplash_file.h"
+@@ -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;
-@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
- }
-
+@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
+ if (pp->blobs_loaded < 1)
+ continue;
--void bootsplash_do_render_background(struct fb_info *info)
-+/*
-+ * Copy from source and blend into the destination picture.
-+ * Currently assumes that the source picture is 24bpp.
-+ * Currently assumes that the destination is <= 32bpp.
-+ */
-+static int splash_convert_to_fb(u8 *dst,
-+ const struct fb_var_screeninfo *dst_var,
-+ unsigned int dst_stride,
-+ unsigned int dst_xoff,
-+ unsigned int dst_yoff,
-+ const u8 *src,
-+ unsigned int src_width,
-+ unsigned int src_height)
-+{
-+ unsigned int x, y;
-+ unsigned int src_stride = 3 * src_width; /* Assume 24bpp packed */
-+ u32 dst_octpp = dst_var->bits_per_pixel / 8;
-+
-+ dst_xoff += dst_var->xoffset;
-+ dst_yoff += dst_var->yoffset;
-+
-+ /* Copy with stride and pixel size adjustment */
-+ for (y = 0;
-+ y < src_height && y + dst_yoff < dst_var->yres_virtual;
-+ y++) {
-+ const u8 *srcline = src + (y * src_stride);
-+ u8 *dstline = dst + ((y + dst_yoff) * dst_stride)
-+ + (dst_xoff * dst_octpp);
-+
-+ for (x = 0;
-+ x < src_width && x + dst_xoff < dst_var->xres_virtual;
-+ x++) {
-+ u8 red, green, blue;
-+ u32 dstpix;
-+
-+ /* Read pixel */
-+ red = *srcline++;
-+ green = *srcline++;
-+ blue = *srcline++;
-+
-+ /* Write pixel */
-+ dstpix = pack_pixel(dst_var, red, green, blue);
-+ memcpy(dstline, &dstpix, dst_octpp);
-+
-+ dstline += dst_octpp;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
+- bp = &pp->blobs[0];
++ /* Skip static pictures when refreshing animations */
++ if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
++ continue;
+
-+void bootsplash_do_render_background(struct fb_info *info,
-+ const struct splash_file_priv *fp)
- {
- unsigned int x, y;
- u32 dstpix;
- u32 dst_octpp = info->var.bits_per_pixel / 8;
-
- dstpix = pack_pixel(&info->var,
-- 0,
-- 0,
-- 0);
-+ fp->header->bg_red,
-+ fp->header->bg_green,
-+ fp->header->bg_blue);
-
- for (y = 0; y < info->var.yres_virtual; y++) {
- u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
-@@ -91,3 +145,44 @@ void bootsplash_do_render_background(struct fb_info *info)
- }
++ 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_render_pictures(struct fb_info *info,
-+ const struct splash_file_priv *fp)
++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_blob_priv *bp;
+ struct splash_pic_priv *pp = &fp->pics[i];
-+ long dst_xoff, dst_yoff;
+
-+ if (pp->blobs_loaded < 1)
++ if (pp->blobs_loaded < 2
++ || pp->pic_header->anim_loop > pp->blobs_loaded)
+ continue;
+
-+ bp = &pp->blobs[0];
-+
-+ if (!bp || bp->blob_header->type != 0)
-+ continue;
-+
-+ dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
-+ dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
-+
-+ if (dst_xoff < 0
-+ || dst_yoff < 0
-+ || dst_xoff + pp->pic_header->width > info->var.xres
-+ || dst_yoff + pp->pic_header->height > info->var.yres) {
-+ pr_info_once("Picture %u is out of bounds at current resolution: %dx%d\n"
-+ "(this will only be printed once every reboot)\n",
-+ i, info->var.xres, info->var.yres);
-+
-+ 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;
+ }
-+
-+ /* Draw next splash frame */
-+ splash_convert_to_fb(info->screen_buffer, &info->var,
-+ info->fix.line_length, dst_xoff, dst_yoff,
-+ bp->data,
-+ pp->pic_header->width, pp->pic_header->height);
+ }
+}
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
-new file mode 100644
-index 000000000000..89dc9cca8f0c
---- /dev/null
+index 71cedcc68933..b3af0a3c6487 100644
+--- a/include/uapi/linux/bootsplash_file.h
+++ b/include/uapi/linux/bootsplash_file.h
-@@ -0,0 +1,118 @@
-+/*
-+ * Kernel based bootsplash.
-+ *
-+ * (File format)
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
-+ */
-+
-+#ifndef __BOOTSPLASH_FILE_H
-+#define __BOOTSPLASH_FILE_H
-+
-+
-+#define BOOTSPLASH_VERSION 55561
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+
-+
-+/*
-+ * On-disk types
-+ *
-+ * A splash file consists of:
-+ * - One single 'struct splash_file_header'
-+ * - An array of 'struct splash_pic_header'
-+ * - An array of raw data blocks, each padded to 16 bytes and
-+ * preceded by a 'struct splash_blob_header'
-+ *
-+ * A single-frame splash may look like this:
-+ *
-+ * +--------------------+
-+ * | |
-+ * | splash_file_header |
-+ * | -> num_blobs = 1 |
-+ * | -> num_pics = 1 |
-+ * | |
-+ * +--------------------+
-+ * | |
-+ * | splash_pic_header |
-+ * | |
-+ * +--------------------+
-+ * | |
-+ * | splash_blob_header |
-+ * | -> type = 0 |
-+ * | -> picture_id = 0 |
-+ * | |
-+ * | (raw RGB data) |
-+ * | (pad to 16 bytes) |
-+ * | |
-+ * +--------------------+
-+ *
-+ * All multi-byte values are stored on disk in the native format
-+ * expected by the system the file will be used on.
-+ */
-+#define BOOTSPLASH_MAGIC_BE "Linux bootsplash"
-+#define BOOTSPLASH_MAGIC_LE "hsalpstoob xuniL"
-+
-+struct splash_file_header {
-+ uint8_t id[16]; /* "Linux bootsplash" (no trailing NUL) */
-+
-+ /* Splash file format version to avoid clashes */
-+ uint16_t version;
-+
-+ /* The background color */
-+ uint8_t bg_red;
-+ uint8_t bg_green;
-+ uint8_t bg_blue;
-+ uint8_t bg_reserved;
-+
-+ /*
-+ * Number of pic/blobs so we can allocate memory for internal
-+ * structures ahead of time when reading the file
-+ */
-+ uint16_t num_blobs;
-+ uint8_t num_pics;
-+
-+ uint8_t padding[103];
-+} __attribute__((__packed__));
-+
-+
-+struct splash_pic_header {
-+ uint16_t width;
-+ uint16_t height;
+@@ -77,7 +77,17 @@ struct splash_file_header {
+ uint16_t num_blobs;
+ uint8_t num_pics;
+
+- uint8_t padding[103];
++ uint8_t unused_1;
+
+ /*
-+ * Number of data packages associated with this picture.
-+ * Currently, the only use for more than 1 is for animations.
++ * 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.
+ */
-+ uint8_t num_blobs;
-+
-+ uint8_t padding[27];
-+} __attribute__((__packed__));
-+
-+
-+struct splash_blob_header {
-+ /* Length of the data block in bytes. */
-+ uint32_t length;
++ 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];
+ /*
-+ * Type of the contents.
-+ * 0 - Raw RGB data.
++ * Animation type.
++ * 0 - off
++ * 1 - forward loop
+ */
-+ uint16_t type;
++ uint8_t anim_type;
+
+ /*
-+ * Picture this blob is associated with.
-+ * Blobs will be added to a picture in the order they are
-+ * found in the file.
++ * 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 picture_id;
++ uint8_t anim_loop;
+
-+ uint8_t padding[9];
-+} __attribute__((__packed__));
++ 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
+ #endif
diff --git a/0008-bootsplash.patch b/0008-bootsplash.patch
index 216953762e2..d6c6db659c5 100644
--- a/0008-bootsplash.patch
+++ b/0008-bootsplash.patch
@@ -1,66 +1,82 @@
+diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
+index 2ebaba16f785..416735ab6dc1 100644
+--- a/drivers/tty/vt/vt.c
++++ b/drivers/tty/vt/vt.c
+@@ -105,6 +105,7 @@
+ #include <linux/ctype.h>
+ #include <linux/bsearch.h>
+ #include <linux/gcd.h>
++#include <linux/bootsplash.h>
+
+ #define MAX_NR_CON_DRIVER 16
+
+@@ -4235,6 +4236,7 @@ void do_unblank_screen(int leaving_gfx)
+ }
+
+ console_blanked = 0;
++ bootsplash_mark_dirty();
+ if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
+ /* Low-level driver cannot restore -> do it ourselves */
+ update_screen(vc);
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
-index 843c5400fefc..815b007f81ca 100644
+index c8642142cfea..13fcaabbc2ca 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
-@@ -112,6 +112,8 @@ void bootsplash_render_full(struct fb_info *info)
-
- bootsplash_do_render_pictures(info, splash_state.file);
+@@ -165,6 +165,13 @@ bool bootsplash_would_render_now(void)
+ && bootsplash_is_enabled();
+ }
-+ bootsplash_do_render_flush(info);
++void bootsplash_mark_dirty(void)
++{
++ mutex_lock(&splash_state.data_lock);
++ splash_state.splash_fb = NULL;
++ mutex_unlock(&splash_state.data_lock);
++}
+
- out:
- mutex_unlock(&splash_state.data_lock);
- }
-diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
-index 71e2a27ac0b8..0acb383aa4e3 100644
---- a/drivers/video/fbdev/core/bootsplash_internal.h
-+++ b/drivers/video/fbdev/core/bootsplash_internal.h
-@@ -89,6 +89,7 @@ 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);
-+void bootsplash_do_render_flush(struct fb_info *info);
+ bool bootsplash_is_enabled(void)
+ {
+ bool was_enabled;
+@@ -206,9 +213,7 @@ void bootsplash_enable(void)
+ 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);
++ bootsplash_mark_dirty();
- void bootsplash_free_file(struct splash_file_priv *fp);
-diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
-index 2ae36949d0e3..8c09c306ff67 100644
---- a/drivers/video/fbdev/core/bootsplash_render.c
-+++ b/drivers/video/fbdev/core/bootsplash_render.c
-@@ -186,3 +186,36 @@ void bootsplash_do_render_pictures(struct fb_info *info,
- pp->pic_header->width, pp->pic_header->height);
+ schedule_work(&splash_state.work_redraw_vc);
}
- }
-+
-+
-+void bootsplash_do_render_flush(struct fb_info *info)
-+{
-+ /*
-+ * FB drivers using deferred_io (such as Xen) need to sync the
-+ * screen after modifying its contents. When the FB is mmap()ed
-+ * from userspace, this happens via a dirty pages callback, but
-+ * when modifying the FB from the kernel, there is no such thing.
-+ *
-+ * So let's issue a fake fb_copyarea (copying the FB onto itself)
-+ * to trick the FB driver into syncing the screen.
-+ *
-+ * A few DRM drivers' FB implementations are broken by not using
-+ * deferred_io when they really should - we match on the known
-+ * bad ones manually for now.
-+ */
-+ if (info->fbdefio
-+ || !strcmp(info->fix.id, "astdrmfb")
-+ || !strcmp(info->fix.id, "cirrusdrmfb")
-+ || !strcmp(info->fix.id, "mgadrmfb")) {
-+ struct fb_copyarea area;
+@@ -272,9 +277,7 @@ 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);
++ bootsplash_mark_dirty();
+
+ if (bootsplash_would_render_now())
+ schedule_work(&splash_state.work_redraw_vc);
+diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
+index c6dd0b43180d..4075098aaadd 100644
+--- a/include/linux/bootsplash.h
++++ b/include/linux/bootsplash.h
+@@ -19,6 +19,8 @@ extern void bootsplash_render_full(struct fb_info *info);
+
+ extern bool bootsplash_would_render_now(void);
+
++extern void bootsplash_mark_dirty(void);
+
-+ area.dx = 0;
-+ area.dy = 0;
-+ area.width = info->var.xres;
-+ area.height = info->var.yres;
-+ area.sx = 0;
-+ area.sy = 0;
+ extern bool bootsplash_is_enabled(void);
+ extern void bootsplash_disable(void);
+ extern void bootsplash_enable(void);
+@@ -31,6 +33,8 @@ extern void bootsplash_init(void);
+
+ #define bootsplash_would_render_now() (false)
+
++#define bootsplash_mark_dirty()
+
-+ info->fbops->fb_copyarea(info, &area);
-+ }
-+}
+ #define bootsplash_is_enabled() (false)
+ #define bootsplash_disable()
+ #define bootsplash_enable()
diff --git a/0009-bootsplash.patch b/0009-bootsplash.patch
index 7eb54aff7e0..e8cd479312b 100644
--- a/0009-bootsplash.patch
+++ b/0009-bootsplash.patch
@@ -1,215 +1,42 @@
-diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
-index 8c09c306ff67..07e3a4eab811 100644
---- a/drivers/video/fbdev/core/bootsplash_render.c
-+++ b/drivers/video/fbdev/core/bootsplash_render.c
-@@ -155,6 +155,7 @@ void bootsplash_do_render_pictures(struct fb_info *info,
- for (i = 0; i < fp->header->num_pics; i++) {
- struct splash_blob_priv *bp;
- struct splash_pic_priv *pp = &fp->pics[i];
-+ const struct splash_pic_header *ph = pp->pic_header;
- long dst_xoff, dst_yoff;
+diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
+index f4166263bb3a..a248429194bb 100644
+--- a/drivers/tty/vt/keyboard.c
++++ b/drivers/tty/vt/keyboard.c
+@@ -47,6 +47,8 @@
- if (pp->blobs_loaded < 1)
-@@ -165,8 +166,139 @@ void bootsplash_do_render_pictures(struct fb_info *info,
- if (!bp || bp->blob_header->type != 0)
- continue;
+ #include <asm/irq_regs.h>
-- dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
-- dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
-+ switch (ph->position) {
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_LEFT:
-+ dst_xoff = 0;
-+ dst_yoff = 0;
++#include <linux/bootsplash.h>
+
-+ dst_xoff += ph->position_offset;
-+ dst_yoff += ph->position_offset;
-+ break;
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = 0;
-+
-+ dst_yoff += ph->position_offset;
-+ break;
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_RIGHT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_yoff = 0;
-+
-+ dst_xoff -= ph->position_offset;
-+ dst_yoff += ph->position_offset;
-+ break;
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_RIGHT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff -= ph->position_offset;
-+ break;
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_RIGHT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+
-+ dst_xoff -= ph->position_offset;
-+ dst_yoff -= ph->position_offset;
-+ break;
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+
-+ dst_yoff -= ph->position_offset;
-+ break;
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_LEFT:
-+ dst_xoff = 0 + ph->position_offset;
-+ dst_yoff = info->var.yres - pp->pic_header->height
-+ - ph->position_offset;
-+ break;
-+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_LEFT:
-+ dst_xoff = 0;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff += ph->position_offset;
-+ break;
-+
-+ case SPLASH_CORNER_TOP_LEFT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff -= ph->position_offset;
-+ dst_yoff -= ph->position_offset;
-+ break;
-+ case SPLASH_CORNER_TOP:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_yoff -= ph->position_offset;
-+ break;
-+ case SPLASH_CORNER_TOP_RIGHT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff += ph->position_offset;
-+ dst_yoff -= ph->position_offset;
-+ break;
-+ case SPLASH_CORNER_RIGHT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff += ph->position_offset;
-+ break;
-+ case SPLASH_CORNER_BOTTOM_RIGHT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff += ph->position_offset;
-+ dst_yoff += ph->position_offset;
-+ break;
-+ case SPLASH_CORNER_BOTTOM:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_yoff += ph->position_offset;
-+ break;
-+ case SPLASH_CORNER_BOTTOM_LEFT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff -= ph->position_offset;
-+ dst_yoff += ph->position_offset;
-+ break;
-+ case SPLASH_CORNER_LEFT:
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+
-+ dst_xoff -= ph->position_offset;
-+ break;
-+
-+ default:
-+ /* As a fallback, center the picture. */
-+ dst_xoff = info->var.xres - pp->pic_header->width;
-+ dst_xoff /= 2;
-+ dst_yoff = info->var.yres - pp->pic_header->height;
-+ dst_yoff /= 2;
-+ break;
-+ }
-
- if (dst_xoff < 0
- || dst_yoff < 0
-diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
-index 89dc9cca8f0c..71cedcc68933 100644
---- a/include/uapi/linux/bootsplash_file.h
-+++ b/include/uapi/linux/bootsplash_file.h
-@@ -91,7 +91,32 @@ struct splash_pic_header {
- */
- uint8_t num_blobs;
-
-- uint8_t padding[27];
-+ /*
-+ * Corner to move the picture to / from.
-+ * 0x00 - Top left
-+ * 0x01 - Top
-+ * 0x02 - Top right
-+ * 0x03 - Right
-+ * 0x04 - Bottom right
-+ * 0x05 - Bottom
-+ * 0x06 - Bottom left
-+ * 0x07 - Left
-+ *
-+ * Flags:
-+ * 0x10 - Calculate offset from the corner towards the center,
-+ * rather than from the center towards the corner
-+ */
-+ uint8_t position;
-+
-+ /*
-+ * Pixel offset from the selected position.
-+ * Example: If the picture is in the top right corner, it will
-+ * be placed position_offset pixels from the top and
-+ * position_offset pixels from the right margin.
-+ */
-+ uint16_t position_offset;
-+
-+ uint8_t padding[24];
- } __attribute__((__packed__));
+ extern void ctrl_alt_del(void);
+ /*
+@@ -1353,6 +1355,28 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+ }
+ #endif
-@@ -115,4 +140,22 @@ struct splash_blob_header {
- uint8_t padding[9];
- } __attribute__((__packed__));
-
-+
-+
-+
-+/*
-+ * Enums for on-disk types
-+ */
-+enum splash_position {
-+ SPLASH_CORNER_TOP_LEFT = 0,
-+ SPLASH_CORNER_TOP = 1,
-+ SPLASH_CORNER_TOP_RIGHT = 2,
-+ SPLASH_CORNER_RIGHT = 3,
-+ SPLASH_CORNER_BOTTOM_RIGHT = 4,
-+ SPLASH_CORNER_BOTTOM = 5,
-+ SPLASH_CORNER_BOTTOM_LEFT = 6,
-+ SPLASH_CORNER_LEFT = 7,
-+ SPLASH_POS_FLAG_CORNER = 0x10,
-+};
++ /* Trap keys when bootsplash is shown */
++ if (bootsplash_would_render_now()) {
++ /* Deactivate bootsplash on ESC or Alt+Fxx VT switch */
++ if (keycode >= KEY_F1 && keycode <= KEY_F12) {
++ bootsplash_disable();
++
++ /*
++ * No return here since we want to actually
++ * perform the VT switch.
++ */
++ } else {
++ if (keycode == KEY_ESC)
++ bootsplash_disable();
++
++ /*
++ * Just drop any other keys.
++ * Their effect would be hidden by the splash.
++ */
++ return;
++ }
++ }
+
- #endif
+ if (kbd->kbdmode == VC_MEDIUMRAW) {
+ /*
+ * This is extended medium raw mode, with keys above 127
diff --git a/0010-bootsplash.patch b/0010-bootsplash.patch
index 2785c5e6527..8a3b715ce46 100644
--- a/0010-bootsplash.patch
+++ b/0010-bootsplash.patch
@@ -1,327 +1,21 @@
-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,
+diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
+index 3ffc1ce29023..bc6a24c9dfa8 100644
+--- a/drivers/tty/sysrq.c
++++ b/drivers/tty/sysrq.c
+@@ -49,6 +49,7 @@
+ #include <linux/syscalls.h>
+ #include <linux/of.h>
+ #include <linux/rcupdate.h>
++#include <linux/bootsplash.h>
+
+ #include <asm/ptrace.h>
+ #include <asm/irq_regs.h>
+@@ -104,6 +105,8 @@ static void sysrq_handle_SAK(int key)
{
- 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;
-+ }
+ struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+ schedule_work(SAK_work);
+
- 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);
- }
++ bootsplash_disable();
}
-+
-+
-+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
+ static struct sysrq_key_op sysrq_SAK_op = {
+ .handler = sysrq_handle_SAK,
diff --git a/0011-bootsplash.patch b/0011-bootsplash.patch
index d6c6db659c5..add68e7b275 100644
--- a/0011-bootsplash.patch
+++ b/0011-bootsplash.patch
@@ -1,82 +1,21 @@
-diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
-index 2ebaba16f785..416735ab6dc1 100644
---- a/drivers/tty/vt/vt.c
-+++ b/drivers/tty/vt/vt.c
-@@ -105,6 +105,7 @@
- #include <linux/ctype.h>
- #include <linux/bsearch.h>
- #include <linux/gcd.h>
-+#include <linux/bootsplash.h>
-
- #define MAX_NR_CON_DRIVER 16
-
-@@ -4235,6 +4236,7 @@ void do_unblank_screen(int leaving_gfx)
- }
-
- console_blanked = 0;
-+ bootsplash_mark_dirty();
- if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
- /* Low-level driver cannot restore -> do it ourselves */
- update_screen(vc);
-diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
-index c8642142cfea..13fcaabbc2ca 100644
---- a/drivers/video/fbdev/core/bootsplash.c
-+++ b/drivers/video/fbdev/core/bootsplash.c
-@@ -165,6 +165,13 @@ bool bootsplash_would_render_now(void)
- && bootsplash_is_enabled();
- }
-
-+void bootsplash_mark_dirty(void)
-+{
-+ mutex_lock(&splash_state.data_lock);
-+ splash_state.splash_fb = NULL;
-+ mutex_unlock(&splash_state.data_lock);
-+}
-+
- bool bootsplash_is_enabled(void)
- {
- bool was_enabled;
-@@ -206,9 +213,7 @@ void bootsplash_enable(void)
-
- 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);
-+ bootsplash_mark_dirty();
-
- schedule_work(&splash_state.work_redraw_vc);
- }
-@@ -272,9 +277,7 @@ 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);
-+ bootsplash_mark_dirty();
-
- if (bootsplash_would_render_now())
- schedule_work(&splash_state.work_redraw_vc);
-diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
-index c6dd0b43180d..4075098aaadd 100644
---- a/include/linux/bootsplash.h
-+++ b/include/linux/bootsplash.h
-@@ -19,6 +19,8 @@ extern void bootsplash_render_full(struct fb_info *info);
-
- extern bool bootsplash_would_render_now(void);
-
-+extern void bootsplash_mark_dirty(void);
+diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
+index 9a39a6fcfe98..8a9c67e1c5d8 100644
+--- a/drivers/video/fbdev/core/fbcon.c
++++ b/drivers/video/fbdev/core/fbcon.c
+@@ -1343,6 +1343,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
+ int y;
+ int c = scr_readw((u16 *) vc->vc_pos);
+
++ /*
++ * Disable the splash here so we don't have to hook into
++ * vt_console_print() in drivers/tty/vt/vt.c
++ *
++ * We'd disable the splash just before the call to
++ * hide_cursor() anyway, so this spot is just fine.
++ */
++ if (oops_in_progress)
++ bootsplash_disable();
+
- extern bool bootsplash_is_enabled(void);
- extern void bootsplash_disable(void);
- extern void bootsplash_enable(void);
-@@ -31,6 +33,8 @@ extern void bootsplash_init(void);
-
- #define bootsplash_would_render_now() (false)
+ ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
-+#define bootsplash_mark_dirty()
-+
- #define bootsplash_is_enabled() (false)
- #define bootsplash_disable()
- #define bootsplash_enable()
+ if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
diff --git a/0012-bootsplash.patch b/0012-bootsplash.patch
index e8cd479312b..e5c1fd0c860 100644
--- a/0012-bootsplash.patch
+++ b/0012-bootsplash.patch
@@ -1,42 +1,321 @@
-diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
-index f4166263bb3a..a248429194bb 100644
---- a/drivers/tty/vt/keyboard.c
-+++ b/drivers/tty/vt/keyboard.c
-@@ -47,6 +47,8 @@
-
- #include <asm/irq_regs.h>
-
-+#include <linux/bootsplash.h>
-+
- extern void ctrl_alt_del(void);
-
- /*
-@@ -1353,6 +1355,28 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
- }
- #endif
-
-+ /* Trap keys when bootsplash is shown */
-+ if (bootsplash_would_render_now()) {
-+ /* Deactivate bootsplash on ESC or Alt+Fxx VT switch */
-+ if (keycode >= KEY_F1 && keycode <= KEY_F12) {
-+ bootsplash_disable();
-+
-+ /*
-+ * No return here since we want to actually
-+ * perform the VT switch.
-+ */
-+ } else {
-+ if (keycode == KEY_ESC)
-+ bootsplash_disable();
-+
-+ /*
-+ * Just drop any other keys.
-+ * Their effect would be hidden by the splash.
-+ */
-+ return;
-+ }
-+ }
-+
- if (kbd->kbdmode == VC_MEDIUMRAW) {
- /*
- * This is extended medium raw mode, with keys above 127
+diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
+new file mode 100644
+index 000000000000..742c7b035ded
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
+@@ -0,0 +1,11 @@
++What: /sys/devices/platform/bootsplash.0/enabled
++Date: Oct 2017
++KernelVersion: 4.14
++Contact: Max Staudt <mstaudt@suse.de>
++Description:
++ Can be set and read.
++
++ 0: Splash is disabled.
++ 1: Splash is shown whenever fbcon would show a text console
++ (i.e. no graphical application is running), and a splash
++ file is loaded.
+diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
+new file mode 100644
+index 000000000000..611f0c558925
+--- /dev/null
++++ b/Documentation/bootsplash.rst
+@@ -0,0 +1,285 @@
++====================
++The Linux bootsplash
++====================
++
++:Date: November, 2017
++:Author: Max Staudt <mstaudt@suse.de>
++
++
++The Linux bootsplash is a graphical replacement for the '``quiet``' boot
++option, typically showing a logo and a spinner animation as the system starts.
++
++Currently, it is a part of the Framebuffer Console support, and can be found
++as ``CONFIG_BOOTSPLASH`` in the kernel configuration. This means that as long
++as it is enabled, it hijacks fbcon's output and draws a splash screen instead.
++
++Purely compiling in the bootsplash will not render it functional - to actually
++render a splash, you will also need a splash theme file. See the example
++utility and script in ``tools/bootsplash`` for a live demo.
++
++
++
++Motivation
++==========
++
++- The '``quiet``' boot option only suppresses most messages during boot, but
++ errors are still shown.
++
++- A user space implementation can only show a logo once user space has been
++ initialized far enough to allow this. A kernel splash can display a splash
++ immediately as soon as fbcon can be displayed.
++
++- Implementing a splash screen in user space (e.g. Plymouth) is problematic
++ due to resource conflicts.
++
++ For example, if Plymouth is keeping ``/dev/fb0`` (provided via vesafb/efifb)
++ open, then most DRM drivers can't replace it because the address space is
++ still busy - thus leading to a VRAM reservation error.
++
++ See: https://bugzilla.opensuse.org/show_bug.cgi?id=980750
++
++
++
++Command line arguments
++======================
++
++``bootsplash.bootfile``
++ Which file in the initramfs to load.
++
++ The splash theme is loaded via request_firmware(), thus to load
++ ``/lib/firmware/bootsplash/mytheme`` pass the command line:
++
++ ``bootsplash.bootfile=bootsplash/mytheme``
++
++ Note: The splash file *has to be* in the initramfs, as it needs to be
++ available when the splash is initialized early on.
++
++ Default: none, i.e. a non-functional splash, falling back to showing text.
++
++
++
++sysfs run-time configuration
++============================
++
++``/sys/devices/platform/bootsplash.0/enabled``
++ Enable/disable the bootsplash.
++ The system boots with this set to 1, but will not show a splash unless
++ a splash theme file is also loaded.
++
++
++
++Kconfig
++=======
++
++``BOOTSPLASH``
++ Whether to compile in bootsplash support
++ (depends on fbcon compiled in, i.e. ``FRAMEBUFFER_CONSOLE=y``)
++
++
++
++Bootsplash file format
++======================
++
++A file specified in the kernel configuration as ``CONFIG_BOOTSPLASH_FILE``
++or specified on the command line as ``bootsplash.bootfile`` will be loaded
++and displayed as soon as fbcon is initialized.
++
++
++Main blocks
++-----------
++
++There are 3 main blocks in each file:
++
++ - one File header
++ - n Picture headers
++ - m (Blob header + payload) blocks
++
++
++Structures
++----------
++
++The on-disk structures are defined in
++``drivers/video/fbdev/core/bootsplash_file.h`` and represent these blocks:
++
++ - ``struct splash_file_header``
++
++ Represents the file header, with splash-wide information including:
++
++ - The magic string "``Linux bootsplash``" on big-endian platforms
++ (the reverse on little endian)
++ - The file format version (for incompatible updates, hopefully never)
++ - The background color
++ - Number of picture and blob blocks
++ - Animation speed (we only allow one delay for all animations)
++
++ The file header is followed by the first picture header.
++
++
++ - ``struct splash_picture_header``
++
++ Represents an object (picture) drawn on screen, including its immutable
++ properties:
++ - Width, height
++ - Positioning relative to screen corners or in the center
++ - Animation, if any
++ - Animation type
++ - Number of blobs
++
++ The picture header is followed by another picture header, up until n
++ picture headers (as defined in the file header) have been read. Then,
++ the (blob header, payload) pairs follow.
++
++
++ - ``struct splash_blob_header``
++ (followed by payload)
++
++ Represents one raw data stream. So far, only picture data is defined.
++
++ The blob header is followed by a payload, then padding to n*16 bytes,
++ then (if further blobs are defined in the file header) a further blob
++ header.
++
++
++Alignment
++---------
++
++The bootsplash file is designed to be loaded into memory as-is.
++
++All structures are a multiple of 16 bytes long, all elements therein are
++aligned to multiples of their length, and the payloads are always padded
++up to multiples of 16 bytes. This is to allow aligned accesses in all
++cases while still simply mapping the structures over an in-memory copy of
++the bootsplash file.
++
++
++Further information
++-------------------
++
++Please see ``drivers/video/fbdev/core/bootsplash_file.h`` for further
++details and possible values in the file.
++
++
++
++Hooks - how the bootsplash is integrated
++========================================
++
++``drivers/video/fbdev/core/fbcon.c``
++ ``fbcon_init()`` calls ``bootsplash_init()``, which loads the default
++ bootsplash file or the one specified on the kernel command line.
++
++ ``fbcon_switch()`` draws the bootsplash when it's active, and is also
++ one of the callers of ``set_blitting_type()``.
++
++ ``set_blitting_type()`` calls ``fbcon_set_dummyops()`` when the
++ bootsplash is active, overriding the text rendering functions.
++
++ ``fbcon_cursor()`` will call ``bootsplash_disable()`` when an oops is
++ being printed in order to make a kernel panic visible.
++
++``drivers/video/fbdev/core/dummyblit.c``
++ This contains the dummy text rendering functions used to suppress text
++ output while the bootsplash is shown.
++
++``drivers/tty/vt/keyboard.c``
++ ``kbd_keycode()`` can call ``bootsplash_disable()`` when the user
++ presses ESC or F1-F12 (changing VT). This is to provide a built-in way
++ of disabling the splash manually at any time.
++
++
++
++FAQ: Frequently Asked Questions
++===============================
++
++I want to see the log! How do I show the log?
++---------------------------------------------
++
++Press ESC while the splash is shown, or remove the ``bootsplash.bootfile``
++parameter from the kernel cmdline. Without that parameter, the bootsplash
++will boot disabled.
++
++
++Why use FB instead of modern DRM/KMS?
++-------------------------------------
++
++This is a semantic problem:
++ - What memory to draw the splash to?
++ - And what mode will the screen be set to?
++
++Using the fbdev emulation solves these issues.
++
++Let's start from a bare KMS system, without fbcon, and without fbdev
++emulation. In this case, as long as userspace doesn't open the KMS
++device, the state of the screen is undefined. No framebuffer is
++allocated in video RAM, and no particular mode is set.
++
++In this case, we'd have to allocate a framebuffer to show the splash,
++and set our mode ourselves. This either wastes a screenful of video RAM
++if the splash is to co-exist with the userspace program's own allocated
++framebuffer, or there is a flicker as we deactivate and delete the
++bootsplash's framebuffer and hand control over to userspace. Since we
++may set a different mode than userspace, we'd also have flicker due
++to mode switching.
++
++This logic is already contained in every KMS driver that performs fbdev
++emulation. So we might as well use that. And the correct API to do so is
++fbdev. Plus, we get compatibility with old, pure fbdev drivers for free.
++With the fbdev emulation, there is *always* a well-defined framebuffer
++to draw on. And the selection of mode has already been done by the
++graphics driver, so we don't need to reinvent that wheel, either.
++Finally, if userspace decides to use /dev/fbX, we don't have to worry
++about wasting video RAM, either.
++
++
++Why is the bootsplash integrated in fbcon?
++------------------------------------------
++
++Right now, the bootsplash is drawn from within fbcon, as this allows us
++to easily know *when* to draw - i.e. when we're safe from fbcon and
++userspace drawing all over our beautiful splash logo.
++
++Separating them is not easy - see the to-do list below.
++
++
++
++TO DO list for future development
++=================================
++
++Second enable/disable switch for the system
++-------------------------------------------
++
++It may be helpful to differentiate between the system and the user
++switching off the bootsplash. Thus, the system may make it disappear and
++reappear e.g. for a password prompt, yet once the user has pressed ESC,
++it could stay gone.
++
++
++Fix buggy DRM/KMS drivers
++-------------------------
++
++Currently, the splash code manually checks for fbdev emulation provided by
++the ast, cirrus, and mgag200 DRM/KMS drivers.
++These drivers use a manual mechanism similar to deferred I/O for their FB
++emulation, and thus need to be manually flushed onto the screen in the same
++way.
++
++This may be improved upon in several ways:
++
++1. Changing these drivers to expose the fbdev BO's memory directly, like
++ bochsdrmfb does.
++2. Creating a new fb_ops->fb_flush() API to allow the kernel to flush the
++ framebuffer once the bootsplash has been drawn into it.
++
++
++Separating from fbcon
++---------------------
++
++Separating these two components would yield independence from fbcon being
++compiled into the kernel, and thus lowering code size in embedded
++applications.
++
++To do this cleanly will involve a clean separation of users of an FB device
++within the kernel, i.e. fbcon, bootsplash, and userspace. Right now, the
++legacy fbcon code and VT code co-operate to switch between fbcon and
++userspace (by setting the VT into KD_GRAPHICS mode). Installing a muxer
++between these components ensues refactoring of old code and checking for
++correct locking.
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 5c237445761e..7ffac272434e 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -2709,6 +2709,8 @@ BOOTSPLASH
+ M: Max Staudt <mstaudt@suse.de>
+ L: linux-fbdev@vger.kernel.org
+ S: Maintained
++F: Documentation/ABI/testing/sysfs-platform-bootsplash
++F: Documentation/bootsplash.rst
+ F: drivers/video/fbdev/core/bootsplash*.*
+ F: drivers/video/fbdev/core/dummycon.c
+ F: include/linux/bootsplash.h
diff --git a/0013-bootsplash.patch b/0013-bootsplash.patch
index 8a3b715ce46..8e87eb46318 100644
--- a/0013-bootsplash.patch
+++ b/0013-bootsplash.patch
@@ -1,21 +1,129 @@
-diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
-index 3ffc1ce29023..bc6a24c9dfa8 100644
---- a/drivers/tty/sysrq.c
-+++ b/drivers/tty/sysrq.c
-@@ -49,6 +49,7 @@
- #include <linux/syscalls.h>
- #include <linux/of.h>
- #include <linux/rcupdate.h>
-+#include <linux/bootsplash.h>
+diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
+index 742c7b035ded..f8f4b259220e 100644
+--- a/Documentation/ABI/testing/sysfs-platform-bootsplash
++++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
+@@ -9,3 +9,35 @@ Description:
+ 1: Splash is shown whenever fbcon would show a text console
+ (i.e. no graphical application is running), and a splash
+ file is loaded.
++
++What: /sys/devices/platform/bootsplash.0/drop_splash
++Date: Oct 2017
++KernelVersion: 4.14
++Contact: Max Staudt <mstaudt@suse.de>
++Description:
++ Can only be set.
++
++ Any value written will cause the current splash theme file
++ to be unloaded and the text console to be redrawn.
++
++What: /sys/devices/platform/bootsplash.0/load_file
++Date: Oct 2017
++KernelVersion: 4.14
++Contact: Max Staudt <mstaudt@suse.de>
++Description:
++ Can only be set.
++
++ Any value written will cause the splash to be disabled and
++ internal memory structures to be freed.
++
++ A firmware path written will cause a new theme file to be
++ loaded and the current bootsplash to be replaced.
++ The current enabled/disabled status is not touched.
++ If the splash is already active, it will be redrawn.
++
++ The path has to be a path in /lib/firmware since
++ request_firmware() is used to fetch the data.
++
++ When setting the splash from the shell, echo -n has to be
++ used as any trailing '\n' newline will be interpreted as
++ part of the path.
+diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
+index 611f0c558925..b35aba5093e8 100644
+--- a/Documentation/bootsplash.rst
++++ b/Documentation/bootsplash.rst
+@@ -67,6 +67,14 @@ sysfs run-time configuration
+ a splash theme file is also loaded.
+
- #include <asm/ptrace.h>
- #include <asm/irq_regs.h>
-@@ -104,6 +105,8 @@ static void sysrq_handle_SAK(int key)
- {
- struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
- schedule_work(SAK_work);
-+
-+ bootsplash_disable();
++``/sys/devices/platform/bootsplash.0/drop_splash``
++ Unload splash data and free memory.
++
++``/sys/devices/platform/bootsplash.0/load_file``
++ Load a splash file from ``/lib/firmware/``.
++ Note that trailing newlines will be interpreted as part of the file name.
++
++
+
+ Kconfig
+ =======
+diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
+index 13fcaabbc2ca..16cb0493629d 100644
+--- a/drivers/video/fbdev/core/bootsplash.c
++++ b/drivers/video/fbdev/core/bootsplash.c
+@@ -251,11 +251,65 @@ static ssize_t splash_store_enabled(struct device *device,
+ return count;
}
- static struct sysrq_key_op sysrq_SAK_op = {
- .handler = sysrq_handle_SAK,
+
++static ssize_t splash_store_drop_splash(struct device *device,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct splash_file_priv *fp;
++
++ if (!buf || !count || !splash_state.file)
++ return count;
++
++ mutex_lock(&splash_state.data_lock);
++ fp = splash_state.file;
++ splash_state.file = NULL;
++ mutex_unlock(&splash_state.data_lock);
++
++ /* Redraw the text console */
++ schedule_work(&splash_state.work_redraw_vc);
++
++ bootsplash_free_file(fp);
++
++ return count;
++}
++
++static ssize_t splash_store_load_file(struct device *device,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct splash_file_priv *fp, *fp_old;
++
++ if (!count)
++ return 0;
++
++ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
++ buf);
++
++ if (!fp)
++ return -ENXIO;
++
++ mutex_lock(&splash_state.data_lock);
++ fp_old = splash_state.file;
++ splash_state.splash_fb = NULL;
++ splash_state.file = fp;
++ mutex_unlock(&splash_state.data_lock);
++
++ /* Update the splash or text console */
++ schedule_work(&splash_state.work_redraw_vc);
++
++ bootsplash_free_file(fp_old);
++ return count;
++}
++
+ static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
++static DEVICE_ATTR(drop_splash, 0200, NULL, splash_store_drop_splash);
++static DEVICE_ATTR(load_file, 0200, NULL, splash_store_load_file);
+
+
+ static struct attribute *splash_dev_attrs[] = {
+ &dev_attr_enabled.attr,
++ &dev_attr_drop_splash.attr,
++ &dev_attr_load_file.attr,
+ NULL
+ };
+
diff --git a/0014-bootsplash.patch b/0014-bootsplash.patch
index add68e7b275..5d8ea1fe295 100644
--- a/0014-bootsplash.patch
+++ b/0014-bootsplash.patch
@@ -1,21 +1,511 @@
-diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
-index 9a39a6fcfe98..8a9c67e1c5d8 100644
---- a/drivers/video/fbdev/core/fbcon.c
-+++ b/drivers/video/fbdev/core/fbcon.c
-@@ -1343,6 +1343,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
- int y;
- int c = scr_readw((u16 *) vc->vc_pos);
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 7ffac272434e..ddff07cd794c 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -2715,6 +2715,7 @@ F: drivers/video/fbdev/core/bootsplash*.*
+ F: drivers/video/fbdev/core/dummycon.c
+ F: include/linux/bootsplash.h
+ F: include/uapi/linux/bootsplash_file.h
++F: tools/bootsplash/*
-+ /*
-+ * Disable the splash here so we don't have to hook into
-+ * vt_console_print() in drivers/tty/vt/vt.c
-+ *
-+ * We'd disable the splash just before the call to
-+ * hide_cursor() anyway, so this spot is just fine.
-+ */
-+ if (oops_in_progress)
-+ bootsplash_disable();
-+
- ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
-
- if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
+ BPF (Safe dynamic programs and tools)
+ M: Alexei Starovoitov <ast@kernel.org>
+diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore
+new file mode 100644
+index 000000000000..091b99a17567
+--- /dev/null
++++ b/tools/bootsplash/.gitignore
+@@ -0,0 +1 @@
++bootsplash-packer
+diff --git a/tools/bootsplash/Makefile b/tools/bootsplash/Makefile
+new file mode 100644
+index 000000000000..0ad8e8a84942
+--- /dev/null
++++ b/tools/bootsplash/Makefile
+@@ -0,0 +1,9 @@
++CC := $(CROSS_COMPILE)gcc
++CFLAGS := -I../../usr/include
++
++PROGS := bootsplash-packer
++
++all: $(PROGS)
++
++clean:
++ rm -fr $(PROGS)
+diff --git a/tools/bootsplash/bootsplash-packer.c b/tools/bootsplash/bootsplash-packer.c
+new file mode 100644
+index 000000000000..ffb6a8b69885
+--- /dev/null
++++ b/tools/bootsplash/bootsplash-packer.c
+@@ -0,0 +1,471 @@
++/*
++ * Kernel based bootsplash.
++ *
++ * (Splash file packer tool)
++ *
++ * Authors:
++ * Max Staudt <mstaudt@suse.de>
++ *
++ * SPDX-License-Identifier: GPL-2.0
++ */
++
++#include <endian.h>
++#include <getopt.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <linux/bootsplash_file.h>
++
++
++static void print_help(char *progname)
++{
++ printf("Usage: %s [OPTIONS] outfile\n", progname);
++ printf("\n"
++ "Options, executed in order given:\n"
++ " -h, --help Print this help message\n"
++ "\n"
++ " --bg_red <u8> Background color (red part)\n"
++ " --bg_green <u8> Background color (green part)\n"
++ " --bg_blue <u8> Background color (blue part)\n"
++ " --bg_reserved <u8> (do not use)\n"
++ " --frame_ms <u16> Minimum milliseconds between animation steps\n"
++ "\n"
++ " --picture Start describing the next picture\n"
++ " --pic_width <u16> Picture width in pixels\n"
++ " --pic_height <u16> Picture height in pixels\n"
++ " --pic_position <u8> Coarse picture placement:\n"
++ " 0x00 - Top left\n"
++ " 0x01 - Top\n"
++ " 0x02 - Top right\n"
++ " 0x03 - Right\n"
++ " 0x04 - Bottom right\n"
++ " 0x05 - Bottom\n"
++ " 0x06 - Bottom left\n"
++ " 0x07 - Left\n"
++ "\n"
++ " Flags:\n"
++ " 0x10 - Calculate offset from corner towards center,\n"
++ " rather than from center towards corner\n"
++ " --pic_position_offset <u16> Distance from base position in pixels\n"
++ " --pic_anim_type <u8> Animation type:\n"
++ " 0 - None\n"
++ " 1 - Forward loop\n"
++ " --pic_anim_loop <u8> Loop point for animation\n"
++ "\n"
++ " --blob <filename> Include next data stream\n"
++ " --blob_type <u16> Type of data\n"
++ " --blob_picture_id <u8> Picture to associate this blob with, starting at 0\n"
++ " (default: number of last --picture)\n"
++ "\n");
++ printf("This tool will write %s files.\n\n",
++#if __BYTE_ORDER == __BIG_ENDIAN
++ "Big Endian (BE)");
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
++ "Little Endian (LE)");
++#else
++#error
++#endif
++}
++
++
++struct blob_entry {
++ struct blob_entry *next;
++
++ char *fn;
++
++ struct splash_blob_header header;
++};
++
++
++static void dump_file_header(struct splash_file_header *h)
++{
++ printf(" --- File header ---\n");
++ printf("\n");
++ printf(" version: %5u\n", h->version);
++ printf("\n");
++ printf(" bg_red: %5u\n", h->bg_red);
++ printf(" bg_green: %5u\n", h->bg_green);
++ printf(" bg_blue: %5u\n", h->bg_blue);
++ printf(" bg_reserved: %5u\n", h->bg_reserved);
++ printf("\n");
++ printf(" num_blobs: %5u\n", h->num_blobs);
++ printf(" num_pics: %5u\n", h->num_pics);
++ printf("\n");
++ printf(" frame_ms: %5u\n", h->frame_ms);
++ printf("\n");
++}
++
++static void dump_pic_header(struct splash_pic_header *ph)
++{
++ printf(" --- Picture header ---\n");
++ printf("\n");
++ printf(" width: %5u\n", ph->width);
++ printf(" height: %5u\n", ph->height);
++ printf("\n");
++ printf(" num_blobs: %5u\n", ph->num_blobs);
++ printf("\n");
++ printf(" position: %0x3x\n", ph->position);
++ printf(" position_offset: %5u\n", ph->position_offset);
++ printf("\n");
++ printf(" anim_type: %5u\n", ph->anim_type);
++ printf(" anim_loop: %5u\n", ph->anim_loop);
++ printf("\n");
++}
++
++static void dump_blob(struct blob_entry *b)
++{
++ printf(" --- Blob header ---\n");
++ printf("\n");
++ printf(" length: %7u\n", b->header.length);
++ printf(" type: %7u\n", b->header.type);
++ printf("\n");
++ printf(" picture_id: %7u\n", b->header.picture_id);
++ printf("\n");
++}
++
++
++#define OPT_MAX(var, max) \
++ do { \
++ if ((var) > max) { \
++ fprintf(stderr, "--%s: Invalid value\n", \
++ long_options[option_index].name); \
++ break; \
++ } \
++ } while (0)
++
++static struct option long_options[] = {
++ {"help", 0, 0, 'h'},
++ {"bg_red", 1, 0, 10001},
++ {"bg_green", 1, 0, 10002},
++ {"bg_blue", 1, 0, 10003},
++ {"bg_reserved", 1, 0, 10004},
++ {"frame_ms", 1, 0, 10005},
++ {"picture", 0, 0, 20000},
++ {"pic_width", 1, 0, 20001},
++ {"pic_height", 1, 0, 20002},
++ {"pic_position", 1, 0, 20003},
++ {"pic_position_offset", 1, 0, 20004},
++ {"pic_anim_type", 1, 0, 20005},
++ {"pic_anim_loop", 1, 0, 20006},
++ {"blob", 1, 0, 30000},
++ {"blob_type", 1, 0, 30001},
++ {"blob_picture_id", 1, 0, 30002},
++ {NULL, 0, NULL, 0}
++};
++
++
++int main(int argc, char **argv)
++{
++ FILE *of;
++ char *ofn;
++ int c;
++ int option_index = 0;
++
++ unsigned long ul;
++ struct splash_file_header fh = {};
++ struct splash_pic_header ph[255];
++ struct blob_entry *blob_first = NULL;
++ struct blob_entry *blob_last = NULL;
++ struct blob_entry *blob_cur = NULL;
++
++ if (argc < 2) {
++ print_help(argv[0]);
++ return EXIT_FAILURE;
++ }
++
++
++ /* Parse and and execute user commands */
++ while ((c = getopt_long(argc, argv, "h",
++ long_options, &option_index)) != -1) {
++ switch (c) {
++ case 10001: /* bg_red */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ fh.bg_red = ul;
++ break;
++ case 10002: /* bg_green */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ fh.bg_green = ul;
++ break;
++ case 10003: /* bg_blue */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ fh.bg_blue = ul;
++ break;
++ case 10004: /* bg_reserved */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ fh.bg_reserved = ul;
++ break;
++ case 10005: /* frame_ms */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 65535);
++ fh.frame_ms = ul;
++ break;
++
++
++ case 20000: /* picture */
++ if (fh.num_pics >= 255) {
++ fprintf(stderr, "--%s: Picture array full\n",
++ long_options[option_index].name);
++ break;
++ }
++
++ fh.num_pics++;
++ break;
++
++ case 20001: /* pic_width */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 65535);
++ ph[fh.num_pics - 1].width = ul;
++ break;
++
++ case 20002: /* pic_height */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 65535);
++ ph[fh.num_pics - 1].height = ul;
++ break;
++
++ case 20003: /* pic_position */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ ph[fh.num_pics - 1].position = ul;
++ break;
++
++ case 20004: /* pic_position_offset */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ ph[fh.num_pics - 1].position_offset = ul;
++ break;
++
++ case 20005: /* pic_anim_type */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ ph[fh.num_pics - 1].anim_type = ul;
++ break;
++
++ case 20006: /* pic_anim_loop */
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ ph[fh.num_pics - 1].anim_loop = ul;
++ break;
++
++
++ case 30000: /* blob */
++ if (fh.num_blobs >= 65535) {
++ fprintf(stderr, "--%s: Blob array full\n",
++ long_options[option_index].name);
++ break;
++ }
++
++ blob_cur = calloc(1, sizeof(struct blob_entry));
++ if (!blob_cur) {
++ fprintf(stderr, "--%s: Out of memory\n",
++ long_options[option_index].name);
++ break;
++ }
++
++ blob_cur->fn = optarg;
++ if (fh.num_pics)
++ blob_cur->header.picture_id = fh.num_pics - 1;
++
++ if (!blob_first)
++ blob_first = blob_cur;
++ if (blob_last)
++ blob_last->next = blob_cur;
++ blob_last = blob_cur;
++ fh.num_blobs++;
++ break;
++
++ case 30001: /* blob_type */
++ if (!blob_cur) {
++ fprintf(stderr, "--%s: No blob selected\n",
++ long_options[option_index].name);
++ break;
++ }
++
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ blob_cur->header.type = ul;
++ break;
++
++ case 30002: /* blob_picture_id */
++ if (!blob_cur) {
++ fprintf(stderr, "--%s: No blob selected\n",
++ long_options[option_index].name);
++ break;
++ }
++
++ ul = strtoul(optarg, NULL, 0);
++ OPT_MAX(ul, 255);
++ blob_cur->header.picture_id = ul;
++ break;
++
++
++
++ case 'h':
++ case '?':
++ default:
++ print_help(argv[0]);
++ goto EXIT;
++ } /* switch (c) */
++ } /* while ((c = getopt_long(...)) != -1) */
++
++ /* Consume and drop lone arguments */
++ while (optind < argc) {
++ ofn = argv[optind];
++ optind++;
++ }
++
++
++ /* Read file lengths */
++ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
++ FILE *f;
++ long pos;
++ int i;
++
++ if (!blob_cur->fn)
++ continue;
++
++ f = fopen(blob_cur->fn, "rb");
++ if (!f)
++ goto ERR_FILE_LEN;
++
++ if (fseek(f, 0, SEEK_END))
++ goto ERR_FILE_LEN;
++
++ pos = ftell(f);
++ if (pos < 0 || pos > (1 << 30))
++ goto ERR_FILE_LEN;
++
++ blob_cur->header.length = pos;
++
++ fclose(f);
++ continue;
++
++ERR_FILE_LEN:
++ fprintf(stderr, "Error getting file length (or too long): %s\n",
++ blob_cur->fn);
++ if (f)
++ fclose(f);
++ continue;
++ }
++
++
++ /* Set magic headers */
++#if __BYTE_ORDER == __BIG_ENDIAN
++ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_BE, 16);
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
++ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_LE, 16);
++#else
++#error
++#endif
++ fh.version = BOOTSPLASH_VERSION;
++
++ /* Set blob counts */
++ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
++ if (blob_cur->header.picture_id < fh.num_pics)
++ ph[blob_cur->header.picture_id].num_blobs++;
++ }
++
++
++ /* Dump structs */
++ dump_file_header(&fh);
++
++ for (ul = 0; ul < fh.num_pics; ul++)
++ dump_pic_header(&ph[ul]);
++
++ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next)
++ dump_blob(blob_cur);
++
++
++ /* Write to file */
++ printf("Writing splash to file: %s\n", ofn);
++ of = fopen(ofn, "wb");
++ if (!of)
++ goto ERR_WRITING;
++
++ if (fwrite(&fh, sizeof(struct splash_file_header), 1, of) != 1)
++ goto ERR_WRITING;
++
++ for (ul = 0; ul < fh.num_pics; ul++) {
++ if (fwrite(&ph[ul], sizeof(struct splash_pic_header), 1, of)
++ != 1)
++ goto ERR_WRITING;
++ }
++
++ blob_cur = blob_first;
++ while (blob_cur) {
++ struct blob_entry *blob_old = blob_cur;
++ FILE *f;
++ char *buf[256];
++ uint32_t left;
++
++ if (fwrite(&blob_cur->header,
++ sizeof(struct splash_blob_header), 1, of) != 1)
++ goto ERR_WRITING;
++
++ if (!blob_cur->header.length || !blob_cur->fn)
++ continue;
++
++ f = fopen(blob_cur->fn, "rb");
++ if (!f)
++ goto ERR_FILE_COPY;
++
++ left = blob_cur->header.length;
++ while (left >= sizeof(buf)) {
++ if (fread(buf, sizeof(buf), 1, f) != 1)
++ goto ERR_FILE_COPY;
++ if (fwrite(buf, sizeof(buf), 1, of) != 1)
++ goto ERR_FILE_COPY;
++ left -= sizeof(buf);
++ }
++ if (left) {
++ if (fread(buf, left, 1, f) != 1)
++ goto ERR_FILE_COPY;
++ if (fwrite(buf, left, 1, of) != 1)
++ goto ERR_FILE_COPY;
++ }
++
++ /* Pad data stream to 16 bytes */
++ if (left % 16) {
++ if (fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
++ 16 - (left % 16), 1, of) != 1)
++ goto ERR_FILE_COPY;
++ }
++
++ fclose(f);
++ blob_cur = blob_cur->next;
++ free(blob_old);
++ continue;
++
++ERR_FILE_COPY:
++ if (f)
++ fclose(f);
++ goto ERR_WRITING;
++ }
++
++ fclose(of);
++
++EXIT:
++ return EXIT_SUCCESS;
++
++
++ERR_WRITING:
++ fprintf(stderr, "Error writing splash.\n");
++ fprintf(stderr, "The output file is probably corrupt.\n");
++ if (of)
++ fclose(of);
++
++ while (blob_cur) {
++ struct blob_entry *blob_old = blob_cur;
++
++ blob_cur = blob_cur->next;
++ free(blob_old);
++ }
++
++ return EXIT_FAILURE;
++}
diff --git a/0015-bootsplash.patch b/0015-bootsplash.patch
index e5c1fd0c860..0924d29e7d4 100644
--- a/0015-bootsplash.patch
+++ b/0015-bootsplash.patch
@@ -1,321 +1,102 @@
-diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
-new file mode 100644
-index 000000000000..742c7b035ded
---- /dev/null
-+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
-@@ -0,0 +1,11 @@
-+What: /sys/devices/platform/bootsplash.0/enabled
-+Date: Oct 2017
-+KernelVersion: 4.14
-+Contact: Max Staudt <mstaudt@suse.de>
-+Description:
-+ Can be set and read.
-+
-+ 0: Splash is disabled.
-+ 1: Splash is shown whenever fbcon would show a text console
-+ (i.e. no graphical application is running), and a splash
-+ file is loaded.
diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
-new file mode 100644
-index 000000000000..611f0c558925
---- /dev/null
+index b35aba5093e8..d4f132eca615 100644
+--- a/Documentation/bootsplash.rst
+++ b/Documentation/bootsplash.rst
-@@ -0,0 +1,285 @@
-+====================
-+The Linux bootsplash
-+====================
-+
-+:Date: November, 2017
-+:Author: Max Staudt <mstaudt@suse.de>
-+
-+
-+The Linux bootsplash is a graphical replacement for the '``quiet``' boot
-+option, typically showing a logo and a spinner animation as the system starts.
-+
-+Currently, it is a part of the Framebuffer Console support, and can be found
-+as ``CONFIG_BOOTSPLASH`` in the kernel configuration. This means that as long
-+as it is enabled, it hijacks fbcon's output and draws a splash screen instead.
-+
-+Purely compiling in the bootsplash will not render it functional - to actually
-+render a splash, you will also need a splash theme file. See the example
-+utility and script in ``tools/bootsplash`` for a live demo.
-+
-+
-+
-+Motivation
-+==========
-+
-+- The '``quiet``' boot option only suppresses most messages during boot, but
-+ errors are still shown.
-+
-+- A user space implementation can only show a logo once user space has been
-+ initialized far enough to allow this. A kernel splash can display a splash
-+ immediately as soon as fbcon can be displayed.
-+
-+- Implementing a splash screen in user space (e.g. Plymouth) is problematic
-+ due to resource conflicts.
-+
-+ For example, if Plymouth is keeping ``/dev/fb0`` (provided via vesafb/efifb)
-+ open, then most DRM drivers can't replace it because the address space is
-+ still busy - thus leading to a VRAM reservation error.
-+
-+ See: https://bugzilla.opensuse.org/show_bug.cgi?id=980750
-+
-+
-+
-+Command line arguments
-+======================
-+
-+``bootsplash.bootfile``
-+ Which file in the initramfs to load.
-+
-+ The splash theme is loaded via request_firmware(), thus to load
-+ ``/lib/firmware/bootsplash/mytheme`` pass the command line:
-+
-+ ``bootsplash.bootfile=bootsplash/mytheme``
-+
-+ Note: The splash file *has to be* in the initramfs, as it needs to be
-+ available when the splash is initialized early on.
-+
-+ Default: none, i.e. a non-functional splash, falling back to showing text.
-+
-+
-+
-+sysfs run-time configuration
-+============================
-+
-+``/sys/devices/platform/bootsplash.0/enabled``
-+ Enable/disable the bootsplash.
-+ The system boots with this set to 1, but will not show a splash unless
-+ a splash theme file is also loaded.
-+
-+
-+
-+Kconfig
-+=======
-+
-+``BOOTSPLASH``
-+ Whether to compile in bootsplash support
-+ (depends on fbcon compiled in, i.e. ``FRAMEBUFFER_CONSOLE=y``)
-+
-+
-+
-+Bootsplash file format
-+======================
-+
-+A file specified in the kernel configuration as ``CONFIG_BOOTSPLASH_FILE``
-+or specified on the command line as ``bootsplash.bootfile`` will be loaded
-+and displayed as soon as fbcon is initialized.
-+
-+
-+Main blocks
-+-----------
-+
-+There are 3 main blocks in each file:
-+
-+ - one File header
-+ - n Picture headers
-+ - m (Blob header + payload) blocks
-+
-+
-+Structures
-+----------
-+
-+The on-disk structures are defined in
-+``drivers/video/fbdev/core/bootsplash_file.h`` and represent these blocks:
-+
-+ - ``struct splash_file_header``
-+
-+ Represents the file header, with splash-wide information including:
-+
-+ - The magic string "``Linux bootsplash``" on big-endian platforms
-+ (the reverse on little endian)
-+ - The file format version (for incompatible updates, hopefully never)
-+ - The background color
-+ - Number of picture and blob blocks
-+ - Animation speed (we only allow one delay for all animations)
-+
-+ The file header is followed by the first picture header.
-+
-+
-+ - ``struct splash_picture_header``
-+
-+ Represents an object (picture) drawn on screen, including its immutable
-+ properties:
-+ - Width, height
-+ - Positioning relative to screen corners or in the center
-+ - Animation, if any
-+ - Animation type
-+ - Number of blobs
-+
-+ The picture header is followed by another picture header, up until n
-+ picture headers (as defined in the file header) have been read. Then,
-+ the (blob header, payload) pairs follow.
-+
-+
-+ - ``struct splash_blob_header``
-+ (followed by payload)
-+
-+ Represents one raw data stream. So far, only picture data is defined.
-+
-+ The blob header is followed by a payload, then padding to n*16 bytes,
-+ then (if further blobs are defined in the file header) a further blob
-+ header.
-+
-+
-+Alignment
-+---------
-+
-+The bootsplash file is designed to be loaded into memory as-is.
-+
-+All structures are a multiple of 16 bytes long, all elements therein are
-+aligned to multiples of their length, and the payloads are always padded
-+up to multiples of 16 bytes. This is to allow aligned accesses in all
-+cases while still simply mapping the structures over an in-memory copy of
-+the bootsplash file.
-+
-+
-+Further information
-+-------------------
-+
-+Please see ``drivers/video/fbdev/core/bootsplash_file.h`` for further
-+details and possible values in the file.
-+
-+
-+
-+Hooks - how the bootsplash is integrated
-+========================================
-+
-+``drivers/video/fbdev/core/fbcon.c``
-+ ``fbcon_init()`` calls ``bootsplash_init()``, which loads the default
-+ bootsplash file or the one specified on the kernel command line.
-+
-+ ``fbcon_switch()`` draws the bootsplash when it's active, and is also
-+ one of the callers of ``set_blitting_type()``.
-+
-+ ``set_blitting_type()`` calls ``fbcon_set_dummyops()`` when the
-+ bootsplash is active, overriding the text rendering functions.
-+
-+ ``fbcon_cursor()`` will call ``bootsplash_disable()`` when an oops is
-+ being printed in order to make a kernel panic visible.
-+
-+``drivers/video/fbdev/core/dummyblit.c``
-+ This contains the dummy text rendering functions used to suppress text
-+ output while the bootsplash is shown.
-+
-+``drivers/tty/vt/keyboard.c``
-+ ``kbd_keycode()`` can call ``bootsplash_disable()`` when the user
-+ presses ESC or F1-F12 (changing VT). This is to provide a built-in way
-+ of disabling the splash manually at any time.
-+
-+
-+
-+FAQ: Frequently Asked Questions
+@@ -195,6 +195,16 @@ Hooks - how the bootsplash is integrated
+
+
+
++Crating a bootsplash theme file
+===============================
+
-+I want to see the log! How do I show the log?
-+---------------------------------------------
-+
-+Press ESC while the splash is shown, or remove the ``bootsplash.bootfile``
-+parameter from the kernel cmdline. Without that parameter, the bootsplash
-+will boot disabled.
-+
-+
-+Why use FB instead of modern DRM/KMS?
-+-------------------------------------
-+
-+This is a semantic problem:
-+ - What memory to draw the splash to?
-+ - And what mode will the screen be set to?
-+
-+Using the fbdev emulation solves these issues.
-+
-+Let's start from a bare KMS system, without fbcon, and without fbdev
-+emulation. In this case, as long as userspace doesn't open the KMS
-+device, the state of the screen is undefined. No framebuffer is
-+allocated in video RAM, and no particular mode is set.
-+
-+In this case, we'd have to allocate a framebuffer to show the splash,
-+and set our mode ourselves. This either wastes a screenful of video RAM
-+if the splash is to co-exist with the userspace program's own allocated
-+framebuffer, or there is a flicker as we deactivate and delete the
-+bootsplash's framebuffer and hand control over to userspace. Since we
-+may set a different mode than userspace, we'd also have flicker due
-+to mode switching.
-+
-+This logic is already contained in every KMS driver that performs fbdev
-+emulation. So we might as well use that. And the correct API to do so is
-+fbdev. Plus, we get compatibility with old, pure fbdev drivers for free.
-+With the fbdev emulation, there is *always* a well-defined framebuffer
-+to draw on. And the selection of mode has already been done by the
-+graphics driver, so we don't need to reinvent that wheel, either.
-+Finally, if userspace decides to use /dev/fbX, we don't have to worry
-+about wasting video RAM, either.
-+
-+
-+Why is the bootsplash integrated in fbcon?
-+------------------------------------------
-+
-+Right now, the bootsplash is drawn from within fbcon, as this allows us
-+to easily know *when* to draw - i.e. when we're safe from fbcon and
-+userspace drawing all over our beautiful splash logo.
++A simple tool for theme file creation is included in ``tools/bootsplash``.
+
-+Separating them is not easy - see the to-do list below.
++There is also an example shell script, as an example on how to use the tool
++and in order to generate a reference bootsplash file.
+
+
+
-+TO DO list for future development
-+=================================
-+
-+Second enable/disable switch for the system
-+-------------------------------------------
-+
-+It may be helpful to differentiate between the system and the user
-+switching off the bootsplash. Thus, the system may make it disappear and
-+reappear e.g. for a password prompt, yet once the user has pressed ESC,
-+it could stay gone.
-+
-+
-+Fix buggy DRM/KMS drivers
-+-------------------------
-+
-+Currently, the splash code manually checks for fbdev emulation provided by
-+the ast, cirrus, and mgag200 DRM/KMS drivers.
-+These drivers use a manual mechanism similar to deferred I/O for their FB
-+emulation, and thus need to be manually flushed onto the screen in the same
-+way.
-+
-+This may be improved upon in several ways:
-+
-+1. Changing these drivers to expose the fbdev BO's memory directly, like
-+ bochsdrmfb does.
-+2. Creating a new fb_ops->fb_flush() API to allow the kernel to flush the
-+ framebuffer once the bootsplash has been drawn into it.
-+
-+
-+Separating from fbcon
-+---------------------
-+
-+Separating these two components would yield independence from fbcon being
-+compiled into the kernel, and thus lowering code size in embedded
-+applications.
-+
-+To do this cleanly will involve a clean separation of users of an FB device
-+within the kernel, i.e. fbcon, bootsplash, and userspace. Right now, the
-+legacy fbcon code and VT code co-operate to switch between fbcon and
-+userspace (by setting the VT into KD_GRAPHICS mode). Installing a muxer
-+between these components ensues refactoring of old code and checking for
-+correct locking.
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 5c237445761e..7ffac272434e 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -2709,6 +2709,8 @@ BOOTSPLASH
- M: Max Staudt <mstaudt@suse.de>
- L: linux-fbdev@vger.kernel.org
- S: Maintained
-+F: Documentation/ABI/testing/sysfs-platform-bootsplash
-+F: Documentation/bootsplash.rst
- F: drivers/video/fbdev/core/bootsplash*.*
- F: drivers/video/fbdev/core/dummycon.c
- F: include/linux/bootsplash.h
+ FAQ: Frequently Asked Questions
+ ===============================
+
+diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore
+index 091b99a17567..5dfced41ba82 100644
+--- a/tools/bootsplash/.gitignore
++++ b/tools/bootsplash/.gitignore
+@@ -1 +1,4 @@
+ bootsplash-packer
++bootsplash
++logo.rgb
++throbber*.rgb
+diff --git a/tools/bootsplash/bootsplash-tux.sh b/tools/bootsplash/bootsplash-tux.sh
+new file mode 100755
+index 000000000000..1078f87644b9
+--- /dev/null
++++ b/tools/bootsplash/bootsplash-tux.sh
+@@ -0,0 +1,66 @@
++#!/bin/bash
++#
++# A simple script to show how to create a bootsplash.
++# Do with it whatever you wish.
++#
++# This needs ImageMagick for the 'convert' and 'identify' tools.
++#
++
++LOGO=../../Documentation/logo.gif
++LOGO_WIDTH=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 1)
++LOGO_HEIGHT=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 2)
++
++THROBBER=ajax-loader.gif
++THROBBER_WIDTH=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \
++ cut -d x -f 1)
++THROBBER_HEIGHT=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \
++ cut -d x -f 2)
++
++convert -alpha remove \
++ -background "#ff3a40" \
++ $LOGO \
++ logo.rgb
++
++convert -alpha remove \
++ -background "#ff3a40" \
++ $THROBBER \
++ throbber%02d.rgb
++
++
++make clean
++make bootsplash-packer
++
++
++# Let's put Tux in the center of an orange background.
++./bootsplash-packer \
++ --bg_red 0xff \
++ --bg_green 0x3a \
++ --bg_blue 0x40 \
++ --frame_ms 48 \
++ --picture \
++ --pic_width $LOGO_WIDTH \
++ --pic_height $LOGO_HEIGHT \
++ --pic_position 0 \
++ --blob logo.rgb \
++ --picture \
++ --pic_width $THROBBER_WIDTH \
++ --pic_height $THROBBER_HEIGHT \
++ --pic_position 0x14 \
++ --pic_position_offset 20 \
++ --pic_anim_type 1 \
++ --pic_anim_loop 0 \
++ --blob throbber00.rgb \
++ --blob throbber01.rgb \
++ --blob throbber02.rgb \
++ --blob throbber03.rgb \
++ --blob throbber04.rgb \
++ --blob throbber05.rgb \
++ --blob throbber06.rgb \
++ --blob throbber07.rgb \
++ --blob throbber08.rgb \
++ --blob throbber09.rgb \
++ --blob throbber10.rgb \
++ --blob throbber11.rgb \
++ bootsplash
++
++rm *.rgb
diff --git a/0016-bootsplash.patch b/0016-bootsplash.patch
deleted file mode 100644
index 8e87eb46318..00000000000
--- a/0016-bootsplash.patch
+++ /dev/null
@@ -1,129 +0,0 @@
-diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
-index 742c7b035ded..f8f4b259220e 100644
---- a/Documentation/ABI/testing/sysfs-platform-bootsplash
-+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
-@@ -9,3 +9,35 @@ Description:
- 1: Splash is shown whenever fbcon would show a text console
- (i.e. no graphical application is running), and a splash
- file is loaded.
-+
-+What: /sys/devices/platform/bootsplash.0/drop_splash
-+Date: Oct 2017
-+KernelVersion: 4.14
-+Contact: Max Staudt <mstaudt@suse.de>
-+Description:
-+ Can only be set.
-+
-+ Any value written will cause the current splash theme file
-+ to be unloaded and the text console to be redrawn.
-+
-+What: /sys/devices/platform/bootsplash.0/load_file
-+Date: Oct 2017
-+KernelVersion: 4.14
-+Contact: Max Staudt <mstaudt@suse.de>
-+Description:
-+ Can only be set.
-+
-+ Any value written will cause the splash to be disabled and
-+ internal memory structures to be freed.
-+
-+ A firmware path written will cause a new theme file to be
-+ loaded and the current bootsplash to be replaced.
-+ The current enabled/disabled status is not touched.
-+ If the splash is already active, it will be redrawn.
-+
-+ The path has to be a path in /lib/firmware since
-+ request_firmware() is used to fetch the data.
-+
-+ When setting the splash from the shell, echo -n has to be
-+ used as any trailing '\n' newline will be interpreted as
-+ part of the path.
-diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
-index 611f0c558925..b35aba5093e8 100644
---- a/Documentation/bootsplash.rst
-+++ b/Documentation/bootsplash.rst
-@@ -67,6 +67,14 @@ sysfs run-time configuration
- a splash theme file is also loaded.
-
-
-+``/sys/devices/platform/bootsplash.0/drop_splash``
-+ Unload splash data and free memory.
-+
-+``/sys/devices/platform/bootsplash.0/load_file``
-+ Load a splash file from ``/lib/firmware/``.
-+ Note that trailing newlines will be interpreted as part of the file name.
-+
-+
-
- Kconfig
- =======
-diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
-index 13fcaabbc2ca..16cb0493629d 100644
---- a/drivers/video/fbdev/core/bootsplash.c
-+++ b/drivers/video/fbdev/core/bootsplash.c
-@@ -251,11 +251,65 @@ static ssize_t splash_store_enabled(struct device *device,
- return count;
- }
-
-+static ssize_t splash_store_drop_splash(struct device *device,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct splash_file_priv *fp;
-+
-+ if (!buf || !count || !splash_state.file)
-+ return count;
-+
-+ mutex_lock(&splash_state.data_lock);
-+ fp = splash_state.file;
-+ splash_state.file = NULL;
-+ mutex_unlock(&splash_state.data_lock);
-+
-+ /* Redraw the text console */
-+ schedule_work(&splash_state.work_redraw_vc);
-+
-+ bootsplash_free_file(fp);
-+
-+ return count;
-+}
-+
-+static ssize_t splash_store_load_file(struct device *device,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct splash_file_priv *fp, *fp_old;
-+
-+ if (!count)
-+ return 0;
-+
-+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
-+ buf);
-+
-+ if (!fp)
-+ return -ENXIO;
-+
-+ mutex_lock(&splash_state.data_lock);
-+ fp_old = splash_state.file;
-+ splash_state.splash_fb = NULL;
-+ splash_state.file = fp;
-+ mutex_unlock(&splash_state.data_lock);
-+
-+ /* Update the splash or text console */
-+ schedule_work(&splash_state.work_redraw_vc);
-+
-+ bootsplash_free_file(fp_old);
-+ return count;
-+}
-+
- static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
-+static DEVICE_ATTR(drop_splash, 0200, NULL, splash_store_drop_splash);
-+static DEVICE_ATTR(load_file, 0200, NULL, splash_store_load_file);
-
-
- static struct attribute *splash_dev_attrs[] = {
- &dev_attr_enabled.attr,
-+ &dev_attr_drop_splash.attr,
-+ &dev_attr_load_file.attr,
- NULL
- };
-
diff --git a/0017-bootsplash.patch b/0017-bootsplash.patch
deleted file mode 100644
index 5d8ea1fe295..00000000000
--- a/0017-bootsplash.patch
+++ /dev/null
@@ -1,511 +0,0 @@
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 7ffac272434e..ddff07cd794c 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -2715,6 +2715,7 @@ F: drivers/video/fbdev/core/bootsplash*.*
- F: drivers/video/fbdev/core/dummycon.c
- F: include/linux/bootsplash.h
- F: include/uapi/linux/bootsplash_file.h
-+F: tools/bootsplash/*
-
- BPF (Safe dynamic programs and tools)
- M: Alexei Starovoitov <ast@kernel.org>
-diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore
-new file mode 100644
-index 000000000000..091b99a17567
---- /dev/null
-+++ b/tools/bootsplash/.gitignore
-@@ -0,0 +1 @@
-+bootsplash-packer
-diff --git a/tools/bootsplash/Makefile b/tools/bootsplash/Makefile
-new file mode 100644
-index 000000000000..0ad8e8a84942
---- /dev/null
-+++ b/tools/bootsplash/Makefile
-@@ -0,0 +1,9 @@
-+CC := $(CROSS_COMPILE)gcc
-+CFLAGS := -I../../usr/include
-+
-+PROGS := bootsplash-packer
-+
-+all: $(PROGS)
-+
-+clean:
-+ rm -fr $(PROGS)
-diff --git a/tools/bootsplash/bootsplash-packer.c b/tools/bootsplash/bootsplash-packer.c
-new file mode 100644
-index 000000000000..ffb6a8b69885
---- /dev/null
-+++ b/tools/bootsplash/bootsplash-packer.c
-@@ -0,0 +1,471 @@
-+/*
-+ * Kernel based bootsplash.
-+ *
-+ * (Splash file packer tool)
-+ *
-+ * Authors:
-+ * Max Staudt <mstaudt@suse.de>
-+ *
-+ * SPDX-License-Identifier: GPL-2.0
-+ */
-+
-+#include <endian.h>
-+#include <getopt.h>
-+#include <stdint.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+
-+#include <linux/bootsplash_file.h>
-+
-+
-+static void print_help(char *progname)
-+{
-+ printf("Usage: %s [OPTIONS] outfile\n", progname);
-+ printf("\n"
-+ "Options, executed in order given:\n"
-+ " -h, --help Print this help message\n"
-+ "\n"
-+ " --bg_red <u8> Background color (red part)\n"
-+ " --bg_green <u8> Background color (green part)\n"
-+ " --bg_blue <u8> Background color (blue part)\n"
-+ " --bg_reserved <u8> (do not use)\n"
-+ " --frame_ms <u16> Minimum milliseconds between animation steps\n"
-+ "\n"
-+ " --picture Start describing the next picture\n"
-+ " --pic_width <u16> Picture width in pixels\n"
-+ " --pic_height <u16> Picture height in pixels\n"
-+ " --pic_position <u8> Coarse picture placement:\n"
-+ " 0x00 - Top left\n"
-+ " 0x01 - Top\n"
-+ " 0x02 - Top right\n"
-+ " 0x03 - Right\n"
-+ " 0x04 - Bottom right\n"
-+ " 0x05 - Bottom\n"
-+ " 0x06 - Bottom left\n"
-+ " 0x07 - Left\n"
-+ "\n"
-+ " Flags:\n"
-+ " 0x10 - Calculate offset from corner towards center,\n"
-+ " rather than from center towards corner\n"
-+ " --pic_position_offset <u16> Distance from base position in pixels\n"
-+ " --pic_anim_type <u8> Animation type:\n"
-+ " 0 - None\n"
-+ " 1 - Forward loop\n"
-+ " --pic_anim_loop <u8> Loop point for animation\n"
-+ "\n"
-+ " --blob <filename> Include next data stream\n"
-+ " --blob_type <u16> Type of data\n"
-+ " --blob_picture_id <u8> Picture to associate this blob with, starting at 0\n"
-+ " (default: number of last --picture)\n"
-+ "\n");
-+ printf("This tool will write %s files.\n\n",
-+#if __BYTE_ORDER == __BIG_ENDIAN
-+ "Big Endian (BE)");
-+#elif __BYTE_ORDER == __LITTLE_ENDIAN
-+ "Little Endian (LE)");
-+#else
-+#error
-+#endif
-+}
-+
-+
-+struct blob_entry {
-+ struct blob_entry *next;
-+
-+ char *fn;
-+
-+ struct splash_blob_header header;
-+};
-+
-+
-+static void dump_file_header(struct splash_file_header *h)
-+{
-+ printf(" --- File header ---\n");
-+ printf("\n");
-+ printf(" version: %5u\n", h->version);
-+ printf("\n");
-+ printf(" bg_red: %5u\n", h->bg_red);
-+ printf(" bg_green: %5u\n", h->bg_green);
-+ printf(" bg_blue: %5u\n", h->bg_blue);
-+ printf(" bg_reserved: %5u\n", h->bg_reserved);
-+ printf("\n");
-+ printf(" num_blobs: %5u\n", h->num_blobs);
-+ printf(" num_pics: %5u\n", h->num_pics);
-+ printf("\n");
-+ printf(" frame_ms: %5u\n", h->frame_ms);
-+ printf("\n");
-+}
-+
-+static void dump_pic_header(struct splash_pic_header *ph)
-+{
-+ printf(" --- Picture header ---\n");
-+ printf("\n");
-+ printf(" width: %5u\n", ph->width);
-+ printf(" height: %5u\n", ph->height);
-+ printf("\n");
-+ printf(" num_blobs: %5u\n", ph->num_blobs);
-+ printf("\n");
-+ printf(" position: %0x3x\n", ph->position);
-+ printf(" position_offset: %5u\n", ph->position_offset);
-+ printf("\n");
-+ printf(" anim_type: %5u\n", ph->anim_type);
-+ printf(" anim_loop: %5u\n", ph->anim_loop);
-+ printf("\n");
-+}
-+
-+static void dump_blob(struct blob_entry *b)
-+{
-+ printf(" --- Blob header ---\n");
-+ printf("\n");
-+ printf(" length: %7u\n", b->header.length);
-+ printf(" type: %7u\n", b->header.type);
-+ printf("\n");
-+ printf(" picture_id: %7u\n", b->header.picture_id);
-+ printf("\n");
-+}
-+
-+
-+#define OPT_MAX(var, max) \
-+ do { \
-+ if ((var) > max) { \
-+ fprintf(stderr, "--%s: Invalid value\n", \
-+ long_options[option_index].name); \
-+ break; \
-+ } \
-+ } while (0)
-+
-+static struct option long_options[] = {
-+ {"help", 0, 0, 'h'},
-+ {"bg_red", 1, 0, 10001},
-+ {"bg_green", 1, 0, 10002},
-+ {"bg_blue", 1, 0, 10003},
-+ {"bg_reserved", 1, 0, 10004},
-+ {"frame_ms", 1, 0, 10005},
-+ {"picture", 0, 0, 20000},
-+ {"pic_width", 1, 0, 20001},
-+ {"pic_height", 1, 0, 20002},
-+ {"pic_position", 1, 0, 20003},
-+ {"pic_position_offset", 1, 0, 20004},
-+ {"pic_anim_type", 1, 0, 20005},
-+ {"pic_anim_loop", 1, 0, 20006},
-+ {"blob", 1, 0, 30000},
-+ {"blob_type", 1, 0, 30001},
-+ {"blob_picture_id", 1, 0, 30002},
-+ {NULL, 0, NULL, 0}
-+};
-+
-+
-+int main(int argc, char **argv)
-+{
-+ FILE *of;
-+ char *ofn;
-+ int c;
-+ int option_index = 0;
-+
-+ unsigned long ul;
-+ struct splash_file_header fh = {};
-+ struct splash_pic_header ph[255];
-+ struct blob_entry *blob_first = NULL;
-+ struct blob_entry *blob_last = NULL;
-+ struct blob_entry *blob_cur = NULL;
-+
-+ if (argc < 2) {
-+ print_help(argv[0]);
-+ return EXIT_FAILURE;
-+ }
-+
-+
-+ /* Parse and and execute user commands */
-+ while ((c = getopt_long(argc, argv, "h",
-+ long_options, &option_index)) != -1) {
-+ switch (c) {
-+ case 10001: /* bg_red */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ fh.bg_red = ul;
-+ break;
-+ case 10002: /* bg_green */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ fh.bg_green = ul;
-+ break;
-+ case 10003: /* bg_blue */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ fh.bg_blue = ul;
-+ break;
-+ case 10004: /* bg_reserved */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ fh.bg_reserved = ul;
-+ break;
-+ case 10005: /* frame_ms */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 65535);
-+ fh.frame_ms = ul;
-+ break;
-+
-+
-+ case 20000: /* picture */
-+ if (fh.num_pics >= 255) {
-+ fprintf(stderr, "--%s: Picture array full\n",
-+ long_options[option_index].name);
-+ break;
-+ }
-+
-+ fh.num_pics++;
-+ break;
-+
-+ case 20001: /* pic_width */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 65535);
-+ ph[fh.num_pics - 1].width = ul;
-+ break;
-+
-+ case 20002: /* pic_height */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 65535);
-+ ph[fh.num_pics - 1].height = ul;
-+ break;
-+
-+ case 20003: /* pic_position */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ ph[fh.num_pics - 1].position = ul;
-+ break;
-+
-+ case 20004: /* pic_position_offset */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ ph[fh.num_pics - 1].position_offset = ul;
-+ break;
-+
-+ case 20005: /* pic_anim_type */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ ph[fh.num_pics - 1].anim_type = ul;
-+ break;
-+
-+ case 20006: /* pic_anim_loop */
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ ph[fh.num_pics - 1].anim_loop = ul;
-+ break;
-+
-+
-+ case 30000: /* blob */
-+ if (fh.num_blobs >= 65535) {
-+ fprintf(stderr, "--%s: Blob array full\n",
-+ long_options[option_index].name);
-+ break;
-+ }
-+
-+ blob_cur = calloc(1, sizeof(struct blob_entry));
-+ if (!blob_cur) {
-+ fprintf(stderr, "--%s: Out of memory\n",
-+ long_options[option_index].name);
-+ break;
-+ }
-+
-+ blob_cur->fn = optarg;
-+ if (fh.num_pics)
-+ blob_cur->header.picture_id = fh.num_pics - 1;
-+
-+ if (!blob_first)
-+ blob_first = blob_cur;
-+ if (blob_last)
-+ blob_last->next = blob_cur;
-+ blob_last = blob_cur;
-+ fh.num_blobs++;
-+ break;
-+
-+ case 30001: /* blob_type */
-+ if (!blob_cur) {
-+ fprintf(stderr, "--%s: No blob selected\n",
-+ long_options[option_index].name);
-+ break;
-+ }
-+
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ blob_cur->header.type = ul;
-+ break;
-+
-+ case 30002: /* blob_picture_id */
-+ if (!blob_cur) {
-+ fprintf(stderr, "--%s: No blob selected\n",
-+ long_options[option_index].name);
-+ break;
-+ }
-+
-+ ul = strtoul(optarg, NULL, 0);
-+ OPT_MAX(ul, 255);
-+ blob_cur->header.picture_id = ul;
-+ break;
-+
-+
-+
-+ case 'h':
-+ case '?':
-+ default:
-+ print_help(argv[0]);
-+ goto EXIT;
-+ } /* switch (c) */
-+ } /* while ((c = getopt_long(...)) != -1) */
-+
-+ /* Consume and drop lone arguments */
-+ while (optind < argc) {
-+ ofn = argv[optind];
-+ optind++;
-+ }
-+
-+
-+ /* Read file lengths */
-+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
-+ FILE *f;
-+ long pos;
-+ int i;
-+
-+ if (!blob_cur->fn)
-+ continue;
-+
-+ f = fopen(blob_cur->fn, "rb");
-+ if (!f)
-+ goto ERR_FILE_LEN;
-+
-+ if (fseek(f, 0, SEEK_END))
-+ goto ERR_FILE_LEN;
-+
-+ pos = ftell(f);
-+ if (pos < 0 || pos > (1 << 30))
-+ goto ERR_FILE_LEN;
-+
-+ blob_cur->header.length = pos;
-+
-+ fclose(f);
-+ continue;
-+
-+ERR_FILE_LEN:
-+ fprintf(stderr, "Error getting file length (or too long): %s\n",
-+ blob_cur->fn);
-+ if (f)
-+ fclose(f);
-+ continue;
-+ }
-+
-+
-+ /* Set magic headers */
-+#if __BYTE_ORDER == __BIG_ENDIAN
-+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_BE, 16);
-+#elif __BYTE_ORDER == __LITTLE_ENDIAN
-+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_LE, 16);
-+#else
-+#error
-+#endif
-+ fh.version = BOOTSPLASH_VERSION;
-+
-+ /* Set blob counts */
-+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
-+ if (blob_cur->header.picture_id < fh.num_pics)
-+ ph[blob_cur->header.picture_id].num_blobs++;
-+ }
-+
-+
-+ /* Dump structs */
-+ dump_file_header(&fh);
-+
-+ for (ul = 0; ul < fh.num_pics; ul++)
-+ dump_pic_header(&ph[ul]);
-+
-+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next)
-+ dump_blob(blob_cur);
-+
-+
-+ /* Write to file */
-+ printf("Writing splash to file: %s\n", ofn);
-+ of = fopen(ofn, "wb");
-+ if (!of)
-+ goto ERR_WRITING;
-+
-+ if (fwrite(&fh, sizeof(struct splash_file_header), 1, of) != 1)
-+ goto ERR_WRITING;
-+
-+ for (ul = 0; ul < fh.num_pics; ul++) {
-+ if (fwrite(&ph[ul], sizeof(struct splash_pic_header), 1, of)
-+ != 1)
-+ goto ERR_WRITING;
-+ }
-+
-+ blob_cur = blob_first;
-+ while (blob_cur) {
-+ struct blob_entry *blob_old = blob_cur;
-+ FILE *f;
-+ char *buf[256];
-+ uint32_t left;
-+
-+ if (fwrite(&blob_cur->header,
-+ sizeof(struct splash_blob_header), 1, of) != 1)
-+ goto ERR_WRITING;
-+
-+ if (!blob_cur->header.length || !blob_cur->fn)
-+ continue;
-+
-+ f = fopen(blob_cur->fn, "rb");
-+ if (!f)
-+ goto ERR_FILE_COPY;
-+
-+ left = blob_cur->header.length;
-+ while (left >= sizeof(buf)) {
-+ if (fread(buf, sizeof(buf), 1, f) != 1)
-+ goto ERR_FILE_COPY;
-+ if (fwrite(buf, sizeof(buf), 1, of) != 1)
-+ goto ERR_FILE_COPY;
-+ left -= sizeof(buf);
-+ }
-+ if (left) {
-+ if (fread(buf, left, 1, f) != 1)
-+ goto ERR_FILE_COPY;
-+ if (fwrite(buf, left, 1, of) != 1)
-+ goto ERR_FILE_COPY;
-+ }
-+
-+ /* Pad data stream to 16 bytes */
-+ if (left % 16) {
-+ if (fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
-+ 16 - (left % 16), 1, of) != 1)
-+ goto ERR_FILE_COPY;
-+ }
-+
-+ fclose(f);
-+ blob_cur = blob_cur->next;
-+ free(blob_old);
-+ continue;
-+
-+ERR_FILE_COPY:
-+ if (f)
-+ fclose(f);
-+ goto ERR_WRITING;
-+ }
-+
-+ fclose(of);
-+
-+EXIT:
-+ return EXIT_SUCCESS;
-+
-+
-+ERR_WRITING:
-+ fprintf(stderr, "Error writing splash.\n");
-+ fprintf(stderr, "The output file is probably corrupt.\n");
-+ if (of)
-+ fclose(of);
-+
-+ while (blob_cur) {
-+ struct blob_entry *blob_old = blob_cur;
-+
-+ blob_cur = blob_cur->next;
-+ free(blob_old);
-+ }
-+
-+ return EXIT_FAILURE;
-+}
diff --git a/0018-bootsplash.patch b/0018-bootsplash.patch
deleted file mode 100644
index 0924d29e7d4..00000000000
--- a/0018-bootsplash.patch
+++ /dev/null
@@ -1,102 +0,0 @@
-diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
-index b35aba5093e8..d4f132eca615 100644
---- a/Documentation/bootsplash.rst
-+++ b/Documentation/bootsplash.rst
-@@ -195,6 +195,16 @@ Hooks - how the bootsplash is integrated
-
-
-
-+Crating a bootsplash theme file
-+===============================
-+
-+A simple tool for theme file creation is included in ``tools/bootsplash``.
-+
-+There is also an example shell script, as an example on how to use the tool
-+and in order to generate a reference bootsplash file.
-+
-+
-+
- FAQ: Frequently Asked Questions
- ===============================
-
-diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore
-index 091b99a17567..5dfced41ba82 100644
---- a/tools/bootsplash/.gitignore
-+++ b/tools/bootsplash/.gitignore
-@@ -1 +1,4 @@
- bootsplash-packer
-+bootsplash
-+logo.rgb
-+throbber*.rgb
-diff --git a/tools/bootsplash/bootsplash-tux.sh b/tools/bootsplash/bootsplash-tux.sh
-new file mode 100755
-index 000000000000..1078f87644b9
---- /dev/null
-+++ b/tools/bootsplash/bootsplash-tux.sh
-@@ -0,0 +1,66 @@
-+#!/bin/bash
-+#
-+# A simple script to show how to create a bootsplash.
-+# Do with it whatever you wish.
-+#
-+# This needs ImageMagick for the 'convert' and 'identify' tools.
-+#
-+
-+LOGO=../../Documentation/logo.gif
-+LOGO_WIDTH=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 1)
-+LOGO_HEIGHT=$(identify $LOGO | cut -d " " -f 3 | cut -d x -f 2)
-+
-+THROBBER=ajax-loader.gif
-+THROBBER_WIDTH=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \
-+ cut -d x -f 1)
-+THROBBER_HEIGHT=$(identify $THROBBER | head -1 | cut -d " " -f 3 | \
-+ cut -d x -f 2)
-+
-+convert -alpha remove \
-+ -background "#ff3a40" \
-+ $LOGO \
-+ logo.rgb
-+
-+convert -alpha remove \
-+ -background "#ff3a40" \
-+ $THROBBER \
-+ throbber%02d.rgb
-+
-+
-+make clean
-+make bootsplash-packer
-+
-+
-+# Let's put Tux in the center of an orange background.
-+./bootsplash-packer \
-+ --bg_red 0xff \
-+ --bg_green 0x3a \
-+ --bg_blue 0x40 \
-+ --frame_ms 48 \
-+ --picture \
-+ --pic_width $LOGO_WIDTH \
-+ --pic_height $LOGO_HEIGHT \
-+ --pic_position 0 \
-+ --blob logo.rgb \
-+ --picture \
-+ --pic_width $THROBBER_WIDTH \
-+ --pic_height $THROBBER_HEIGHT \
-+ --pic_position 0x14 \
-+ --pic_position_offset 20 \
-+ --pic_anim_type 1 \
-+ --pic_anim_loop 0 \
-+ --blob throbber00.rgb \
-+ --blob throbber01.rgb \
-+ --blob throbber02.rgb \
-+ --blob throbber03.rgb \
-+ --blob throbber04.rgb \
-+ --blob throbber05.rgb \
-+ --blob throbber06.rgb \
-+ --blob throbber07.rgb \
-+ --blob throbber08.rgb \
-+ --blob throbber09.rgb \
-+ --blob throbber10.rgb \
-+ --blob throbber11.rgb \
-+ bootsplash
-+
-+rm *.rgb
diff --git a/PKGBUILD b/PKGBUILD
index 871193e3667..c7b275b6bc4 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -80,8 +80,9 @@ source=(
"enable_additional_cpu_optimizations-$_gcc_more_v.tar.gz::https://github.com/graysky2/kernel_gcc_patch/archive/$_gcc_more_v.tar.gz"
0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch
0002-ZEN-Add-CONFIG-for-unprivileged_userns_clone.patch
- 0003-iwlwifi-mvm-disable-TX-AMSDU-on-older-NICs.patch
- 0004-iwlwifi-Add-support-for-SAR-South-Korea-limitation.patch
+ 0003-bootsplash.patch
+ 0004-bootsplash.patch
+ 0005-bootsplash.patch
0006-bootsplash.patch
0007-bootsplash.patch
0008-bootsplash.patch
@@ -92,16 +93,13 @@ source=(
0013-bootsplash.patch
0014-bootsplash.patch
0015-bootsplash.patch
- 0016-bootsplash.patch
- 0017-bootsplash.patch
- 0018-bootsplash.patch
'ajax-loader.gif'
)
validpgpkeys=(
'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds
'647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman
)
-sha256sums=('b6f02a4b306ca5cd314d72615bfc2650166969613135da202630e6c4e1b5d4e6'
+sha256sums=('0c2a831f993dc8a8a8e1ca4186b467de72ff173c6f5855e2aab70f6f7fb033f9'
'SKIP'
'1c4d5500a3b4995035c2e940fc0ad2a2dae7be047c8eb20c097444e348258f87'
'ae2e95db94ef7176207c690224169594d49445e04249d2499e9d2fbc117a0b21'
@@ -109,8 +107,6 @@ sha256sums=('b6f02a4b306ca5cd314d72615bfc2650166969613135da202630e6c4e1b5d4e6'
'ad6344badc91ad0630caacde83f7f9b97276f80d26a20619a87952be65492c65'
'f1abc13a8d859fbf6350040e45d7f04ad551a6d39f113ba96fbbd820118c0e36'
'91fafa76bf9cb32159ac7f22191b3589278b91e65bc4505cf2fc6013b8037bf3'
- '63e4378e69e2f23ed87af32a4951477a6d82d4ac0de2295db46502c8120da9d9'
- 'fc96300831506965383ef30bc46b72735dc45bb97dea2ccb8b9450c005d2f020'
'ef926edbd866d95464eb86f7565de572eb97ecfa0369d3b2e078016a0e71a871'
'a504f6cf84094e08eaa3cc5b28440261797bf4f06f04993ee46a20628ff2b53c'
'e096b127a5208f56d368d2cb938933454d7200d70c86b763aa22c38e0ddb8717'