efi_gop.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. * EFI application disk support
  3. *
  4. * Copyright (c) 2016 Alexander Graf
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <dm.h>
  10. #include <efi_loader.h>
  11. #include <inttypes.h>
  12. #include <lcd.h>
  13. #include <malloc.h>
  14. #include <video.h>
  15. DECLARE_GLOBAL_DATA_PTR;
  16. static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
  17. struct efi_gop_obj {
  18. /* Generic EFI object parent class data */
  19. struct efi_object parent;
  20. /* EFI Interface callback struct for gop */
  21. struct efi_gop ops;
  22. /* The only mode we support */
  23. struct efi_gop_mode_info info;
  24. struct efi_gop_mode mode;
  25. /* Fields we only have acces to during init */
  26. u32 bpix;
  27. void *fb;
  28. };
  29. static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
  30. efi_uintn_t *size_of_info,
  31. struct efi_gop_mode_info **info)
  32. {
  33. struct efi_gop_obj *gopobj;
  34. EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info);
  35. gopobj = container_of(this, struct efi_gop_obj, ops);
  36. *size_of_info = sizeof(gopobj->info);
  37. *info = &gopobj->info;
  38. return EFI_EXIT(EFI_SUCCESS);
  39. }
  40. static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
  41. {
  42. EFI_ENTRY("%p, %x", this, mode_number);
  43. if (mode_number != 0)
  44. return EFI_EXIT(EFI_INVALID_PARAMETER);
  45. return EFI_EXIT(EFI_SUCCESS);
  46. }
  47. static inline struct efi_gop_pixel efi_vid16_to_blt_col(u16 vid)
  48. {
  49. struct efi_gop_pixel blt = {
  50. .reserved = 0,
  51. };
  52. blt.blue = (vid & 0x1f) << 3;
  53. vid >>= 5;
  54. blt.green = (vid & 0x3f) << 2;
  55. vid >>= 6;
  56. blt.red = (vid & 0x1f) << 3;
  57. return blt;
  58. }
  59. static inline u16 efi_blt_col_to_vid16(struct efi_gop_pixel *blt)
  60. {
  61. return (u16)(blt->red >> 3) << 11 |
  62. (u16)(blt->green >> 2) << 5 |
  63. (u16)(blt->blue >> 3);
  64. }
  65. efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer,
  66. u32 operation, efi_uintn_t sx,
  67. efi_uintn_t sy, efi_uintn_t dx,
  68. efi_uintn_t dy, efi_uintn_t width,
  69. efi_uintn_t height, efi_uintn_t delta)
  70. {
  71. struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops);
  72. efi_uintn_t i, j, linelen;
  73. u32 *fb32 = gopobj->fb;
  74. u16 *fb16 = gopobj->fb;
  75. if (delta)
  76. linelen = delta;
  77. else
  78. linelen = width;
  79. EFI_ENTRY("%p, %p, %u, %zu, %zu, %zu, %zu, %zu, %zu, %zu", this,
  80. buffer, operation, sx, sy, dx, dy, width, height, delta);
  81. /* Check source rectangle */
  82. switch (operation) {
  83. case EFI_BLT_VIDEO_FILL:
  84. break;
  85. case EFI_BLT_BUFFER_TO_VIDEO:
  86. if (sx + width > linelen)
  87. return EFI_EXIT(EFI_INVALID_PARAMETER);
  88. break;
  89. case EFI_BLT_VIDEO_TO_BLT_BUFFER:
  90. case EFI_BLT_VIDEO_TO_VIDEO:
  91. if (sx + width > gopobj->info.width ||
  92. sy + height > gopobj->info.height)
  93. return EFI_EXIT(EFI_INVALID_PARAMETER);
  94. break;
  95. default:
  96. return EFI_EXIT(EFI_INVALID_PARAMETER);
  97. }
  98. /* Check destination rectangle */
  99. switch (operation) {
  100. case EFI_BLT_VIDEO_FILL:
  101. case EFI_BLT_BUFFER_TO_VIDEO:
  102. case EFI_BLT_VIDEO_TO_VIDEO:
  103. if (dx + width > gopobj->info.width ||
  104. dy + height > gopobj->info.height)
  105. return EFI_EXIT(EFI_INVALID_PARAMETER);
  106. break;
  107. case EFI_BLT_VIDEO_TO_BLT_BUFFER:
  108. if (dx + width > linelen)
  109. return EFI_EXIT(EFI_INVALID_PARAMETER);
  110. break;
  111. }
  112. for (i = 0; i < height; i++) {
  113. for (j = 0; j < width; j++) {
  114. struct efi_gop_pixel pix;
  115. /* Read source pixel */
  116. switch (operation) {
  117. case EFI_BLT_VIDEO_FILL:
  118. pix = *buffer;
  119. break;
  120. case EFI_BLT_BUFFER_TO_VIDEO:
  121. pix = buffer[linelen * (i + sy) + j + sx];
  122. break;
  123. case EFI_BLT_VIDEO_TO_BLT_BUFFER:
  124. case EFI_BLT_VIDEO_TO_VIDEO:
  125. switch (gopobj->bpix) {
  126. #ifdef CONFIG_DM_VIDEO
  127. case VIDEO_BPP32:
  128. #else
  129. case LCD_COLOR32:
  130. #endif
  131. pix = *(struct efi_gop_pixel *)&fb32[
  132. gopobj->info.width *
  133. (i + sy) + j + sx];
  134. break;
  135. #ifdef CONFIG_DM_VIDEO
  136. case VIDEO_BPP16:
  137. #else
  138. case LCD_COLOR16:
  139. #endif
  140. pix = efi_vid16_to_blt_col(fb16[
  141. gopobj->info.width *
  142. (i + sy) + j + sx]);
  143. break;
  144. default:
  145. return EFI_EXIT(EFI_UNSUPPORTED);
  146. }
  147. break;
  148. }
  149. /* Write destination pixel */
  150. switch (operation) {
  151. case EFI_BLT_VIDEO_TO_BLT_BUFFER:
  152. buffer[linelen * (i + dy) + j + dx] = pix;
  153. break;
  154. case EFI_BLT_BUFFER_TO_VIDEO:
  155. case EFI_BLT_VIDEO_FILL:
  156. case EFI_BLT_VIDEO_TO_VIDEO:
  157. switch (gopobj->bpix) {
  158. #ifdef CONFIG_DM_VIDEO
  159. case VIDEO_BPP32:
  160. #else
  161. case LCD_COLOR32:
  162. #endif
  163. fb32[gopobj->info.width *
  164. (i + dy) + j + dx] = *(u32 *)&pix;
  165. break;
  166. #ifdef CONFIG_DM_VIDEO
  167. case VIDEO_BPP16:
  168. #else
  169. case LCD_COLOR16:
  170. #endif
  171. fb16[gopobj->info.width *
  172. (i + dy) + j + dx] =
  173. efi_blt_col_to_vid16(&pix);
  174. break;
  175. default:
  176. return EFI_EXIT(EFI_UNSUPPORTED);
  177. }
  178. break;
  179. }
  180. }
  181. }
  182. #ifdef CONFIG_DM_VIDEO
  183. video_sync_all();
  184. #else
  185. lcd_sync();
  186. #endif
  187. return EFI_EXIT(EFI_SUCCESS);
  188. }
  189. /*
  190. * Install graphical output protocol.
  191. *
  192. * If no supported video device exists this is not considered as an
  193. * error.
  194. */
  195. efi_status_t efi_gop_register(void)
  196. {
  197. struct efi_gop_obj *gopobj;
  198. u32 bpix, col, row;
  199. u64 fb_base, fb_size;
  200. void *fb;
  201. efi_status_t ret;
  202. #ifdef CONFIG_DM_VIDEO
  203. struct udevice *vdev;
  204. struct video_priv *priv;
  205. /* We only support a single video output device for now */
  206. if (uclass_first_device(UCLASS_VIDEO, &vdev) || !vdev) {
  207. debug("WARNING: No video device\n");
  208. return EFI_SUCCESS;
  209. }
  210. priv = dev_get_uclass_priv(vdev);
  211. bpix = priv->bpix;
  212. col = video_get_xsize(vdev);
  213. row = video_get_ysize(vdev);
  214. fb_base = (uintptr_t)priv->fb;
  215. fb_size = priv->fb_size;
  216. fb = priv->fb;
  217. #else
  218. int line_len;
  219. bpix = panel_info.vl_bpix;
  220. col = panel_info.vl_col;
  221. row = panel_info.vl_row;
  222. fb_base = gd->fb_base;
  223. fb_size = lcd_get_size(&line_len);
  224. fb = (void*)gd->fb_base;
  225. #endif
  226. switch (bpix) {
  227. #ifdef CONFIG_DM_VIDEO
  228. case VIDEO_BPP16:
  229. case VIDEO_BPP32:
  230. #else
  231. case LCD_COLOR32:
  232. case LCD_COLOR16:
  233. #endif
  234. break;
  235. default:
  236. /* So far, we only work in 16 or 32 bit mode */
  237. debug("WARNING: Unsupported video mode\n");
  238. return EFI_SUCCESS;
  239. }
  240. gopobj = calloc(1, sizeof(*gopobj));
  241. if (!gopobj) {
  242. printf("ERROR: Out of memory\n");
  243. return EFI_OUT_OF_RESOURCES;
  244. }
  245. /* Hook up to the device list */
  246. efi_add_handle(&gopobj->parent);
  247. /* Fill in object data */
  248. ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid,
  249. &gopobj->ops);
  250. if (ret != EFI_SUCCESS) {
  251. printf("ERROR: Failure adding gop protocol\n");
  252. return ret;
  253. }
  254. gopobj->ops.query_mode = gop_query_mode;
  255. gopobj->ops.set_mode = gop_set_mode;
  256. gopobj->ops.blt = gop_blt;
  257. gopobj->ops.mode = &gopobj->mode;
  258. gopobj->mode.max_mode = 1;
  259. gopobj->mode.info = &gopobj->info;
  260. gopobj->mode.info_size = sizeof(gopobj->info);
  261. #ifdef CONFIG_DM_VIDEO
  262. if (bpix == VIDEO_BPP32)
  263. #else
  264. if (bpix == LCD_COLOR32)
  265. #endif
  266. {
  267. /* With 32bit color space we can directly expose the fb */
  268. gopobj->mode.fb_base = fb_base;
  269. gopobj->mode.fb_size = fb_size;
  270. }
  271. gopobj->info.version = 0;
  272. gopobj->info.width = col;
  273. gopobj->info.height = row;
  274. gopobj->info.pixel_format = EFI_GOT_RGBA8;
  275. gopobj->info.pixels_per_scanline = col;
  276. gopobj->bpix = bpix;
  277. gopobj->fb = fb;
  278. return EFI_SUCCESS;
  279. }