efi.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. #define LOG_CATEGORY LOGC_EFI
  8. #include <common.h>
  9. #include <dm.h>
  10. #include <efi_api.h>
  11. #include <log.h>
  12. #include <vesa.h>
  13. #include <video.h>
  14. struct pixel {
  15. u8 pos;
  16. u8 size;
  17. };
  18. static const struct efi_framebuffer {
  19. struct pixel red;
  20. struct pixel green;
  21. struct pixel blue;
  22. struct pixel rsvd;
  23. } efi_framebuffer_format_map[] = {
  24. [EFI_GOT_RGBA8] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} },
  25. [EFI_GOT_BGRA8] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} },
  26. };
  27. static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size)
  28. {
  29. u8 first, len;
  30. first = 0;
  31. len = 0;
  32. if (mask) {
  33. while (!(mask & 0x1)) {
  34. mask = mask >> 1;
  35. first++;
  36. }
  37. while (mask & 0x1) {
  38. mask = mask >> 1;
  39. len++;
  40. }
  41. }
  42. *pos = first;
  43. *size = len;
  44. }
  45. /**
  46. * get_mode_info() - Ask EFI for the mode information
  47. *
  48. * Gets info from the graphics-output protocol
  49. *
  50. * @vesa: Place to put the mode information
  51. * @fbp: Returns the address of the frame buffer
  52. * @infop: Returns a pointer to the mode info
  53. * Returns: 0 if OK, -ENOSYS if boot services are not available, -ENOTSUPP if
  54. * the protocol is not supported by EFI
  55. */
  56. static int get_mode_info(struct vesa_mode_info *vesa, u64 *fbp,
  57. struct efi_gop_mode_info **infop)
  58. {
  59. efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
  60. struct efi_boot_services *boot = efi_get_boot();
  61. struct efi_gop_mode *mode;
  62. struct efi_gop *gop;
  63. int ret;
  64. if (!boot)
  65. return log_msg_ret("sys", -ENOSYS);
  66. ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop);
  67. if (ret)
  68. return log_msg_ret("prot", -ENOTSUPP);
  69. mode = gop->mode;
  70. log_debug("maxmode %u, mode %u, info %p, size %lx, fb %lx, fb_size %lx\n",
  71. mode->max_mode, mode->mode, mode->info, mode->info_size,
  72. (ulong)mode->fb_base, (ulong)mode->fb_size);
  73. vesa->phys_base_ptr = mode->fb_base;
  74. *fbp = mode->fb_base;
  75. vesa->x_resolution = mode->info->width;
  76. vesa->y_resolution = mode->info->height;
  77. *infop = mode->info;
  78. return 0;
  79. }
  80. /**
  81. * get_mode_from_entry() - Obtain fb info from the EFIET_GOP_MODE payload entry
  82. *
  83. * This gets the mode information provided by the stub to the payload and puts
  84. * it into a vesa structure. It also returns the mode information.
  85. *
  86. * @vesa: Place to put the mode information
  87. * @fbp: Returns the address of the frame buffer
  88. * @infop: Returns a pointer to the mode info
  89. * Returns: 0 if OK, -ve on error
  90. */
  91. static int get_mode_from_entry(struct vesa_mode_info *vesa, u64 *fbp,
  92. struct efi_gop_mode_info **infop)
  93. {
  94. struct efi_gop_mode *mode;
  95. int size;
  96. int ret;
  97. ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size);
  98. if (ret) {
  99. printf("EFI graphics output entry not found\n");
  100. return ret;
  101. }
  102. vesa->phys_base_ptr = mode->fb_base;
  103. *fbp = mode->fb_base;
  104. vesa->x_resolution = mode->info->width;
  105. vesa->y_resolution = mode->info->height;
  106. *infop = mode->info;
  107. return 0;
  108. }
  109. static int save_vesa_mode(struct vesa_mode_info *vesa, u64 *fbp)
  110. {
  111. const struct efi_framebuffer *fbinfo;
  112. struct efi_gop_mode_info *info;
  113. int ret;
  114. if (IS_ENABLED(CONFIG_EFI_APP))
  115. ret = get_mode_info(vesa, fbp, &info);
  116. else
  117. ret = get_mode_from_entry(vesa, fbp, &info);
  118. if (ret) {
  119. printf("EFI graphics output protocol not found (err=%dE)\n",
  120. ret);
  121. return ret;
  122. }
  123. if (info->pixel_format < EFI_GOT_BITMASK) {
  124. fbinfo = &efi_framebuffer_format_map[info->pixel_format];
  125. vesa->red_mask_size = fbinfo->red.size;
  126. vesa->red_mask_pos = fbinfo->red.pos;
  127. vesa->green_mask_size = fbinfo->green.size;
  128. vesa->green_mask_pos = fbinfo->green.pos;
  129. vesa->blue_mask_size = fbinfo->blue.size;
  130. vesa->blue_mask_pos = fbinfo->blue.pos;
  131. vesa->reserved_mask_size = fbinfo->rsvd.size;
  132. vesa->reserved_mask_pos = fbinfo->rsvd.pos;
  133. vesa->bits_per_pixel = 32;
  134. vesa->bytes_per_scanline = info->pixels_per_scanline * 4;
  135. } else if (info->pixel_format == EFI_GOT_BITMASK) {
  136. efi_find_pixel_bits(info->pixel_bitmask[0],
  137. &vesa->red_mask_pos,
  138. &vesa->red_mask_size);
  139. efi_find_pixel_bits(info->pixel_bitmask[1],
  140. &vesa->green_mask_pos,
  141. &vesa->green_mask_size);
  142. efi_find_pixel_bits(info->pixel_bitmask[2],
  143. &vesa->blue_mask_pos,
  144. &vesa->blue_mask_size);
  145. efi_find_pixel_bits(info->pixel_bitmask[3],
  146. &vesa->reserved_mask_pos,
  147. &vesa->reserved_mask_size);
  148. vesa->bits_per_pixel = vesa->red_mask_size +
  149. vesa->green_mask_size +
  150. vesa->blue_mask_size +
  151. vesa->reserved_mask_size;
  152. vesa->bytes_per_scanline = (info->pixels_per_scanline *
  153. vesa->bits_per_pixel) / 8;
  154. } else {
  155. log_err("Unknown framebuffer format: %d\n", info->pixel_format);
  156. return -EINVAL;
  157. }
  158. return 0;
  159. }
  160. static int efi_video_probe(struct udevice *dev)
  161. {
  162. struct video_uc_plat *plat = dev_get_uclass_plat(dev);
  163. struct video_priv *uc_priv = dev_get_uclass_priv(dev);
  164. struct vesa_mode_info *vesa = &mode_info.vesa;
  165. u64 fb;
  166. int ret;
  167. /* Initialize vesa_mode_info structure */
  168. ret = save_vesa_mode(vesa, &fb);
  169. if (ret)
  170. goto err;
  171. ret = vesa_setup_video_priv(vesa, fb, uc_priv, plat);
  172. if (ret)
  173. goto err;
  174. printf("Video: %dx%dx%d @ %lx\n", uc_priv->xsize, uc_priv->ysize,
  175. vesa->bits_per_pixel, (ulong)fb);
  176. return 0;
  177. err:
  178. printf("No video mode configured in EFI!\n");
  179. return ret;
  180. }
  181. static int efi_video_bind(struct udevice *dev)
  182. {
  183. if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
  184. struct video_uc_plat *plat = dev_get_uclass_plat(dev);
  185. struct vesa_mode_info vesa;
  186. int ret;
  187. u64 fb;
  188. /*
  189. * Initialise vesa_mode_info structure so we can figure out the
  190. * required framebuffer size. If something goes wrong, just do
  191. * without a copy framebuffer
  192. */
  193. ret = save_vesa_mode(&vesa, &fb);
  194. if (!ret) {
  195. /* this is not reached if the EFI call failed */
  196. plat->copy_size = vesa.bytes_per_scanline *
  197. vesa.y_resolution;
  198. }
  199. }
  200. return 0;
  201. }
  202. static const struct udevice_id efi_video_ids[] = {
  203. { .compatible = "efi-fb" },
  204. { }
  205. };
  206. U_BOOT_DRIVER(efi_video) = {
  207. .name = "efi_video",
  208. .id = UCLASS_VIDEO,
  209. .of_match = efi_video_ids,
  210. .bind = efi_video_bind,
  211. .probe = efi_video_probe,
  212. };