From d6fa79a01b358793499e8a8ab77229d1e3b92122 Mon Sep 17 00:00:00 2001 From: Petr Hodina Date: Wed, 24 Aug 2022 06:23:03 +0200 Subject: [PATCH] nongnu: Add linux-pinephone and linux-pinephone-pro. * nongnu/packages/linux.scm (linux-pinephone-urls, pinephone-linux, linux-pinephone, linux-pinephone-pro): New variables. * nongnu/packages/patches/linux-pinephone-pro-defconfig-guix-fix.patch: New file. * nongnu/packages/patches/pinephone-0001-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0002-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0003-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0004-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0005-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0006-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0007-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0008-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0009-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0010-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-0011-bootsplash.patch: New file. * nongnu/packages/patches/pinephone-drop-modem-power-node.patch: New file. * nongnu/packages/patches/pinephone-fbcon-remove-no-op-fbcon_set_origin.patch: New file. * nongnu/packages/patches/pinephone-pro-add-modem-ri.patch.patch: New file. * nongnu/packages/patches/pinephone-pro-remove-modem-node.patch: New file. * nongnu/packages/patches/pinephone-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch: New file. * nongnu/packages/patches/pinephone-revert-fbcon-remove-soft-scrollback-code.patch: New file. asd --- nongnu/packages/linux.scm | 64 ++ ...nux-pinephone-pro-defconfig-guix-fix.patch | 13 + .../patches/pinephone-0001-bootsplash.patch | 750 ++++++++++++++++++ .../patches/pinephone-0002-bootsplash.patch | 657 +++++++++++++++ .../patches/pinephone-0003-bootsplash.patch | 66 ++ .../patches/pinephone-0004-bootsplash.patch | 215 +++++ .../patches/pinephone-0005-bootsplash.patch | 327 ++++++++ .../patches/pinephone-0006-bootsplash.patch | 82 ++ .../patches/pinephone-0007-bootsplash.patch | 42 + .../patches/pinephone-0008-bootsplash.patch | 21 + .../patches/pinephone-0009-bootsplash.patch | 21 + .../patches/pinephone-0010-bootsplash.patch | 308 +++++++ .../patches/pinephone-0011-bootsplash.patch | 499 ++++++++++++ .../pinephone-drop-modem-power-node.patch | 175 ++++ ...-fbcon-remove-no-op-fbcon_set_origin.patch | 31 + .../pinephone-pro-add-modem-ri.patch.patch | 52 ++ .../pinephone-pro-remove-modem-node.patch | 86 ++ ...usued-softback_lines-cursor-argument.patch | 150 ++++ ...rt-fbcon-remove-soft-scrollback-code.patch | 500 ++++++++++++ 19 files changed, 4059 insertions(+) create mode 100644 nongnu/packages/patches/linux-pinephone-pro-defconfig-guix-fix.patch create mode 100644 nongnu/packages/patches/pinephone-0001-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0002-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0003-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0004-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0005-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0006-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0007-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0008-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0009-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0010-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-0011-bootsplash.patch create mode 100644 nongnu/packages/patches/pinephone-drop-modem-power-node.patch create mode 100644 nongnu/packages/patches/pinephone-fbcon-remove-no-op-fbcon_set_origin.patch create mode 100644 nongnu/packages/patches/pinephone-pro-add-modem-ri.patch.patch create mode 100644 nongnu/packages/patches/pinephone-pro-remove-modem-node.patch create mode 100644 nongnu/packages/patches/pinephone-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch create mode 100644 nongnu/packages/patches/pinephone-revert-fbcon-remove-soft-scrollback-code.patch diff --git a/nongnu/packages/linux.scm b/nongnu/packages/linux.scm index 6319a7a..b99d31c 100644 --- a/nongnu/packages/linux.scm +++ b/nongnu/packages/linux.scm @@ -35,6 +35,7 @@ #:use-module (guix build-system linux-module) #:use-module (guix build-system trivial) #:use-module (ice-9 match) + #:use-module (srfi srfi-1) #:use-module (nonguix licenses) #:export (corrupt-linux)) @@ -43,6 +44,12 @@ (list (string-append "https://www.kernel.org/pub/linux/kernel/v" (version-major version) ".x/linux-" version ".tar.xz"))) +(define (linux-pinephone-urls version commit) + "Return a list of URLS for Linux VERSION." + (list (string-append + "https://github.com/megous/linux/archive/refs/tags/orange-pi-" + (version-major+minor version) "-" commit ".tar.gz"))) + (define* (corrupt-linux freedo #:key (name "linux")) (package (inherit @@ -59,6 +66,55 @@ "The unmodified Linux kernel, including nonfree blobs, for running Guix System on hardware which requires nonfree software to function."))) +;; Linux kernel fork for PinePhone and PinePhone Pro +(define* (pinephone-linux freedo version-megi release defconfig #:key (name "linux")) + (package + (inherit + (customize-linux + #:name name + #:defconfig defconfig + #:source (origin (inherit (package-source freedo)) + (method url-fetch) + (file-name (string-append name "-" (version-major+minor + version-megi) + "-guix.tar.gz")) + (uri (linux-pinephone-urls version-megi + release)) + (patches + (parameterize + ((%patch-path + (map (lambda (directory) + (string-append directory "/nongnu/packages/patches")) + %load-path))) + (search-patches + "linux-pinephone-pro-defconfig-guix-fix.patch")))))) +; ;; Port bootsplash patches +;;;"pinephone-0001-bootsplash.patch" +;;;"pinephone-0002-bootsplash.patch" +;;"pinephone-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch" +;;;"pinephone-0003-bootsplash.patch" +;;"pinephone-fbcon-remove-no-op-fbcon_set_origin.patch" +;;;"pinephone-0004-bootsplash.patch" +;;"pinephone-revert-fbcon-remove-soft-scrollback-code.patch" +;;;"pinephone-0005-bootsplash.patch" +;;;"pinephone-0004-bootsplash.patch" +;;;"pinephone-0006-bootsplash.patch" +;;;"pinephone-0007-bootsplash.patch" +;;;"pinephone-0008-bootsplash.patch" +;;;"pinephone-0009-bootsplash.patch" +;;;"pinephone-0010-bootsplash.patch" +;;;"pinephone-0011-bootsplash.patch" +;;"pinephone-drop-modem-power-node.patch" +;;"pinephone-pro-add-modem-ri.patch.patch" +;;"pinephone-pro-remove-modem-node.patch" +; )))))) + (version (package-version freedo)) + (home-page "https://www.kernel.org/") + (synopsis "Linux kernel with nonfree binary blobs included") + (description + "The unmodified Linux kernel, including nonfree blobs, for running Guix +System on hardware which requires nonfree software to function."))) + (define-public linux-6.1 (corrupt-linux linux-libre-6.1)) @@ -91,6 +147,14 @@ System on hardware which requires nonfree software to function."))) (define-public linux-arm64-generic-lts linux-arm64-generic-5.15) +(define-public linux-pinephone-pro + (pinephone-linux linux-libre-arm64-generic "6.1" "20230104-1712" "pinephone_pro_defconfig" +#:name "linux-pinephone-pro")) + +(define-public linux-pinephone + (pinephone-linux linux-libre-arm64-generic "6.1" "20230104-1712" "pinephone_defconfig" +#:name "linux-pinephone")) + (define-public linux-firmware (package (name "linux-firmware") diff --git a/nongnu/packages/patches/linux-pinephone-pro-defconfig-guix-fix.patch b/nongnu/packages/patches/linux-pinephone-pro-defconfig-guix-fix.patch new file mode 100644 index 0000000..a82318e --- /dev/null +++ b/nongnu/packages/patches/linux-pinephone-pro-defconfig-guix-fix.patch @@ -0,0 +1,13 @@ +--- a/arch/arm64/configs/pinephone_pro_defconfig.orig 2023-01-14 08:25:28.004411948 +0100 ++++ b/arch/arm64/configs/pinephone_pro_defconfig 2023-01-14 08:47:08.696514744 +0100 +@@ -252,8 +252,8 @@ + CONFIG_UEVENT_HELPER=y + CONFIG_DEVTMPFS=y + CONFIG_DEVTMPFS_MOUNT=y +-#CONFIG_EXTRA_FIRMWARE="regulatory.db regulatory.db.p7s brcm/brcmfmac43455-sdio.bin brcm/brcmfmac43455-sdio.pine64,pinephone-pro.txt brcm/brcmfmac43455-sdio.clm_blob brcm/BCM4345C0.hcd rockchip/dptx.bin" +-#CONFIG_EXTRA_FIRMWARE_DIR="/workspace/megous.com/orangepi-pc/firmware" ++CONFIG_EXTRA_FIRMWARE="" ++# CONFIG_EXTRA_FIRMWARE_DIR is not set + CONFIG_ARM_SCMI_PROTOCOL=y + CONFIG_ARM_SCPI_PROTOCOL=y + CONFIG_MTD=y diff --git a/nongnu/packages/patches/pinephone-0001-bootsplash.patch b/nongnu/packages/patches/pinephone-0001-bootsplash.patch new file mode 100644 index 0000000..1e259bf --- /dev/null +++ b/nongnu/packages/patches/pinephone-0001-bootsplash.patch @@ -0,0 +1,750 @@ +diff --git a/MAINTAINERS b/MAINTAINERS +index a74227ad082e..b5633b56391e 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3582,6 +3614,18 @@ F: drivers/net/bonding/ + F: include/net/bond* + F: include/uapi/linux/if_bonding.h + ++BOOTSPLASH ++M: Max Staudt ++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 ++F: include/uapi/linux/bootsplash_file.h ++F: tools/bootsplash/* ++ + BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER + M: Dan Robertson + L: linux-iio@vger.kernel.org +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 ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#define pr_fmt(fmt) "bootsplash: " fmt ++ ++ ++#include ++#include ++#include ++#include /* dev_warn() */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* console_blanked */ ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#ifndef __BOOTSPLASH_INTERNAL_H ++#define __BOOTSPLASH_INTERNAL_H ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ++ * 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 ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#define pr_fmt(fmt) "bootsplash: " fmt ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#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 "); ++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 + + #include "fbcon.h" ++#include + + #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 ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#ifndef __LINUX_BOOTSPLASH_H ++#define __LINUX_BOOTSPLASH_H ++ ++#include ++ ++ ++#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/nongnu/packages/patches/pinephone-0002-bootsplash.patch b/nongnu/packages/patches/pinephone-0002-bootsplash.patch new file mode 100644 index 0000000..e8d4cc8 --- /dev/null +++ b/nongnu/packages/patches/pinephone-0002-bootsplash.patch @@ -0,0 +1,657 @@ +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 + + #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 + #include ++#include + #include + #include + #include + ++#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 ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#define pr_fmt(fmt) "bootsplash: " fmt ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + + #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 ++ * ++ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++ */ ++ ++#ifndef __BOOTSPLASH_FILE_H ++#define __BOOTSPLASH_FILE_H ++ ++ ++#define BOOTSPLASH_VERSION 55561 ++ ++ ++#include ++#include ++ ++ ++/* ++ * 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/nongnu/packages/patches/pinephone-0003-bootsplash.patch b/nongnu/packages/patches/pinephone-0003-bootsplash.patch new file mode 100644 index 0000000..2169537 --- /dev/null +++ b/nongnu/packages/patches/pinephone-0003-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/nongnu/packages/patches/pinephone-0004-bootsplash.patch b/nongnu/packages/patches/pinephone-0004-bootsplash.patch new file mode 100644 index 0000000..7eb54af --- /dev/null +++ b/nongnu/packages/patches/pinephone-0004-bootsplash.patch @@ -0,0 +1,215 @@ +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; + + 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; + +- 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; ++ } + + 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__)); + + +@@ -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, ++}; ++ + #endif diff --git a/nongnu/packages/patches/pinephone-0005-bootsplash.patch b/nongnu/packages/patches/pinephone-0005-bootsplash.patch new file mode 100644 index 0000000..2785c5e --- /dev/null +++ b/nongnu/packages/patches/pinephone-0005-bootsplash.patch @@ -0,0 +1,327 @@ +diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c +index 815b007f81ca..c8642142cfea 100644 +--- a/drivers/video/fbdev/core/bootsplash.c ++++ b/drivers/video/fbdev/core/bootsplash.c +@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored) + console_unlock(); + } + ++static void splash_callback_animation(struct work_struct *ignored) ++{ ++ if (bootsplash_would_render_now()) { ++ /* This will also re-schedule this delayed worker */ ++ splash_callback_redraw_vc(ignored); ++ } ++} ++ + + static bool is_fb_compatible(const struct fb_info *info) + { +@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info) + */ + void bootsplash_render_full(struct fb_info *info) + { ++ bool is_update = false; ++ + mutex_lock(&splash_state.data_lock); + +- if (!is_fb_compatible(info)) +- goto out; ++ /* ++ * If we've painted on this FB recently, we don't have to do ++ * the sanity checks and background drawing again. ++ */ ++ if (splash_state.splash_fb == info) ++ is_update = true; ++ ++ ++ if (!is_update) { ++ /* Check whether we actually support this FB. */ ++ splash_state.splash_fb = NULL; ++ ++ if (!is_fb_compatible(info)) ++ goto out; ++ ++ /* Draw the background only once */ ++ bootsplash_do_render_background(info, splash_state.file); + +- bootsplash_do_render_background(info, splash_state.file); ++ /* Mark this FB as last seen */ ++ splash_state.splash_fb = info; ++ } + +- bootsplash_do_render_pictures(info, splash_state.file); ++ bootsplash_do_render_pictures(info, splash_state.file, is_update); + + bootsplash_do_render_flush(info); + ++ bootsplash_do_step_animations(splash_state.file); ++ ++ /* Schedule update for animated splash screens */ ++ if (splash_state.file->frame_ms > 0) ++ schedule_delayed_work(&splash_state.dwork_animation, ++ msecs_to_jiffies( ++ splash_state.file->frame_ms)); ++ + out: + mutex_unlock(&splash_state.data_lock); + } +@@ -169,8 +204,14 @@ void bootsplash_enable(void) + + was_enabled = test_and_set_bit(0, &splash_state.enabled); + +- if (!was_enabled) ++ if (!was_enabled) { ++ /* Force a full redraw when the splash is re-activated */ ++ mutex_lock(&splash_state.data_lock); ++ splash_state.splash_fb = NULL; ++ mutex_unlock(&splash_state.data_lock); ++ + schedule_work(&splash_state.work_redraw_vc); ++ } + } + + +@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev); + */ + static int splash_resume(struct device *device) + { ++ /* ++ * Force full redraw on resume since we've probably lost the ++ * framebuffer's contents meanwhile ++ */ ++ mutex_lock(&splash_state.data_lock); ++ splash_state.splash_fb = NULL; ++ mutex_unlock(&splash_state.data_lock); ++ + if (bootsplash_would_render_now()) + schedule_work(&splash_state.work_redraw_vc); + +@@ -235,6 +284,7 @@ static int splash_resume(struct device *device) + + static int splash_suspend(struct device *device) + { ++ cancel_delayed_work_sync(&splash_state.dwork_animation); + cancel_work_sync(&splash_state.work_redraw_vc); + + return 0; +@@ -296,6 +346,8 @@ void bootsplash_init(void) + set_bit(0, &splash_state.enabled); + + INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc); ++ INIT_DELAYED_WORK(&splash_state.dwork_animation, ++ splash_callback_animation); + + + if (!splash_state.bootfile || !strlen(splash_state.bootfile)) +diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h +index 0acb383aa4e3..b3a74835d90f 100644 +--- a/drivers/video/fbdev/core/bootsplash_internal.h ++++ b/drivers/video/fbdev/core/bootsplash_internal.h +@@ -37,6 +37,8 @@ struct splash_pic_priv { + + struct splash_blob_priv *blobs; + u16 blobs_loaded; ++ ++ u16 anim_nextframe; + }; + + +@@ -45,6 +47,12 @@ struct splash_file_priv { + const struct splash_file_header *header; + + struct splash_pic_priv *pics; ++ ++ /* ++ * A local copy of the frame delay in the header. ++ * We modify it to keep the code simple. ++ */ ++ u16 frame_ms; + }; + + +@@ -71,6 +79,7 @@ struct splash_priv { + struct platform_device *splash_device; + + struct work_struct work_redraw_vc; ++ struct delayed_work dwork_animation; + + /* Splash data structures including lock for everything below */ + struct mutex data_lock; +@@ -88,8 +97,10 @@ struct splash_priv { + void bootsplash_do_render_background(struct fb_info *info, + const struct splash_file_priv *fp); + void bootsplash_do_render_pictures(struct fb_info *info, +- const struct splash_file_priv *fp); ++ const struct splash_file_priv *fp, ++ bool is_update); + void bootsplash_do_render_flush(struct fb_info *info); ++void bootsplash_do_step_animations(struct splash_file_priv *fp); + + + void bootsplash_free_file(struct splash_file_priv *fp); +diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c +index fd807571ab7d..1f661b2d4cc9 100644 +--- a/drivers/video/fbdev/core/bootsplash_load.c ++++ b/drivers/video/fbdev/core/bootsplash_load.c +@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + { + const struct firmware *fw; + struct splash_file_priv *fp; ++ bool have_anim = false; + unsigned int i; + const u8 *walker; + +@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + goto err; + } + ++ if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) { ++ pr_warn("Picture %u: Unsupported animation type %u.\n", ++ i, ph->anim_type); ++ ++ ph->anim_type = SPLASH_ANIM_NONE; ++ } ++ + pp->pic_header = ph; + pp->blobs = vzalloc(ph->num_blobs + * sizeof(struct splash_blob_priv)); +@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + /* Walk over pictures and ensure all blob slots are filled */ + for (i = 0; i < fp->header->num_pics; i++) { + struct splash_pic_priv *pp = &fp->pics[i]; ++ const struct splash_pic_header *ph = pp->pic_header; + + if (pp->blobs_loaded != pp->pic_header->num_blobs) { + pr_err("Picture %u doesn't have all blob slots filled.\n", +@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device, + + goto err; + } ++ ++ if (ph->anim_type ++ && ph->num_blobs > 1 ++ && ph->anim_loop < pp->blobs_loaded) ++ have_anim = true; + } + ++ if (!have_anim) ++ /* Disable animation timer if there is nothing to animate */ ++ fp->frame_ms = 0; ++ else ++ /* Enforce minimum delay between frames */ ++ fp->frame_ms = max((u16)20, fp->header->frame_ms); ++ + pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n", + fw->size, + fp->header->num_pics, +diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c +index 07e3a4eab811..76033606ca8a 100644 +--- a/drivers/video/fbdev/core/bootsplash_render.c ++++ b/drivers/video/fbdev/core/bootsplash_render.c +@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info, + + + void bootsplash_do_render_pictures(struct fb_info *info, +- const struct splash_file_priv *fp) ++ const struct splash_file_priv *fp, ++ bool is_update) + { + unsigned int i; + +@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info, + if (pp->blobs_loaded < 1) + continue; + +- bp = &pp->blobs[0]; ++ /* Skip static pictures when refreshing animations */ ++ if (ph->anim_type == SPLASH_ANIM_NONE && is_update) ++ continue; ++ ++ bp = &pp->blobs[pp->anim_nextframe]; + + if (!bp || bp->blob_header->type != 0) + continue; +@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info) + info->fbops->fb_copyarea(info, &area); + } + } ++ ++ ++void bootsplash_do_step_animations(struct splash_file_priv *fp) ++{ ++ unsigned int i; ++ ++ /* Step every animation once */ ++ for (i = 0; i < fp->header->num_pics; i++) { ++ struct splash_pic_priv *pp = &fp->pics[i]; ++ ++ if (pp->blobs_loaded < 2 ++ || pp->pic_header->anim_loop > pp->blobs_loaded) ++ continue; ++ ++ if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) { ++ pp->anim_nextframe++; ++ if (pp->anim_nextframe >= pp->pic_header->num_blobs) ++ pp->anim_nextframe = pp->pic_header->anim_loop; ++ } ++ } ++} +diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h +index 71cedcc68933..b3af0a3c6487 100644 +--- a/include/uapi/linux/bootsplash_file.h ++++ b/include/uapi/linux/bootsplash_file.h +@@ -77,7 +77,17 @@ struct splash_file_header { + uint16_t num_blobs; + uint8_t num_pics; + +- uint8_t padding[103]; ++ uint8_t unused_1; ++ ++ /* ++ * Milliseconds to wait before painting the next frame in ++ * an animation. ++ * This is actually a minimum, as the system is allowed to ++ * stall for longer between frames. ++ */ ++ uint16_t frame_ms; ++ ++ uint8_t padding[100]; + } __attribute__((__packed__)); + + +@@ -116,7 +126,23 @@ struct splash_pic_header { + */ + uint16_t position_offset; + +- uint8_t padding[24]; ++ /* ++ * Animation type. ++ * 0 - off ++ * 1 - forward loop ++ */ ++ uint8_t anim_type; ++ ++ /* ++ * Animation loop point. ++ * Actual meaning depends on animation type: ++ * Type 0 - Unused ++ * 1 - Frame at which to restart the forward loop ++ * (allowing for "intro" frames) ++ */ ++ uint8_t anim_loop; ++ ++ uint8_t padding[22]; + } __attribute__((__packed__)); + + +@@ -158,4 +184,9 @@ enum splash_position { + SPLASH_POS_FLAG_CORNER = 0x10, + }; + ++enum splash_anim_type { ++ SPLASH_ANIM_NONE = 0, ++ SPLASH_ANIM_LOOP_FORWARD = 1, ++}; ++ + #endif diff --git a/nongnu/packages/patches/pinephone-0006-bootsplash.patch b/nongnu/packages/patches/pinephone-0006-bootsplash.patch new file mode 100644 index 0000000..d6c6db6 --- /dev/null +++ b/nongnu/packages/patches/pinephone-0006-bootsplash.patch @@ -0,0 +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 + #include + #include ++#include + + #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); ++ + 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() ++ + #define bootsplash_is_enabled() (false) + #define bootsplash_disable() + #define bootsplash_enable() diff --git a/nongnu/packages/patches/pinephone-0007-bootsplash.patch b/nongnu/packages/patches/pinephone-0007-bootsplash.patch new file mode 100644 index 0000000..3f82eb0 --- /dev/null +++ b/nongnu/packages/patches/pinephone-0007-bootsplash.patch @@ -0,0 +1,42 @@ +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 +@@ -49,6 +49,8 @@ + + #include + ++#include ++ + /* + * Exported functions/variables + */ +@@ -1413,6 +1415,28 @@ static void kbd_keycode(unsigned int key + } + #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/nongnu/packages/patches/pinephone-0008-bootsplash.patch b/nongnu/packages/patches/pinephone-0008-bootsplash.patch new file mode 100644 index 0000000..8a3b715 --- /dev/null +++ b/nongnu/packages/patches/pinephone-0008-bootsplash.patch @@ -0,0 +1,21 @@ +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 + #include + #include ++#include + + #include + #include +@@ -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(); + } + static struct sysrq_key_op sysrq_SAK_op = { + .handler = sysrq_handle_SAK, diff --git a/nongnu/packages/patches/pinephone-0009-bootsplash.patch b/nongnu/packages/patches/pinephone-0009-bootsplash.patch new file mode 100644 index 0000000..add68e7 --- /dev/null +++ b/nongnu/packages/patches/pinephone-0009-bootsplash.patch @@ -0,0 +1,21 @@ +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(); ++ + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + + if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) diff --git a/nongnu/packages/patches/pinephone-0010-bootsplash.patch b/nongnu/packages/patches/pinephone-0010-bootsplash.patch new file mode 100644 index 0000000..c74b4da --- /dev/null +++ b/nongnu/packages/patches/pinephone-0010-bootsplash.patch @@ -0,0 +1,308 @@ +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 ++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 ++ ++ ++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/nongnu/packages/patches/pinephone-0011-bootsplash.patch b/nongnu/packages/patches/pinephone-0011-bootsplash.patch new file mode 100644 index 0000000..4e0c98f --- /dev/null +++ b/nongnu/packages/patches/pinephone-0011-bootsplash.patch @@ -0,0 +1,499 @@ +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 ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++ ++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 Background color (red part)\n" ++ " --bg_green Background color (green part)\n" ++ " --bg_blue Background color (blue part)\n" ++ " --bg_reserved (do not use)\n" ++ " --frame_ms Minimum milliseconds between animation steps\n" ++ "\n" ++ " --picture Start describing the next picture\n" ++ " --pic_width Picture width in pixels\n" ++ " --pic_height Picture height in pixels\n" ++ " --pic_position 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 Distance from base position in pixels\n" ++ " --pic_anim_type Animation type:\n" ++ " 0 - None\n" ++ " 1 - Forward loop\n" ++ " --pic_anim_loop Loop point for animation\n" ++ "\n" ++ " --blob Include next data stream\n" ++ " --blob_type Type of data\n" ++ " --blob_picture_id 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/nongnu/packages/patches/pinephone-drop-modem-power-node.patch b/nongnu/packages/patches/pinephone-drop-modem-power-node.patch new file mode 100644 index 0000000..b90eced --- /dev/null +++ b/nongnu/packages/patches/pinephone-drop-modem-power-node.patch @@ -0,0 +1,175 @@ +From 602d05e416ae0d0fba3022fa2c3d195164b406c6 Mon Sep 17 00:00:00 2001 +From: Clayton Craft +Date: Wed, 16 Dec 2020 20:16:14 -0800 +Subject: [PATCH] dts: pinephone: drop modem-power node + +--- + .../allwinner/sun50i-a64-pinephone-1.0.dts | 26 +++--------------- + .../allwinner/sun50i-a64-pinephone-1.1.dts | 27 +++---------------- + .../allwinner/sun50i-a64-pinephone-1.2.dts | 27 +++---------------- + .../dts/allwinner/sun50i-a64-pinephone.dtsi | 12 +++++++++ + 4 files changed, 24 insertions(+), 68 deletions(-) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts +index a21c6d78a..7f0cfdafe 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts +@@ -86,28 +86,6 @@ ®_drivevbus { + status = "okay"; + }; + +-&uart3 { +- modem { +- compatible = "quectel,eg25"; +- char-device-name = "modem-power"; +- +- power-supply = <®_vbat_bb>; /* PL7 */ +- +- enable-gpios = <&pio 7 8 GPIO_ACTIVE_LOW>; /* PH8 */ +- reset-gpios = <&pio 2 4 GPIO_ACTIVE_HIGH>; /* PC4 */ +- pwrkey-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ +- +- sleep-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */ +- wakeup-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2-RI */ +- +- cts-gpios = <&pio 3 5 GPIO_ACTIVE_HIGH>; /* PD5-CTS */ +- dtr-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6-DTR */ +- rts-gpios = <&pio 3 4 GPIO_ACTIVE_HIGH>; /* PD4-RTS */ +- +- quectel,qdai = "1,1,0,1,0,0,1,1"; +- }; +-}; +- + &usbphy { + usb-role-switch; + +@@ -118,6 +96,10 @@ usb0_drd_sw: endpoint { + }; + }; + ++&ring_indicator { ++ gpios = <&pio 1 2 GPIO_ACTIVE_LOW>; /* PB2 */ ++}; ++ + &sgm3140 { + enable-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */ + flash-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */ +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts +index 61ff56b17..5e85ddc12 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts +@@ -109,34 +109,15 @@ ®_drivevbus { + status = "okay"; + }; + ++&ring_indicator { ++ gpios = <&pio 1 2 GPIO_ACTIVE_LOW>; /* PB2 */ ++}; ++ + &sgm3140 { + enable-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */ + flash-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */ + }; + +-&uart3 { +- modem { +- compatible = "quectel,eg25"; +- char-device-name = "modem-power"; +- +- power-supply = <®_vbat_bb>; /* PL7 */ +- +- enable-gpios = <&pio 7 8 GPIO_ACTIVE_LOW>; /* PH8 */ +- reset-gpios = <&pio 2 4 GPIO_ACTIVE_HIGH>; /* PC4 */ +- pwrkey-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ +- //status-pwrkey-multiplexed; /* status acts as pwrkey */ +- +- sleep-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */ +- wakeup-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2-RI */ +- +- dtr-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6-DTR */ +- cts-gpios = <&pio 3 5 GPIO_ACTIVE_HIGH>; /* PD5-CTS */ +- rts-gpios = <&pio 3 4 GPIO_ACTIVE_HIGH>; /* PD4-RTS */ +- +- quectel,qdai = "1,1,0,1,0,0,1,1"; +- }; +-}; +- + &usbphy { + usb-role-switch; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts +index fe7d567a8..f4b9b0991 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts +@@ -101,34 +101,15 @@ ®_anx1v0 { + enable-active-high; + }; + ++&ring_indicator { ++ gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL6 */ ++}; ++ + &sgm3140 { + enable-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */ + flash-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */ + }; + +-&uart3 { +- modem { +- compatible = "quectel,eg25"; +- char-device-name = "modem-power"; +- +- power-supply = <®_vbat_bb>; /* PL7 */ +- +- enable-gpios = <&pio 7 8 GPIO_ACTIVE_LOW>; /* PH8 */ +- reset-gpios = <&pio 2 4 GPIO_ACTIVE_HIGH>; /* PC4 */ +- status-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */ +- pwrkey-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ +- +- host-ready-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */ +- wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6-RI */ +- +- dtr-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2-DTR */ +- cts-gpios = <&pio 3 5 GPIO_ACTIVE_HIGH>; /* PD5-CTS */ +- rts-gpios = <&pio 3 4 GPIO_ACTIVE_HIGH>; /* PD4-RTS */ +- +- quectel,qdai = "1,1,0,1,0,0,1,1"; +- }; +-}; +- + &usbphy { + usb-role-switch; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +index 346113382..7b48126d1 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +@@ -192,6 +192,17 @@ ec25_codec: ec25-codec { + sound-name-prefix = "Modem"; + }; + ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ ring_indicator: ring-indicator { ++ label = "Ring Indicator"; ++ linux,can-disable; ++ linux,code = ; ++ wakeup-source; ++ }; ++ }; ++ + i2c_csi: i2c-csi { + compatible = "i2c-gpio"; + sda-gpios = <&pio 4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; /* PE13 */ +@@ -264,6 +275,7 @@ reg_usb_5v: usb-5v { + reg_vbat_bb: vbat-bb { + compatible = "regulator-fixed"; + regulator-name = "vbat-bb"; ++ regulator-always-on; + regulator-min-microvolt = <3500000>; + regulator-max-microvolt = <3500000>; + gpio = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */ +-- +2.31.1 + diff --git a/nongnu/packages/patches/pinephone-fbcon-remove-no-op-fbcon_set_origin.patch b/nongnu/packages/patches/pinephone-fbcon-remove-no-op-fbcon_set_origin.patch new file mode 100644 index 0000000..6491c54 --- /dev/null +++ b/nongnu/packages/patches/pinephone-fbcon-remove-no-op-fbcon_set_origin.patch @@ -0,0 +1,31 @@ +--- b/drivers/video/fbdev/core/fbcon.c ++++ a/drivers/video/fbdev/core/fbcon.c +@@ -163,6 +163,8 @@ + + #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) + ++static int fbcon_set_origin(struct vc_data *); ++ + static int fbcon_cursor_noblink; + + #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) +@@ -2633,6 +2635,11 @@ + } + } + ++static int fbcon_set_origin(struct vc_data *vc) ++{ ++ return 0; ++} ++ + void fbcon_suspended(struct fb_info *info) + { + struct vc_data *vc = NULL; +@@ -3103,6 +3110,7 @@ + .con_font_default = fbcon_set_def_font, + .con_font_copy = fbcon_copy_font, + .con_set_palette = fbcon_set_palette, ++ .con_set_origin = fbcon_set_origin, + .con_invert_region = fbcon_invert_region, + .con_screen_pos = fbcon_screen_pos, + .con_getxy = fbcon_getxy, diff --git a/nongnu/packages/patches/pinephone-pro-add-modem-ri.patch.patch b/nongnu/packages/patches/pinephone-pro-add-modem-ri.patch.patch new file mode 100644 index 0000000..c02d27f --- /dev/null +++ b/nongnu/packages/patches/pinephone-pro-add-modem-ri.patch.patch @@ -0,0 +1,52 @@ +From fc38b73e2556211d698849b78a4623dc163b7d49 Mon Sep 17 00:00:00 2001 +From: Arnaud Ferraris +Date: Wed, 8 Dec 2021 23:43:08 +0100 +Subject: [PATCH 3/4] arm64: dts: rk3399-pinephone-pro: add modem RI pin + +Taht way the modem can wake the phone on incoming calls/messages. + +Signed-off-by: Arnaud Ferraris +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index c9365e604..b3b091ea7 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -160,6 +160,21 @@ power { + }; + }; + ++ gpio-key-ri { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ri_pin>; ++ ++ ring_indicator: ring-indicator { ++ label = "ring-indicator"; ++ linux,can-disable; ++ linux,code = ; ++ gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_LOW>; ++ wakeup-event-action = ; ++ wakeup-source; ++ }; ++ }; ++ + // in1 - digital mic daughhterboard + // in2 - headset mic + // in3 - modem output (muxed with mono) +@@ -1150,6 +1165,10 @@ flash_pins: flash-pins { + }; + + modem { ++ ri_pin: ri-pin { ++ rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ + vcc_4g_5v_en: vcc-4g-5v-en-pin { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; +-- +2.34.1 + diff --git a/nongnu/packages/patches/pinephone-pro-remove-modem-node.patch b/nongnu/packages/patches/pinephone-pro-remove-modem-node.patch new file mode 100644 index 0000000..24be3b4 --- /dev/null +++ b/nongnu/packages/patches/pinephone-pro-remove-modem-node.patch @@ -0,0 +1,86 @@ +From 60d8aedea7c8c390ee744730ab3e565ea84496fb Mon Sep 17 00:00:00 2001 +From: Danct12 +Date: Fri, 10 Dec 2021 23:01:34 +0700 +Subject: [PATCH] arm64: dts: rk3399-pinephone-pro: Remove modem node + +Since we don't use modem-power driver, this can be removed +for eg25-manager. +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 40 +------------------ + 1 file changed, 2 insertions(+), 38 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 61c990764..13141c643 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -326,6 +326,7 @@ vcc_4g_5v: vcc-4g-5v { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; ++ regulator-always-on; + }; + + vcc_4g: vcc-4g { +@@ -338,6 +339,7 @@ vcc_4g: vcc-4g { + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + vin-supply = <&vcc_sysin>; ++ regulator-always-on; + }; + + vcc1v8_codec: vcc1v8-codec-regulator { +@@ -1058,31 +1060,6 @@ mipi_in_panel: endpoint { + + &uart3 { + status = "okay"; +- +- modem { +- compatible = "quectel,eg25"; +- char-device-name = "modem-power"; +- +- pinctrl-names = "default"; +- pinctrl-0 = <&modem_control_pins>; +- +- power-supply = <&vcc_4g>; +- vbus-supply = <&vcc_4g_5v>; +- +- enable-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; // W_DISABLE# +- reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; +- status-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>; +- pwrkey-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; +- +- host-ready-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; // apready +- wakeup-gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; // ri +- +- dtr-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; +- cts-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; +- rts-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>; +- +- quectel,qdai = "3,0,0,4,0,0,1,1"; +- }; + }; + + &pmu_io_domains { +@@ -1153,19 +1130,6 @@ vcc_4g_5v_en: vcc-4g-5v-en-pin { + vcc_4g_en: vcc-4g-en-pin { + rockchip,pins = <4 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; +- +- modem_control_pins: modem-control-pins { +- rockchip,pins = +- <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, +- <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, +- <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>, +- <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>, +- <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>, +- <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>, +- <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>, +- <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>, +- <3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; +- }; + }; + + pmic { +-- +2.34.1 + diff --git a/nongnu/packages/patches/pinephone-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch b/nongnu/packages/patches/pinephone-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch new file mode 100644 index 0000000..e7d4da5 --- /dev/null +++ b/nongnu/packages/patches/pinephone-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch @@ -0,0 +1,150 @@ +--- b/drivers/video/fbdev/core/bitblit.c ++++ a/drivers/video/fbdev/core/bitblit.c +@@ -234,7 +234,7 @@ + } + + static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, ++ int softback_lines, int fg, int bg) +- int fg, int bg) + { + struct fb_cursor cursor; + struct fbcon_ops *ops = info->fbcon_par; +@@ -247,6 +247,15 @@ + + cursor.set = 0; + ++ if (softback_lines) { ++ if (y + softback_lines >= vc->vc_rows) { ++ mode = CM_ERASE; ++ ops->cursor_flash = 0; ++ return; ++ } else ++ y += softback_lines; ++ } ++ + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); +--- b/drivers/video/fbdev/core/fbcon.c ++++ a/drivers/video/fbdev/core/fbcon.c +@@ -394,7 +394,7 @@ + c = scr_readw((u16 *) vc->vc_pos); + mode = (!ops->cursor_flash || ops->cursor_state.enable) ? + CM_ERASE : CM_DRAW; ++ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), +- ops->cursor(vc, info, mode, get_color(vc, info, c, 1), + get_color(vc, info, c, 0)); + console_unlock(); + } +@@ -1345,7 +1345,7 @@ + + ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; + ++ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), +- ops->cursor(vc, info, mode, get_color(vc, info, c, 1), + get_color(vc, info, c, 0)); + } + +--- b/drivers/video/fbdev/core/fbcon.h ++++ a/drivers/video/fbdev/core/fbcon.h +@@ -62,7 +62,7 @@ + void (*clear_margins)(struct vc_data *vc, struct fb_info *info, + int color, int bottom_only); + void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode, ++ int softback_lines, int fg, int bg); +- int fg, int bg); + int (*update_start)(struct fb_info *info); + int (*rotate_font)(struct fb_info *info, struct vc_data *vc); + struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ +--- b/drivers/video/fbdev/core/fbcon_ccw.c ++++ a/drivers/video/fbdev/core/fbcon_ccw.c +@@ -219,7 +219,7 @@ + } + + static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, ++ int softback_lines, int fg, int bg) +- int fg, int bg) + { + struct fb_cursor cursor; + struct fbcon_ops *ops = info->fbcon_par; +@@ -236,6 +236,15 @@ + + cursor.set = 0; + ++ if (softback_lines) { ++ if (y + softback_lines >= vc->vc_rows) { ++ mode = CM_ERASE; ++ ops->cursor_flash = 0; ++ return; ++ } else ++ y += softback_lines; ++ } ++ + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); +--- b/drivers/video/fbdev/core/fbcon_cw.c ++++ a/drivers/video/fbdev/core/fbcon_cw.c +@@ -202,7 +202,7 @@ + } + + static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, ++ int softback_lines, int fg, int bg) +- int fg, int bg) + { + struct fb_cursor cursor; + struct fbcon_ops *ops = info->fbcon_par; +@@ -219,6 +219,15 @@ + + cursor.set = 0; + ++ if (softback_lines) { ++ if (y + softback_lines >= vc->vc_rows) { ++ mode = CM_ERASE; ++ ops->cursor_flash = 0; ++ return; ++ } else ++ y += softback_lines; ++ } ++ + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); +--- b/drivers/video/fbdev/core/fbcon_ud.c ++++ a/drivers/video/fbdev/core/fbcon_ud.c +@@ -249,7 +249,7 @@ + } + + static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, ++ int softback_lines, int fg, int bg) +- int fg, int bg) + { + struct fb_cursor cursor; + struct fbcon_ops *ops = info->fbcon_par; +@@ -267,6 +267,15 @@ + + cursor.set = 0; + ++ if (softback_lines) { ++ if (y + softback_lines >= vc->vc_rows) { ++ mode = CM_ERASE; ++ ops->cursor_flash = 0; ++ return; ++ } else ++ y += softback_lines; ++ } ++ + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); +--- b/drivers/video/fbdev/core/tileblit.c ++++ a/drivers/video/fbdev/core/tileblit.c +@@ -80,7 +80,7 @@ + } + + static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, ++ int softback_lines, int fg, int bg) +- int fg, int bg) + { + struct fb_tilecursor cursor; + int use_sw = (vc->vc_cursor_type & 0x10); diff --git a/nongnu/packages/patches/pinephone-revert-fbcon-remove-soft-scrollback-code.patch b/nongnu/packages/patches/pinephone-revert-fbcon-remove-soft-scrollback-code.patch new file mode 100644 index 0000000..491fbe0 --- /dev/null +++ b/nongnu/packages/patches/pinephone-revert-fbcon-remove-soft-scrollback-code.patch @@ -0,0 +1,500 @@ +--- b/drivers/video/fbdev/core/fbcon.c ++++ a/drivers/video/fbdev/core/fbcon.c +@@ -124,6 +124,12 @@ static int logo_lines; + /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO + enums. */ + static int logo_shown = FBCON_LOGO_CANSHOW; ++/* Software scrollback */ ++static int fbcon_softback_size = 32768; ++static unsigned long softback_buf, softback_curr; ++static unsigned long softback_in; ++static unsigned long softback_top, softback_end; ++static int softback_lines; + /* console mappings */ + static unsigned int first_fb_vc; + static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1; +@@ -163,6 +169,8 @@ static int margin_color; + + static const struct consw fb_con; + ++#define CM_SOFTBACK (8) ++ + #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) + + static int fbcon_set_origin(struct vc_data *); +@@ -347,6 +355,18 @@ static int get_color(struct vc_data *vc, + return color; + } + ++static void fbcon_update_softback(struct vc_data *vc) ++{ ++ int l = fbcon_softback_size / vc->vc_size_row; ++ ++ if (l > 5) ++ softback_end = softback_buf + l * vc->vc_size_row; ++ else ++ /* Smaller scrollback makes no sense, and 0 would screw ++ the operation totally */ ++ softback_top = 0; ++} ++ + static void fb_flashcursor(struct work_struct *work) + { + struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work); +@@ -379,7 +399,7 @@ static void fb_flashcursor(struct work_s + c = scr_readw((u16 *) vc->vc_pos); + mode = (!ops->cursor_flash || ops->cursor_state.enable) ? + CM_ERASE : CM_DRAW; +- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), ++ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1), + get_color(vc, info, c, 0)); + console_unlock(); + +@@ -419,7 +439,13 @@ static int __init fb_console_setup(char + } + + if (!strncmp(options, "scrollback:", 11)) { +- pr_warn("Ignoring scrollback size option\n"); ++ options += 11; ++ if (*options) { ++ fbcon_softback_size = simple_strtoul(options, &options, 0); ++ if (*options == 'k' || *options == 'K') { ++ fbcon_softback_size *= 1024; ++ } ++ } + continue; + } + +@@ -959,6 +985,31 @@ static const char *fbcon_startup(void) + + set_blitting_type(vc, info); + ++ if (info->fix.type != FB_TYPE_TEXT) { ++ if (fbcon_softback_size) { ++ if (!softback_buf) { ++ softback_buf = ++ (unsigned long) ++ kvmalloc(fbcon_softback_size, ++ GFP_KERNEL); ++ if (!softback_buf) { ++ fbcon_softback_size = 0; ++ softback_top = 0; ++ } ++ } ++ } else { ++ if (softback_buf) { ++ kvfree((void *) softback_buf); ++ softback_buf = 0; ++ softback_top = 0; ++ } ++ } ++ if (softback_buf) ++ softback_in = softback_top = softback_curr = ++ softback_buf; ++ softback_lines = 0; ++ } ++ + /* Setup default font */ + if (!p->fontdata && !vc->vc_font.data) { + if (!fontname[0] || !(font = find_font(fontname))) +@@ -1129,6 +1180,9 @@ static void fbcon_init(struct vc_data *v + if (logo) + fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); + ++ if (vc == svc && softback_buf) ++ fbcon_update_softback(vc); ++ + if (ops->rotate_font && ops->rotate_font(info, vc)) { + ops->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info); +@@ -1152,6 +1206,9 @@ static void fbcon_release_all(void) + struct fb_info *info; + int i, j, mapped; + ++ kvfree((void *)softback_buf); ++ softback_buf = 0UL; ++ + fbcon_for_each_registered_fb(i) { + mapped = 0; + info = fbcon_registered_fb[i]; +@@ -1312,6 +1369,7 @@ static void fbcon_cursor(struct vc_data + { + struct fb_info *info = fbcon_info_from_console(vc->vc_num); + struct fbcon_ops *ops = info->fbcon_par; ++ int y; + int c = scr_readw((u16 *) vc->vc_pos); + + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); +@@ -1325,11 +1383,19 @@ static void fbcon_cursor(struct vc_data + fbcon_add_cursor_work(info); + + ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; ++ if (mode & CM_SOFTBACK) { ++ mode &= ~CM_SOFTBACK; ++ y = softback_lines; ++ } else { ++ if (softback_lines) ++ fbcon_set_origin(vc); ++ y = 0; ++ } + + if (!ops->cursor) + return; + +- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), ++ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1), + get_color(vc, info, c, 0)); + } + +@@ -1399,6 +1465,8 @@ static void fbcon_set_disp(struct fb_inf + + if (con_is_visible(vc)) { + update_screen(vc); ++ if (softback_buf) ++ fbcon_update_softback(vc); + } + } + +@@ -1536,6 +1604,99 @@ static __inline__ void ypan_down_redraw( + scrollback_current = 0; + } + ++static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p, ++ long delta) ++{ ++ int count = vc->vc_rows; ++ unsigned short *d, *s; ++ unsigned long n; ++ int line = 0; ++ ++ d = (u16 *) softback_curr; ++ if (d == (u16 *) softback_in) ++ d = (u16 *) vc->vc_origin; ++ n = softback_curr + delta * vc->vc_size_row; ++ softback_lines -= delta; ++ if (delta < 0) { ++ if (softback_curr < softback_top && n < softback_buf) { ++ n += softback_end - softback_buf; ++ if (n < softback_top) { ++ softback_lines -= ++ (softback_top - n) / vc->vc_size_row; ++ n = softback_top; ++ } ++ } else if (softback_curr >= softback_top ++ && n < softback_top) { ++ softback_lines -= ++ (softback_top - n) / vc->vc_size_row; ++ n = softback_top; ++ } ++ } else { ++ if (softback_curr > softback_in && n >= softback_end) { ++ n += softback_buf - softback_end; ++ if (n > softback_in) { ++ n = softback_in; ++ softback_lines = 0; ++ } ++ } else if (softback_curr <= softback_in && n > softback_in) { ++ n = softback_in; ++ softback_lines = 0; ++ } ++ } ++ if (n == softback_curr) ++ return; ++ softback_curr = n; ++ s = (u16 *) softback_curr; ++ if (s == (u16 *) softback_in) ++ s = (u16 *) vc->vc_origin; ++ while (count--) { ++ unsigned short *start; ++ unsigned short *le; ++ unsigned short c; ++ int x = 0; ++ unsigned short attr = 1; ++ ++ start = s; ++ le = advance_row(s, 1); ++ do { ++ c = scr_readw(s); ++ if (attr != (c & 0xff00)) { ++ attr = c & 0xff00; ++ if (s > start) { ++ fbcon_putcs(vc, start, s - start, ++ line, x); ++ x += s - start; ++ start = s; ++ } ++ } ++ if (c == scr_readw(d)) { ++ if (s > start) { ++ fbcon_putcs(vc, start, s - start, ++ line, x); ++ x += s - start + 1; ++ start = s + 1; ++ } else { ++ x++; ++ start++; ++ } ++ } ++ s++; ++ d++; ++ } while (s < le); ++ if (s > start) ++ fbcon_putcs(vc, start, s - start, line, x); ++ line++; ++ if (d == (u16 *) softback_end) ++ d = (u16 *) softback_buf; ++ if (d == (u16 *) softback_in) ++ d = (u16 *) vc->vc_origin; ++ if (s == (u16 *) softback_end) ++ s = (u16 *) softback_buf; ++ if (s == (u16 *) softback_in) ++ s = (u16 *) vc->vc_origin; ++ } ++} ++ + static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, + int line, int count, int dy) + { +@@ -1740,6 +1901,31 @@ static void fbcon_bmove(struct vc_data * + p->vrows - p->yscroll); + } + ++static inline void fbcon_softback_note(struct vc_data *vc, int t, ++ int count) ++{ ++ unsigned short *p; ++ ++ if (vc->vc_num != fg_console) ++ return; ++ p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row); ++ ++ while (count) { ++ scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row); ++ count--; ++ p = advance_row(p, 1); ++ softback_in += vc->vc_size_row; ++ if (softback_in == softback_end) ++ softback_in = softback_buf; ++ if (softback_in == softback_top) { ++ softback_top += vc->vc_size_row; ++ if (softback_top == softback_end) ++ softback_top = softback_buf; ++ } ++ } ++ softback_curr = softback_in; ++} ++ + static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, + enum con_scroll dir, unsigned int count) + { +@@ -1762,6 +1948,8 @@ static bool fbcon_scroll(struct vc_data + case SM_UP: + if (count > vc->vc_rows) /* Maximum realistic size */ + count = vc->vc_rows; ++ if (softback_top) ++ fbcon_softback_note(vc, t, count); + switch (fb_scrollmode(p)) { + case SCROLL_MOVE: + fbcon_redraw_blit(vc, info, p, t, b - t - count, +@@ -2076,6 +2264,14 @@ static int fbcon_switch(struct vc_data * + info = fbcon_info_from_console(vc->vc_num); + ops = info->fbcon_par; + ++ if (softback_top) { ++ if (softback_lines) ++ fbcon_set_origin(vc); ++ softback_top = softback_curr = softback_in = softback_buf; ++ softback_lines = 0; ++ fbcon_update_softback(vc); ++ } ++ + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; + +@@ -2406,6 +2602,9 @@ static int fbcon_do_set_font(struct vc_d + int resize; + char *old_data = NULL; + ++ if (con_is_visible(vc) && softback_lines) ++ fbcon_set_origin(vc); ++ + resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); + if (p->userfont) + old_data = vc->vc_font.data; +@@ -2428,6 +2627,8 @@ static int fbcon_do_set_font(struct vc_d + cols /= w; + rows /= h; + vc_resize(vc, cols, rows); ++ if (con_is_visible(vc) && softback_buf) ++ fbcon_update_softback(vc); + } else if (con_is_visible(vc) + && vc->vc_mode == KD_TEXT) { + fbcon_clear_margins(vc, 0); +@@ -2582,7 +2783,19 @@ static void fbcon_set_palette(struct vc_ + + static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset) + { +- return (u16 *) (vc->vc_origin + offset); ++ unsigned long p; ++ int line; ++ ++ if (vc->vc_num != fg_console || !softback_lines) ++ return (u16 *) (vc->vc_origin + offset); ++ line = offset / vc->vc_size_row; ++ if (line >= softback_lines) ++ return (u16 *) (vc->vc_origin + offset - ++ softback_lines * vc->vc_size_row); ++ p = softback_curr + offset; ++ if (p >= softback_end) ++ p += softback_buf - softback_end; ++ return (u16 *) p; + } + + static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, +@@ -2596,7 +2809,22 @@ static unsigned long fbcon_getxy(struct + + x = offset % vc->vc_cols; + y = offset / vc->vc_cols; ++ if (vc->vc_num == fg_console) ++ y += softback_lines; ++ ret = pos + (vc->vc_cols - x) * 2; ++ } else if (vc->vc_num == fg_console && softback_lines) { ++ unsigned long offset = pos - softback_curr; ++ ++ if (pos < softback_curr) ++ offset += softback_end - softback_buf; ++ offset /= 2; ++ x = offset % vc->vc_cols; ++ y = offset / vc->vc_cols; + ret = pos + (vc->vc_cols - x) * 2; ++ if (ret == softback_end) ++ ret = softback_buf; ++ if (ret == softback_in) ++ ret = vc->vc_origin; + } else { + /* Should not happen */ + x = y = 0; +@@ -2624,11 +2852,106 @@ static void fbcon_invert_region(struct v + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | + (((a) & 0x0700) << 4); + scr_writew(a, p++); ++ if (p == (u16 *) softback_end) ++ p = (u16 *) softback_buf; ++ if (p == (u16 *) softback_in) ++ p = (u16 *) vc->vc_origin; ++ } ++} ++ ++static void fbcon_scrolldelta(struct vc_data *vc, int lines) ++{ ++ struct fb_info *info = registered_fb[con2fb_map[fg_console]]; ++ struct fbcon_ops *ops = info->fbcon_par; ++ struct fbcon_display *disp = &fb_display[fg_console]; ++ int offset, limit, scrollback_old; ++ ++ if (softback_top) { ++ if (vc->vc_num != fg_console) ++ return; ++ if (vc->vc_mode != KD_TEXT || !lines) ++ return; ++ if (logo_shown >= 0) { ++ struct vc_data *conp2 = vc_cons[logo_shown].d; ++ ++ if (conp2->vc_top == logo_lines ++ && conp2->vc_bottom == conp2->vc_rows) ++ conp2->vc_top = 0; ++ if (logo_shown == vc->vc_num) { ++ unsigned long p, q; ++ int i; ++ ++ p = softback_in; ++ q = vc->vc_origin + ++ logo_lines * vc->vc_size_row; ++ for (i = 0; i < logo_lines; i++) { ++ if (p == softback_top) ++ break; ++ if (p == softback_buf) ++ p = softback_end; ++ p -= vc->vc_size_row; ++ q -= vc->vc_size_row; ++ scr_memcpyw((u16 *) q, (u16 *) p, ++ vc->vc_size_row); ++ } ++ softback_in = softback_curr = p; ++ update_region(vc, vc->vc_origin, ++ logo_lines * vc->vc_cols); ++ } ++ logo_shown = FBCON_LOGO_CANSHOW; ++ } ++ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); ++ fbcon_redraw_softback(vc, disp, lines); ++ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); ++ return; + } ++ ++ if (!scrollback_phys_max) ++ return; ++ ++ scrollback_old = scrollback_current; ++ scrollback_current -= lines; ++ if (scrollback_current < 0) ++ scrollback_current = 0; ++ else if (scrollback_current > scrollback_max) ++ scrollback_current = scrollback_max; ++ if (scrollback_current == scrollback_old) ++ return; ++ ++ if (fbcon_is_inactive(vc, info)) ++ return; ++ ++ fbcon_cursor(vc, CM_ERASE); ++ ++ offset = disp->yscroll - scrollback_current; ++ limit = disp->vrows; ++ switch (disp->scrollmode) { ++ case SCROLL_WRAP_MOVE: ++ info->var.vmode |= FB_VMODE_YWRAP; ++ break; ++ case SCROLL_PAN_MOVE: ++ case SCROLL_PAN_REDRAW: ++ limit -= vc->vc_rows; ++ info->var.vmode &= ~FB_VMODE_YWRAP; ++ break; ++ } ++ if (offset < 0) ++ offset += limit; ++ else if (offset >= limit) ++ offset -= limit; ++ ++ ops->var.xoffset = 0; ++ ops->var.yoffset = offset * vc->vc_font.height; ++ ops->update_start(info); ++ ++ if (!scrollback_current) ++ fbcon_cursor(vc, CM_DRAW); + } + + static int fbcon_set_origin(struct vc_data *vc) + { ++ if (softback_lines) ++ fbcon_scrolldelta(vc, softback_lines); + return 0; + } + +@@ -2692,6 +3015,8 @@ static void fbcon_modechanged(struct fb_ + + fbcon_set_palette(vc, color_table); + update_screen(vc); ++ if (softback_buf) ++ fbcon_update_softback(vc); + } + } + +@@ -3154,6 +3479,7 @@ static const struct consw fb_con = { + .con_font_get = fbcon_get_font, + .con_font_default = fbcon_set_def_font, + .con_set_palette = fbcon_set_palette, ++ .con_scrolldelta = fbcon_scrolldelta, + .con_set_origin = fbcon_set_origin, + .con_invert_region = fbcon_invert_region, + .con_screen_pos = fbcon_screen_pos,