Merge tag 'fbdev-v4.19' of https://github.com/bzolnier/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Aug 2018 22:44:58 +0000 (15:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Aug 2018 22:44:58 +0000 (15:44 -0700)
Pull fbdev updates from Bartlomiej Zolnierkiewicz:
 "Mostly small fixes and cleanups for fb drivers (the biggest updates
  are for udlfb and pxafb drivers). This also adds deferred console
  takeover support to the console code and efifb driver.

  Summary:

   - add support for deferred console takeover, when enabled defers
     fbcon taking over the console from the dummy console until the
     first text is displayed on the console - together with the "quiet"
     kernel commandline option this allows fbcon to still be used
     together with a smooth graphical bootup (Hans de Goede)

   - improve console locking debugging code (Thomas Zimmermann)

   - copy the ACPI BGRT boot graphics to the framebuffer when deferred
     console takeover support is used in efifb driver (Hans de Goede)

   - update udlfb driver - fix lost console when the user unplugs a USB
     adapter, fix the screen corruption issue, fix locking and add some
     performance optimizations (Mikulas Patocka)

   - update pxafb driver - fix using uninitialized memory, switch to
     devm_* API, handle initialization errors and add support for
     lcd-supply regulator (Daniel Mack)

   - add support for boards booted with a DeviceTree in pxa3xx_gcu
     driver (Daniel Mack)

   - rename omap2 module to omap2fb.ko to avoid conflicts with omap1
     driver (Arnd Bergmann)

   - enable ACPI-based enumeration for goldfishfb driver (Yu Ning)

   - fix goldfishfb driver to make user space Android code use 60 fps
     (Christoffer Dall)

   - print big fat warning when nomodeset kernel parameter is used in
     vgacon driver (Lyude Paul)

   - remove VLA usage from fsl-diu-fb driver (Kees Cook)

   - misc fixes (Julia Lawall, Geert Uytterhoeven, Fredrik Noring,
     Yisheng Xie, Dan Carpenter, Daniel Vetter, Anton Vasilyev, Randy
     Dunlap, Gustavo A. R. Silva, Colin Ian King, Fengguang Wu)

   - misc cleanups (Roman Kiryanov, Yisheng Xie, Colin Ian King)"

* tag 'fbdev-v4.19' of https://github.com/bzolnier/linux: (54 commits)
  Documentation/fb: corrections for fbcon.txt
  fbcon: Do not takeover the console from atomic context
  dummycon: Stop exporting dummycon_[un]register_output_notifier
  fbcon: Only defer console takeover if the current console driver is the dummycon
  fbcon: Only allow FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER if fbdev is builtin
  fbdev: omap2: omapfb: fix ifnullfree.cocci warnings
  fbdev: omap2: omapfb: fix bugon.cocci warnings
  fbdev: omap2: omapfb: fix boolreturn.cocci warnings
  fb: amifb: fix build warnings when not builtin
  fbdev/core: Disable console-lock warnings when fb.lockless_register_fb is set
  console: Replace #if 0 with atomic var 'ignore_console_lock_warning'
  udlfb: use spin_lock_irq instead of spin_lock_irqsave
  udlfb: avoid prefetch
  udlfb: optimization - test the backing buffer
  udlfb: allow reallocating the framebuffer
  udlfb: set line_length in dlfb_ops_set_par
  udlfb: handle allocation failure
  udlfb: set optimal write delay
  udlfb: make a local copy of fb_ops
  udlfb: don't switch if we are switching to the same videomode
  ...

1  2 
drivers/video/fbdev/efifb.c
drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c
kernel/printk/printk.c

  #include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
  #include <drm/drm_connector.h>  /* For DRM_MODE_PANEL_ORIENTATION_* */
  
