On Sat, Aug 06, 2022 at 07:32:24PM +0300, Markuss Broks wrote:
> Add early console support for generic linear framebuffer devices.
> This driver supports probing from cmdline early parameters
> or from the device-tree using information in simple-framebuffer node.
> The EFI functionality should be retained in whole.
> The driver was disabled on ARM because of a bug in early_ioremap
> implementation on ARM and on IA64 because of lack of early_memremap_prot.
> 
> Signed-off-by: Markuss Broks <markuss.br...@gmail.com>
> ---
>  .../admin-guide/kernel-parameters.txt         |  12 +-
>  MAINTAINERS                                   |   5 +
>  drivers/firmware/efi/Kconfig                  |   7 +-
>  drivers/firmware/efi/Makefile                 |   1 -
>  drivers/firmware/efi/earlycon.c               | 246 --------------
>  drivers/video/console/Kconfig                 |  11 +
>  drivers/video/console/Makefile                |   1 +
>  drivers/video/console/earlycon.c              | 305 ++++++++++++++++++

Ok I have a more fundamental issue with this than the lack of proper patch
splitting I mentioned in the other thread.

This is the wrong place.

drivers/video/console is about the various vt console implementations,
which supply a struct consw to con_register_driver.

This otoh is an (early) kernel/printk console implemented using struct
console. Totally different thing, and really shouldn't end up in
drivers/video/console imo. Somewhere in drivers/firmware might still be
the best place, the sysfb stuff is also there. Maybe
drivers/firmware/sysfb_earlycon.c?

Also patch split is still an issue here, like I and Greg already said.
-Daniel

