Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2015 Google, Inc * * Access to the EFI information table */ #define LOG_CATEGORY LOGC_EFI #include <efi.h> #include <efi_loader.h> #include <efi_stub.h> #include <errno.h> #include <mapmem.h> #include <asm/global_data.h> #include <efi_api.h> #include <dm/of.h> #include <dm/ofnode.h> #include <dm/of_access.h> #include <log.h> DECLARE_GLOBAL_DATA_PTR; int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) { struct efi_entry_hdr *entry; struct efi_info_hdr *info; int ret; if (!gd->arch.table) return -ENODATA; info = map_sysmem(gd->arch.table, 0); if (info->version != EFI_TABLE_VERSION) { ret = -EPROTONOSUPPORT; goto err; } entry = (struct efi_entry_hdr *)((ulong)info + info->hdr_size); while (entry->type != EFIET_END) { if (entry->type == type) { if (entry->addr) *datap = map_sysmem(entry->addr, entry->size); else *datap = entry + 1; *sizep = entry->size; return 0; } entry = (struct efi_entry_hdr *)((ulong)entry + entry->link); } ret = -ENOENT; err: unmap_sysmem(info); return -ENOSYS; } static int of_populate_framebuffer(struct device_node *root) { struct device_node *chosen, *fb; struct efi_entry_gopmode *mode; ofnode node; int ret, size; u64 reg[2]; char fb_node_name[50] = { 0 }; ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); if (ret) { printf("EFI graphics output entry not found\n"); return ret; } fb = of_find_node_opts_by_path(root, "/chosen/framebuffer", NULL); /* framebuffer already defined */ if (fb) return 0; chosen = of_find_node_opts_by_path(root, "/chosen", NULL); if (!chosen) { ret = of_add_subnode(root, "chosen", -1, &chosen); if (ret) { debug("Failed to add chosen node\n"); return ret; } } node = np_to_ofnode(chosen); ofnode_write_u32(node, "#address-cells", 2); ofnode_write_u32(node, "#size-cells", 2); /* * In order for of_translate_one() to correctly detect an empty ranges property, the value * pointer has to be non-null even though the length is 0. */ of_write_prop(chosen, "ranges", 0, (void *)FDT_ADDR_T_NONE); snprintf(fb_node_name, sizeof(fb_node_name), "framebuffer@%llx", mode->fb_base); ret = of_add_subnode(chosen, fb_node_name, -1, &fb); if (ret) { debug("Failed to add framebuffer node\n"); return ret; } node = np_to_ofnode(fb); ofnode_write_string(node, "compatible", "simple-framebuffer"); reg[0] = cpu_to_fdt64(mode->fb_base); reg[1] = cpu_to_fdt64(mode->fb_size); ofnode_write_prop(node, "reg", reg, sizeof(reg), true); ofnode_write_u32(node, "width", mode->info->width); ofnode_write_u32(node, "height", mode->info->height); ofnode_write_u32(node, "stride", mode->info->pixels_per_scanline * 4); ofnode_write_string(node, "format", "a8r8g8b8"); return 0; } int of_populate_from_efi(struct device_node *root) { int ret = 0; if (CONFIG_IS_ENABLED(VIDEO_SIMPLE) && CONFIG_IS_ENABLED(OF_LIVE)) ret = of_populate_framebuffer(root); return ret; } static bool efi_mem_type_is_usable(u32 type) { switch (type) { case EFI_CONVENTIONAL_MEMORY: case EFI_LOADER_DATA: case EFI_LOADER_CODE: case EFI_BOOT_SERVICES_CODE: return true; case EFI_RESERVED_MEMORY_TYPE: case EFI_UNUSABLE_MEMORY: case EFI_UNACCEPTED_MEMORY_TYPE: case EFI_RUNTIME_SERVICES_DATA: case EFI_MMAP_IO: case EFI_MMAP_IO_PORT: case EFI_PERSISTENT_MEMORY_TYPE: default: return false; } } int dram_init_banksize_from_efi(void) { struct efi_mem_desc *desc, *end; struct efi_entry_memmap *map; int ret, size, bank = 0; int num_banks; ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); if (ret) { /* We should have stopped in dram_init(), something is wrong */ debug("%s: Missing memory map\n", __func__); return -ENXIO; } end = (struct efi_mem_desc *)((ulong)map + size); desc = map->desc; for (num_banks = 0; desc < end && num_banks < CONFIG_NR_DRAM_BANKS; desc = efi_get_next_mem_desc(desc, map->desc_size)) { /* * We only use conventional memory and ignore * anything less than 1MB. */ log_debug("EFI bank #%d: start %llx, size %llx type %u\n", bank, desc->physical_start, desc->num_pages << EFI_PAGE_SHIFT, desc->type); bank++; if (!efi_mem_type_is_usable(desc->type) || (desc->num_pages << EFI_PAGE_SHIFT) < 1 << 20) continue; gd->bd->bi_dram[num_banks].start = desc->physical_start; gd->bd->bi_dram[num_banks].size = desc->num_pages << EFI_PAGE_SHIFT; num_banks++; } return 0; } /* Called by U-Boot's EFI subsystem to add known memory. In our case * we need to add some specific memory types from the original bootloaders * EFI memory map */ void efi_add_known_memory_from_efi(void) { struct efi_mem_desc *desc, *end; struct efi_entry_memmap *map; int ret, size; EFI_PRINT("Adding known memory from previous stage EFI bootloader\n"); ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size); if (ret) { EFI_PRINT("%s: Missing memory map\n", __func__); return; } end = (struct efi_mem_desc *)((ulong)map + size); for (desc = map->desc; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) { switch (desc->type) { case EFI_RESERVED_MEMORY_TYPE: efi_update_memory_map(desc->physical_start, desc->num_pages, desc->type, false, false); break; default: continue; } } } |