18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Framebuffer driver for EFI/UEFI based system 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (c) 2006 Edgar Hucek <gimli@dark-green.com> 68c2ecf20Sopenharmony_ci * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/efi.h> 128c2ecf20Sopenharmony_ci#include <linux/efi-bgrt.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/fb.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/printk.h> 188c2ecf20Sopenharmony_ci#include <linux/screen_info.h> 198c2ecf20Sopenharmony_ci#include <video/vga.h> 208c2ecf20Sopenharmony_ci#include <asm/efi.h> 218c2ecf20Sopenharmony_ci#include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */ 228c2ecf20Sopenharmony_ci#include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct bmp_file_header { 258c2ecf20Sopenharmony_ci u16 id; 268c2ecf20Sopenharmony_ci u32 file_size; 278c2ecf20Sopenharmony_ci u32 reserved; 288c2ecf20Sopenharmony_ci u32 bitmap_offset; 298c2ecf20Sopenharmony_ci} __packed; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct bmp_dib_header { 328c2ecf20Sopenharmony_ci u32 dib_header_size; 338c2ecf20Sopenharmony_ci s32 width; 348c2ecf20Sopenharmony_ci s32 height; 358c2ecf20Sopenharmony_ci u16 planes; 368c2ecf20Sopenharmony_ci u16 bpp; 378c2ecf20Sopenharmony_ci u32 compression; 388c2ecf20Sopenharmony_ci u32 bitmap_size; 398c2ecf20Sopenharmony_ci u32 horz_resolution; 408c2ecf20Sopenharmony_ci u32 vert_resolution; 418c2ecf20Sopenharmony_ci u32 colors_used; 428c2ecf20Sopenharmony_ci u32 colors_important; 438c2ecf20Sopenharmony_ci} __packed; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic bool use_bgrt = true; 468c2ecf20Sopenharmony_cistatic bool request_mem_succeeded = false; 478c2ecf20Sopenharmony_cistatic u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic struct fb_var_screeninfo efifb_defined = { 508c2ecf20Sopenharmony_ci .activate = FB_ACTIVATE_NOW, 518c2ecf20Sopenharmony_ci .height = -1, 528c2ecf20Sopenharmony_ci .width = -1, 538c2ecf20Sopenharmony_ci .right_margin = 32, 548c2ecf20Sopenharmony_ci .upper_margin = 16, 558c2ecf20Sopenharmony_ci .lower_margin = 4, 568c2ecf20Sopenharmony_ci .vsync_len = 4, 578c2ecf20Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic struct fb_fix_screeninfo efifb_fix = { 618c2ecf20Sopenharmony_ci .id = "EFI VGA", 628c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 638c2ecf20Sopenharmony_ci .accel = FB_ACCEL_NONE, 648c2ecf20Sopenharmony_ci .visual = FB_VISUAL_TRUECOLOR, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, 688c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, 698c2ecf20Sopenharmony_ci struct fb_info *info) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * Set a single color register. The values supplied are 738c2ecf20Sopenharmony_ci * already rounded down to the hardware's capabilities 748c2ecf20Sopenharmony_ci * (according to the entries in the `var' structure). Return 758c2ecf20Sopenharmony_ci * != 0 for invalid regno. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (regno >= info->cmap.len) 798c2ecf20Sopenharmony_ci return 1; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (regno < 16) { 828c2ecf20Sopenharmony_ci red >>= 16 - info->var.red.length; 838c2ecf20Sopenharmony_ci green >>= 16 - info->var.green.length; 848c2ecf20Sopenharmony_ci blue >>= 16 - info->var.blue.length; 858c2ecf20Sopenharmony_ci ((u32 *)(info->pseudo_palette))[regno] = 868c2ecf20Sopenharmony_ci (red << info->var.red.offset) | 878c2ecf20Sopenharmony_ci (green << info->var.green.offset) | 888c2ecf20Sopenharmony_ci (blue << info->var.blue.offset); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * If fbcon deffered console takeover is configured, the intent is for the 958c2ecf20Sopenharmony_ci * framebuffer to show the boot graphics (e.g. vendor logo) until there is some 968c2ecf20Sopenharmony_ci * (error) message to display. But the boot graphics may have been destroyed by 978c2ecf20Sopenharmony_ci * e.g. option ROM output, detect this and restore the boot graphics. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ 1008c2ecf20Sopenharmony_ci defined CONFIG_ACPI_BGRT 1018c2ecf20Sopenharmony_cistatic void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci u8 r, g, b; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci while (width--) { 1068c2ecf20Sopenharmony_ci b = *src++; 1078c2ecf20Sopenharmony_ci g = *src++; 1088c2ecf20Sopenharmony_ci r = *src++; 1098c2ecf20Sopenharmony_ci *dst++ = (r << si->red_pos) | 1108c2ecf20Sopenharmony_ci (g << si->green_pos) | 1118c2ecf20Sopenharmony_ci (b << si->blue_pos); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#ifdef CONFIG_X86 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * On x86 some firmwares use a low non native resolution for the display when 1188c2ecf20Sopenharmony_ci * they have shown some text messages. While keeping the bgrt filled with info 1198c2ecf20Sopenharmony_ci * for the native resolution. If the bgrt image intended for the native 1208c2ecf20Sopenharmony_ci * resolution still fits, it will be displayed very close to the right edge of 1218c2ecf20Sopenharmony_ci * the display looking quite bad. This function checks for this. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cistatic bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * All x86 firmwares horizontally center the image (the yoffset 1278c2ecf20Sopenharmony_ci * calculations differ between boards, but xoffset is predictable). 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci u32 expected_xoffset = (si->lfb_width - bmp_width) / 2; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return bgrt_tab.image_offset_x == expected_xoffset; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci#else 1348c2ecf20Sopenharmony_cistatic bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return true; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci#endif 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void efifb_show_boot_graphics(struct fb_info *info) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y; 1438c2ecf20Sopenharmony_ci struct screen_info *si = &screen_info; 1448c2ecf20Sopenharmony_ci struct bmp_file_header *file_header; 1458c2ecf20Sopenharmony_ci struct bmp_dib_header *dib_header; 1468c2ecf20Sopenharmony_ci void *bgrt_image = NULL; 1478c2ecf20Sopenharmony_ci u8 *dst = info->screen_base; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (!use_bgrt) 1508c2ecf20Sopenharmony_ci return; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (!bgrt_tab.image_address) { 1538c2ecf20Sopenharmony_ci pr_info("efifb: No BGRT, not showing boot graphics\n"); 1548c2ecf20Sopenharmony_ci return; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (bgrt_tab.status & 0x06) { 1588c2ecf20Sopenharmony_ci pr_info("efifb: BGRT rotation bits set, not showing boot graphics\n"); 1598c2ecf20Sopenharmony_ci return; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Avoid flashing the logo if we're going to print std probe messages */ 1638c2ecf20Sopenharmony_ci if (console_loglevel > CONSOLE_LOGLEVEL_QUIET) 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* bgrt_tab.status is unreliable, so we don't check it */ 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (si->lfb_depth != 32) { 1698c2ecf20Sopenharmony_ci pr_info("efifb: not 32 bits, not showing boot graphics\n"); 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size, 1748c2ecf20Sopenharmony_ci MEMREMAP_WB); 1758c2ecf20Sopenharmony_ci if (!bgrt_image) { 1768c2ecf20Sopenharmony_ci pr_warn("efifb: Ignoring BGRT: failed to map image memory\n"); 1778c2ecf20Sopenharmony_ci return; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header))) 1818c2ecf20Sopenharmony_ci goto error; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci file_header = bgrt_image; 1848c2ecf20Sopenharmony_ci if (file_header->id != 0x4d42 || file_header->reserved != 0) 1858c2ecf20Sopenharmony_ci goto error; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci dib_header = bgrt_image + sizeof(*file_header); 1888c2ecf20Sopenharmony_ci if (dib_header->dib_header_size != 40 || dib_header->width < 0 || 1898c2ecf20Sopenharmony_ci dib_header->planes != 1 || dib_header->bpp != 24 || 1908c2ecf20Sopenharmony_ci dib_header->compression != 0) 1918c2ecf20Sopenharmony_ci goto error; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci bmp_width = dib_header->width; 1948c2ecf20Sopenharmony_ci bmp_height = abs(dib_header->height); 1958c2ecf20Sopenharmony_ci bmp_pitch = round_up(3 * bmp_width, 4); 1968c2ecf20Sopenharmony_ci screen_pitch = si->lfb_linelength; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if ((file_header->bitmap_offset + bmp_pitch * bmp_height) > 1998c2ecf20Sopenharmony_ci bgrt_image_size) 2008c2ecf20Sopenharmony_ci goto error; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width || 2038c2ecf20Sopenharmony_ci (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height) 2048c2ecf20Sopenharmony_ci goto error; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (!efifb_bgrt_sanity_check(si, bmp_width)) 2078c2ecf20Sopenharmony_ci goto error; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci pr_info("efifb: showing boot graphics\n"); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) { 2128c2ecf20Sopenharmony_ci /* Only background? */ 2138c2ecf20Sopenharmony_ci if (y < bgrt_tab.image_offset_y || 2148c2ecf20Sopenharmony_ci y >= (bgrt_tab.image_offset_y + bmp_height)) { 2158c2ecf20Sopenharmony_ci memset(dst, 0, 4 * si->lfb_width); 2168c2ecf20Sopenharmony_ci continue; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci src_y = y - bgrt_tab.image_offset_y; 2208c2ecf20Sopenharmony_ci /* Positive header height means upside down row order */ 2218c2ecf20Sopenharmony_ci if (dib_header->height > 0) 2228c2ecf20Sopenharmony_ci src_y = (bmp_height - 1) - src_y; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci memset(dst, 0, bgrt_tab.image_offset_x * 4); 2258c2ecf20Sopenharmony_ci dst_x = bgrt_tab.image_offset_x; 2268c2ecf20Sopenharmony_ci efifb_copy_bmp(bgrt_image + file_header->bitmap_offset + 2278c2ecf20Sopenharmony_ci src_y * bmp_pitch, 2288c2ecf20Sopenharmony_ci (u32 *)dst + dst_x, bmp_width, si); 2298c2ecf20Sopenharmony_ci dst_x += bmp_width; 2308c2ecf20Sopenharmony_ci memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci memunmap(bgrt_image); 2348c2ecf20Sopenharmony_ci return; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cierror: 2378c2ecf20Sopenharmony_ci memunmap(bgrt_image); 2388c2ecf20Sopenharmony_ci pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n"); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci#else 2418c2ecf20Sopenharmony_cistatic inline void efifb_show_boot_graphics(struct fb_info *info) {} 2428c2ecf20Sopenharmony_ci#endif 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void efifb_destroy(struct fb_info *info) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci if (info->screen_base) { 2478c2ecf20Sopenharmony_ci if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC)) 2488c2ecf20Sopenharmony_ci iounmap(info->screen_base); 2498c2ecf20Sopenharmony_ci else 2508c2ecf20Sopenharmony_ci memunmap(info->screen_base); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci if (request_mem_succeeded) 2538c2ecf20Sopenharmony_ci release_mem_region(info->apertures->ranges[0].base, 2548c2ecf20Sopenharmony_ci info->apertures->ranges[0].size); 2558c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic const struct fb_ops efifb_ops = { 2598c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2608c2ecf20Sopenharmony_ci .fb_destroy = efifb_destroy, 2618c2ecf20Sopenharmony_ci .fb_setcolreg = efifb_setcolreg, 2628c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 2638c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 2648c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 2658c2ecf20Sopenharmony_ci}; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int efifb_setup(char *options) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci char *this_opt; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (options && *options) { 2728c2ecf20Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 2738c2ecf20Sopenharmony_ci if (!*this_opt) continue; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci efifb_setup_from_dmi(&screen_info, this_opt); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (!strncmp(this_opt, "base:", 5)) 2788c2ecf20Sopenharmony_ci screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0); 2798c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "stride:", 7)) 2808c2ecf20Sopenharmony_ci screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4; 2818c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "height:", 7)) 2828c2ecf20Sopenharmony_ci screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0); 2838c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "width:", 6)) 2848c2ecf20Sopenharmony_ci screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); 2858c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "nowc")) 2868c2ecf20Sopenharmony_ci mem_flags &= ~EFI_MEMORY_WC; 2878c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "nobgrt")) 2888c2ecf20Sopenharmony_ci use_bgrt = false; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic inline bool fb_base_is_valid(void) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci if (screen_info.lfb_base) 2988c2ecf20Sopenharmony_ci return true; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)) 3018c2ecf20Sopenharmony_ci return false; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (screen_info.ext_lfb_base) 3048c2ecf20Sopenharmony_ci return true; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return false; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define efifb_attr_decl(name, fmt) \ 3108c2ecf20Sopenharmony_cistatic ssize_t name##_show(struct device *dev, \ 3118c2ecf20Sopenharmony_ci struct device_attribute *attr, \ 3128c2ecf20Sopenharmony_ci char *buf) \ 3138c2ecf20Sopenharmony_ci{ \ 3148c2ecf20Sopenharmony_ci return sprintf(buf, fmt "\n", (screen_info.lfb_##name)); \ 3158c2ecf20Sopenharmony_ci} \ 3168c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name) 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ciefifb_attr_decl(base, "0x%x"); 3198c2ecf20Sopenharmony_ciefifb_attr_decl(linelength, "%u"); 3208c2ecf20Sopenharmony_ciefifb_attr_decl(height, "%u"); 3218c2ecf20Sopenharmony_ciefifb_attr_decl(width, "%u"); 3228c2ecf20Sopenharmony_ciefifb_attr_decl(depth, "%u"); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic struct attribute *efifb_attrs[] = { 3258c2ecf20Sopenharmony_ci &dev_attr_base.attr, 3268c2ecf20Sopenharmony_ci &dev_attr_linelength.attr, 3278c2ecf20Sopenharmony_ci &dev_attr_width.attr, 3288c2ecf20Sopenharmony_ci &dev_attr_height.attr, 3298c2ecf20Sopenharmony_ci &dev_attr_depth.attr, 3308c2ecf20Sopenharmony_ci NULL 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(efifb); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic bool pci_dev_disabled; /* FB base matches BAR of a disabled device */ 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */ 3378c2ecf20Sopenharmony_cistatic struct resource *bar_resource; 3388c2ecf20Sopenharmony_cistatic u64 bar_offset; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int efifb_probe(struct platform_device *dev) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct fb_info *info; 3438c2ecf20Sopenharmony_ci int err, orientation; 3448c2ecf20Sopenharmony_ci unsigned int size_vmode; 3458c2ecf20Sopenharmony_ci unsigned int size_remap; 3468c2ecf20Sopenharmony_ci unsigned int size_total; 3478c2ecf20Sopenharmony_ci char *option = NULL; 3488c2ecf20Sopenharmony_ci efi_memory_desc_t md; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) 3518c2ecf20Sopenharmony_ci return -ENODEV; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (fb_get_options("efifb", &option)) 3548c2ecf20Sopenharmony_ci return -ENODEV; 3558c2ecf20Sopenharmony_ci efifb_setup(option); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* We don't get linelength from UGA Draw Protocol, only from 3588c2ecf20Sopenharmony_ci * EFI Graphics Protocol. So if it's not in DMI, and it's not 3598c2ecf20Sopenharmony_ci * passed in from the user, we really can't use the framebuffer. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci if (!screen_info.lfb_linelength) 3628c2ecf20Sopenharmony_ci return -ENODEV; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (!screen_info.lfb_depth) 3658c2ecf20Sopenharmony_ci screen_info.lfb_depth = 32; 3668c2ecf20Sopenharmony_ci if (!screen_info.pages) 3678c2ecf20Sopenharmony_ci screen_info.pages = 1; 3688c2ecf20Sopenharmony_ci if (!fb_base_is_valid()) { 3698c2ecf20Sopenharmony_ci printk(KERN_DEBUG "efifb: invalid framebuffer address\n"); 3708c2ecf20Sopenharmony_ci return -ENODEV; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci printk(KERN_INFO "efifb: probing for efifb\n"); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* just assume they're all unset if any are */ 3758c2ecf20Sopenharmony_ci if (!screen_info.blue_size) { 3768c2ecf20Sopenharmony_ci screen_info.blue_size = 8; 3778c2ecf20Sopenharmony_ci screen_info.blue_pos = 0; 3788c2ecf20Sopenharmony_ci screen_info.green_size = 8; 3798c2ecf20Sopenharmony_ci screen_info.green_pos = 8; 3808c2ecf20Sopenharmony_ci screen_info.red_size = 8; 3818c2ecf20Sopenharmony_ci screen_info.red_pos = 16; 3828c2ecf20Sopenharmony_ci screen_info.rsvd_size = 8; 3838c2ecf20Sopenharmony_ci screen_info.rsvd_pos = 24; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci efifb_fix.smem_start = screen_info.lfb_base; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) { 3898c2ecf20Sopenharmony_ci u64 ext_lfb_base; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32; 3928c2ecf20Sopenharmony_ci efifb_fix.smem_start |= ext_lfb_base; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (bar_resource && 3968c2ecf20Sopenharmony_ci bar_resource->start + bar_offset != efifb_fix.smem_start) { 3978c2ecf20Sopenharmony_ci dev_info(&efifb_pci_dev->dev, 3988c2ecf20Sopenharmony_ci "BAR has moved, updating efifb address\n"); 3998c2ecf20Sopenharmony_ci efifb_fix.smem_start = bar_resource->start + bar_offset; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci efifb_defined.bits_per_pixel = screen_info.lfb_depth; 4038c2ecf20Sopenharmony_ci efifb_defined.xres = screen_info.lfb_width; 4048c2ecf20Sopenharmony_ci efifb_defined.yres = screen_info.lfb_height; 4058c2ecf20Sopenharmony_ci efifb_fix.line_length = screen_info.lfb_linelength; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* size_vmode -- that is the amount of memory needed for the 4088c2ecf20Sopenharmony_ci * used video mode, i.e. the minimum amount of 4098c2ecf20Sopenharmony_ci * memory we need. */ 4108c2ecf20Sopenharmony_ci size_vmode = efifb_defined.yres * efifb_fix.line_length; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* size_total -- all video memory we have. Used for 4138c2ecf20Sopenharmony_ci * entries, ressource allocation and bounds 4148c2ecf20Sopenharmony_ci * checking. */ 4158c2ecf20Sopenharmony_ci size_total = screen_info.lfb_size; 4168c2ecf20Sopenharmony_ci if (size_total < size_vmode) 4178c2ecf20Sopenharmony_ci size_total = size_vmode; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* size_remap -- the amount of video memory we are going to 4208c2ecf20Sopenharmony_ci * use for efifb. With modern cards it is no 4218c2ecf20Sopenharmony_ci * option to simply use size_total as that 4228c2ecf20Sopenharmony_ci * wastes plenty of kernel address space. */ 4238c2ecf20Sopenharmony_ci size_remap = size_vmode * 2; 4248c2ecf20Sopenharmony_ci if (size_remap > size_total) 4258c2ecf20Sopenharmony_ci size_remap = size_total; 4268c2ecf20Sopenharmony_ci if (size_remap % PAGE_SIZE) 4278c2ecf20Sopenharmony_ci size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE); 4288c2ecf20Sopenharmony_ci efifb_fix.smem_len = size_remap; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) { 4318c2ecf20Sopenharmony_ci request_mem_succeeded = true; 4328c2ecf20Sopenharmony_ci } else { 4338c2ecf20Sopenharmony_ci /* We cannot make this fatal. Sometimes this comes from magic 4348c2ecf20Sopenharmony_ci spaces our resource handlers simply don't know about */ 4358c2ecf20Sopenharmony_ci pr_warn("efifb: cannot reserve video memory at 0x%lx\n", 4368c2ecf20Sopenharmony_ci efifb_fix.smem_start); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); 4408c2ecf20Sopenharmony_ci if (!info) { 4418c2ecf20Sopenharmony_ci err = -ENOMEM; 4428c2ecf20Sopenharmony_ci goto err_release_mem; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci platform_set_drvdata(dev, info); 4458c2ecf20Sopenharmony_ci info->pseudo_palette = info->par; 4468c2ecf20Sopenharmony_ci info->par = NULL; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci info->apertures = alloc_apertures(1); 4498c2ecf20Sopenharmony_ci if (!info->apertures) { 4508c2ecf20Sopenharmony_ci err = -ENOMEM; 4518c2ecf20Sopenharmony_ci goto err_release_fb; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci info->apertures->ranges[0].base = efifb_fix.smem_start; 4548c2ecf20Sopenharmony_ci info->apertures->ranges[0].size = size_remap; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (efi_enabled(EFI_MEMMAP) && 4578c2ecf20Sopenharmony_ci !efi_mem_desc_lookup(efifb_fix.smem_start, &md)) { 4588c2ecf20Sopenharmony_ci if ((efifb_fix.smem_start + efifb_fix.smem_len) > 4598c2ecf20Sopenharmony_ci (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) { 4608c2ecf20Sopenharmony_ci pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n", 4618c2ecf20Sopenharmony_ci efifb_fix.smem_start); 4628c2ecf20Sopenharmony_ci err = -EIO; 4638c2ecf20Sopenharmony_ci goto err_release_fb; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci /* 4668c2ecf20Sopenharmony_ci * If the UEFI memory map covers the efifb region, we may only 4678c2ecf20Sopenharmony_ci * remap it using the attributes the memory map prescribes. 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci md.attribute &= EFI_MEMORY_UC | EFI_MEMORY_WC | 4708c2ecf20Sopenharmony_ci EFI_MEMORY_WT | EFI_MEMORY_WB; 4718c2ecf20Sopenharmony_ci if (md.attribute) { 4728c2ecf20Sopenharmony_ci mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB; 4738c2ecf20Sopenharmony_ci mem_flags &= md.attribute; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci if (mem_flags & EFI_MEMORY_WC) 4778c2ecf20Sopenharmony_ci info->screen_base = ioremap_wc(efifb_fix.smem_start, 4788c2ecf20Sopenharmony_ci efifb_fix.smem_len); 4798c2ecf20Sopenharmony_ci else if (mem_flags & EFI_MEMORY_UC) 4808c2ecf20Sopenharmony_ci info->screen_base = ioremap(efifb_fix.smem_start, 4818c2ecf20Sopenharmony_ci efifb_fix.smem_len); 4828c2ecf20Sopenharmony_ci else if (mem_flags & EFI_MEMORY_WT) 4838c2ecf20Sopenharmony_ci info->screen_base = memremap(efifb_fix.smem_start, 4848c2ecf20Sopenharmony_ci efifb_fix.smem_len, MEMREMAP_WT); 4858c2ecf20Sopenharmony_ci else if (mem_flags & EFI_MEMORY_WB) 4868c2ecf20Sopenharmony_ci info->screen_base = memremap(efifb_fix.smem_start, 4878c2ecf20Sopenharmony_ci efifb_fix.smem_len, MEMREMAP_WB); 4888c2ecf20Sopenharmony_ci if (!info->screen_base) { 4898c2ecf20Sopenharmony_ci pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n", 4908c2ecf20Sopenharmony_ci efifb_fix.smem_len, efifb_fix.smem_start); 4918c2ecf20Sopenharmony_ci err = -EIO; 4928c2ecf20Sopenharmony_ci goto err_release_fb; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci efifb_show_boot_graphics(info); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n", 4988c2ecf20Sopenharmony_ci efifb_fix.smem_start, size_remap/1024, size_total/1024); 4998c2ecf20Sopenharmony_ci pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", 5008c2ecf20Sopenharmony_ci efifb_defined.xres, efifb_defined.yres, 5018c2ecf20Sopenharmony_ci efifb_defined.bits_per_pixel, efifb_fix.line_length, 5028c2ecf20Sopenharmony_ci screen_info.pages); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci efifb_defined.xres_virtual = efifb_defined.xres; 5058c2ecf20Sopenharmony_ci efifb_defined.yres_virtual = efifb_fix.smem_len / 5068c2ecf20Sopenharmony_ci efifb_fix.line_length; 5078c2ecf20Sopenharmony_ci pr_info("efifb: scrolling: redraw\n"); 5088c2ecf20Sopenharmony_ci efifb_defined.yres_virtual = efifb_defined.yres; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* some dummy values for timing to make fbset happy */ 5118c2ecf20Sopenharmony_ci efifb_defined.pixclock = 10000000 / efifb_defined.xres * 5128c2ecf20Sopenharmony_ci 1000 / efifb_defined.yres; 5138c2ecf20Sopenharmony_ci efifb_defined.left_margin = (efifb_defined.xres / 8) & 0xf8; 5148c2ecf20Sopenharmony_ci efifb_defined.hsync_len = (efifb_defined.xres / 8) & 0xf8; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci efifb_defined.red.offset = screen_info.red_pos; 5178c2ecf20Sopenharmony_ci efifb_defined.red.length = screen_info.red_size; 5188c2ecf20Sopenharmony_ci efifb_defined.green.offset = screen_info.green_pos; 5198c2ecf20Sopenharmony_ci efifb_defined.green.length = screen_info.green_size; 5208c2ecf20Sopenharmony_ci efifb_defined.blue.offset = screen_info.blue_pos; 5218c2ecf20Sopenharmony_ci efifb_defined.blue.length = screen_info.blue_size; 5228c2ecf20Sopenharmony_ci efifb_defined.transp.offset = screen_info.rsvd_pos; 5238c2ecf20Sopenharmony_ci efifb_defined.transp.length = screen_info.rsvd_size; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci pr_info("efifb: %s: " 5268c2ecf20Sopenharmony_ci "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", 5278c2ecf20Sopenharmony_ci "Truecolor", 5288c2ecf20Sopenharmony_ci screen_info.rsvd_size, 5298c2ecf20Sopenharmony_ci screen_info.red_size, 5308c2ecf20Sopenharmony_ci screen_info.green_size, 5318c2ecf20Sopenharmony_ci screen_info.blue_size, 5328c2ecf20Sopenharmony_ci screen_info.rsvd_pos, 5338c2ecf20Sopenharmony_ci screen_info.red_pos, 5348c2ecf20Sopenharmony_ci screen_info.green_pos, 5358c2ecf20Sopenharmony_ci screen_info.blue_pos); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci efifb_fix.ypanstep = 0; 5388c2ecf20Sopenharmony_ci efifb_fix.ywrapstep = 0; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci info->fbops = &efifb_ops; 5418c2ecf20Sopenharmony_ci info->var = efifb_defined; 5428c2ecf20Sopenharmony_ci info->fix = efifb_fix; 5438c2ecf20Sopenharmony_ci info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci orientation = drm_get_panel_orientation_quirk(efifb_defined.xres, 5468c2ecf20Sopenharmony_ci efifb_defined.yres); 5478c2ecf20Sopenharmony_ci switch (orientation) { 5488c2ecf20Sopenharmony_ci default: 5498c2ecf20Sopenharmony_ci info->fbcon_rotate_hint = FB_ROTATE_UR; 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP: 5528c2ecf20Sopenharmony_ci info->fbcon_rotate_hint = FB_ROTATE_UD; 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci case DRM_MODE_PANEL_ORIENTATION_LEFT_UP: 5558c2ecf20Sopenharmony_ci info->fbcon_rotate_hint = FB_ROTATE_CCW; 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP: 5588c2ecf20Sopenharmony_ci info->fbcon_rotate_hint = FB_ROTATE_CW; 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci err = sysfs_create_groups(&dev->dev.kobj, efifb_groups); 5638c2ecf20Sopenharmony_ci if (err) { 5648c2ecf20Sopenharmony_ci pr_err("efifb: cannot add sysfs attrs\n"); 5658c2ecf20Sopenharmony_ci goto err_unmap; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci err = fb_alloc_cmap(&info->cmap, 256, 0); 5688c2ecf20Sopenharmony_ci if (err < 0) { 5698c2ecf20Sopenharmony_ci pr_err("efifb: cannot allocate colormap\n"); 5708c2ecf20Sopenharmony_ci goto err_groups; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci err = register_framebuffer(info); 5738c2ecf20Sopenharmony_ci if (err < 0) { 5748c2ecf20Sopenharmony_ci pr_err("efifb: cannot register framebuffer\n"); 5758c2ecf20Sopenharmony_ci goto err_fb_dealoc; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci fb_info(info, "%s frame buffer device\n", info->fix.id); 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cierr_fb_dealoc: 5818c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 5828c2ecf20Sopenharmony_cierr_groups: 5838c2ecf20Sopenharmony_ci sysfs_remove_groups(&dev->dev.kobj, efifb_groups); 5848c2ecf20Sopenharmony_cierr_unmap: 5858c2ecf20Sopenharmony_ci if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC)) 5868c2ecf20Sopenharmony_ci iounmap(info->screen_base); 5878c2ecf20Sopenharmony_ci else 5888c2ecf20Sopenharmony_ci memunmap(info->screen_base); 5898c2ecf20Sopenharmony_cierr_release_fb: 5908c2ecf20Sopenharmony_ci framebuffer_release(info); 5918c2ecf20Sopenharmony_cierr_release_mem: 5928c2ecf20Sopenharmony_ci if (request_mem_succeeded) 5938c2ecf20Sopenharmony_ci release_mem_region(efifb_fix.smem_start, size_total); 5948c2ecf20Sopenharmony_ci return err; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int efifb_remove(struct platform_device *pdev) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct fb_info *info = platform_get_drvdata(pdev); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci unregister_framebuffer(info); 6028c2ecf20Sopenharmony_ci sysfs_remove_groups(&pdev->dev.kobj, efifb_groups); 6038c2ecf20Sopenharmony_ci framebuffer_release(info); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return 0; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic struct platform_driver efifb_driver = { 6098c2ecf20Sopenharmony_ci .driver = { 6108c2ecf20Sopenharmony_ci .name = "efi-framebuffer", 6118c2ecf20Sopenharmony_ci }, 6128c2ecf20Sopenharmony_ci .probe = efifb_probe, 6138c2ecf20Sopenharmony_ci .remove = efifb_remove, 6148c2ecf20Sopenharmony_ci}; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cibuiltin_platform_driver(efifb_driver); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci#if defined(CONFIG_PCI) 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci u16 word; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci efifb_pci_dev = dev; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci pci_read_config_word(dev, PCI_COMMAND, &word); 6278c2ecf20Sopenharmony_ci if (!(word & PCI_COMMAND_MEMORY)) { 6288c2ecf20Sopenharmony_ci pci_dev_disabled = true; 6298c2ecf20Sopenharmony_ci dev_err(&dev->dev, 6308c2ecf20Sopenharmony_ci "BAR %d: assigned to efifb but device is disabled!\n", 6318c2ecf20Sopenharmony_ci idx); 6328c2ecf20Sopenharmony_ci return; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci bar_resource = &dev->resource[idx]; 6368c2ecf20Sopenharmony_ci bar_offset = offset; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic void efifb_fixup_resources(struct pci_dev *dev) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci u64 base = screen_info.lfb_base; 6448c2ecf20Sopenharmony_ci u64 size = screen_info.lfb_size; 6458c2ecf20Sopenharmony_ci int i; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (efifb_pci_dev || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) 6488c2ecf20Sopenharmony_ci return; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) 6518c2ecf20Sopenharmony_ci base |= (u64)screen_info.ext_lfb_base << 32; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (!base) 6548c2ecf20Sopenharmony_ci return; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci for (i = 0; i < PCI_STD_NUM_BARS; i++) { 6578c2ecf20Sopenharmony_ci struct resource *res = &dev->resource[i]; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (!(res->flags & IORESOURCE_MEM)) 6608c2ecf20Sopenharmony_ci continue; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (res->start <= base && res->end >= base + size - 1) { 6638c2ecf20Sopenharmony_ci record_efifb_bar_resource(dev, i, base - res->start); 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 6698c2ecf20Sopenharmony_ci 16, efifb_fixup_resources); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci#endif 672