root/drivers/firmware/efi/libstub/gop.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_bits
  2. setup_pixel_info
  3. setup_gop32
  4. setup_gop64
  5. efi_setup_gop

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* -----------------------------------------------------------------------
   3  *
   4  *   Copyright 2011 Intel Corporation; author Matt Fleming
   5  *
   6  * ----------------------------------------------------------------------- */
   7 
   8 #include <linux/efi.h>
   9 #include <linux/screen_info.h>
  10 #include <asm/efi.h>
  11 #include <asm/setup.h>
  12 
  13 static void find_bits(unsigned long mask, u8 *pos, u8 *size)
  14 {
  15         u8 first, len;
  16 
  17         first = 0;
  18         len = 0;
  19 
  20         if (mask) {
  21                 while (!(mask & 0x1)) {
  22                         mask = mask >> 1;
  23                         first++;
  24                 }
  25 
  26                 while (mask & 0x1) {
  27                         mask = mask >> 1;
  28                         len++;
  29                 }
  30         }
  31 
  32         *pos = first;
  33         *size = len;
  34 }
  35 
  36 static void
  37 setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
  38                  struct efi_pixel_bitmask pixel_info, int pixel_format)
  39 {
  40         if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
  41                 si->lfb_depth = 32;
  42                 si->lfb_linelength = pixels_per_scan_line * 4;
  43                 si->red_size = 8;
  44                 si->red_pos = 0;
  45                 si->green_size = 8;
  46                 si->green_pos = 8;
  47                 si->blue_size = 8;
  48                 si->blue_pos = 16;
  49                 si->rsvd_size = 8;
  50                 si->rsvd_pos = 24;
  51         } else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) {
  52                 si->lfb_depth = 32;
  53                 si->lfb_linelength = pixels_per_scan_line * 4;
  54                 si->red_size = 8;
  55                 si->red_pos = 16;
  56                 si->green_size = 8;
  57                 si->green_pos = 8;
  58                 si->blue_size = 8;
  59                 si->blue_pos = 0;
  60                 si->rsvd_size = 8;
  61                 si->rsvd_pos = 24;
  62         } else if (pixel_format == PIXEL_BIT_MASK) {
  63                 find_bits(pixel_info.red_mask, &si->red_pos, &si->red_size);
  64                 find_bits(pixel_info.green_mask, &si->green_pos,
  65                           &si->green_size);
  66                 find_bits(pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
  67                 find_bits(pixel_info.reserved_mask, &si->rsvd_pos,
  68                           &si->rsvd_size);
  69                 si->lfb_depth = si->red_size + si->green_size +
  70                         si->blue_size + si->rsvd_size;
  71                 si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
  72         } else {
  73                 si->lfb_depth = 4;
  74                 si->lfb_linelength = si->lfb_width / 2;
  75                 si->red_size = 0;
  76                 si->red_pos = 0;
  77                 si->green_size = 0;
  78                 si->green_pos = 0;
  79                 si->blue_size = 0;
  80                 si->blue_pos = 0;
  81                 si->rsvd_size = 0;
  82                 si->rsvd_pos = 0;
  83         }
  84 }
  85 
  86 static efi_status_t
  87 setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
  88             efi_guid_t *proto, unsigned long size, void **gop_handle)
  89 {
  90         struct efi_graphics_output_protocol_32 *gop32, *first_gop;
  91         unsigned long nr_gops;
  92         u16 width, height;
  93         u32 pixels_per_scan_line;
  94         u32 ext_lfb_base;
  95         u64 fb_base;
  96         struct efi_pixel_bitmask pixel_info;
  97         int pixel_format;
  98         efi_status_t status;
  99         u32 *handles = (u32 *)(unsigned long)gop_handle;
 100         int i;
 101 
 102         first_gop = NULL;
 103         gop32 = NULL;
 104 
 105         nr_gops = size / sizeof(u32);
 106         for (i = 0; i < nr_gops; i++) {
 107                 struct efi_graphics_output_protocol_mode_32 *mode;
 108                 struct efi_graphics_output_mode_info *info = NULL;
 109                 efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
 110                 bool conout_found = false;
 111                 void *dummy = NULL;
 112                 efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
 113                 u64 current_fb_base;
 114 
 115                 status = efi_call_early(handle_protocol, h,
 116                                         proto, (void **)&gop32);
 117                 if (status != EFI_SUCCESS)
 118                         continue;
 119 
 120                 status = efi_call_early(handle_protocol, h,
 121                                         &conout_proto, &dummy);
 122                 if (status == EFI_SUCCESS)
 123                         conout_found = true;
 124 
 125                 mode = (void *)(unsigned long)gop32->mode;
 126                 info = (void *)(unsigned long)mode->info;
 127                 current_fb_base = mode->frame_buffer_base;
 128 
 129                 if ((!first_gop || conout_found) &&
 130                     info->pixel_format != PIXEL_BLT_ONLY) {
 131                         /*
 132                          * Systems that use the UEFI Console Splitter may
 133                          * provide multiple GOP devices, not all of which are
 134                          * backed by real hardware. The workaround is to search
 135                          * for a GOP implementing the ConOut protocol, and if
 136                          * one isn't found, to just fall back to the first GOP.
 137                          */
 138                         width = info->horizontal_resolution;
 139                         height = info->vertical_resolution;
 140                         pixel_format = info->pixel_format;
 141                         pixel_info = info->pixel_information;
 142                         pixels_per_scan_line = info->pixels_per_scan_line;
 143                         fb_base = current_fb_base;
 144 
 145                         /*
 146                          * Once we've found a GOP supporting ConOut,
 147                          * don't bother looking any further.
 148                          */
 149                         first_gop = gop32;
 150                         if (conout_found)
 151                                 break;
 152                 }
 153         }
 154 
 155         /* Did we find any GOPs? */
 156         if (!first_gop)
 157                 return EFI_NOT_FOUND;
 158 
 159         /* EFI framebuffer */
 160         si->orig_video_isVGA = VIDEO_TYPE_EFI;
 161 
 162         si->lfb_width = width;
 163         si->lfb_height = height;
 164         si->lfb_base = fb_base;
 165 
 166         ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
 167         if (ext_lfb_base) {
 168                 si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
 169                 si->ext_lfb_base = ext_lfb_base;
 170         }
 171 
 172         si->pages = 1;
 173 
 174         setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
 175 
 176         si->lfb_size = si->lfb_linelength * si->lfb_height;
 177 
 178         si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
 179 
 180         return EFI_SUCCESS;
 181 }
 182 
 183 static efi_status_t
 184 setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
 185             efi_guid_t *proto, unsigned long size, void **gop_handle)
 186 {
 187         struct efi_graphics_output_protocol_64 *gop64, *first_gop;
 188         unsigned long nr_gops;
 189         u16 width, height;
 190         u32 pixels_per_scan_line;
 191         u32 ext_lfb_base;
 192         u64 fb_base;
 193         struct efi_pixel_bitmask pixel_info;
 194         int pixel_format;
 195         efi_status_t status;
 196         u64 *handles = (u64 *)(unsigned long)gop_handle;
 197         int i;
 198 
 199         first_gop = NULL;
 200         gop64 = NULL;
 201 
 202         nr_gops = size / sizeof(u64);
 203         for (i = 0; i < nr_gops; i++) {
 204                 struct efi_graphics_output_protocol_mode_64 *mode;
 205                 struct efi_graphics_output_mode_info *info = NULL;
 206                 efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
 207                 bool conout_found = false;
 208                 void *dummy = NULL;
 209                 efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
 210                 u64 current_fb_base;
 211 
 212                 status = efi_call_early(handle_protocol, h,
 213                                         proto, (void **)&gop64);
 214                 if (status != EFI_SUCCESS)
 215                         continue;
 216 
 217                 status = efi_call_early(handle_protocol, h,
 218                                         &conout_proto, &dummy);
 219                 if (status == EFI_SUCCESS)
 220                         conout_found = true;
 221 
 222                 mode = (void *)(unsigned long)gop64->mode;
 223                 info = (void *)(unsigned long)mode->info;
 224                 current_fb_base = mode->frame_buffer_base;
 225 
 226                 if ((!first_gop || conout_found) &&
 227                     info->pixel_format != PIXEL_BLT_ONLY) {
 228                         /*
 229                          * Systems that use the UEFI Console Splitter may
 230                          * provide multiple GOP devices, not all of which are
 231                          * backed by real hardware. The workaround is to search
 232                          * for a GOP implementing the ConOut protocol, and if
 233                          * one isn't found, to just fall back to the first GOP.
 234                          */
 235                         width = info->horizontal_resolution;
 236                         height = info->vertical_resolution;
 237                         pixel_format = info->pixel_format;
 238                         pixel_info = info->pixel_information;
 239                         pixels_per_scan_line = info->pixels_per_scan_line;
 240                         fb_base = current_fb_base;
 241 
 242                         /*
 243                          * Once we've found a GOP supporting ConOut,
 244                          * don't bother looking any further.
 245                          */
 246                         first_gop = gop64;
 247                         if (conout_found)
 248                                 break;
 249                 }
 250         }
 251 
 252         /* Did we find any GOPs? */
 253         if (!first_gop)
 254                 return EFI_NOT_FOUND;
 255 
 256         /* EFI framebuffer */
 257         si->orig_video_isVGA = VIDEO_TYPE_EFI;
 258 
 259         si->lfb_width = width;
 260         si->lfb_height = height;
 261         si->lfb_base = fb_base;
 262 
 263         ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
 264         if (ext_lfb_base) {
 265                 si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
 266                 si->ext_lfb_base = ext_lfb_base;
 267         }
 268 
 269         si->pages = 1;
 270 
 271         setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
 272 
 273         si->lfb_size = si->lfb_linelength * si->lfb_height;
 274 
 275         si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
 276 
 277         return EFI_SUCCESS;
 278 }
 279 
 280 /*
 281  * See if we have Graphics Output Protocol
 282  */
 283 efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
 284                            struct screen_info *si, efi_guid_t *proto,
 285                            unsigned long size)
 286 {
 287         efi_status_t status;
 288         void **gop_handle = NULL;
 289 
 290         status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
 291                                 size, (void **)&gop_handle);
 292         if (status != EFI_SUCCESS)
 293                 return status;
 294 
 295         status = efi_call_early(locate_handle,
 296                                 EFI_LOCATE_BY_PROTOCOL,
 297                                 proto, NULL, &size, gop_handle);
 298         if (status != EFI_SUCCESS)
 299                 goto free_handle;
 300 
 301         if (efi_is_64bit()) {
 302                 status = setup_gop64(sys_table_arg, si, proto, size,
 303                                      gop_handle);
 304         } else {
 305                 status = setup_gop32(sys_table_arg, si, proto, size,
 306                                      gop_handle);
 307         }
 308 
 309 free_handle:
 310         efi_call_early(free_pool, gop_handle);
 311         return status;
 312 }

/* [<][>][^][v][top][bottom][index][help] */