gop.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. __gop_query32(efi_system_table_t *sys_table_arg,
  82. struct efi_graphics_output_protocol_32 *gop32,
  83. struct efi_graphics_output_mode_info **info,
  84. unsigned long *size, u64 *fb_base)
  85. {
  86. struct efi_graphics_output_protocol_mode_32 *mode;
  87. efi_graphics_output_protocol_query_mode query_mode;
  88. efi_status_t status;
  89. unsigned long m;
  90. m = gop32->mode;
  91. mode = (struct efi_graphics_output_protocol_mode_32 *)m;
  92. query_mode = (void *)(unsigned long)gop32->query_mode;
  93. status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size,
  94. info);
  95. if (status != EFI_SUCCESS)
  96. return status;
  97. *fb_base = mode->frame_buffer_base;
  98. return status;
  99. }
  100. static efi_status_t
  101. setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
  102. efi_guid_t *proto, unsigned long size, void **gop_handle)
  103. {
  104. struct efi_graphics_output_protocol_32 *gop32, *first_gop;
  105. unsigned long nr_gops;
  106. u16 width, height;
  107. u32 pixels_per_scan_line;
  108. u32 ext_lfb_base;
  109. u64 fb_base;
  110. struct efi_pixel_bitmask pixel_info;
  111. int pixel_format;
  112. efi_status_t status = EFI_NOT_FOUND;
  113. u32 *handles = (u32 *)(unsigned long)gop_handle;
  114. int i;
  115. first_gop = NULL;
  116. gop32 = NULL;
  117. nr_gops = size / sizeof(u32);
  118. for (i = 0; i < nr_gops; i++) {
  119. struct efi_graphics_output_mode_info *info = NULL;
  120. efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
  121. bool conout_found = false;
  122. void *dummy = NULL;
  123. efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
  124. u64 current_fb_base;
  125. status = efi_call_early(handle_protocol, h,
  126. proto, (void **)&gop32);
  127. if (status != EFI_SUCCESS)
  128. continue;
  129. status = efi_call_early(handle_protocol, h,
  130. &conout_proto, &dummy);
  131. if (status == EFI_SUCCESS)
  132. conout_found = true;
  133. status = __gop_query32(sys_table_arg, gop32, &info, &size,
  134. &current_fb_base);
  135. if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
  136. info->pixel_format != PIXEL_BLT_ONLY) {
  137. /*
  138. * Systems that use the UEFI Console Splitter may
  139. * provide multiple GOP devices, not all of which are
  140. * backed by real hardware. The workaround is to search
  141. * for a GOP implementing the ConOut protocol, and if
  142. * one isn't found, to just fall back to the first GOP.
  143. */
  144. width = info->horizontal_resolution;
  145. height = info->vertical_resolution;
  146. pixel_format = info->pixel_format;
  147. pixel_info = info->pixel_information;
  148. pixels_per_scan_line = info->pixels_per_scan_line;
  149. fb_base = current_fb_base;
  150. /*
  151. * Once we've found a GOP supporting ConOut,
  152. * don't bother looking any further.
  153. */
  154. first_gop = gop32;
  155. if (conout_found)
  156. break;
  157. }
  158. }
  159. /* Did we find any GOPs? */
  160. if (!first_gop)
  161. goto out;
  162. /* EFI framebuffer */
  163. si->orig_video_isVGA = VIDEO_TYPE_EFI;
  164. si->lfb_width = width;
  165. si->lfb_height = height;
  166. si->lfb_base = fb_base;
  167. ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
  168. if (ext_lfb_base) {
  169. si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
  170. si->ext_lfb_base = ext_lfb_base;
  171. }
  172. si->pages = 1;
  173. setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
  174. si->lfb_size = si->lfb_linelength * si->lfb_height;
  175. si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
  176. out:
  177. return status;
  178. }
  179. static efi_status_t
  180. __gop_query64(efi_system_table_t *sys_table_arg,
  181. struct efi_graphics_output_protocol_64 *gop64,
  182. struct efi_graphics_output_mode_info **info,
  183. unsigned long *size, u64 *fb_base)
  184. {
  185. struct efi_graphics_output_protocol_mode_64 *mode;
  186. efi_graphics_output_protocol_query_mode query_mode;
  187. efi_status_t status;
  188. unsigned long m;
  189. m = gop64->mode;
  190. mode = (struct efi_graphics_output_protocol_mode_64 *)m;
  191. query_mode = (void *)(unsigned long)gop64->query_mode;
  192. status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size,
  193. info);
  194. if (status != EFI_SUCCESS)
  195. return status;
  196. *fb_base = mode->frame_buffer_base;
  197. return status;
  198. }
  199. static efi_status_t
  200. setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
  201. efi_guid_t *proto, unsigned long size, void **gop_handle)
  202. {
  203. struct efi_graphics_output_protocol_64 *gop64, *first_gop;
  204. unsigned long nr_gops;
  205. u16 width, height;
  206. u32 pixels_per_scan_line;
  207. u32 ext_lfb_base;
  208. u64 fb_base;
  209. struct efi_pixel_bitmask pixel_info;
  210. int pixel_format;
  211. efi_status_t status = EFI_NOT_FOUND;
  212. u64 *handles = (u64 *)(unsigned long)gop_handle;
  213. int i;
  214. first_gop = NULL;
  215. gop64 = NULL;
  216. nr_gops = size / sizeof(u64);
  217. for (i = 0; i < nr_gops; i++) {
  218. struct efi_graphics_output_mode_info *info = NULL;
  219. efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
  220. bool conout_found = false;
  221. void *dummy = NULL;
  222. efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
  223. u64 current_fb_base;
  224. status = efi_call_early(handle_protocol, h,
  225. proto, (void **)&gop64);
  226. if (status != EFI_SUCCESS)
  227. continue;
  228. status = efi_call_early(handle_protocol, h,
  229. &conout_proto, &dummy);
  230. if (status == EFI_SUCCESS)
  231. conout_found = true;
  232. status = __gop_query64(sys_table_arg, gop64, &info, &size,
  233. &current_fb_base);
  234. if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
  235. info->pixel_format != PIXEL_BLT_ONLY) {
  236. /*
  237. * Systems that use the UEFI Console Splitter may
  238. * provide multiple GOP devices, not all of which are
  239. * backed by real hardware. The workaround is to search
  240. * for a GOP implementing the ConOut protocol, and if
  241. * one isn't found, to just fall back to the first GOP.
  242. */
  243. width = info->horizontal_resolution;
  244. height = info->vertical_resolution;
  245. pixel_format = info->pixel_format;
  246. pixel_info = info->pixel_information;
  247. pixels_per_scan_line = info->pixels_per_scan_line;
  248. fb_base = current_fb_base;
  249. /*
  250. * Once we've found a GOP supporting ConOut,
  251. * don't bother looking any further.
  252. */
  253. first_gop = gop64;
  254. if (conout_found)
  255. break;
  256. }
  257. }
  258. /* Did we find any GOPs? */
  259. if (!first_gop)
  260. goto out;
  261. /* EFI framebuffer */
  262. si->orig_video_isVGA = VIDEO_TYPE_EFI;
  263. si->lfb_width = width;
  264. si->lfb_height = height;
  265. si->lfb_base = fb_base;
  266. ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
  267. if (ext_lfb_base) {
  268. si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
  269. si->ext_lfb_base = ext_lfb_base;
  270. }
  271. si->pages = 1;
  272. setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
  273. si->lfb_size = si->lfb_linelength * si->lfb_height;
  274. si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
  275. out:
  276. return status;
  277. }
  278. /*
  279. * See if we have Graphics Output Protocol
  280. */
  281. efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
  282. struct screen_info *si, efi_guid_t *proto,
  283. unsigned long size)
  284. {
  285. efi_status_t status;
  286. void **gop_handle = NULL;
  287. status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
  288. size, (void **)&gop_handle);
  289. if (status != EFI_SUCCESS)
  290. return status;
  291. status = efi_call_early(locate_handle,
  292. EFI_LOCATE_BY_PROTOCOL,
  293. proto, NULL, &size, gop_handle);
  294. if (status != EFI_SUCCESS)
  295. goto free_handle;
  296. if (efi_is_64bit()) {
  297. status = setup_gop64(sys_table_arg, si, proto, size,
  298. gop_handle);
  299. } else {
  300. status = setup_gop32(sys_table_arg, si, proto, size,
  301. gop_handle);
  302. }
  303. free_handle:
  304. efi_call_early(free_pool, gop_handle);
  305. return status;
  306. }