18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Extensible Firmware Interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on Extensible Firmware Interface Specification version 2.4 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2013 - 2015 Linaro Ltd. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "efi: " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/efi.h> 138c2ecf20Sopenharmony_ci#include <linux/fwnode.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/memblock.h> 168c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_address.h> 198c2ecf20Sopenharmony_ci#include <linux/of_fdt.h> 208c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 218c2ecf20Sopenharmony_ci#include <linux/screen_info.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/efi.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int __init is_memory(efi_memory_desc_t *md) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC)) 288c2ecf20Sopenharmony_ci return 1; 298c2ecf20Sopenharmony_ci return 0; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Translate a EFI virtual address into a physical address: this is necessary, 348c2ecf20Sopenharmony_ci * as some data members of the EFI system table are virtually remapped after 358c2ecf20Sopenharmony_ci * SetVirtualAddressMap() has been called. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic phys_addr_t __init efi_to_phys(unsigned long addr) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci efi_memory_desc_t *md; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci for_each_efi_memory_desc(md) { 428c2ecf20Sopenharmony_ci if (!(md->attribute & EFI_MEMORY_RUNTIME)) 438c2ecf20Sopenharmony_ci continue; 448c2ecf20Sopenharmony_ci if (md->virt_addr == 0) 458c2ecf20Sopenharmony_ci /* no virtual mapping has been installed by the stub */ 468c2ecf20Sopenharmony_ci break; 478c2ecf20Sopenharmony_ci if (md->virt_addr <= addr && 488c2ecf20Sopenharmony_ci (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT)) 498c2ecf20Sopenharmony_ci return md->phys_addr + addr - md->virt_addr; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci return addr; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR; 558c2ecf20Sopenharmony_cistatic __initdata unsigned long cpu_state_table = EFI_INVALID_TABLE_ADDR; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const efi_config_table_type_t arch_tables[] __initconst = { 588c2ecf20Sopenharmony_ci {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, &screen_info_table}, 598c2ecf20Sopenharmony_ci {LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table}, 608c2ecf20Sopenharmony_ci {} 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void __init init_screen_info(void) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct screen_info *si; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM) && 688c2ecf20Sopenharmony_ci screen_info_table != EFI_INVALID_TABLE_ADDR) { 698c2ecf20Sopenharmony_ci si = early_memremap_ro(screen_info_table, sizeof(*si)); 708c2ecf20Sopenharmony_ci if (!si) { 718c2ecf20Sopenharmony_ci pr_err("Could not map screen_info config table\n"); 728c2ecf20Sopenharmony_ci return; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci screen_info = *si; 758c2ecf20Sopenharmony_ci early_memunmap(si, sizeof(*si)); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* dummycon on ARM needs non-zero values for columns/lines */ 788c2ecf20Sopenharmony_ci screen_info.orig_video_cols = 80; 798c2ecf20Sopenharmony_ci screen_info.orig_video_lines = 25; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && 838c2ecf20Sopenharmony_ci memblock_is_map_memory(screen_info.lfb_base)) 848c2ecf20Sopenharmony_ci memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int __init uefi_init(u64 efi_system_table) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci efi_config_table_t *config_tables; 908c2ecf20Sopenharmony_ci efi_system_table_t *systab; 918c2ecf20Sopenharmony_ci size_t table_size; 928c2ecf20Sopenharmony_ci int retval; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci systab = early_memremap_ro(efi_system_table, sizeof(efi_system_table_t)); 958c2ecf20Sopenharmony_ci if (systab == NULL) { 968c2ecf20Sopenharmony_ci pr_warn("Unable to map EFI system table.\n"); 978c2ecf20Sopenharmony_ci return -ENOMEM; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci set_bit(EFI_BOOT, &efi.flags); 1018c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) 1028c2ecf20Sopenharmony_ci set_bit(EFI_64BIT, &efi.flags); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci retval = efi_systab_check_header(&systab->hdr, 2); 1058c2ecf20Sopenharmony_ci if (retval) 1068c2ecf20Sopenharmony_ci goto out; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci efi.runtime = systab->runtime; 1098c2ecf20Sopenharmony_ci efi.runtime_version = systab->hdr.revision; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci efi_systab_report_header(&systab->hdr, efi_to_phys(systab->fw_vendor)); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci table_size = sizeof(efi_config_table_t) * systab->nr_tables; 1148c2ecf20Sopenharmony_ci config_tables = early_memremap_ro(efi_to_phys(systab->tables), 1158c2ecf20Sopenharmony_ci table_size); 1168c2ecf20Sopenharmony_ci if (config_tables == NULL) { 1178c2ecf20Sopenharmony_ci pr_warn("Unable to map EFI config table array.\n"); 1188c2ecf20Sopenharmony_ci retval = -ENOMEM; 1198c2ecf20Sopenharmony_ci goto out; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci retval = efi_config_parse_tables(config_tables, systab->nr_tables, 1228c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_ARM) ? arch_tables 1238c2ecf20Sopenharmony_ci : NULL); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci early_memunmap(config_tables, table_size); 1268c2ecf20Sopenharmony_ciout: 1278c2ecf20Sopenharmony_ci early_memunmap(systab, sizeof(efi_system_table_t)); 1288c2ecf20Sopenharmony_ci return retval; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* 1328c2ecf20Sopenharmony_ci * Return true for regions that can be used as System RAM. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic __init int is_usable_memory(efi_memory_desc_t *md) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci switch (md->type) { 1378c2ecf20Sopenharmony_ci case EFI_LOADER_CODE: 1388c2ecf20Sopenharmony_ci case EFI_LOADER_DATA: 1398c2ecf20Sopenharmony_ci case EFI_ACPI_RECLAIM_MEMORY: 1408c2ecf20Sopenharmony_ci case EFI_BOOT_SERVICES_CODE: 1418c2ecf20Sopenharmony_ci case EFI_BOOT_SERVICES_DATA: 1428c2ecf20Sopenharmony_ci case EFI_CONVENTIONAL_MEMORY: 1438c2ecf20Sopenharmony_ci case EFI_PERSISTENT_MEMORY: 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * Special purpose memory is 'soft reserved', which means it 1468c2ecf20Sopenharmony_ci * is set aside initially, but can be hotplugged back in or 1478c2ecf20Sopenharmony_ci * be assigned to the dax driver after boot. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci if (efi_soft_reserve_enabled() && 1508c2ecf20Sopenharmony_ci (md->attribute & EFI_MEMORY_SP)) 1518c2ecf20Sopenharmony_ci return false; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * According to the spec, these regions are no longer reserved 1558c2ecf20Sopenharmony_ci * after calling ExitBootServices(). However, we can only use 1568c2ecf20Sopenharmony_ci * them as System RAM if they can be mapped writeback cacheable. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci return (md->attribute & EFI_MEMORY_WB); 1598c2ecf20Sopenharmony_ci default: 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return false; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic __init void reserve_regions(void) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci efi_memory_desc_t *md; 1688c2ecf20Sopenharmony_ci u64 paddr, npages, size; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (efi_enabled(EFI_DBG)) 1718c2ecf20Sopenharmony_ci pr_info("Processing EFI memory map:\n"); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* 1748c2ecf20Sopenharmony_ci * Discard memblocks discovered so far: if there are any at this 1758c2ecf20Sopenharmony_ci * point, they originate from memory nodes in the DT, and UEFI 1768c2ecf20Sopenharmony_ci * uses its own memory map instead. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci memblock_dump_all(); 1798c2ecf20Sopenharmony_ci memblock_remove(0, PHYS_ADDR_MAX); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci for_each_efi_memory_desc(md) { 1828c2ecf20Sopenharmony_ci paddr = md->phys_addr; 1838c2ecf20Sopenharmony_ci npages = md->num_pages; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (efi_enabled(EFI_DBG)) { 1868c2ecf20Sopenharmony_ci char buf[64]; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci pr_info(" 0x%012llx-0x%012llx %s\n", 1898c2ecf20Sopenharmony_ci paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, 1908c2ecf20Sopenharmony_ci efi_md_typeattr_format(buf, sizeof(buf), md)); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci memrange_efi_to_native(&paddr, &npages); 1948c2ecf20Sopenharmony_ci size = npages << PAGE_SHIFT; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (is_memory(md)) { 1978c2ecf20Sopenharmony_ci early_init_dt_add_memory_arch(paddr, size); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!is_usable_memory(md)) 2008c2ecf20Sopenharmony_ci memblock_mark_nomap(paddr, size); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* keep ACPI reclaim memory intact for kexec etc. */ 2038c2ecf20Sopenharmony_ci if (md->type == EFI_ACPI_RECLAIM_MEMORY) 2048c2ecf20Sopenharmony_ci memblock_reserve(paddr, size); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_civoid __init efi_init(void) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct efi_memory_map_data data; 2128c2ecf20Sopenharmony_ci u64 efi_system_table; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Grab UEFI information placed in FDT by stub */ 2158c2ecf20Sopenharmony_ci efi_system_table = efi_get_fdt_params(&data); 2168c2ecf20Sopenharmony_ci if (!efi_system_table) 2178c2ecf20Sopenharmony_ci return; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (efi_memmap_init_early(&data) < 0) { 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * If we are booting via UEFI, the UEFI memory map is the only 2228c2ecf20Sopenharmony_ci * description of memory we have, so there is little point in 2238c2ecf20Sopenharmony_ci * proceeding if we cannot access it. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci panic("Unable to map EFI memory map.\n"); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci WARN(efi.memmap.desc_version != 1, 2298c2ecf20Sopenharmony_ci "Unexpected EFI_MEMORY_DESCRIPTOR version %ld", 2308c2ecf20Sopenharmony_ci efi.memmap.desc_version); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (uefi_init(efi_system_table) < 0) { 2338c2ecf20Sopenharmony_ci efi_memmap_unmap(); 2348c2ecf20Sopenharmony_ci return; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci reserve_regions(); 2388c2ecf20Sopenharmony_ci efi_esrt_init(); 2398c2ecf20Sopenharmony_ci efi_mokvar_table_init(); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci memblock_reserve(data.phys_map & PAGE_MASK, 2428c2ecf20Sopenharmony_ci PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK))); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci init_screen_info(); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM 2478c2ecf20Sopenharmony_ci /* ARM does not permit early mappings to persist across paging_init() */ 2488c2ecf20Sopenharmony_ci efi_memmap_unmap(); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (cpu_state_table != EFI_INVALID_TABLE_ADDR) { 2518c2ecf20Sopenharmony_ci struct efi_arm_entry_state *state; 2528c2ecf20Sopenharmony_ci bool dump_state = true; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci state = early_memremap_ro(cpu_state_table, 2558c2ecf20Sopenharmony_ci sizeof(struct efi_arm_entry_state)); 2568c2ecf20Sopenharmony_ci if (state == NULL) { 2578c2ecf20Sopenharmony_ci pr_warn("Unable to map CPU entry state table.\n"); 2588c2ecf20Sopenharmony_ci return; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if ((state->sctlr_before_ebs & 1) == 0) 2628c2ecf20Sopenharmony_ci pr_warn(FW_BUG "EFI stub was entered with MMU and Dcache disabled, please fix your firmware!\n"); 2638c2ecf20Sopenharmony_ci else if ((state->sctlr_after_ebs & 1) == 0) 2648c2ecf20Sopenharmony_ci pr_warn(FW_BUG "ExitBootServices() returned with MMU and Dcache disabled, please fix your firmware!\n"); 2658c2ecf20Sopenharmony_ci else 2668c2ecf20Sopenharmony_ci dump_state = false; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (dump_state || efi_enabled(EFI_DBG)) { 2698c2ecf20Sopenharmony_ci pr_info("CPSR at EFI stub entry : 0x%08x\n", state->cpsr_before_ebs); 2708c2ecf20Sopenharmony_ci pr_info("SCTLR at EFI stub entry : 0x%08x\n", state->sctlr_before_ebs); 2718c2ecf20Sopenharmony_ci pr_info("CPSR after ExitBootServices() : 0x%08x\n", state->cpsr_after_ebs); 2728c2ecf20Sopenharmony_ci pr_info("SCTLR after ExitBootServices(): 0x%08x\n", state->sctlr_after_ebs); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci early_memunmap(state, sizeof(struct efi_arm_entry_state)); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci#endif 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic bool efifb_overlaps_pci_range(const struct of_pci_range *range) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci u64 fb_base = screen_info.lfb_base; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) 2848c2ecf20Sopenharmony_ci fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return fb_base >= range->cpu_addr && 2878c2ecf20Sopenharmony_ci fb_base < (range->cpu_addr + range->size); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct device_node *find_pci_overlap_node(void) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct device_node *np; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci for_each_node_by_type(np, "pci") { 2958c2ecf20Sopenharmony_ci struct of_pci_range_parser parser; 2968c2ecf20Sopenharmony_ci struct of_pci_range range; 2978c2ecf20Sopenharmony_ci int err; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci err = of_pci_range_parser_init(&parser, np); 3008c2ecf20Sopenharmony_ci if (err) { 3018c2ecf20Sopenharmony_ci pr_warn("of_pci_range_parser_init() failed: %d\n", err); 3028c2ecf20Sopenharmony_ci continue; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci for_each_of_pci_range(&parser, &range) 3068c2ecf20Sopenharmony_ci if (efifb_overlaps_pci_range(&range)) 3078c2ecf20Sopenharmony_ci return np; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci return NULL; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* 3138c2ecf20Sopenharmony_ci * If the efifb framebuffer is backed by a PCI graphics controller, we have 3148c2ecf20Sopenharmony_ci * to ensure that this relation is expressed using a device link when 3158c2ecf20Sopenharmony_ci * running in DT mode, or the probe order may be reversed, resulting in a 3168c2ecf20Sopenharmony_ci * resource reservation conflict on the memory window that the efifb 3178c2ecf20Sopenharmony_ci * framebuffer steals from the PCIe host bridge. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_cistatic int efifb_add_links(const struct fwnode_handle *fwnode, 3208c2ecf20Sopenharmony_ci struct device *dev) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct device_node *sup_np; 3238c2ecf20Sopenharmony_ci struct device *sup_dev; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci sup_np = find_pci_overlap_node(); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * If there's no PCI graphics controller backing the efifb, we are 3298c2ecf20Sopenharmony_ci * done here. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci if (!sup_np) 3328c2ecf20Sopenharmony_ci return 0; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci sup_dev = get_dev_from_fwnode(&sup_np->fwnode); 3358c2ecf20Sopenharmony_ci of_node_put(sup_np); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* 3388c2ecf20Sopenharmony_ci * Return -ENODEV if the PCI graphics controller device hasn't been 3398c2ecf20Sopenharmony_ci * registered yet. This ensures that efifb isn't allowed to probe 3408c2ecf20Sopenharmony_ci * and this function is retried again when new devices are 3418c2ecf20Sopenharmony_ci * registered. 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci if (!sup_dev) 3448c2ecf20Sopenharmony_ci return -ENODEV; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* 3478c2ecf20Sopenharmony_ci * If this fails, retrying this function at a later point won't 3488c2ecf20Sopenharmony_ci * change anything. So, don't return an error after this. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci if (!device_link_add(dev, sup_dev, fw_devlink_get_flags())) 3518c2ecf20Sopenharmony_ci dev_warn(dev, "device_link_add() failed\n"); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci put_device(sup_dev); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic const struct fwnode_operations efifb_fwnode_ops = { 3598c2ecf20Sopenharmony_ci .add_links = efifb_add_links, 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic struct fwnode_handle efifb_fwnode = { 3638c2ecf20Sopenharmony_ci .ops = &efifb_fwnode_ops, 3648c2ecf20Sopenharmony_ci}; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int __init register_gop_device(void) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct platform_device *pd; 3698c2ecf20Sopenharmony_ci int err; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci pd = platform_device_alloc("efi-framebuffer", 0); 3758c2ecf20Sopenharmony_ci if (!pd) 3768c2ecf20Sopenharmony_ci return -ENOMEM; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI)) 3798c2ecf20Sopenharmony_ci pd->dev.fwnode = &efifb_fwnode; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci err = platform_device_add_data(pd, &screen_info, sizeof(screen_info)); 3828c2ecf20Sopenharmony_ci if (err) 3838c2ecf20Sopenharmony_ci return err; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return platform_device_add(pd); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_cisubsys_initcall(register_gop_device); 388