>  8 files changed, 332 insertions(+), 256 deletions(-)
>  delete mode 100644 drivers/firmware/efi/earlycon.c
>  create mode 100644 drivers/video/console/earlycon.c
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt 
> b/Documentation/admin-guide/kernel-parameters.txt
> index 
> 8090130b544b0701237a7b657a29c83c000a60f4..bccb1ac8978eb5cf7e2bb20834b1881b27040666
>  100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -1281,12 +1281,9 @@
>                       specified address. The serial port must already be
>                       setup and configured. Options are not yet supported.
>  
> -             efifb,[options]
> +             efifb
>                       Start an early, unaccelerated console on the EFI
> -                     memory mapped framebuffer (if available). On cache
> -                     coherent non-x86 systems that use system memory for
> -                     the framebuffer, pass the 'ram' option so that it is
> -                     mapped with the correct attributes.
> +                     memory mapped framebuffer (if available).
>  
>               linflex,<addr>
>                       Use early console provided by Freescale LINFlexD UART
> @@ -1294,6 +1291,11 @@
>                       address must be provided, and the serial port must
>                       already be setup and configured.
>  
> +             simplefb,<addr>,<width>x<height>x<bpp>
> +                     Use early console with simple framebuffer that is
> +                     pre-initialized by firmware. A valid base address,
> +                     width, height and pixel size must be provided.
> +
>       earlyprintk=    [X86,SH,ARM,M68k,S390]
>                       earlyprintk=vga
>                       earlyprintk=sclp
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 
> 1fc9ead83d2aa3e60ccc4cfa8ee16df09ef579bf..af8b8e289483b6a264d477145061bd0e0ba34a25
>  100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7033,6 +7033,11 @@ Q:     
> http://patchwork.linuxtv.org/project/linux-media/list/
>  T:   git git://linuxtv.org/anttip/media_tree.git
>  F:   drivers/media/tuners/e4000*
>  
> +EARLY CONSOLE FRAMEBUFFER DRIVER
> +M:   Markuss Broks <markuss.br...@gmail.com>
> +S:   Maintained
> +F:   drivers/video/console/earlycon.c
> +
>  EARTH_PT1 MEDIA DRIVER
>  M:   Akihiro Tsukada <tsk...@gmail.com>
>  L:   linux-me...@vger.kernel.org
> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> index 
> 7aa4717cdcac46f91dd202f868c463388eb02735..ea76ccfb9bcd8ba44ddca06052eaa442ed6c30f7
>  100644
> --- a/drivers/firmware/efi/Kconfig
> +++ b/drivers/firmware/efi/Kconfig
> @@ -259,10 +259,9 @@ config EFI_DISABLE_PCI_DMA
>         may be used to override this option.
>  
>  config EFI_EARLYCON
> -     def_bool y
> -     depends on SERIAL_EARLYCON && !ARM && !IA64
> -     select FONT_SUPPORT
> -     select ARCH_USE_MEMREMAP_PROT
> +     bool "EFI early console support"
> +     select FB_EARLYCON
> +     default y
>  
>  config EFI_CUSTOM_SSDT_OVERLAYS
>       bool "Load custom ACPI SSDT overlay from an EFI variable"
> diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
> index 
> c02ff25dd47707090a2ab86ee4f330e467f878f5..64eea61fbb43d76ec2d5416d467dfbb9aa21bda0
>  100644
> --- a/drivers/firmware/efi/Makefile
> +++ b/drivers/firmware/efi/Makefile
> @@ -44,6 +44,5 @@ obj-$(CONFIG_ARM64)                 += $(arm-obj-y)
>  riscv-obj-$(CONFIG_EFI)                      := efi-init.o riscv-runtime.o
>  obj-$(CONFIG_RISCV)                  += $(riscv-obj-y)
>  obj-$(CONFIG_EFI_CAPSULE_LOADER)     += capsule-loader.o
> -obj-$(CONFIG_EFI_EARLYCON)           += earlycon.o
>  obj-$(CONFIG_UEFI_CPER_ARM)          += cper-arm.o
>  obj-$(CONFIG_UEFI_CPER_X86)          += cper-x86.o
> diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
> deleted file mode 100644
> index 
> a52236e11e5f73ddea5bb1f42ca2ca7c42425dab..0000000000000000000000000000000000000000
> --- a/drivers/firmware/efi/earlycon.c
> +++ /dev/null
> @@ -1,246 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -/*
> - * Copyright (C) 2013 Intel Corporation; author Matt Fleming
> - */
> -
> -#include <linux/console.h>
> -#include <linux/efi.h>
> -#include <linux/font.h>
> -#include <linux/io.h>
> -#include <linux/kernel.h>
> -#include <linux/serial_core.h>
> -#include <linux/screen_info.h>
> -
> -#include <asm/early_ioremap.h>
> -
> -static const struct console *earlycon_console __initdata;
> -static const struct font_desc *font;
> -static u32 efi_x, efi_y;
> -static u64 fb_base;
> -static bool fb_wb;
> -static void *efi_fb;
> -
> -/*
> - * EFI earlycon needs to use early_memremap() to map the framebuffer.
> - * But early_memremap() is not usable for 'earlycon=efifb keep_bootcon',
> - * memremap() should be used instead. memremap() will be available after
> - * paging_init() which is earlier than initcall callbacks. Thus adding this
> - * early initcall function early_efi_map_fb() to map the whole EFI 
> framebuffer.
> - */
> -static int __init efi_earlycon_remap_fb(void)
> -{
> -     /* bail if there is no bootconsole or it has been disabled already */
> -     if (!earlycon_console || !(earlycon_console->flags & CON_ENABLED))
> -             return 0;
> -
> -     efi_fb = memremap(fb_base, screen_info.lfb_size,
> -                       fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
> -
> -     return efi_fb ? 0 : -ENOMEM;
> -}
> -early_initcall(efi_earlycon_remap_fb);
> -
> -static int __init efi_earlycon_unmap_fb(void)
> -{
> -     /* unmap the bootconsole fb unless keep_bootcon has left it enabled */
> -     if (efi_fb && !(earlycon_console->flags & CON_ENABLED))
> -             memunmap(efi_fb);
> -     return 0;
> -}
> -late_initcall(efi_earlycon_unmap_fb);
> -
> -static __ref void *efi_earlycon_map(unsigned long start, unsigned long len)
> -{
> -     pgprot_t fb_prot;
> -
> -     if (efi_fb)
> -             return efi_fb + start;
> -
> -     fb_prot = fb_wb ? PAGE_KERNEL : pgprot_writecombine(PAGE_KERNEL);
> -     return early_memremap_prot(fb_base + start, len, pgprot_val(fb_prot));
> -}
> -
> -static __ref void efi_earlycon_unmap(void *addr, unsigned long len)
> -{
> -     if (efi_fb)
> -             return;
> -
> -     early_memunmap(addr, len);
> -}
> -
> -static void efi_earlycon_clear_scanline(unsigned int y)
> -{
> -     unsigned long *dst;
> -     u16 len;
> -
> -     len = screen_info.lfb_linelength;
> -     dst = efi_earlycon_map(y*len, len);
> -     if (!dst)
> -             return;
> -
> -     memset(dst, 0, len);
> -     efi_earlycon_unmap(dst, len);
> -}
> -
> -static void efi_earlycon_scroll_up(void)
> -{
> -     unsigned long *dst, *src;
> -     u16 len;
> -     u32 i, height;
> -
> -     len = screen_info.lfb_linelength;
> -     height = screen_info.lfb_height;
> -
> -     for (i = 0; i < height - font->height; i++) {
> -             dst = efi_earlycon_map(i*len, len);
> -             if (!dst)
> -                     return;
> -
> -             src = efi_earlycon_map((i + font->height) * len, len);
> -             if (!src) {
> -                     efi_earlycon_unmap(dst, len);
> -                     return;
> -             }
> -
> -             memmove(dst, src, len);
> -
> -             efi_earlycon_unmap(src, len);
> -             efi_earlycon_unmap(dst, len);
> -     }
> -}
> -
> -static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int 
> h)
> -{
> -     const u32 color_black = 0x00000000;
> -     const u32 color_white = 0x00ffffff;
> -     const u8 *src;
> -     int m, n, bytes;
> -     u8 x;
> -
> -     bytes = BITS_TO_BYTES(font->width);
> -     src = font->data + c * font->height * bytes + h * bytes;
> -
> -     for (m = 0; m < font->width; m++) {
> -             n = m % 8;
> -             x = *(src + m / 8);
> -             if ((x >> (7 - n)) & 1)
> -                     *dst = color_white;
> -             else
> -                     *dst = color_black;
> -             dst++;
> -     }
> -}
> -
> -static void
> -efi_earlycon_write(struct console *con, const char *str, unsigned int num)
> -{
> -     struct screen_info *si;
> -     unsigned int len;
> -     const char *s;
> -     void *dst;
> -
> -     si = &screen_info;
> -     len = si->lfb_linelength;
> -
> -     while (num) {
> -             unsigned int linemax;
> -             unsigned int h, count = 0;
> -
> -             for (s = str; *s && *s != '\n'; s++) {
> -                     if (count == num)
> -                             break;
> -                     count++;
> -             }
> -
> -             linemax = (si->lfb_width - efi_x) / font->width;
> -             if (count > linemax)
> -                     count = linemax;
> -
> -             for (h = 0; h < font->height; h++) {
> -                     unsigned int n, x;
> -
> -                     dst = efi_earlycon_map((efi_y + h) * len, len);
> -                     if (!dst)
> -                             return;
> -
> -                     s = str;
> -                     n = count;
> -                     x = efi_x;
> -
> -                     while (n-- > 0) {
> -                             efi_earlycon_write_char(dst + x*4, *s, h);
> -                             x += font->width;
> -                             s++;
> -                     }
> -
> -                     efi_earlycon_unmap(dst, len);
> -             }
> -
> -             num -= count;
> -             efi_x += count * font->width;
> -             str += count;
> -
> -             if (num > 0 && *s == '\n') {
> -                     efi_x = 0;
> -                     efi_y += font->height;
> -                     str++;
> -                     num--;
> -             }
> -
> -             if (efi_x + font->width > si->lfb_width) {
> -                     efi_x = 0;
> -                     efi_y += font->height;
> -             }
> -
> -             if (efi_y + font->height > si->lfb_height) {
> -                     u32 i;
> -
> -                     efi_y -= font->height;
> -                     efi_earlycon_scroll_up();
> -
> -                     for (i = 0; i < font->height; i++)
> -                             efi_earlycon_clear_scanline(efi_y + i);
> -             }
> -     }
> -}
> -
> -static int __init efi_earlycon_setup(struct earlycon_device *device,
> -                                  const char *opt)
> -{
> -     struct screen_info *si;
> -     u16 xres, yres;
> -     u32 i;
> -
> -     if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
> -             return -ENODEV;
> -
> -     fb_base = screen_info.lfb_base;
> -     if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
> -             fb_base |= (u64)screen_info.ext_lfb_base << 32;
> -
> -     fb_wb = opt && !strcmp(opt, "ram");
> -
> -     si = &screen_info;
> -     xres = si->lfb_width;
> -     yres = si->lfb_height;
> -
> -     /*
> -      * efi_earlycon_write_char() implicitly assumes a framebuffer with
> -      * 32 bits per pixel.
> -      */
> -     if (si->lfb_depth != 32)
> -             return -ENODEV;
> -
> -     font = get_default_font(xres, yres, -1, -1);
> -     if (!font)
> -             return -ENODEV;
> -
> -     efi_y = rounddown(yres, font->height) - font->height;
> -     for (i = 0; i < (yres - efi_y) / font->height; i++)
> -             efi_earlycon_scroll_up();
> -
> -     device->con->write = efi_earlycon_write;
> -     earlycon_console = device->con;
> -     return 0;
> -}
> -EARLYCON_DECLARE(efifb, efi_earlycon_setup);
> diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
> index 
> 40c50fa2dd70c33a1549141b15e6cba721352d2d..8052507e058fce37f5a51058e58ae2eb10d9669a
>  100644
> --- a/drivers/video/console/Kconfig
> +++ b/drivers/video/console/Kconfig
> @@ -69,6 +69,17 @@ config DUMMY_CONSOLE_ROWS
>         monitor.
>         Select 25 if you use a 640x480 resolution by default.
>  
> +config FB_EARLYCON
> +     bool "Generic framebuffer early console"
> +     depends on SERIAL_EARLYCON && !ARM && !IA64
> +     select FONT_SUPPORT
> +     select ARCH_USE_MEMREMAP_PROT
> +     help
> +       Say Y here if you want early console support for firmware established
> +       linear framebuffer. Unless you are using EFI framebuffer, you need to
> +       specify framebuffer geometry and address in device-tree or in kernel
> +       command line.
> +
>  config FRAMEBUFFER_CONSOLE
>       bool "Framebuffer Console support"
>       depends on FB && !UML
> diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
> index 
> db07b784bd2ccdcbffde933926ed5cee2bbbc7d4..7818faee587fc9c40b429617cfa224c0ccbc557c
>  100644
> --- a/drivers/video/console/Makefile
> +++ b/drivers/video/console/Makefile
> @@ -9,4 +9,5 @@ obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o
>  obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
>  obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
>  
> +obj-$(CONFIG_FB_EARLYCON)         += earlycon.o
>  obj-$(CONFIG_FB_STI)              += sticore.o
> diff --git a/drivers/video/console/earlycon.c 
> b/drivers/video/console/earlycon.c
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..54436587e3db90034652dcc144669dca91b863d5
> --- /dev/null
> +++ b/drivers/video/console/earlycon.c
> @@ -0,0 +1,305 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2013 Intel Corporation; author Matt Fleming
> + * Copyright (C) 2022 Markuss Broks <markuss.br...@gmail.com>
> + */
> +
> +#include <asm/early_ioremap.h>
> +#include <linux/console.h>
> +#include <linux/efi.h>
> +#include <linux/font.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/serial_core.h>
> +#include <linux/screen_info.h>
> +
> +struct fb_earlycon {
> +     u32 x, y, curr_x, curr_y, depth, stride;
> +     size_t size;
> +     phys_addr_t phys_base;
> +     void __iomem *virt_base;
> +};
> +
> +static const struct console *earlycon_console __initconst;
> +static struct fb_earlycon info;
> +static const struct font_desc *font;
> +
> +static int __init simplefb_earlycon_remap_fb(void)
> +{
> +     unsigned long mapping;
> +     /* bail if there is no bootconsole or it has been disabled already */
> +     if (!earlycon_console || !(earlycon_console->flags & CON_ENABLED))
> +             return 0;
> +
> +     if (region_intersects(info.phys_base, info.size,
> +                           IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE) == 
> REGION_INTERSECTS)             
> +             mapping = MEMREMAP_WB;
> +     else
> +             mapping = MEMREMAP_WC;
> +
> +     info.virt_base = memremap(info.phys_base, info.size, mapping);
> +
> +     return info.virt_base ? 0 : -ENOMEM;
> +}
> +early_initcall(simplefb_earlycon_remap_fb);
> +
> +static int __init simplefb_earlycon_unmap_fb(void)
> +{
> +     /* unmap the bootconsole fb unless keep_bootcon has left it enabled */
> +     if (info.virt_base && !(earlycon_console->flags & CON_ENABLED))
> +             memunmap(info.virt_base);
> +     return 0;
> +}
> +late_initcall(simplefb_earlycon_unmap_fb);
> +
> +static __ref void *simplefb_earlycon_map(unsigned long start, unsigned long 
> len)
> +{
> +     pgprot_t fb_prot;
> +
> +     if (info.virt_base)
> +             return info.virt_base + start;
> +
> +     fb_prot = PAGE_KERNEL;
> +     return early_memremap_prot(info.phys_base + start, len, 
> pgprot_val(fb_prot));
> +}
> +
> +static __ref void simplefb_earlycon_unmap(void *addr, unsigned long len)
> +{
> +     if (info.virt_base)
> +             return;
> +
> +     early_memunmap(addr, len);
> +}
> +
> +static void simplefb_earlycon_clear_scanline(unsigned int y)
> +{
> +     unsigned long *dst;
> +     u16 len;
> +
> +     len = info.stride;
> +     dst = simplefb_earlycon_map(y * len, len);
> +     if (!dst)
> +             return;
> +
> +     memset(dst, 0, len);
> +     simplefb_earlycon_unmap(dst, len);
> +}
> +
> +static void simplefb_earlycon_scroll_up(void)
> +{
> +     unsigned long *dst, *src;
> +     u16 len;
> +     u32 i, height;
> +
> +     len = info.stride;
> +     height = info.y;
> +
> +     for (i = 0; i < height - font->height; i++) {
> +             dst = simplefb_earlycon_map(i * len, len);
> +             if (!dst)
> +                     return;
> +
> +             src = simplefb_earlycon_map((i + font->height) * len, len);
> +             if (!src) {
> +                     simplefb_earlycon_unmap(dst, len);
> +                     return;
> +             }
> +
> +             memmove(dst, src, len);
> +
> +             simplefb_earlycon_unmap(src, len);
> +             simplefb_earlycon_unmap(dst, len);
> +     }
> +}
> +
> +static void simplefb_earlycon_write_char(u8 *dst, unsigned char c, unsigned 
> int h)
> +{
> +     const u8 *src;
> +     int m, n, bytes;
> +     u8 x;
> +
> +     bytes = BITS_TO_BYTES(font->width);
> +     src = font->data + c * font->height * bytes + h * bytes;
> +
> +     for (m = 0; m < font->width; m++) {
> +             n = m % 8;
> +             x = *(src + m / 8);
> +             if ((x >> (7 - n)) & 1)
> +                     memset(dst, 0xff, (info.depth / 8));
> +             else
> +                     memset(dst, 0, (info.depth / 8));
> +             dst += (info.depth / 8);
> +     }
> +}
> +
> +static void
> +simplefb_earlycon_write(struct console *con, const char *str, unsigned int 
> num)
> +{
> +     unsigned int len;
> +     const char *s;
> +     void *dst;
> +
> +     len = info.stride;
> +
> +     while (num) {
> +             unsigned int linemax;
> +             unsigned int h, count = 0;
> +
> +             for (s = str; *s && *s != '\n'; s++) {
> +                     if (count == num)
> +                             break;
> +                     count++;
> +             }
> +
> +             linemax = (info.x - info.curr_x) / font->width;
> +             if (count > linemax)
> +                     count = linemax;
> +
> +             for (h = 0; h < font->height; h++) {
> +                     unsigned int n, x;
> +
> +                     dst = simplefb_earlycon_map((info.curr_y + h) * len, 
> len);
> +                     if (!dst)
> +                             return;
> +
> +                     s = str;
> +                     n = count;
> +                     x = info.curr_x;
> +
> +                     while (n-- > 0) {
> +                             simplefb_earlycon_write_char(dst + (x * 4), *s, 
> h);
> +                             x += font->width;
> +                             s++;
> +                     }
> +
> +                     simplefb_earlycon_unmap(dst, len);
> +             }
> +
> +             num -= count;
> +             info.curr_x += count * font->width;
> +             str += count;
> +
> +             if (num > 0 && *s == '\n') {
> +                     info.curr_x = 0;
> +                     info.curr_y += font->height;
> +                     str++;
> +                     num--;
> +             }
> +
> +             if (info.curr_x + font->width > info.x) {
> +                     info.curr_x = 0;
> +                     info.curr_y += font->height;
> +             }
> +
> +             if (info.curr_y + font->height > info.y) {
> +                     u32 i;
> +
> +                     info.curr_y -= font->height;
> +                     simplefb_earlycon_scroll_up();
> +
> +                     for (i = 0; i < font->height; i++)
> +                             simplefb_earlycon_clear_scanline(info.curr_y + 
> i);
> +             }
> +     }
> +}
> +
> +static int __init simplefb_earlycon_setup_common(struct earlycon_device 
> *device,
> +                                              const char *opt)
> +{
> +     int i;
> +
> +     info.size = info.x * info.y * (info.depth / 8);
> +
> +     font = get_default_font(info.x, info.y, -1, -1);
> +     if (!font)
> +             return -ENODEV;
> +
> +     info.curr_y = rounddown(info.y, font->height) - font->height;
> +     for (i = 0; i < (info.y - info.curr_y) / font->height; i++)
> +             simplefb_earlycon_scroll_up();
> +
> +     device->con->write = simplefb_earlycon_write;
> +     earlycon_console = device->con;
> +     return 0;
> +}
> +
> +static int __init simplefb_earlycon_setup(struct earlycon_device *device,
> +                                       const char *opt)
> +{
> +     struct uart_port *port = &device->port;
> +     int ret;
> +
> +     if (!port->mapbase)
> +             return -ENODEV;
> +
> +     info.phys_base = port->mapbase;
> +
> +     ret = sscanf(device->options, "%ux%ux%u", &info.x, &info.y, 
> &info.depth);
> +     if (ret != 3)
> +             return -ENODEV;
> +
> +     info.stride = info.x * (info.depth / 8);
> +
> +     return simplefb_earlycon_setup_common(device, opt);
> +}
> +
> +EARLYCON_DECLARE(simplefb, simplefb_earlycon_setup);
> +
> +#ifdef CONFIG_EFI_EARLYCON
> +static int __init simplefb_earlycon_setup_efi(struct earlycon_device *device,
> +                                           const char *opt)
> +{
> +     if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
> +             return -ENODEV;
> +
> +     info.phys_base = screen_info.lfb_base;
> +     if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
> +             info.phys_base |= (u64)screen_info.ext_lfb_base << 32;
> +
> +     info.x = screen_info.lfb_width;
> +     info.y = screen_info.lfb_height;
> +     info.depth = screen_info.lfb_depth;
> +     info.stride = screen_info.lfb_linelength;
> +
> +     return simplefb_earlycon_setup_common(device, opt);
> +}
> +
> +EARLYCON_DECLARE(efifb, simplefb_earlycon_setup_efi);
> +#endif
> +
> +#ifdef CONFIG_OF_EARLY_FLATTREE
> +static int __init simplefb_earlycon_setup_of(struct earlycon_device *device,
> +                                          const char *opt)
> +{
> +     struct uart_port *port = &device->port;
> +     const __be32 *val;
> +
> +     if (!port->mapbase)
> +             return -ENODEV;
> +
> +     info.phys_base = port->mapbase;
> +
> +     val = of_get_flat_dt_prop(device->offset, "width", NULL);
> +     if (!val)
> +             return -ENODEV;
> +     info.x = be32_to_cpu(*val);
> +
> +     val = of_get_flat_dt_prop(device->offset, "height", NULL);
> +     if (!val)
> +             return -ENODEV;
> +     info.y = be32_to_cpu(*val);
> +
> +     val = of_get_flat_dt_prop(device->offset, "stride", NULL);
> +     if (!val)
> +             return -ENODEV;
> +     info.stride = be32_to_cpu(*val);
> +     info.depth = (info.stride / info.x) * 8;
> +
> +     return simplefb_earlycon_setup_common(device, opt);
> +}
> +
> +OF_EARLYCON_DECLARE(simplefb, "simple-framebuffer", 
> simplefb_earlycon_setup_of);
> +#endif
> -- 
> 2.37.0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

Reply via email to