root/drivers/video/fbdev/efifb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. efifb_setcolreg
  2. efifb_copy_bmp
  3. efifb_bgrt_sanity_check
  4. efifb_bgrt_sanity_check
  5. efifb_show_boot_graphics
  6. efifb_show_boot_graphics
  7. efifb_destroy
  8. efifb_setup
  9. fb_base_is_valid
  10. efifb_probe
  11. efifb_remove
  12. record_efifb_bar_resource
  13. efifb_fixup_resources

   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 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         if (regno >= info->cmap.len)
  79                 return 1;
  80 
  81         if (regno < 16) {
  82                 red   >>= 16 - info->var.red.length;
  83                 green >>= 16 - info->var.green.length;
  84                 blue  >>= 16 - info->var.blue.length;
  85                 ((u32 *)(info->pseudo_palette))[regno] =
  86                         (red   << info->var.red.offset)   |
  87                         (green << info->var.green.offset) |
  88                         (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 static inline void efifb_show_boot_graphics(struct fb_info *info) {}
 242 #endif
 243 
 244 static void efifb_destroy(struct fb_info *info)
 245 {
 246         if (info->screen_base) {
 247                 if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
 248                         iounmap(info->screen_base);
 249                 else
 250                         memunmap(info->screen_base);
 251         }
 252         if (request_mem_succeeded)
 253                 release_mem_region(info->apertures->ranges[0].base,
 254                                    info->apertures->ranges[0].size);
 255         fb_dealloc_cmap(&info->cmap);
 256 }
 257 
 258 static 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 static int efifb_setup(char *options)
 268 {
 269         char *this_opt;
 270 
 271         if (options && *options) {
 272                 while ((this_opt = strsep(&options, ",")) != NULL) {
 273                         if (!*this_opt) continue;
 274 
 275                         efifb_setup_from_dmi(&screen_info, this_opt);
 276 
 277                         if (!strncmp(this_opt, "base:", 5))
 278                                 screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
 279                         else if (!strncmp(this_opt, "stride:", 7))
 280                                 screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
 281                         else if (!strncmp(this_opt, "height:", 7))
 282                                 screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
 283                         else if (!strncmp(this_opt, "width:", 6))
 284                                 screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
 285                         else if (!strcmp(this_opt, "nowc"))
 286                                 mem_flags &= ~EFI_MEMORY_WC;
 287                         else if (!strcmp(this_opt, "nobgrt"))
 288                                 use_bgrt = false;
 289                 }
 290         }
 291 
 292         return 0;
 293 }
 294 
 295 static inline bool fb_base_is_valid(void)
 296 {
 297         if (screen_info.lfb_base)
 298                 return true;
 299 
 300         if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
 301                 return false;
 302 
 303         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 efifb_attr_decl(base, "0x%x");
 319 efifb_attr_decl(linelength, "%u");
 320 efifb_attr_decl(height, "%u");
 321 efifb_attr_decl(width, "%u");
 322 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 static int efifb_probe(struct platform_device *dev)
 341 {
 342         struct fb_info *info;
 343         int err, orientation;
 344         unsigned int size_vmode;
 345         unsigned int size_remap;
 346         unsigned int size_total;
 347         char *option = NULL;
 348         efi_memory_desc_t md;
 349 
 350         if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
 351                 return -ENODEV;
 352 
 353         if (fb_get_options("efifb", &option))
 354                 return -ENODEV;
 355         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         if (!screen_info.lfb_linelength)
 362                 return -ENODEV;
 363 
 364         if (!screen_info.lfb_depth)
 365                 screen_info.lfb_depth = 32;
 366         if (!screen_info.pages)
 367                 screen_info.pages = 1;
 368         if (!fb_base_is_valid()) {
 369                 printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
 370                 return -ENODEV;
 371         }
 372         printk(KERN_INFO "efifb: probing for efifb\n");
 373 
 374         /* just assume they're all unset if any are */
 375         if (!screen_info.blue_size) {
 376                 screen_info.blue_size = 8;
 377                 screen_info.blue_pos = 0;
 378                 screen_info.green_size = 8;
 379                 screen_info.green_pos = 8;
 380                 screen_info.red_size = 8;
 381                 screen_info.red_pos = 16;
 382                 screen_info.rsvd_size = 8;
 383                 screen_info.rsvd_pos = 24;
 384         }
 385 
 386         efifb_fix.smem_start = screen_info.lfb_base;
 387 
 388         if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
 389                 u64 ext_lfb_base;
 390 
 391                 ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
 392                 efifb_fix.smem_start |= ext_lfb_base;
 393         }
 394 
 395         if (bar_resource &&
 396             bar_resource->start + bar_offset != efifb_fix.smem_start) {
 397                 dev_info(&efifb_pci_dev->dev,
 398                          "BAR has moved, updating efifb address\n");
 399                 efifb_fix.smem_start = bar_resource->start + bar_offset;
 400         }
 401 
 402         efifb_defined.bits_per_pixel = screen_info.lfb_depth;
 403         efifb_defined.xres = screen_info.lfb_width;
 404         efifb_defined.yres = screen_info.lfb_height;
 405         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         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         size_total = screen_info.lfb_size;
 416         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         size_remap  = size_vmode * 2;
 424         if (size_remap > size_total)
 425                 size_remap = size_total;
 426         if (size_remap % PAGE_SIZE)
 427                 size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
 428         efifb_fix.smem_len = size_remap;
 429 
 430         if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
 431                 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                 pr_warn("efifb: cannot reserve video memory at 0x%lx\n",
 436                         efifb_fix.smem_start);
 437         }
 438 
 439         info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
 440         if (!info) {
 441                 err = -ENOMEM;
 442                 goto err_release_mem;
 443         }
 444         platform_set_drvdata(dev, info);
 445         info->pseudo_palette = info->par;
 446         info->par = NULL;
 447 
 448         info->apertures = alloc_apertures(1);
 449         if (!info->apertures) {
 450                 err = -ENOMEM;
 451                 goto err_release_fb;
 452         }
 453         info->apertures->ranges[0].base = efifb_fix.smem_start;
 454         info->apertures->ranges[0].size = size_remap;
 455 
 456         if (efi_enabled(EFI_BOOT) &&
 457             !efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
 458                 if ((efifb_fix.smem_start + efifb_fix.smem_len) >
 459                     (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
 460                         pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
 461                                efifb_fix.smem_start);
 462                         err = -EIO;
 463                         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                 md.attribute &= EFI_MEMORY_UC | EFI_MEMORY_WC |
 470                                 EFI_MEMORY_WT | EFI_MEMORY_WB;
 471                 if (md.attribute) {
 472                         mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
 473                         mem_flags &= md.attribute;
 474                 }
 475         }
 476         if (mem_flags & EFI_MEMORY_WC)
 477                 info->screen_base = ioremap_wc(efifb_fix.smem_start,
 478                                                efifb_fix.smem_len);
 479         else if (mem_flags & EFI_MEMORY_UC)
 480                 info->screen_base = ioremap(efifb_fix.smem_start,
 481                                             efifb_fix.smem_len);
 482         else if (mem_flags & EFI_MEMORY_WT)
 483                 info->screen_base = memremap(efifb_fix.smem_start,
 484                                              efifb_fix.smem_len, MEMREMAP_WT);
 485         else if (mem_flags & EFI_MEMORY_WB)
 486                 info->screen_base = memremap(efifb_fix.smem_start,
 487                                              efifb_fix.smem_len, MEMREMAP_WB);
 488         if (!info->screen_base) {
 489                 pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
 490                         efifb_fix.smem_len, efifb_fix.smem_start);
 491                 err = -EIO;
 492                 goto err_release_fb;
 493         }
 494 
 495         efifb_show_boot_graphics(info);
 496 
 497         pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
 498                efifb_fix.smem_start, size_remap/1024, size_total/1024);
 499         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         efifb_defined.xres_virtual = efifb_defined.xres;
 505         efifb_defined.yres_virtual = efifb_fix.smem_len /
 506                                         efifb_fix.line_length;
 507         pr_info("efifb: scrolling: redraw\n");
 508         efifb_defined.yres_virtual = efifb_defined.yres;
 509 
 510         /* some dummy values for timing to make fbset happy */
 511         efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
 512                                         1000 / efifb_defined.yres;
 513         efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
 514         efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
 515 
 516         efifb_defined.red.offset    = screen_info.red_pos;
 517         efifb_defined.red.length    = screen_info.red_size;
 518         efifb_defined.green.offset  = screen_info.green_pos;
 519         efifb_defined.green.length  = screen_info.green_size;
 520         efifb_defined.blue.offset   = screen_info.blue_pos;
 521         efifb_defined.blue.length   = screen_info.blue_size;
 522         efifb_defined.transp.offset = screen_info.rsvd_pos;
 523         efifb_defined.transp.length = screen_info.rsvd_size;
 524 
 525         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         efifb_fix.ypanstep  = 0;
 538         efifb_fix.ywrapstep = 0;
 539 
 540         info->fbops = &efifb_ops;
 541         info->var = efifb_defined;
 542         info->fix = efifb_fix;
 543         info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
 544 
 545         orientation = drm_get_panel_orientation_quirk(efifb_defined.xres,
 546                                                       efifb_defined.yres);
 547         switch (orientation) {
 548         default:
 549                 info->fbcon_rotate_hint = FB_ROTATE_UR;
 550                 break;
 551         case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
 552                 info->fbcon_rotate_hint = FB_ROTATE_UD;
 553                 break;
 554         case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
 555                 info->fbcon_rotate_hint = FB_ROTATE_CCW;
 556                 break;
 557         case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
 558                 info->fbcon_rotate_hint = FB_ROTATE_CW;
 559                 break;
 560         }
 561 
 562         err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
 563         if (err) {
 564                 pr_err("efifb: cannot add sysfs attrs\n");
 565                 goto err_unmap;
 566         }
 567         err = fb_alloc_cmap(&info->cmap, 256, 0);
 568         if (err < 0) {
 569                 pr_err("efifb: cannot allocate colormap\n");
 570                 goto err_groups;
 571         }
 572         err = register_framebuffer(info);
 573         if (err < 0) {
 574                 pr_err("efifb: cannot register framebuffer\n");
 575                 goto err_fb_dealoc;
 576         }
 577         fb_info(info, "%s frame buffer device\n", info->fix.id);
 578         return 0;
 579 
 580 err_fb_dealoc:
 581         fb_dealloc_cmap(&info->cmap);
 582 err_groups:
 583         sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
 584 err_unmap:
 585         if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
 586                 iounmap(info->screen_base);
 587         else
 588                 memunmap(info->screen_base);
 589 err_release_fb:
 590         framebuffer_release(info);
 591 err_release_mem:
 592         if (request_mem_succeeded)
 593                 release_mem_region(efifb_fix.smem_start, size_total);
 594         return err;
 595 }
 596 
 597 static int efifb_remove(struct platform_device *pdev)
 598 {
 599         struct fb_info *info = platform_get_drvdata(pdev);
 600 
 601         unregister_framebuffer(info);
 602         sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
 603         framebuffer_release(info);
 604 
 605         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 builtin_platform_driver(efifb_driver);
 617 
 618 #if defined(CONFIG_PCI)
 619 
 620 static void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset)
 621 {
 622         u16 word;
 623 
 624         efifb_pci_dev = dev;
 625 
 626         pci_read_config_word(dev, PCI_COMMAND, &word);
 627         if (!(word & PCI_COMMAND_MEMORY)) {
 628                 pci_dev_disabled = true;
 629                 dev_err(&dev->dev,
 630                         "BAR %d: assigned to efifb but device is disabled!\n",
 631                         idx);
 632                 return;
 633         }
 634 
 635         bar_resource = &dev->resource[idx];
 636         bar_offset = offset;
 637 
 638         dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx);
 639 }
 640 
 641 static void efifb_fixup_resources(struct pci_dev *dev)
 642 {
 643         u64 base = screen_info.lfb_base;
 644         u64 size = screen_info.lfb_size;
 645         int i;
 646 
 647         if (efifb_pci_dev || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
 648                 return;
 649 
 650         if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
 651                 base |= (u64)screen_info.ext_lfb_base << 32;
 652 
 653         if (!base)
 654                 return;
 655 
 656         for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
 657                 struct resource *res = &dev->resource[i];
 658 
 659                 if (!(res->flags & IORESOURCE_MEM))
 660                         continue;
 661 
 662                 if (res->start <= base && res->end >= base + size - 1) {
 663                         record_efifb_bar_resource(dev, i, base - res->start);
 664                         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

/* [<][>][^][v][top][bottom][index][help] */