LcdGraphicsOutputDxe.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /** @file
  2. This file implements the Graphics Output protocol for Arm platforms
  3. Copyright (c) 2011-2018, ARM Ltd. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <PiDxe.h>
  7. #include <Library/BaseMemoryLib.h>
  8. #include <Library/DevicePathLib.h>
  9. #include <Library/UefiBootServicesTableLib.h>
  10. #include <Library/UefiRuntimeServicesTableLib.h>
  11. #include <Library/MemoryAllocationLib.h>
  12. #include <Guid/GlobalVariable.h>
  13. #include "LcdGraphicsOutputDxe.h"
  14. //
  15. // Global variables
  16. //
  17. BOOLEAN mDisplayInitialized = FALSE;
  18. LCD_INSTANCE mLcdTemplate = {
  19. LCD_INSTANCE_SIGNATURE,
  20. NULL, // Handle
  21. { // ModeInfo
  22. 0, // Version
  23. 0, // HorizontalResolution
  24. 0, // VerticalResolution
  25. PixelBltOnly, // PixelFormat
  26. { 0 }, // PixelInformation
  27. 0, // PixelsPerScanLine
  28. },
  29. {
  30. 0, // MaxMode;
  31. 0, // Mode;
  32. NULL, // Info;
  33. 0, // SizeOfInfo;
  34. 0, // FrameBufferBase;
  35. 0 // FrameBufferSize;
  36. },
  37. { // Gop
  38. LcdGraphicsQueryMode, // QueryMode
  39. LcdGraphicsSetMode, // SetMode
  40. LcdGraphicsBlt, // Blt
  41. NULL // *Mode
  42. },
  43. { // DevicePath
  44. {
  45. {
  46. HARDWARE_DEVICE_PATH, HW_VENDOR_DP,
  47. {
  48. (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
  49. (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
  50. },
  51. },
  52. // Hardware Device Path for Lcd
  53. EFI_CALLER_ID_GUID // Use the driver's GUID
  54. },
  55. {
  56. END_DEVICE_PATH_TYPE,
  57. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  58. {
  59. sizeof (EFI_DEVICE_PATH_PROTOCOL),
  60. 0
  61. }
  62. }
  63. },
  64. (EFI_EVENT)NULL // ExitBootServicesEvent
  65. };
  66. EFI_STATUS
  67. LcdInstanceContructor (
  68. OUT LCD_INSTANCE** NewInstance
  69. )
  70. {
  71. LCD_INSTANCE* Instance;
  72. Instance = AllocateCopyPool (sizeof (LCD_INSTANCE), &mLcdTemplate);
  73. if (Instance == NULL) {
  74. return EFI_OUT_OF_RESOURCES;
  75. }
  76. Instance->Gop.Mode = &Instance->Mode;
  77. Instance->Gop.Mode->MaxMode = LcdPlatformGetMaxMode ();
  78. Instance->Mode.Info = &Instance->ModeInfo;
  79. *NewInstance = Instance;
  80. return EFI_SUCCESS;
  81. }
  82. //
  83. // Function Definitions
  84. //
  85. EFI_STATUS
  86. InitializeDisplay (
  87. IN LCD_INSTANCE* Instance
  88. )
  89. {
  90. EFI_STATUS Status = EFI_SUCCESS;
  91. EFI_PHYSICAL_ADDRESS VramBaseAddress;
  92. UINTN VramSize;
  93. Status = LcdPlatformGetVram (&VramBaseAddress, &VramSize);
  94. if (EFI_ERROR (Status)) {
  95. return Status;
  96. }
  97. // Setup the LCD
  98. Status = LcdInitialize (VramBaseAddress);
  99. if (EFI_ERROR (Status)) {
  100. goto EXIT_ERROR_LCD_SHUTDOWN;
  101. }
  102. Status = LcdPlatformInitializeDisplay (Instance->Handle);
  103. if (EFI_ERROR (Status)) {
  104. goto EXIT_ERROR_LCD_SHUTDOWN;
  105. }
  106. // Setup all the relevant mode information
  107. Instance->Gop.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
  108. Instance->Gop.Mode->FrameBufferBase = VramBaseAddress;
  109. // Set the flag before changing the mode, to avoid infinite loops
  110. mDisplayInitialized = TRUE;
  111. // All is ok, so don't deal with any errors
  112. goto EXIT;
  113. EXIT_ERROR_LCD_SHUTDOWN:
  114. DEBUG ((DEBUG_ERROR, "InitializeDisplay: ERROR - Can not initialise the display. Exit Status=%r\n", Status));
  115. LcdShutdown ();
  116. EXIT:
  117. return Status;
  118. }
  119. EFI_STATUS
  120. EFIAPI
  121. LcdGraphicsOutputDxeInitialize (
  122. IN EFI_HANDLE ImageHandle,
  123. IN EFI_SYSTEM_TABLE *SystemTable
  124. )
  125. {
  126. EFI_STATUS Status = EFI_SUCCESS;
  127. LCD_INSTANCE* Instance;
  128. Status = LcdIdentify ();
  129. if (EFI_ERROR (Status)) {
  130. goto EXIT;
  131. }
  132. Status = LcdInstanceContructor (&Instance);
  133. if (EFI_ERROR (Status)) {
  134. goto EXIT;
  135. }
  136. // Install the Graphics Output Protocol and the Device Path
  137. Status = gBS->InstallMultipleProtocolInterfaces (
  138. &Instance->Handle,
  139. &gEfiGraphicsOutputProtocolGuid,
  140. &Instance->Gop,
  141. &gEfiDevicePathProtocolGuid,
  142. &Instance->DevicePath,
  143. NULL
  144. );
  145. if (EFI_ERROR (Status)) {
  146. DEBUG ((DEBUG_ERROR, "LcdGraphicsOutputDxeInitialize: Can not install the protocol. Exit Status=%r\n", Status));
  147. goto EXIT;
  148. }
  149. // Register for an ExitBootServicesEvent
  150. // When ExitBootServices starts, this function will make sure that the
  151. // graphics driver shuts down properly, i.e. it will free up all
  152. // allocated memory and perform any necessary hardware re-configuration.
  153. Status = gBS->CreateEvent (
  154. EVT_SIGNAL_EXIT_BOOT_SERVICES,
  155. TPL_NOTIFY,
  156. LcdGraphicsExitBootServicesEvent,
  157. NULL,
  158. &Instance->ExitBootServicesEvent
  159. );
  160. if (EFI_ERROR (Status)) {
  161. DEBUG ((DEBUG_ERROR, "LcdGraphicsOutputDxeInitialize: Can not install the ExitBootServicesEvent handler. Exit Status=%r\n", Status));
  162. goto EXIT_ERROR_UNINSTALL_PROTOCOL;
  163. }
  164. // To get here, everything must be fine, so just exit
  165. goto EXIT;
  166. EXIT_ERROR_UNINSTALL_PROTOCOL:
  167. // The following function could return an error message,
  168. // however, to get here something must have gone wrong already,
  169. // so preserve the original error, i.e. don't change
  170. // the Status variable, even it fails to uninstall the protocol.
  171. gBS->UninstallMultipleProtocolInterfaces (
  172. Instance->Handle,
  173. &gEfiGraphicsOutputProtocolGuid,
  174. &Instance->Gop, // Uninstall Graphics Output protocol
  175. &gEfiDevicePathProtocolGuid,
  176. &Instance->DevicePath, // Uninstall device path
  177. NULL
  178. );
  179. EXIT:
  180. return Status;
  181. }
  182. /** This function should be called
  183. on Event: ExitBootServices
  184. to free up memory, stop the driver
  185. and uninstall the protocols
  186. **/
  187. VOID
  188. LcdGraphicsExitBootServicesEvent (
  189. IN EFI_EVENT Event,
  190. IN VOID *Context
  191. )
  192. {
  193. // By default, this PCD is FALSE. But if a platform starts a predefined OS
  194. // that does not use a framebuffer then we might want to disable the display
  195. // controller to avoid to display corrupted information on the screen.
  196. if (FeaturePcdGet (PcdGopDisableOnExitBootServices)) {
  197. // Turn-off the Display controller
  198. LcdShutdown ();
  199. }
  200. }
  201. /** GraphicsOutput Protocol function, mapping to
  202. EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode
  203. **/
  204. EFI_STATUS
  205. EFIAPI
  206. LcdGraphicsQueryMode (
  207. IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
  208. IN UINT32 ModeNumber,
  209. OUT UINTN *SizeOfInfo,
  210. OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
  211. )
  212. {
  213. EFI_STATUS Status = EFI_SUCCESS;
  214. LCD_INSTANCE *Instance;
  215. Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
  216. // Setup the hardware if not already done
  217. if (!mDisplayInitialized) {
  218. Status = InitializeDisplay (Instance);
  219. if (EFI_ERROR (Status)) {
  220. goto EXIT;
  221. }
  222. }
  223. // Error checking
  224. if ((This == NULL) ||
  225. (Info == NULL) ||
  226. (SizeOfInfo == NULL) ||
  227. (ModeNumber >= This->Mode->MaxMode)) {
  228. DEBUG ((DEBUG_ERROR, "LcdGraphicsQueryMode: ERROR - For mode number %d : Invalid Parameter.\n", ModeNumber));
  229. Status = EFI_INVALID_PARAMETER;
  230. goto EXIT;
  231. }
  232. *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
  233. if (*Info == NULL) {
  234. Status = EFI_OUT_OF_RESOURCES;
  235. goto EXIT;
  236. }
  237. *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
  238. Status = LcdPlatformQueryMode (ModeNumber, *Info);
  239. if (EFI_ERROR (Status)) {
  240. FreePool (*Info);
  241. }
  242. EXIT:
  243. return Status;
  244. }
  245. /** GraphicsOutput Protocol function, mapping to
  246. EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode
  247. **/
  248. EFI_STATUS
  249. EFIAPI
  250. LcdGraphicsSetMode (
  251. IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
  252. IN UINT32 ModeNumber
  253. )
  254. {
  255. EFI_STATUS Status = EFI_SUCCESS;
  256. EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColour;
  257. LCD_INSTANCE* Instance;
  258. LCD_BPP Bpp;
  259. Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
  260. // Setup the hardware if not already done
  261. if (!mDisplayInitialized) {
  262. Status = InitializeDisplay (Instance);
  263. if (EFI_ERROR (Status)) {
  264. goto EXIT;
  265. }
  266. }
  267. // Check if this mode is supported
  268. if (ModeNumber >= This->Mode->MaxMode) {
  269. DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Unsupported mode number %d .\n", ModeNumber));
  270. Status = EFI_UNSUPPORTED;
  271. goto EXIT;
  272. }
  273. // Set the oscillator frequency to support the new mode
  274. Status = LcdPlatformSetMode (ModeNumber);
  275. if (EFI_ERROR (Status)) {
  276. Status = EFI_DEVICE_ERROR;
  277. goto EXIT;
  278. }
  279. // Update the UEFI mode information
  280. This->Mode->Mode = ModeNumber;
  281. LcdPlatformQueryMode (ModeNumber, &Instance->ModeInfo);
  282. Status = LcdPlatformGetBpp (ModeNumber, &Bpp);
  283. if (EFI_ERROR (Status)) {
  284. DEBUG ((DEBUG_ERROR, "LcdGraphicsSetMode: ERROR - Couldn't get bytes per pixel, status: %r\n", Status));
  285. goto EXIT;
  286. }
  287. This->Mode->FrameBufferSize = Instance->ModeInfo.VerticalResolution
  288. * Instance->ModeInfo.PixelsPerScanLine
  289. * GetBytesPerPixel (Bpp);
  290. // Set the hardware to the new mode
  291. Status = LcdSetMode (ModeNumber);
  292. if (EFI_ERROR (Status)) {
  293. Status = EFI_DEVICE_ERROR;
  294. goto EXIT;
  295. }
  296. // The UEFI spec requires that we now clear the visible portions of the
  297. // output display to black.
  298. // Set the fill colour to black
  299. SetMem (&FillColour, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
  300. // Fill the entire visible area with the same colour.
  301. Status = This->Blt (
  302. This,
  303. &FillColour,
  304. EfiBltVideoFill,
  305. 0,
  306. 0,
  307. 0,
  308. 0,
  309. This->Mode->Info->HorizontalResolution,
  310. This->Mode->Info->VerticalResolution,
  311. 0
  312. );
  313. EXIT:
  314. return Status;
  315. }
  316. UINTN
  317. GetBytesPerPixel (
  318. IN LCD_BPP Bpp
  319. )
  320. {
  321. switch (Bpp) {
  322. case LCD_BITS_PER_PIXEL_24:
  323. return 4;
  324. case LCD_BITS_PER_PIXEL_16_565:
  325. case LCD_BITS_PER_PIXEL_16_555:
  326. case LCD_BITS_PER_PIXEL_12_444:
  327. return 2;
  328. case LCD_BITS_PER_PIXEL_8:
  329. case LCD_BITS_PER_PIXEL_4:
  330. case LCD_BITS_PER_PIXEL_2:
  331. case LCD_BITS_PER_PIXEL_1:
  332. return 1;
  333. default:
  334. return 0;
  335. }
  336. }