+ struct bmp_file_header {
+       u16 id;
+       u32 file_size;
+       u32 reserved;
+       u32 bitmap_offset;
+ } __packed;
+ struct bmp_dib_header {
+       u32 dib_header_size;
+       s32 width;
+       s32 height;
+       u16 planes;
+       u16 bpp;
+       u32 compression;
+       u32 bitmap_size;
+       u32 horz_resolution;
+       u32 vert_resolution;
+       u32 colors_used;
+       u32 colors_important;
+ } __packed;
  static bool request_mem_succeeded = false;
 -static bool nowc = false;
 +static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
  
  static struct fb_var_screeninfo efifb_defined = {
        .activate               = FB_ACTIVATE_NOW,
@@@ -66,14 -89,168 +89,172 @@@ static int efifb_setcolreg(unsigned reg
        return 0;
  }
  
+ /*
+  * If fbcon deffered console takeover is configured, the intent is for the
+  * framebuffer to show the boot graphics (e.g. vendor logo) until there is some
+  * (error) message to display. But the boot graphics may have been destroyed by
+  * e.g. option ROM output, detect this and restore the boot graphics.
+  */
+ #if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \
+     defined CONFIG_ACPI_BGRT
+ static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
+ {
+       u8 r, g, b;
+       while (width--) {
+               b = *src++;
+               g = *src++;
+               r = *src++;
+               *dst++ = (r << si->red_pos)   |
+                        (g << si->green_pos) |
+                        (b << si->blue_pos);
+       }
+ }
+ #ifdef CONFIG_X86
+ /*
+  * On x86 some firmwares use a low non native resolution for the display when
+  * they have shown some text messages. While keeping the bgrt filled with info
+  * for the native resolution. If the bgrt image intended for the native
+  * resolution still fits, it will be displayed very close to the right edge of
+  * the display looking quite bad. This function checks for this.
+  */
+ static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
+ {
+       static const int default_resolutions[][2] = {
+               {  800,  600 },
+               { 1024,  768 },
+               { 1280, 1024 },
+       };
+       u32 i, right_margin;
+       for (i = 0; i < ARRAY_SIZE(default_resolutions); i++) {
+               if (default_resolutions[i][0] == si->lfb_width &&
+                   default_resolutions[i][1] == si->lfb_height)
+                       break;
+       }
+       /* If not a default resolution used for textmode, this should be fine */
+       if (i >= ARRAY_SIZE(default_resolutions))
+               return true;
+       /* If the right margin is 5 times smaller then the left one, reject */
+       right_margin = si->lfb_width - (bgrt_tab.image_offset_x + bmp_width);
+       if (right_margin < (bgrt_tab.image_offset_x / 5))
+               return false;
+       return true;
+ }
+ #else
+ static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
+ {
+       return true;
+ }
+ #endif
+ static void efifb_show_boot_graphics(struct fb_info *info)
+ {
+       u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y;
+       struct screen_info *si = &screen_info;
+       struct bmp_file_header *file_header;
+       struct bmp_dib_header *dib_header;
+       void *bgrt_image = NULL;
+       u8 *dst = info->screen_base;
+       if (!bgrt_tab.image_address) {
+               pr_info("efifb: No BGRT, not showing boot graphics\n");
+               return;
+       }
+       /* Avoid flashing the logo if we're going to print std probe messages */
+       if (console_loglevel > CONSOLE_LOGLEVEL_QUIET)
+               return;
+       /* bgrt_tab.status is unreliable, so we don't check it */
+       if (si->lfb_depth != 32) {
+               pr_info("efifb: not 32 bits, not showing boot graphics\n");
+               return;
+       }
+       bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size,
+                             MEMREMAP_WB);
+       if (!bgrt_image) {
+               pr_warn("efifb: Ignoring BGRT: failed to map image memory\n");
+               return;
+       }
+       if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header)))
+               goto error;
+       file_header = bgrt_image;
+       if (file_header->id != 0x4d42 || file_header->reserved != 0)
+               goto error;
+       dib_header = bgrt_image + sizeof(*file_header);
+       if (dib_header->dib_header_size != 40 || dib_header->width < 0 ||
+           dib_header->planes != 1 || dib_header->bpp != 24 ||
+           dib_header->compression != 0)
+               goto error;
+       bmp_width = dib_header->width;
+       bmp_height = abs(dib_header->height);
+       bmp_pitch = round_up(3 * bmp_width, 4);
+       screen_pitch = si->lfb_linelength;
+       if ((file_header->bitmap_offset + bmp_pitch * bmp_height) >
+                               bgrt_image_size)
+               goto error;
+       if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width ||
+           (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height)
+               goto error;
+       if (!efifb_bgrt_sanity_check(si, bmp_width))
+               goto error;
+       pr_info("efifb: showing boot graphics\n");
+       for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) {
+               /* Only background? */
+               if (y < bgrt_tab.image_offset_y ||
+                   y >= (bgrt_tab.image_offset_y + bmp_height)) {
+                       memset(dst, 0, 4 * si->lfb_width);
+                       continue;
+               }
+               src_y = y - bgrt_tab.image_offset_y;
+               /* Positive header height means upside down row order */
+               if (dib_header->height > 0)
+                       src_y = (bmp_height - 1) - src_y;
+               memset(dst, 0, bgrt_tab.image_offset_x * 4);
+               dst_x = bgrt_tab.image_offset_x;
+               efifb_copy_bmp(bgrt_image + file_header->bitmap_offset +
+                                           src_y * bmp_pitch,
+                              (u32 *)dst + dst_x, bmp_width, si);
+               dst_x += bmp_width;
+               memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4);
+       }
+       memunmap(bgrt_image);
+       return;
+ error:
+       memunmap(bgrt_image);
+       pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n");
+ }
+ #else
+ static inline void efifb_show_boot_graphics(struct fb_info *info) {}
+ #endif
  static void efifb_destroy(struct fb_info *info)
  {
 -      if (info->screen_base)
 -              iounmap(info->screen_base);
 +      if (info->screen_base) {
 +              if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
 +                      iounmap(info->screen_base);
 +              else
 +                      memunmap(info->screen_base);
 +      }
        if (request_mem_succeeded)
                release_mem_region(info->apertures->ranges[0].base,
                                   info->apertures->ranges[0].size);
Simple merge