LCOV - code coverage report
Current view: top level - drivers/video/fbdev - efifb.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 6 242 2.5 %
Date: 2022-04-01 14:58:12 Functions: 2 13 15.4 %
Branches: 2 114 1.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Framebuffer driver for EFI/UEFI based system
       4                 :            :  *
       5                 :            :  * (c) 2006 Edgar Hucek <gimli@dark-green.com>
       6                 :            :  * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
       7                 :            :  *
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/kernel.h>
      11                 :            : #include <linux/efi.h>
      12                 :            : #include <linux/efi-bgrt.h>
      13                 :            : #include <linux/errno.h>
      14                 :            : #include <linux/fb.h>
      15                 :            : #include <linux/pci.h>
      16                 :            : #include <linux/platform_device.h>
      17                 :            : #include <linux/printk.h>
      18                 :            : #include <linux/screen_info.h>
      19                 :            : #include <video/vga.h>
      20                 :            : #include <asm/efi.h>
      21                 :            : #include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
      22                 :            : #include <drm/drm_connector.h>  /* For DRM_MODE_PANEL_ORIENTATION_* */
      23                 :            : 
      24                 :            : struct bmp_file_header {
      25                 :            :         u16 id;
      26                 :            :         u32 file_size;
      27                 :            :         u32 reserved;
      28                 :            :         u32 bitmap_offset;
      29                 :            : } __packed;
      30                 :            : 
      31                 :            : struct bmp_dib_header {
      32                 :            :         u32 dib_header_size;
      33                 :            :         s32 width;
      34                 :            :         s32 height;
      35                 :            :         u16 planes;
      36                 :            :         u16 bpp;
      37                 :            :         u32 compression;
      38                 :            :         u32 bitmap_size;
      39                 :            :         u32 horz_resolution;
      40                 :            :         u32 vert_resolution;
      41                 :            :         u32 colors_used;
      42                 :            :         u32 colors_important;
      43                 :            : } __packed;
      44                 :            : 
      45                 :            : static bool use_bgrt = true;
      46                 :            : static bool request_mem_succeeded = false;
      47                 :            : static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
      48                 :            : 
      49                 :            : static struct fb_var_screeninfo efifb_defined = {
      50                 :            :         .activate               = FB_ACTIVATE_NOW,
      51                 :            :         .height                 = -1,
      52                 :            :         .width                  = -1,
      53                 :            :         .right_margin           = 32,
      54                 :            :         .upper_margin           = 16,
      55                 :            :         .lower_margin           = 4,
      56                 :            :         .vsync_len              = 4,
      57                 :            :         .vmode                  = FB_VMODE_NONINTERLACED,
      58                 :            : };
      59                 :            : 
      60                 :            : static struct fb_fix_screeninfo efifb_fix = {
      61                 :            :         .id                     = "EFI VGA",
      62                 :            :         .type                   = FB_TYPE_PACKED_PIXELS,
      63                 :            :         .accel                  = FB_ACCEL_NONE,
      64                 :            :         .visual                 = FB_VISUAL_TRUECOLOR,
      65                 :            : };
      66                 :            : 
      67                 :          0 : static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
      68                 :            :                            unsigned blue, unsigned transp,
      69                 :            :                            struct fb_info *info)
      70                 :            : {
      71                 :            :         /*
      72                 :            :          *  Set a single color register. The values supplied are
      73                 :            :          *  already rounded down to the hardware's capabilities
      74                 :            :          *  (according to the entries in the `var' structure). Return
      75                 :            :          *  != 0 for invalid regno.
      76                 :            :          */
      77                 :            : 
      78         [ #  # ]:          0 :         if (regno >= info->cmap.len)
      79                 :            :                 return 1;
      80                 :            : 
      81         [ #  # ]:          0 :         if (regno < 16) {
      82                 :          0 :                 red   >>= 16 - info->var.red.length;
      83                 :          0 :                 green >>= 16 - info->var.green.length;
      84                 :          0 :                 blue  >>= 16 - info->var.blue.length;
      85                 :          0 :                 ((u32 *)(info->pseudo_palette))[regno] =
      86                 :          0 :                         (red   << info->var.red.offset)   |
      87                 :          0 :                         (green << info->var.green.offset) |
      88                 :          0 :                         (blue  << info->var.blue.offset);
      89                 :            :         }
      90                 :            :         return 0;
      91                 :            : }
      92                 :            : 
      93                 :            : /*
      94                 :            :  * If fbcon deffered console takeover is configured, the intent is for the
      95                 :            :  * framebuffer to show the boot graphics (e.g. vendor logo) until there is some
      96                 :            :  * (error) message to display. But the boot graphics may have been destroyed by
      97                 :            :  * e.g. option ROM output, detect this and restore the boot graphics.
      98                 :            :  */
      99                 :            : #if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \
     100                 :            :     defined CONFIG_ACPI_BGRT
     101                 :            : static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
     102                 :            : {
     103                 :            :         u8 r, g, b;
     104                 :            : 
     105                 :            :         while (width--) {
     106                 :            :                 b = *src++;
     107                 :            :                 g = *src++;
     108                 :            :                 r = *src++;
     109                 :            :                 *dst++ = (r << si->red_pos)   |
     110                 :            :                          (g << si->green_pos) |
     111                 :            :                          (b << si->blue_pos);
     112                 :            :         }
     113                 :            : }
     114                 :            : 
     115                 :            : #ifdef CONFIG_X86
     116                 :            : /*
     117                 :            :  * On x86 some firmwares use a low non native resolution for the display when
     118                 :            :  * they have shown some text messages. While keeping the bgrt filled with info
     119                 :            :  * for the native resolution. If the bgrt image intended for the native
     120                 :            :  * resolution still fits, it will be displayed very close to the right edge of
     121                 :            :  * the display looking quite bad. This function checks for this.
     122                 :            :  */
     123                 :            : static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
     124                 :            : {
     125                 :            :         /*
     126                 :            :          * All x86 firmwares horizontally center the image (the yoffset
     127                 :            :          * calculations differ between boards, but xoffset is predictable).
     128                 :            :          */
     129                 :            :         u32 expected_xoffset = (si->lfb_width - bmp_width) / 2;
     130                 :            : 
     131                 :            :         return bgrt_tab.image_offset_x == expected_xoffset;
     132                 :            : }
     133                 :            : #else
     134                 :            : static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
     135                 :            : {
     136                 :            :         return true;
     137                 :            : }
     138                 :            : #endif
     139                 :            : 
     140                 :            : static void efifb_show_boot_graphics(struct fb_info *info)
     141                 :            : {
     142                 :            :         u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y;
     143                 :            :         struct screen_info *si = &screen_info;
     144                 :            :         struct bmp_file_header *file_header;
     145                 :            :         struct bmp_dib_header *dib_header;
     146                 :            :         void *bgrt_image = NULL;
     147                 :            :         u8 *dst = info->screen_base;
     148                 :            : 
     149                 :            :         if (!use_bgrt)
     150                 :            :                 return;
     151                 :            : 
     152                 :            :         if (!bgrt_tab.image_address) {
     153                 :            :                 pr_info("efifb: No BGRT, not showing boot graphics\n");
     154                 :            :                 return;
     155                 :            :         }
     156                 :            : 
     157                 :            :         if (bgrt_tab.status & 0x06) {
     158                 :            :                 pr_info("efifb: BGRT rotation bits set, not showing boot graphics\n");
     159                 :            :                 return;
     160                 :            :         }
     161                 :            : 
     162                 :            :         /* Avoid flashing the logo if we're going to print std probe messages */
     163                 :            :         if (console_loglevel > CONSOLE_LOGLEVEL_QUIET)
     164                 :            :                 return;
     165                 :            : 
     166                 :            :         /* bgrt_tab.status is unreliable, so we don't check it */
     167                 :            : 
     168                 :            :         if (si->lfb_depth != 32) {
     169                 :            :                 pr_info("efifb: not 32 bits, not showing boot graphics\n");
     170                 :            :                 return;
     171                 :            :         }
     172                 :            : 
     173                 :            :         bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size,
     174                 :            :                               MEMREMAP_WB);
     175                 :            :         if (!bgrt_image) {
     176                 :            :                 pr_warn("efifb: Ignoring BGRT: failed to map image memory\n");
     177                 :            :                 return;
     178                 :            :         }
     179                 :            : 
     180                 :            :         if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header)))
     181                 :            :                 goto error;
     182                 :            : 
     183                 :            :         file_header = bgrt_image;
     184                 :            :         if (file_header->id != 0x4d42 || file_header->reserved != 0)
     185                 :            :                 goto error;
     186                 :            : 
     187                 :            :         dib_header = bgrt_image + sizeof(*file_header);
     188                 :            :         if (dib_header->dib_header_size != 40 || dib_header->width < 0 ||
     189                 :            :             dib_header->planes != 1 || dib_header->bpp != 24 ||
     190                 :            :             dib_header->compression != 0)
     191                 :            :                 goto error;
     192                 :            : 
     193                 :            :         bmp_width = dib_header->width;
     194                 :            :         bmp_height = abs(dib_header->height);
     195                 :            :         bmp_pitch = round_up(3 * bmp_width, 4);
     196                 :            :         screen_pitch = si->lfb_linelength;
     197                 :            : 
     198                 :            :         if ((file_header->bitmap_offset + bmp_pitch * bmp_height) >
     199                 :            :                                 bgrt_image_size)
     200                 :            :                 goto error;
     201                 :            : 
     202                 :            :         if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width ||
     203                 :            :             (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height)
     204                 :            :                 goto error;
     205                 :            : 
     206                 :            :         if (!efifb_bgrt_sanity_check(si, bmp_width))
     207                 :            :                 goto error;
     208                 :            : 
     209                 :            :         pr_info("efifb: showing boot graphics\n");
     210                 :            : 
     211                 :            :         for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) {
     212                 :            :                 /* Only background? */
     213                 :            :                 if (y < bgrt_tab.image_offset_y ||
     214                 :            :                     y >= (bgrt_tab.image_offset_y + bmp_height)) {
     215                 :            :                         memset(dst, 0, 4 * si->lfb_width);
     216                 :            :                         continue;
     217                 :            :                 }
     218                 :            : 
     219                 :            :                 src_y = y - bgrt_tab.image_offset_y;
     220                 :            :                 /* Positive header height means upside down row order */
     221                 :            :                 if (dib_header->height > 0)
     222                 :            :                         src_y = (bmp_height - 1) - src_y;
     223                 :            : 
     224                 :            :                 memset(dst, 0, bgrt_tab.image_offset_x * 4);
     225                 :            :                 dst_x = bgrt_tab.image_offset_x;
     226                 :            :                 efifb_copy_bmp(bgrt_image + file_header->bitmap_offset +
     227                 :            :                                             src_y * bmp_pitch,
     228                 :            :                                (u32 *)dst + dst_x, bmp_width, si);
     229                 :            :                 dst_x += bmp_width;
     230                 :            :                 memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4);
     231                 :            :         }
     232                 :            : 
     233                 :            :         memunmap(bgrt_image);
     234                 :            :         return;
     235                 :            : 
     236                 :            : error:
     237                 :            :         memunmap(bgrt_image);
     238                 :            :         pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n");
     239                 :            : }
     240                 :            : #else
     241                 :          0 : static inline void efifb_show_boot_graphics(struct fb_info *info) {}
     242                 :            : #endif
     243                 :            : 
     244                 :          0 : static void efifb_destroy(struct fb_info *info)
     245                 :            : {
     246         [ #  # ]:          0 :         if (info->screen_base) {
     247         [ #  # ]:          0 :                 if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
     248                 :          0 :                         iounmap(info->screen_base);
     249                 :            :                 else
     250                 :          0 :                         memunmap(info->screen_base);
     251                 :            :         }
     252         [ #  # ]:          0 :         if (request_mem_succeeded)
     253                 :          0 :                 release_mem_region(info->apertures->ranges[0].base,
     254                 :            :                                    info->apertures->ranges[0].size);
     255                 :          0 :         fb_dealloc_cmap(&info->cmap);
     256                 :          0 : }
     257                 :            : 
     258                 :            : static const struct fb_ops efifb_ops = {
     259                 :            :         .owner          = THIS_MODULE,
     260                 :            :         .fb_destroy     = efifb_destroy,
     261                 :            :         .fb_setcolreg   = efifb_setcolreg,
     262                 :            :         .fb_fillrect    = cfb_fillrect,
     263                 :            :         .fb_copyarea    = cfb_copyarea,
     264                 :            :         .fb_imageblit   = cfb_imageblit,
     265                 :            : };
     266                 :            : 
     267                 :          0 : static int efifb_setup(char *options)
     268                 :            : {
     269                 :          0 :         char *this_opt;
     270                 :            : 
     271   [ #  #  #  # ]:          0 :         if (options && *options) {
     272         [ #  # ]:          0 :                 while ((this_opt = strsep(&options, ",")) != NULL) {
     273         [ #  # ]:          0 :                         if (!*this_opt) continue;
     274                 :            : 
     275                 :          0 :                         efifb_setup_from_dmi(&screen_info, this_opt);
     276                 :            : 
     277         [ #  # ]:          0 :                         if (!strncmp(this_opt, "base:", 5))
     278                 :          0 :                                 screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
     279         [ #  # ]:          0 :                         else if (!strncmp(this_opt, "stride:", 7))
     280                 :          0 :                                 screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
     281         [ #  # ]:          0 :                         else if (!strncmp(this_opt, "height:", 7))
     282                 :          0 :                                 screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
     283         [ #  # ]:          0 :                         else if (!strncmp(this_opt, "width:", 6))
     284                 :          0 :                                 screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
     285         [ #  # ]:          0 :                         else if (!strcmp(this_opt, "nowc"))
     286                 :          0 :                                 mem_flags &= ~EFI_MEMORY_WC;
     287         [ #  # ]:          0 :                         else if (!strcmp(this_opt, "nobgrt"))
     288                 :          0 :                                 use_bgrt = false;
     289                 :            :                 }
     290                 :            :         }
     291                 :            : 
     292                 :          0 :         return 0;
     293                 :            : }
     294                 :            : 
     295                 :          0 : static inline bool fb_base_is_valid(void)
     296                 :            : {
     297                 :          0 :         if (screen_info.lfb_base)
     298                 :            :                 return true;
     299                 :            : 
     300         [ #  # ]:          0 :         if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
     301                 :            :                 return false;
     302                 :            : 
     303         [ #  # ]:          0 :         if (screen_info.ext_lfb_base)
     304                 :            :                 return true;
     305                 :            : 
     306                 :            :         return false;
     307                 :            : }
     308                 :            : 
     309                 :            : #define efifb_attr_decl(name, fmt)                                      \
     310                 :            : static ssize_t name##_show(struct device *dev,                          \
     311                 :            :                            struct device_attribute *attr,               \
     312                 :            :                            char *buf)                                   \
     313                 :            : {                                                                       \
     314                 :            :         return sprintf(buf, fmt "\n", (screen_info.lfb_##name));      \
     315                 :            : }                                                                       \
     316                 :            : static DEVICE_ATTR_RO(name)
     317                 :            : 
     318                 :          0 : efifb_attr_decl(base, "0x%x");
     319                 :          0 : efifb_attr_decl(linelength, "%u");
     320                 :          0 : efifb_attr_decl(height, "%u");
     321                 :          0 : efifb_attr_decl(width, "%u");
     322                 :          0 : efifb_attr_decl(depth, "%u");
     323                 :            : 
     324                 :            : static struct attribute *efifb_attrs[] = {
     325                 :            :         &dev_attr_base.attr,
     326                 :            :         &dev_attr_linelength.attr,
     327                 :            :         &dev_attr_width.attr,
     328                 :            :         &dev_attr_height.attr,
     329                 :            :         &dev_attr_depth.attr,
     330                 :            :         NULL
     331                 :            : };
     332                 :            : ATTRIBUTE_GROUPS(efifb);
     333                 :            : 
     334                 :            : static bool pci_dev_disabled;   /* FB base matches BAR of a disabled device */
     335                 :            : 
     336                 :            : static struct pci_dev *efifb_pci_dev;   /* dev with BAR covering the efifb */
     337                 :            : static struct resource *bar_resource;
     338                 :            : static u64 bar_offset;
     339                 :            : 
     340                 :          0 : static int efifb_probe(struct platform_device *dev)
     341                 :            : {
     342                 :          0 :         struct fb_info *info;
     343                 :          0 :         int err, orientation;
     344                 :          0 :         unsigned int size_vmode;
     345                 :          0 :         unsigned int size_remap;
     346                 :          0 :         unsigned int size_total;
     347                 :          0 :         char *option = NULL;
     348                 :          0 :         efi_memory_desc_t md;
     349                 :            : 
     350   [ #  #  #  # ]:          0 :         if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
     351                 :            :                 return -ENODEV;
     352                 :            : 
     353         [ #  # ]:          0 :         if (fb_get_options("efifb", &option))
     354                 :            :                 return -ENODEV;
     355                 :          0 :         efifb_setup(option);
     356                 :            : 
     357                 :            :         /* We don't get linelength from UGA Draw Protocol, only from
     358                 :            :          * EFI Graphics Protocol.  So if it's not in DMI, and it's not
     359                 :            :          * passed in from the user, we really can't use the framebuffer.
     360                 :            :          */
     361         [ #  # ]:          0 :         if (!screen_info.lfb_linelength)
     362                 :            :                 return -ENODEV;
     363                 :            : 
     364         [ #  # ]:          0 :         if (!screen_info.lfb_depth)
     365                 :          0 :                 screen_info.lfb_depth = 32;
     366         [ #  # ]:          0 :         if (!screen_info.pages)
     367                 :          0 :                 screen_info.pages = 1;
     368         [ #  # ]:          0 :         if (!fb_base_is_valid()) {
     369                 :          0 :                 printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
     370                 :          0 :                 return -ENODEV;
     371                 :            :         }
     372                 :          0 :         printk(KERN_INFO "efifb: probing for efifb\n");
     373                 :            : 
     374                 :            :         /* just assume they're all unset if any are */
     375         [ #  # ]:          0 :         if (!screen_info.blue_size) {
     376                 :          0 :                 screen_info.blue_size = 8;
     377                 :          0 :                 screen_info.blue_pos = 0;
     378                 :          0 :                 screen_info.green_size = 8;
     379                 :          0 :                 screen_info.green_pos = 8;
     380                 :          0 :                 screen_info.red_size = 8;
     381                 :          0 :                 screen_info.red_pos = 16;
     382                 :          0 :                 screen_info.rsvd_size = 8;
     383                 :          0 :                 screen_info.rsvd_pos = 24;
     384                 :            :         }
     385                 :            : 
     386                 :          0 :         efifb_fix.smem_start = screen_info.lfb_base;
     387                 :            : 
     388         [ #  # ]:          0 :         if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
     389                 :          0 :                 u64 ext_lfb_base;
     390                 :            : 
     391                 :          0 :                 ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
     392                 :          0 :                 efifb_fix.smem_start |= ext_lfb_base;
     393                 :            :         }
     394                 :            : 
     395         [ #  # ]:          0 :         if (bar_resource &&
     396         [ #  # ]:          0 :             bar_resource->start + bar_offset != efifb_fix.smem_start) {
     397                 :          0 :                 dev_info(&efifb_pci_dev->dev,
     398                 :            :                          "BAR has moved, updating efifb address\n");
     399                 :          0 :                 efifb_fix.smem_start = bar_resource->start + bar_offset;
     400                 :            :         }
     401                 :            : 
     402                 :          0 :         efifb_defined.bits_per_pixel = screen_info.lfb_depth;
     403                 :          0 :         efifb_defined.xres = screen_info.lfb_width;
     404                 :          0 :         efifb_defined.yres = screen_info.lfb_height;
     405                 :          0 :         efifb_fix.line_length = screen_info.lfb_linelength;
     406                 :            : 
     407                 :            :         /*   size_vmode -- that is the amount of memory needed for the
     408                 :            :          *                 used video mode, i.e. the minimum amount of
     409                 :            :          *                 memory we need. */
     410                 :          0 :         size_vmode = efifb_defined.yres * efifb_fix.line_length;
     411                 :            : 
     412                 :            :         /*   size_total -- all video memory we have. Used for
     413                 :            :          *                 entries, ressource allocation and bounds
     414                 :            :          *                 checking. */
     415                 :          0 :         size_total = screen_info.lfb_size;
     416                 :          0 :         if (size_total < size_vmode)
     417                 :            :                 size_total = size_vmode;
     418                 :            : 
     419                 :            :         /*   size_remap -- the amount of video memory we are going to
     420                 :            :          *                 use for efifb.  With modern cards it is no
     421                 :            :          *                 option to simply use size_total as that
     422                 :            :          *                 wastes plenty of kernel address space. */
     423                 :          0 :         size_remap  = size_vmode * 2;
     424                 :          0 :         if (size_remap > size_total)
     425                 :            :                 size_remap = size_total;
     426         [ #  # ]:          0 :         if (size_remap % PAGE_SIZE)
     427                 :          0 :                 size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
     428                 :          0 :         efifb_fix.smem_len = size_remap;
     429                 :            : 
     430         [ #  # ]:          0 :         if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
     431                 :          0 :                 request_mem_succeeded = true;
     432                 :            :         } else {
     433                 :            :                 /* We cannot make this fatal. Sometimes this comes from magic
     434                 :            :                    spaces our resource handlers simply don't know about */
     435                 :          0 :                 pr_warn("efifb: cannot reserve video memory at 0x%lx\n",
     436                 :            :                         efifb_fix.smem_start);
     437                 :            :         }
     438                 :            : 
     439                 :          0 :         info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
     440         [ #  # ]:          0 :         if (!info) {
     441                 :          0 :                 err = -ENOMEM;
     442                 :          0 :                 goto err_release_mem;
     443                 :            :         }
     444                 :          0 :         platform_set_drvdata(dev, info);
     445                 :          0 :         info->pseudo_palette = info->par;
     446                 :          0 :         info->par = NULL;
     447                 :            : 
     448                 :          0 :         info->apertures = alloc_apertures(1);
     449         [ #  # ]:          0 :         if (!info->apertures) {
     450                 :          0 :                 err = -ENOMEM;
     451                 :          0 :                 goto err_release_fb;
     452                 :            :         }
     453                 :          0 :         info->apertures->ranges[0].base = efifb_fix.smem_start;
     454                 :          0 :         info->apertures->ranges[0].size = size_remap;
     455                 :            : 
     456   [ #  #  #  # ]:          0 :         if (efi_enabled(EFI_BOOT) &&
     457                 :          0 :             !efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
     458                 :          0 :                 if ((efifb_fix.smem_start + efifb_fix.smem_len) >
     459         [ #  # ]:          0 :                     (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
     460                 :          0 :                         pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
     461                 :            :                                efifb_fix.smem_start);
     462                 :          0 :                         err = -EIO;
     463                 :          0 :                         goto err_release_fb;
     464                 :            :                 }
     465                 :            :                 /*
     466                 :            :                  * If the UEFI memory map covers the efifb region, we may only
     467                 :            :                  * remap it using the attributes the memory map prescribes.
     468                 :            :                  */
     469                 :          0 :                 md.attribute &= EFI_MEMORY_UC | EFI_MEMORY_WC |
     470                 :            :                                 EFI_MEMORY_WT | EFI_MEMORY_WB;
     471         [ #  # ]:          0 :                 if (md.attribute) {
     472                 :          0 :                         mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
     473                 :          0 :                         mem_flags &= md.attribute;
     474                 :            :                 }
     475                 :            :         }
     476         [ #  # ]:          0 :         if (mem_flags & EFI_MEMORY_WC)
     477                 :          0 :                 info->screen_base = ioremap_wc(efifb_fix.smem_start,
     478                 :          0 :                                                efifb_fix.smem_len);
     479         [ #  # ]:          0 :         else if (mem_flags & EFI_MEMORY_UC)
     480                 :          0 :                 info->screen_base = ioremap(efifb_fix.smem_start,
     481                 :          0 :                                             efifb_fix.smem_len);
     482         [ #  # ]:          0 :         else if (mem_flags & EFI_MEMORY_WT)
     483                 :          0 :                 info->screen_base = memremap(efifb_fix.smem_start,
     484                 :          0 :                                              efifb_fix.smem_len, MEMREMAP_WT);
     485         [ #  # ]:          0 :         else if (mem_flags & EFI_MEMORY_WB)
     486                 :          0 :                 info->screen_base = memremap(efifb_fix.smem_start,
     487                 :          0 :                                              efifb_fix.smem_len, MEMREMAP_WB);
     488         [ #  # ]:          0 :         if (!info->screen_base) {
     489                 :          0 :                 pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
     490                 :            :                         efifb_fix.smem_len, efifb_fix.smem_start);
     491                 :          0 :                 err = -EIO;
     492                 :          0 :                 goto err_release_fb;
     493                 :            :         }
     494                 :            : 
     495                 :          0 :         efifb_show_boot_graphics(info);
     496                 :            : 
     497                 :          0 :         pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
     498                 :            :                efifb_fix.smem_start, size_remap/1024, size_total/1024);
     499                 :          0 :         pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
     500                 :            :                efifb_defined.xres, efifb_defined.yres,
     501                 :            :                efifb_defined.bits_per_pixel, efifb_fix.line_length,
     502                 :            :                screen_info.pages);
     503                 :            : 
     504                 :          0 :         efifb_defined.xres_virtual = efifb_defined.xres;
     505                 :          0 :         efifb_defined.yres_virtual = efifb_fix.smem_len /
     506                 :          0 :                                         efifb_fix.line_length;
     507                 :          0 :         pr_info("efifb: scrolling: redraw\n");
     508                 :          0 :         efifb_defined.yres_virtual = efifb_defined.yres;
     509                 :            : 
     510                 :            :         /* some dummy values for timing to make fbset happy */
     511                 :          0 :         efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
     512                 :          0 :                                         1000 / efifb_defined.yres;
     513                 :          0 :         efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
     514                 :          0 :         efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
     515                 :            : 
     516                 :          0 :         efifb_defined.red.offset    = screen_info.red_pos;
     517                 :          0 :         efifb_defined.red.length    = screen_info.red_size;
     518                 :          0 :         efifb_defined.green.offset  = screen_info.green_pos;
     519                 :          0 :         efifb_defined.green.length  = screen_info.green_size;
     520                 :          0 :         efifb_defined.blue.offset   = screen_info.blue_pos;
     521                 :          0 :         efifb_defined.blue.length   = screen_info.blue_size;
     522                 :          0 :         efifb_defined.transp.offset = screen_info.rsvd_pos;
     523                 :          0 :         efifb_defined.transp.length = screen_info.rsvd_size;
     524                 :            : 
     525                 :          0 :         pr_info("efifb: %s: "
     526                 :            :                "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
     527                 :            :                "Truecolor",
     528                 :            :                screen_info.rsvd_size,
     529                 :            :                screen_info.red_size,
     530                 :            :                screen_info.green_size,
     531                 :            :                screen_info.blue_size,
     532                 :            :                screen_info.rsvd_pos,
     533                 :            :                screen_info.red_pos,
     534                 :            :                screen_info.green_pos,
     535                 :            :                screen_info.blue_pos);
     536                 :            : 
     537                 :          0 :         efifb_fix.ypanstep  = 0;
     538                 :          0 :         efifb_fix.ywrapstep = 0;
     539                 :            : 
     540                 :          0 :         info->fbops = &efifb_ops;
     541                 :          0 :         info->var = efifb_defined;
     542                 :          0 :         info->fix = efifb_fix;
     543                 :          0 :         info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
     544                 :            : 
     545                 :          0 :         orientation = drm_get_panel_orientation_quirk(efifb_defined.xres,
     546                 :          0 :                                                       efifb_defined.yres);
     547   [ #  #  #  # ]:          0 :         switch (orientation) {
     548                 :          0 :         default:
     549                 :          0 :                 info->fbcon_rotate_hint = FB_ROTATE_UR;
     550                 :          0 :                 break;
     551                 :          0 :         case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
     552                 :          0 :                 info->fbcon_rotate_hint = FB_ROTATE_UD;
     553                 :          0 :                 break;
     554                 :          0 :         case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
     555                 :          0 :                 info->fbcon_rotate_hint = FB_ROTATE_CCW;
     556                 :          0 :                 break;
     557                 :          0 :         case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
     558                 :          0 :                 info->fbcon_rotate_hint = FB_ROTATE_CW;
     559                 :          0 :                 break;
     560                 :            :         }
     561                 :            : 
     562                 :          0 :         err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
     563         [ #  # ]:          0 :         if (err) {
     564                 :          0 :                 pr_err("efifb: cannot add sysfs attrs\n");
     565                 :          0 :                 goto err_unmap;
     566                 :            :         }
     567                 :          0 :         err = fb_alloc_cmap(&info->cmap, 256, 0);
     568         [ #  # ]:          0 :         if (err < 0) {
     569                 :          0 :                 pr_err("efifb: cannot allocate colormap\n");
     570                 :          0 :                 goto err_groups;
     571                 :            :         }
     572                 :          0 :         err = register_framebuffer(info);
     573         [ #  # ]:          0 :         if (err < 0) {
     574                 :          0 :                 pr_err("efifb: cannot register framebuffer\n");
     575                 :          0 :                 goto err_fb_dealoc;
     576                 :            :         }
     577                 :          0 :         fb_info(info, "%s frame buffer device\n", info->fix.id);
     578                 :          0 :         return 0;
     579                 :            : 
     580                 :            : err_fb_dealoc:
     581                 :          0 :         fb_dealloc_cmap(&info->cmap);
     582                 :          0 : err_groups:
     583                 :          0 :         sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
     584                 :          0 : err_unmap:
     585         [ #  # ]:          0 :         if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
     586                 :          0 :                 iounmap(info->screen_base);
     587                 :            :         else
     588                 :          0 :                 memunmap(info->screen_base);
     589                 :          0 : err_release_fb:
     590                 :          0 :         framebuffer_release(info);
     591                 :          0 : err_release_mem:
     592         [ #  # ]:          0 :         if (request_mem_succeeded)
     593                 :          0 :                 release_mem_region(efifb_fix.smem_start, size_total);
     594                 :            :         return err;
     595                 :            : }
     596                 :            : 
     597                 :          0 : static int efifb_remove(struct platform_device *pdev)
     598                 :            : {
     599                 :          0 :         struct fb_info *info = platform_get_drvdata(pdev);
     600                 :            : 
     601                 :          0 :         unregister_framebuffer(info);
     602                 :          0 :         sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
     603                 :          0 :         framebuffer_release(info);
     604                 :            : 
     605                 :          0 :         return 0;
     606                 :            : }
     607                 :            : 
     608                 :            : static struct platform_driver efifb_driver = {
     609                 :            :         .driver = {
     610                 :            :                 .name = "efi-framebuffer",
     611                 :            :         },
     612                 :            :         .probe = efifb_probe,
     613                 :            :         .remove = efifb_remove,
     614                 :            : };
     615                 :            : 
     616                 :          3 : builtin_platform_driver(efifb_driver);
     617                 :            : 
     618                 :            : #if defined(CONFIG_PCI)
     619                 :            : 
     620                 :          0 : static void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset)
     621                 :            : {
     622                 :          0 :         u16 word;
     623                 :            : 
     624                 :          0 :         efifb_pci_dev = dev;
     625                 :            : 
     626                 :          0 :         pci_read_config_word(dev, PCI_COMMAND, &word);
     627         [ #  # ]:          0 :         if (!(word & PCI_COMMAND_MEMORY)) {
     628                 :          0 :                 pci_dev_disabled = true;
     629                 :          0 :                 dev_err(&dev->dev,
     630                 :            :                         "BAR %d: assigned to efifb but device is disabled!\n",
     631                 :            :                         idx);
     632                 :          0 :                 return;
     633                 :            :         }
     634                 :            : 
     635                 :          0 :         bar_resource = &dev->resource[idx];
     636                 :          0 :         bar_offset = offset;
     637                 :            : 
     638                 :          0 :         dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx);
     639                 :            : }
     640                 :            : 
     641                 :          3 : static void efifb_fixup_resources(struct pci_dev *dev)
     642                 :            : {
     643                 :          3 :         u64 base = screen_info.lfb_base;
     644                 :          3 :         u64 size = screen_info.lfb_size;
     645                 :          3 :         int i;
     646                 :            : 
     647   [ +  -  -  + ]:          3 :         if (efifb_pci_dev || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
     648                 :            :                 return;
     649                 :            : 
     650         [ #  # ]:          0 :         if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
     651                 :          0 :                 base |= (u64)screen_info.ext_lfb_base << 32;
     652                 :            : 
     653         [ #  # ]:          0 :         if (!base)
     654                 :            :                 return;
     655                 :            : 
     656         [ #  # ]:          0 :         for (i = 0; i < PCI_STD_NUM_BARS; i++) {
     657                 :          0 :                 struct resource *res = &dev->resource[i];
     658                 :            : 
     659         [ #  # ]:          0 :                 if (!(res->flags & IORESOURCE_MEM))
     660                 :          0 :                         continue;
     661                 :            : 
     662   [ #  #  #  # ]:          0 :                 if (res->start <= base && res->end >= base + size - 1) {
     663                 :          0 :                         record_efifb_bar_resource(dev, i, base - res->start);
     664                 :          0 :                         break;
     665                 :            :                 }
     666                 :            :         }
     667                 :            : }
     668                 :            : DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY,
     669                 :            :                                16, efifb_fixup_resources);
     670                 :            : 
     671                 :            : #endif

Generated by: LCOV version 1.14