gop.c 8.0 KB

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