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 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> * * EFI framebuffer driver based on GOP */ #include <common.h> #include <dm.h> #include <efi_api.h> #include <log.h> #include <vbe.h> #include <video.h> struct pixel { u8 pos; u8 size; }; static const struct efi_framebuffer { struct pixel red; struct pixel green; struct pixel blue; struct pixel rsvd; } efi_framebuffer_format_map[] = { [EFI_GOT_RGBA8] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} }, [EFI_GOT_BGRA8] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} }, }; static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) { u8 first, len; first = 0; len = 0; if (mask) { while (!(mask & 0x1)) { mask = mask >> 1; first++; } while (mask & 0x1) { mask = mask >> 1; len++; } } *pos = first; *size = len; } static int get_mode_info(struct vesa_mode_info *vesa) { efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; struct efi_boot_services *boot = efi_get_boot(); struct efi_gop_mode *mode; struct efi_gop *gop; int ret; if (!boot) return log_msg_ret("sys", -ENOSYS); ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); if (ret) return log_msg_ret("prot", -ENOTSUPP); mode = gop->mode; vesa->phys_base_ptr = mode->fb_base; vesa->x_resolution = mode->info->width; vesa->y_resolution = mode->info->height; return 0; } static int save_vesa_mode(struct vesa_mode_info *vesa) { struct efi_entry_gopmode *mode; const struct efi_framebuffer *fbinfo; int size; int ret; if (IS_ENABLED(CONFIG_EFI_APP)) { ret = get_mode_info(vesa); if (ret) { printf("EFI graphics output protocol not found\n"); return -ENXIO; } } else { ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); if (ret == -ENOENT) { printf("EFI graphics output protocol mode not found\n"); return -ENXIO; } vesa->phys_base_ptr = mode->fb_base; vesa->x_resolution = mode->info->width; vesa->y_resolution = mode->info->height; } if (mode->info->pixel_format < EFI_GOT_BITMASK) { fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; vesa->red_mask_size = fbinfo->red.size; vesa->red_mask_pos = fbinfo->red.pos; vesa->green_mask_size = fbinfo->green.size; vesa->green_mask_pos = fbinfo->green.pos; vesa->blue_mask_size = fbinfo->blue.size; vesa->blue_mask_pos = fbinfo->blue.pos; vesa->reserved_mask_size = fbinfo->rsvd.size; vesa->reserved_mask_pos = fbinfo->rsvd.pos; vesa->bits_per_pixel = 32; vesa->bytes_per_scanline = mode->info->pixels_per_scanline * 4; } else if (mode->info->pixel_format == EFI_GOT_BITMASK) { efi_find_pixel_bits(mode->info->pixel_bitmask[0], &vesa->red_mask_pos, &vesa->red_mask_size); efi_find_pixel_bits(mode->info->pixel_bitmask[1], &vesa->green_mask_pos, &vesa->green_mask_size); efi_find_pixel_bits(mode->info->pixel_bitmask[2], &vesa->blue_mask_pos, &vesa->blue_mask_size); efi_find_pixel_bits(mode->info->pixel_bitmask[3], &vesa->reserved_mask_pos, &vesa->reserved_mask_size); vesa->bits_per_pixel = vesa->red_mask_size + vesa->green_mask_size + vesa->blue_mask_size + vesa->reserved_mask_size; vesa->bytes_per_scanline = (mode->info->pixels_per_scanline * vesa->bits_per_pixel) / 8; } else { debug("efi set unknown framebuffer format: %d\n", mode->info->pixel_format); return -EINVAL; } return 0; } static int efi_video_probe(struct udevice *dev) { struct video_uc_plat *plat = dev_get_uclass_plat(dev); struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct vesa_mode_info *vesa = &mode_info.vesa; int ret; /* Initialize vesa_mode_info structure */ ret = save_vesa_mode(vesa); if (ret) goto err; ret = vbe_setup_video_priv(vesa, uc_priv, plat); if (ret) goto err; printf("Video: %dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, vesa->bits_per_pixel); return 0; err: printf("No video mode configured in EFI!\n"); return ret; } static const struct udevice_id efi_video_ids[] = { { .compatible = "efi-fb" }, { } }; U_BOOT_DRIVER(efi_video) = { .name = "efi_video", .id = UCLASS_VIDEO, .of_match = efi_video_ids, .probe = efi_video_probe, }; |