gop.c 9.1 KB

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