162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generic System Framebuffers 462306a36Sopenharmony_ci * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * EFI Quirks Copyright (c) 2006 Edgar Hucek <gimli@dark-green.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * EFI Quirks 1162306a36Sopenharmony_ci * Several EFI systems do not correctly advertise their boot framebuffers. 1262306a36Sopenharmony_ci * Hence, we use this static table of known broken machines and fix up the 1362306a36Sopenharmony_ci * information so framebuffer drivers can load correctly. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/dmi.h> 1762306a36Sopenharmony_ci#include <linux/err.h> 1862306a36Sopenharmony_ci#include <linux/efi.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/mm.h> 2262306a36Sopenharmony_ci#include <linux/of_address.h> 2362306a36Sopenharmony_ci#include <linux/pci.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/screen_info.h> 2662306a36Sopenharmony_ci#include <linux/sysfb.h> 2762306a36Sopenharmony_ci#include <video/vga.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cienum { 3062306a36Sopenharmony_ci OVERRIDE_NONE = 0x0, 3162306a36Sopenharmony_ci OVERRIDE_BASE = 0x1, 3262306a36Sopenharmony_ci OVERRIDE_STRIDE = 0x2, 3362306a36Sopenharmony_ci OVERRIDE_HEIGHT = 0x4, 3462306a36Sopenharmony_ci OVERRIDE_WIDTH = 0x8, 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct efifb_dmi_info efifb_dmi_list[] = { 3862306a36Sopenharmony_ci [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, 3962306a36Sopenharmony_ci [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */ 4062306a36Sopenharmony_ci [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, 4162306a36Sopenharmony_ci [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */ 4262306a36Sopenharmony_ci [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, 4362306a36Sopenharmony_ci [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE }, 4462306a36Sopenharmony_ci [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE }, 4562306a36Sopenharmony_ci [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE }, 4662306a36Sopenharmony_ci [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE }, 4762306a36Sopenharmony_ci [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, 4862306a36Sopenharmony_ci [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, 4962306a36Sopenharmony_ci [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, 5062306a36Sopenharmony_ci [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, 5162306a36Sopenharmony_ci [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, 5262306a36Sopenharmony_ci [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, 5362306a36Sopenharmony_ci /* 11" Macbook Air 3,1 passes the wrong stride */ 5462306a36Sopenharmony_ci [M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE }, 5562306a36Sopenharmony_ci [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, 5662306a36Sopenharmony_ci [M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */ 5762306a36Sopenharmony_ci [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, 5862306a36Sopenharmony_ci [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, 5962306a36Sopenharmony_ci [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, 6062306a36Sopenharmony_ci [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, 6162306a36Sopenharmony_ci [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, 6262306a36Sopenharmony_ci [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, 6362306a36Sopenharmony_ci [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, 6462306a36Sopenharmony_ci [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE }, 6562306a36Sopenharmony_ci [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, 6662306a36Sopenharmony_ci [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, 6762306a36Sopenharmony_ci [M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE } 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_civoid efifb_setup_from_dmi(struct screen_info *si, const char *opt) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci int i; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < M_UNKNOWN; i++) { 7562306a36Sopenharmony_ci if (efifb_dmi_list[i].base != 0 && 7662306a36Sopenharmony_ci !strcmp(opt, efifb_dmi_list[i].optname)) { 7762306a36Sopenharmony_ci si->lfb_base = efifb_dmi_list[i].base; 7862306a36Sopenharmony_ci si->lfb_linelength = efifb_dmi_list[i].stride; 7962306a36Sopenharmony_ci si->lfb_width = efifb_dmi_list[i].width; 8062306a36Sopenharmony_ci si->lfb_height = efifb_dmi_list[i].height; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define choose_value(dmivalue, fwvalue, field, flags) ({ \ 8662306a36Sopenharmony_ci typeof(fwvalue) _ret_ = fwvalue; \ 8762306a36Sopenharmony_ci if ((flags) & (field)) \ 8862306a36Sopenharmony_ci _ret_ = dmivalue; \ 8962306a36Sopenharmony_ci else if ((fwvalue) == 0) \ 9062306a36Sopenharmony_ci _ret_ = dmivalue; \ 9162306a36Sopenharmony_ci _ret_; \ 9262306a36Sopenharmony_ci }) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int __init efifb_set_system(const struct dmi_system_id *id) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct efifb_dmi_info *info = id->driver_data; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (info->base == 0 && info->height == 0 && info->width == 0 && 9962306a36Sopenharmony_ci info->stride == 0) 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Trust the bootloader over the DMI tables */ 10362306a36Sopenharmony_ci if (screen_info.lfb_base == 0) { 10462306a36Sopenharmony_ci#if defined(CONFIG_PCI) 10562306a36Sopenharmony_ci struct pci_dev *dev = NULL; 10662306a36Sopenharmony_ci int found_bar = 0; 10762306a36Sopenharmony_ci#endif 10862306a36Sopenharmony_ci if (info->base) { 10962306a36Sopenharmony_ci screen_info.lfb_base = choose_value(info->base, 11062306a36Sopenharmony_ci screen_info.lfb_base, OVERRIDE_BASE, 11162306a36Sopenharmony_ci info->flags); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#if defined(CONFIG_PCI) 11462306a36Sopenharmony_ci /* make sure that the address in the table is actually 11562306a36Sopenharmony_ci * on a VGA device's PCI BAR */ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci for_each_pci_dev(dev) { 11862306a36Sopenharmony_ci int i; 11962306a36Sopenharmony_ci if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) 12062306a36Sopenharmony_ci continue; 12162306a36Sopenharmony_ci for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 12262306a36Sopenharmony_ci resource_size_t start, end; 12362306a36Sopenharmony_ci unsigned long flags; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci flags = pci_resource_flags(dev, i); 12662306a36Sopenharmony_ci if (!(flags & IORESOURCE_MEM)) 12762306a36Sopenharmony_ci continue; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (flags & IORESOURCE_UNSET) 13062306a36Sopenharmony_ci continue; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (pci_resource_len(dev, i) == 0) 13362306a36Sopenharmony_ci continue; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci start = pci_resource_start(dev, i); 13662306a36Sopenharmony_ci end = pci_resource_end(dev, i); 13762306a36Sopenharmony_ci if (screen_info.lfb_base >= start && 13862306a36Sopenharmony_ci screen_info.lfb_base < end) { 13962306a36Sopenharmony_ci found_bar = 1; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci if (!found_bar) 14562306a36Sopenharmony_ci screen_info.lfb_base = 0; 14662306a36Sopenharmony_ci#endif 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci if (screen_info.lfb_base) { 15062306a36Sopenharmony_ci screen_info.lfb_linelength = choose_value(info->stride, 15162306a36Sopenharmony_ci screen_info.lfb_linelength, OVERRIDE_STRIDE, 15262306a36Sopenharmony_ci info->flags); 15362306a36Sopenharmony_ci screen_info.lfb_width = choose_value(info->width, 15462306a36Sopenharmony_ci screen_info.lfb_width, OVERRIDE_WIDTH, 15562306a36Sopenharmony_ci info->flags); 15662306a36Sopenharmony_ci screen_info.lfb_height = choose_value(info->height, 15762306a36Sopenharmony_ci screen_info.lfb_height, OVERRIDE_HEIGHT, 15862306a36Sopenharmony_ci info->flags); 15962306a36Sopenharmony_ci if (screen_info.orig_video_isVGA == 0) 16062306a36Sopenharmony_ci screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci screen_info.lfb_linelength = 0; 16362306a36Sopenharmony_ci screen_info.lfb_width = 0; 16462306a36Sopenharmony_ci screen_info.lfb_height = 0; 16562306a36Sopenharmony_ci screen_info.orig_video_isVGA = 0; 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x " 17062306a36Sopenharmony_ci "(%dx%d, stride %d)\n", id->ident, 17162306a36Sopenharmony_ci screen_info.lfb_base, screen_info.lfb_width, 17262306a36Sopenharmony_ci screen_info.lfb_height, screen_info.lfb_linelength); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 1; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \ 17862306a36Sopenharmony_ci { \ 17962306a36Sopenharmony_ci efifb_set_system, \ 18062306a36Sopenharmony_ci name, \ 18162306a36Sopenharmony_ci { \ 18262306a36Sopenharmony_ci DMI_MATCH(DMI_BIOS_VENDOR, vendor), \ 18362306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, name) \ 18462306a36Sopenharmony_ci }, \ 18562306a36Sopenharmony_ci &efifb_dmi_list[enumid] \ 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic const struct dmi_system_id efifb_dmi_system_table[] __initconst = { 18962306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17), 19062306a36Sopenharmony_ci /* At least one of these two will be right; maybe both? */ 19162306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20), 19262306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20), 19362306a36Sopenharmony_ci /* At least one of these two will be right; maybe both? */ 19462306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24), 19562306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24), 19662306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR), 19762306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1), 19862306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1), 19962306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1), 20062306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI), 20162306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1), 20262306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1), 20362306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB), 20462306a36Sopenharmony_ci /* At least one of these two will be right; maybe both? */ 20562306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB), 20662306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB), 20762306a36Sopenharmony_ci /* At least one of these two will be right; maybe both? */ 20862306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB), 20962306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB), 21062306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB), 21162306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1), 21262306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1), 21362306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1), 21462306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA), 21562306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3), 21662306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP), 21762306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2), 21862306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2), 21962306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2), 22062306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR), 22162306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR), 22262306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4), 22362306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1), 22462306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2), 22562306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3), 22662306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1), 22762306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2), 22862306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1), 22962306a36Sopenharmony_ci EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2), 23062306a36Sopenharmony_ci {}, 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* 23462306a36Sopenharmony_ci * Some devices have a portrait LCD but advertise a landscape resolution (and 23562306a36Sopenharmony_ci * pitch). We simply swap width and height for these devices so that we can 23662306a36Sopenharmony_ci * correctly deal with some of them coming with multiple resolutions. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_cistatic const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { 23962306a36Sopenharmony_ci { 24062306a36Sopenharmony_ci /* 24162306a36Sopenharmony_ci * Lenovo MIIX310-10ICR, only some batches have the troublesome 24262306a36Sopenharmony_ci * 800x1280 portrait screen. Luckily the portrait version has 24362306a36Sopenharmony_ci * its own BIOS version, so we match on that. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci .matches = { 24662306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), 24762306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"), 24862306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1HCN44WW"), 24962306a36Sopenharmony_ci }, 25062306a36Sopenharmony_ci }, 25162306a36Sopenharmony_ci { 25262306a36Sopenharmony_ci /* Lenovo MIIX 320-10ICR with 800x1280 portrait screen */ 25362306a36Sopenharmony_ci .matches = { 25462306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), 25562306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, 25662306a36Sopenharmony_ci "Lenovo MIIX 320-10ICR"), 25762306a36Sopenharmony_ci }, 25862306a36Sopenharmony_ci }, 25962306a36Sopenharmony_ci { 26062306a36Sopenharmony_ci /* Lenovo D330 with 800x1280 or 1200x1920 portrait screen */ 26162306a36Sopenharmony_ci .matches = { 26262306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), 26362306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, 26462306a36Sopenharmony_ci "Lenovo ideapad D330-10IGM"), 26562306a36Sopenharmony_ci }, 26662306a36Sopenharmony_ci }, 26762306a36Sopenharmony_ci { 26862306a36Sopenharmony_ci /* Lenovo IdeaPad Duet 3 10IGL5 with 1200x1920 portrait screen */ 26962306a36Sopenharmony_ci .matches = { 27062306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), 27162306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, 27262306a36Sopenharmony_ci "IdeaPad Duet 3 10IGL5"), 27362306a36Sopenharmony_ci }, 27462306a36Sopenharmony_ci }, 27562306a36Sopenharmony_ci { 27662306a36Sopenharmony_ci /* Lenovo Yoga Book X91F / X91L */ 27762306a36Sopenharmony_ci .matches = { 27862306a36Sopenharmony_ci DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), 27962306a36Sopenharmony_ci /* Non exact match to match F + L versions */ 28062306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), 28162306a36Sopenharmony_ci }, 28262306a36Sopenharmony_ci }, 28362306a36Sopenharmony_ci {}, 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic bool efifb_overlaps_pci_range(const struct of_pci_range *range) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci u64 fb_base = screen_info.lfb_base; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) 29162306a36Sopenharmony_ci fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return fb_base >= range->cpu_addr && 29462306a36Sopenharmony_ci fb_base < (range->cpu_addr + range->size); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic struct device_node *find_pci_overlap_node(void) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct device_node *np; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci for_each_node_by_type(np, "pci") { 30262306a36Sopenharmony_ci struct of_pci_range_parser parser; 30362306a36Sopenharmony_ci struct of_pci_range range; 30462306a36Sopenharmony_ci int err; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci err = of_pci_range_parser_init(&parser, np); 30762306a36Sopenharmony_ci if (err) { 30862306a36Sopenharmony_ci pr_warn("of_pci_range_parser_init() failed: %d\n", err); 30962306a36Sopenharmony_ci continue; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci for_each_of_pci_range(&parser, &range) 31362306a36Sopenharmony_ci if (efifb_overlaps_pci_range(&range)) 31462306a36Sopenharmony_ci return np; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci return NULL; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* 32062306a36Sopenharmony_ci * If the efifb framebuffer is backed by a PCI graphics controller, we have 32162306a36Sopenharmony_ci * to ensure that this relation is expressed using a device link when 32262306a36Sopenharmony_ci * running in DT mode, or the probe order may be reversed, resulting in a 32362306a36Sopenharmony_ci * resource reservation conflict on the memory window that the efifb 32462306a36Sopenharmony_ci * framebuffer steals from the PCIe host bridge. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_cistatic int efifb_add_links(struct fwnode_handle *fwnode) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct device_node *sup_np; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci sup_np = find_pci_overlap_node(); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * If there's no PCI graphics controller backing the efifb, we are 33462306a36Sopenharmony_ci * done here. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if (!sup_np) 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci fwnode_link_add(fwnode, of_fwnode_handle(sup_np)); 34062306a36Sopenharmony_ci of_node_put(sup_np); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic const struct fwnode_operations efifb_fwnode_ops = { 34662306a36Sopenharmony_ci .add_links = efifb_add_links, 34762306a36Sopenharmony_ci}; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci#ifdef CONFIG_EFI 35062306a36Sopenharmony_cistatic struct fwnode_handle efifb_fwnode; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci__init void sysfb_apply_efi_quirks(void) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || 35562306a36Sopenharmony_ci !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS)) 35662306a36Sopenharmony_ci dmi_check_system(efifb_dmi_system_table); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && 35962306a36Sopenharmony_ci dmi_check_system(efifb_dmi_swap_width_height)) { 36062306a36Sopenharmony_ci u16 temp = screen_info.lfb_width; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci screen_info.lfb_width = screen_info.lfb_height; 36362306a36Sopenharmony_ci screen_info.lfb_height = temp; 36462306a36Sopenharmony_ci screen_info.lfb_linelength = 4 * screen_info.lfb_width; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci__init void sysfb_set_efifb_fwnode(struct platform_device *pd) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) { 37162306a36Sopenharmony_ci fwnode_init(&efifb_fwnode, &efifb_fwnode_ops); 37262306a36Sopenharmony_ci pd->dev.fwnode = &efifb_fwnode; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci#endif 376