Received: by 2002:a05:6358:bb9e:b0:b9:5105:a5b4 with SMTP id df30csp4911382rwb; Tue, 6 Sep 2022 15:04:01 -0700 (PDT) X-Google-Smtp-Source: AA6agR5cl3GbRU0AEJjGHa9y2m5V8/UlkdZqVFuetvt8I2W7J4UlxbyFOPYDasOXYYjV5tqPYgfU X-Received: by 2002:a17:907:75e8:b0:73d:53dc:661d with SMTP id jz8-20020a17090775e800b0073d53dc661dmr350873ejc.738.1662501841548; Tue, 06 Sep 2022 15:04:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1662501841; cv=none; d=google.com; s=arc-20160816; b=IpTaRPcGqHW/xIkA2TbbOn3pZaAMMZ/oQyfIPWx+P9FgfYaOMEzxdhSSuN6iAKnfvl AwltSwVT1TekTFTVacP2buRE9z2oCMnazPynCGARLx/JbyGBGsxl7ZTAebt4Id4UzESv jSYe2FVsIVgQIySF8SLZ4Fvs4IzTmHQoJUVFU98+jsyZZxfgVES/2ptdyfodDyyr0k/r vss8nDNkoOlm7zIhYuNaqtqXH59EYVw39G8/rNR++0hogE1CWHmfZBxBbGJzzRTYrfLi f5Xkzp5Xn9X7jDooNIiVeyqgcT8CW/ktD3trSyzREtg/Hz6NCjU5VzgchveTsPY2Umra Aeqg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:mail-followup-to:message-id:subject:cc:to:from:date :dkim-signature; bh=4fH2cbocjKm8IFfEl7ud9xUlx7bF7bK6TTkeGAOPSDQ=; b=W265N6AbN7y+qgvcR5Yq47wRrGYlu52/mIwLdLzWMHZgtPF9gLoEMmJa6xIJx26cg4 c4RJ3jyGz8H0q9/n8j6J257lylflMdgM3DZAVwIlgTLuIgegn3Xz3R3afiM+KxJCMaK5 kKRdQTBuh/G+XxNBDcqrz9DhAK9Ml6vY0MqNCFMJuKZX8bJ29b/BecGN972AVrXvt1v1 KYjAM/Jt7cQtZdpQiJNH0FaD3YgTy0lE0LZS6tBIRDnIhSEeVTKUaboZJ9Oe8v7kU9Eh zzwBGimvl516/sDF8gDmznptWMOw3H7XGymYLeyOuKNrlwtCHXvujDFa2/3i3/kQM+6f LoBg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=CIdxA252; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id js16-20020a17090797d000b007414bf4fe5fsi10873651ejc.264.2022.09.06.15.03.33; Tue, 06 Sep 2022 15:04:01 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=CIdxA252; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229766AbiIFVwl (ORCPT + 99 others); Tue, 6 Sep 2022 17:52:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229781AbiIFVwi (ORCPT ); Tue, 6 Sep 2022 17:52:38 -0400 Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C30417E328 for ; Tue, 6 Sep 2022 14:52:29 -0700 (PDT) Received: by mail-ej1-x62e.google.com with SMTP id fg1so4142284ejc.2 for ; Tue, 06 Sep 2022 14:52:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=in-reply-to:content-disposition:mime-version:references :mail-followup-to:message-id:subject:cc:to:from:date:from:to:cc :subject:date; bh=4fH2cbocjKm8IFfEl7ud9xUlx7bF7bK6TTkeGAOPSDQ=; b=CIdxA252uU62YoKWz2+3B6QY6YJ1mgSCTgJ1SDEzkwTKHXkNoKn+UYry5uKq3Asl+x WzZVf1XBr4bK3EBTVkPFfsrYaJtw+0jUjRlntNisOA5TYAePxV/Y6sSS4SBGe9E7JuIZ B1svhBI+Avsg7WtlLcJTYneVu/276qvkD2pVw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=in-reply-to:content-disposition:mime-version:references :mail-followup-to:message-id:subject:cc:to:from:date :x-gm-message-state:from:to:cc:subject:date; bh=4fH2cbocjKm8IFfEl7ud9xUlx7bF7bK6TTkeGAOPSDQ=; b=QnbsgI61Cl0MjsNxTQK8KTAXkqhIWfCUGZ44Sr587UcxWJoBiPGwSZt+plUfCYo8zK K6ci3E1XHKSHaoPGHwBV1oEt+MyYNBNU3T3q3abyJTPt9BHNsv0fmNy7KZ1L8kua50ci +veYHkfBKa2MUbjMkwV8/C+mfzAh4w3iqIEwLtCx8rRGlqxxDDNK6DtzkexzUxMiyTjp i+ba6rSXCfkiz8MJyMrZYbayggbw42UjftKXI2z7ctVv0AtEIcBKyvOaJ9amjxbb05Wl LSIEXVG9KHpXOGcam3HXinV3erF6iFykwmleb86EPSptbDWIHGbzK/btVcEav02kMBdj PUDw== X-Gm-Message-State: ACgBeo0yIisOkoOkUNGy4siKEf4A0TjjeNCJ+jHIV73MYCDJDzAScHMu D0hrjy1yIW/AbPIUMk+IFl2mWQ== X-Received: by 2002:a17:907:94d0:b0:730:7a68:3093 with SMTP id dn16-20020a17090794d000b007307a683093mr346899ejc.760.1662501148262; Tue, 06 Sep 2022 14:52:28 -0700 (PDT) Received: from phenom.ffwll.local (212-51-149-33.fiber7.init7.net. [212.51.149.33]) by smtp.gmail.com with ESMTPSA id g9-20020a50ec09000000b0044ece2a0fedsm2254684edr.84.2022.09.06.14.52.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Sep 2022 14:52:27 -0700 (PDT) Date: Tue, 6 Sep 2022 23:52:24 +0200 From: Daniel Vetter To: Markuss Broks Cc: linux-kernel@vger.kernel.org, ~postmarketos/upstreaming@lists.sr.ht, phone-devel@vger.kernel.org, Jonathan Corbet , Ard Biesheuvel , Greg Kroah-Hartman , Jiri Slaby , Helge Deller , "Paul E. McKenney" , Borislav Petkov , Kees Cook , Andrew Morton , Randy Dunlap , Damien Le Moal , Thomas Zimmermann , Michal Suchanek , Javier Martinez Canillas , Arnd Bergmann , Maarten Lankhorst , Wei Ming Chen , Bartlomiej Zolnierkiewicz , Tony Lindgren , linux-doc@vger.kernel.org, linux-efi@vger.kernel.org, linux-serial@vger.kernel.org, linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org Subject: Re: [PATCH v2 3/3] efi: earlycon: Add support for generic framebuffers and move to console subsystem Message-ID: Mail-Followup-To: Markuss Broks , linux-kernel@vger.kernel.org, ~postmarketos/upstreaming@lists.sr.ht, phone-devel@vger.kernel.org, Jonathan Corbet , Ard Biesheuvel , Greg Kroah-Hartman , Jiri Slaby , Helge Deller , "Paul E. McKenney" , Borislav Petkov , Kees Cook , Andrew Morton , Randy Dunlap , Damien Le Moal , Thomas Zimmermann , Michal Suchanek , Javier Martinez Canillas , Arnd Bergmann , Maarten Lankhorst , Wei Ming Chen , Bartlomiej Zolnierkiewicz , Tony Lindgren , linux-doc@vger.kernel.org, linux-efi@vger.kernel.org, linux-serial@vger.kernel.org, linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org References: <20220806163255.10404-1-markuss.broks@gmail.com> <20220806163255.10404-4-markuss.broks@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20220806163255.10404-4-markuss.broks@gmail.com> X-Operating-System: Linux phenom 5.18.0-4-amd64 X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE, T_SPF_TEMPERROR autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 > --- > .../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, > 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,,xx > + 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 > +S: Maintained > +F: drivers/video/console/earlycon.c > + > EARTH_PT1 MEDIA DRIVER > M: Akihiro Tsukada > L: linux-media@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 > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > - > -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 > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +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