1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> 4 * 5 * EFI framebuffer driver based on GOP 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <efi_api.h> 11 #include <vbe.h> 12 #include <video.h> 13 14 struct pixel { 15 u8 pos; 16 u8 size; 17 }; 18 19 static const struct efi_framebuffer { 20 struct pixel red; 21 struct pixel green; 22 struct pixel blue; 23 struct pixel rsvd; 24 } efi_framebuffer_format_map[] = { 25 [EFI_GOT_RGBA8] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} }, 26 [EFI_GOT_BGRA8] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} }, 27 }; 28 29 static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) 30 { 31 u8 first, len; 32 33 first = 0; 34 len = 0; 35 36 if (mask) { 37 while (!(mask & 0x1)) { 38 mask = mask >> 1; 39 first++; 40 } 41 42 while (mask & 0x1) { 43 mask = mask >> 1; 44 len++; 45 } 46 } 47 48 *pos = first; 49 *size = len; 50 } 51 52 static int save_vesa_mode(struct vesa_mode_info *vesa) 53 { 54 struct efi_entry_gopmode *mode; 55 const struct efi_framebuffer *fbinfo; 56 int size; 57 int ret; 58 59 ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); 60 if (ret == -ENOENT) { 61 debug("efi graphics output protocol mode not found\n"); 62 return -ENXIO; 63 } 64 65 vesa->phys_base_ptr = mode->fb_base; 66 vesa->x_resolution = mode->info->width; 67 vesa->y_resolution = mode->info->height; 68 69 if (mode->info->pixel_format < EFI_GOT_BITMASK) { 70 fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; 71 vesa->red_mask_size = fbinfo->red.size; 72 vesa->red_mask_pos = fbinfo->red.pos; 73 vesa->green_mask_size = fbinfo->green.size; 74 vesa->green_mask_pos = fbinfo->green.pos; 75 vesa->blue_mask_size = fbinfo->blue.size; 76 vesa->blue_mask_pos = fbinfo->blue.pos; 77 vesa->reserved_mask_size = fbinfo->rsvd.size; 78 vesa->reserved_mask_pos = fbinfo->rsvd.pos; 79 80 vesa->bits_per_pixel = 32; 81 vesa->bytes_per_scanline = mode->info->pixels_per_scanline * 4; 82 } else if (mode->info->pixel_format == EFI_GOT_BITMASK) { 83 efi_find_pixel_bits(mode->info->pixel_bitmask[0], 84 &vesa->red_mask_pos, 85 &vesa->red_mask_size); 86 efi_find_pixel_bits(mode->info->pixel_bitmask[1], 87 &vesa->green_mask_pos, 88 &vesa->green_mask_size); 89 efi_find_pixel_bits(mode->info->pixel_bitmask[2], 90 &vesa->blue_mask_pos, 91 &vesa->blue_mask_size); 92 efi_find_pixel_bits(mode->info->pixel_bitmask[3], 93 &vesa->reserved_mask_pos, 94 &vesa->reserved_mask_size); 95 vesa->bits_per_pixel = vesa->red_mask_size + 96 vesa->green_mask_size + 97 vesa->blue_mask_size + 98 vesa->reserved_mask_size; 99 vesa->bytes_per_scanline = (mode->info->pixels_per_scanline * 100 vesa->bits_per_pixel) / 8; 101 } else { 102 debug("efi set unknown framebuffer format: %d\n", 103 mode->info->pixel_format); 104 return -EINVAL; 105 } 106 107 return 0; 108 } 109 110 static int efi_video_probe(struct udevice *dev) 111 { 112 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 113 struct video_priv *uc_priv = dev_get_uclass_priv(dev); 114 struct vesa_mode_info *vesa = &mode_info.vesa; 115 int ret; 116 117 /* Initialize vesa_mode_info structure */ 118 ret = save_vesa_mode(vesa); 119 if (ret) 120 goto err; 121 122 ret = vbe_setup_video_priv(vesa, uc_priv, plat); 123 if (ret) 124 goto err; 125 126 printf("Video: %dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, 127 vesa->bits_per_pixel); 128 129 return 0; 130 131 err: 132 printf("No video mode configured in EFI!\n"); 133 return ret; 134 } 135 136 static const struct udevice_id efi_video_ids[] = { 137 { .compatible = "efi-fb" }, 138 { } 139 }; 140 141 U_BOOT_DRIVER(efi_video) = { 142 .name = "efi_video", 143 .id = UCLASS_VIDEO, 144 .of_match = efi_video_ids, 145 .probe = efi_video_probe, 146 }; 147