1 /** @file
2 
3  Copyright (c) 2011-2014, ARM Ltd. All rights reserved.<BR>
4  This program and the accompanying materials
5  are licensed and made available under the terms and conditions of the BSD License
6  which accompanies this distribution.  The full text of the license may be found at
7  http://opensource.org/licenses/bsd-license.php
8 
9  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #include "LcdGraphicsOutputDxe.h"
15 
16 BOOLEAN mDisplayInitialized = FALSE;
17 
18 LCD_MODE LcdModes[] = {
19   {
20     0, 640, 480,
21     9, 4,
22     96, 16, 48,
23     2, 10, 33
24   },
25   {
26     1, 800, 600,
27     11, 2,
28     120, 56, 64,
29     5, 37, 22
30   },
31   {
32     2, 1024, 768,
33     6, 2,
34     96, 16, 48,
35     2, 10, 33
36   },
37 };
38 
39 LCD_INSTANCE mLcdTemplate = {
40   LCD_INSTANCE_SIGNATURE,
41   NULL, // Handle
42   { // ModeInfo
43     0, // Version
44     0, // HorizontalResolution
45     0, // VerticalResolution
46     PixelBltOnly, // PixelFormat
47     {
48       0xF800, //RedMask;
49       0x7E0, //GreenMask;
50       0x1F, //BlueMask;
51       0x0//ReservedMask
52     }, // PixelInformation
53     0, // PixelsPerScanLine
54   },
55   { // Mode
56     3, // MaxMode;
57     0, // Mode;
58     NULL, // Info;
59     0, // SizeOfInfo;
60     0, // FrameBufferBase;
61     0 // FrameBufferSize;
62   },
63   { // Gop
64     LcdGraphicsQueryMode,  // QueryMode
65     LcdGraphicsSetMode,    // SetMode
66     LcdGraphicsBlt,        // Blt
67     NULL                     // *Mode
68   },
69   { // DevicePath
70     {
71       {
72         HARDWARE_DEVICE_PATH, HW_VENDOR_DP,
73         { (UINT8) (sizeof(VENDOR_DEVICE_PATH)), (UINT8) ((sizeof(VENDOR_DEVICE_PATH)) >> 8) },
74       },
75       // Hardware Device Path for Lcd
76       EFI_CALLER_ID_GUID // Use the driver's GUID
77     },
78     {
79       END_DEVICE_PATH_TYPE,
80       END_ENTIRE_DEVICE_PATH_SUBTYPE,
81       { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0}
82     }
83   }
84 };
85 
86 EFI_STATUS
LcdInstanceContructor(OUT LCD_INSTANCE ** NewInstance)87 LcdInstanceContructor (
88   OUT LCD_INSTANCE** NewInstance
89   )
90 {
91   LCD_INSTANCE* Instance;
92 
93   Instance = AllocateCopyPool (sizeof(LCD_INSTANCE), &mLcdTemplate);
94   if (Instance == NULL) {
95     return EFI_OUT_OF_RESOURCES;
96   }
97 
98   Instance->Gop.Mode          = &Instance->Mode;
99   Instance->Mode.Info         = &Instance->ModeInfo;
100 
101   *NewInstance = Instance;
102   return EFI_SUCCESS;
103 }
104 
105 EFI_STATUS
LcdPlatformGetVram(OUT EFI_PHYSICAL_ADDRESS * VramBaseAddress,OUT UINTN * VramSize)106 LcdPlatformGetVram (
107   OUT EFI_PHYSICAL_ADDRESS*  VramBaseAddress,
108   OUT UINTN*                 VramSize
109   )
110 {
111   EFI_STATUS             Status;
112   EFI_CPU_ARCH_PROTOCOL  *Cpu;
113   UINTN                  MaxSize;
114 
115   MaxSize = 0x500000;
116   *VramSize = MaxSize;
117 
118   // Allocate VRAM from DRAM
119   Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES((MaxSize)), VramBaseAddress);
120   if (EFI_ERROR(Status)) {
121     return Status;
122   }
123 
124   // Ensure the Cpu architectural protocol is already installed
125   Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
126   ASSERT_EFI_ERROR(Status);
127 
128   // Mark the VRAM as un-cacheable. The VRAM is inside the DRAM, which is cacheable.
129   Status = Cpu->SetMemoryAttributes (Cpu, *VramBaseAddress, *VramSize, EFI_MEMORY_UC);
130   if (EFI_ERROR(Status)) {
131     gBS->FreePool (VramBaseAddress);
132     return Status;
133   }
134 
135   return EFI_SUCCESS;
136 }
137 
138 EFI_STATUS
DssSetMode(UINT32 VramBaseAddress,UINTN ModeNumber)139 DssSetMode (
140   UINT32 VramBaseAddress,
141   UINTN  ModeNumber
142   )
143 {
144   // Make sure the interface clock is running
145   MmioWrite32 (CM_ICLKEN_DSS, EN_DSS);
146 
147   // Stop the functional clocks
148   MmioAnd32 (CM_FCLKEN_DSS, ~(EN_DSS1 | EN_DSS2 | EN_TV));
149 
150   // Program the DSS clock divisor
151   MmioWrite32 (CM_CLKSEL_DSS, 0x1000 | (LcdModes[ModeNumber].DssDivisor));
152 
153   // Start the functional clocks
154   MmioOr32 (CM_FCLKEN_DSS, (EN_DSS1 | EN_DSS2 | EN_TV));
155 
156   // Wait for DSS to stabilize
157   gBS->Stall(1);
158 
159   // Reset the subsystem
160   MmioWrite32(DSS_SYSCONFIG, DSS_SOFTRESET);
161   while (!(MmioRead32 (DSS_SYSSTATUS) & DSS_RESETDONE));
162 
163   // Configure LCD parameters
164   MmioWrite32 (DISPC_SIZE_LCD,
165                ((LcdModes[ModeNumber].HorizontalResolution - 1)
166                | ((LcdModes[ModeNumber].VerticalResolution - 1) << 16))
167               );
168   MmioWrite32 (DISPC_TIMING_H,
169                ( (LcdModes[ModeNumber].HSync - 1)
170                | ((LcdModes[ModeNumber].HFrontPorch - 1) << 8)
171                | ((LcdModes[ModeNumber].HBackPorch - 1) << 20))
172               );
173   MmioWrite32 (DISPC_TIMING_V,
174                ( (LcdModes[ModeNumber].VSync - 1)
175                | ((LcdModes[ModeNumber].VFrontPorch - 1) << 8)
176                | ((LcdModes[ModeNumber].VBackPorch - 1) << 20))
177               );
178 
179   // Set the framebuffer to only load frames (no gamma tables)
180   MmioAnd32 (DISPC_CONFIG, CLEARLOADMODE);
181   MmioOr32  (DISPC_CONFIG, LOAD_FRAME_ONLY);
182 
183   // Divisor for the pixel clock
184   MmioWrite32(DISPC_DIVISOR, ((1 << 16) | LcdModes[ModeNumber].DispcDivisor) );
185 
186   // Set up the graphics layer
187   MmioWrite32 (DISPC_GFX_PRELD, 0x2D8);
188   MmioWrite32 (DISPC_GFX_BA0, VramBaseAddress);
189   MmioWrite32 (DISPC_GFX_SIZE,
190                ((LcdModes[ModeNumber].HorizontalResolution - 1)
191                | ((LcdModes[ModeNumber].VerticalResolution - 1) << 16))
192               );
193 
194   MmioWrite32(DISPC_GFX_ATTR, (GFXENABLE | RGB16 | BURSTSIZE16));
195 
196   // Start it all
197   MmioOr32 (DISPC_CONTROL, (LCDENABLE | ACTIVEMATRIX | DATALINES24 | BYPASS_MODE | LCDENABLESIGNAL));
198   MmioOr32 (DISPC_CONTROL, GOLCD);
199 
200   return EFI_SUCCESS;
201 }
202 
203 EFI_STATUS
HwInitializeDisplay(UINTN VramBaseAddress,UINTN VramSize)204 HwInitializeDisplay (
205   UINTN VramBaseAddress,
206   UINTN VramSize
207   )
208 {
209   EFI_STATUS    Status;
210   UINT8         Data;
211   EFI_TPL       OldTpl;
212   EMBEDDED_EXTERNAL_DEVICE   *gTPS65950;
213 
214   // Enable power lines used by TFP410
215   Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
216   ASSERT_EFI_ERROR (Status);
217 
218   OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
219   Data = VAUX_DEV_GRP_P1;
220   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VPLL2_DEV_GRP), 1, &Data);
221   ASSERT_EFI_ERROR(Status);
222 
223   Data = VAUX_DEDICATED_18V;
224   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VPLL2_DEDICATED), 1, &Data);
225   ASSERT_EFI_ERROR (Status);
226 
227   // Power up TFP410 (set GPIO2 on TPS - for BeagleBoard-xM)
228   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATADIR1), 1, &Data);
229   ASSERT_EFI_ERROR (Status);
230   Data |= BIT2;
231   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATADIR1), 1, &Data);
232   ASSERT_EFI_ERROR (Status);
233 
234   Data = BIT2;
235   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, SETGPIODATAOUT1), 1, &Data);
236   ASSERT_EFI_ERROR (Status);
237 
238   gBS->RestoreTPL(OldTpl);
239 
240   // Power up TFP410 (set GPIO 170 - for older BeagleBoards)
241   MmioAnd32 (GPIO6_BASE + GPIO_OE, ~BIT10);
242   MmioOr32  (GPIO6_BASE + GPIO_SETDATAOUT, BIT10);
243 
244   return EFI_SUCCESS;
245 }
246 
247 EFI_STATUS
InitializeDisplay(IN LCD_INSTANCE * Instance)248 InitializeDisplay (
249   IN LCD_INSTANCE* Instance
250   )
251 {
252   EFI_STATUS           Status;
253   UINTN                VramSize;
254   EFI_PHYSICAL_ADDRESS VramBaseAddress;
255 
256   Status = LcdPlatformGetVram (&VramBaseAddress, &VramSize);
257   if (EFI_ERROR (Status)) {
258     return Status;
259   }
260 
261   Instance->Mode.FrameBufferBase = VramBaseAddress;
262   Instance->Mode.FrameBufferSize = VramSize;
263 
264   Status = HwInitializeDisplay((UINTN)VramBaseAddress, VramSize);
265   if (!EFI_ERROR (Status)) {
266     mDisplayInitialized = TRUE;
267   }
268 
269   return Status;
270 }
271 
272 EFI_STATUS
273 EFIAPI
LcdGraphicsQueryMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber,OUT UINTN * SizeOfInfo,OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** Info)274 LcdGraphicsQueryMode (
275   IN EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
276   IN UINT32                                  ModeNumber,
277   OUT UINTN                                  *SizeOfInfo,
278   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION   **Info
279   )
280 {
281   LCD_INSTANCE  *Instance;
282 
283   Instance = LCD_INSTANCE_FROM_GOP_THIS(This);
284 
285   if (!mDisplayInitialized) {
286     InitializeDisplay (Instance);
287   }
288 
289   // Error checking
290   if ( (This == NULL) || (Info == NULL) || (SizeOfInfo == NULL) || (ModeNumber >= This->Mode->MaxMode) ) {
291     DEBUG((DEBUG_ERROR, "LcdGraphicsQueryMode: ERROR - For mode number %d : Invalid Parameter.\n", ModeNumber ));
292     return EFI_INVALID_PARAMETER;
293   }
294 
295   *Info = AllocateCopyPool(sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), &Instance->ModeInfo);
296   if (*Info == NULL) {
297     return EFI_OUT_OF_RESOURCES;
298   }
299 
300   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
301 
302   (*Info)->Version = 0;
303   (*Info)->HorizontalResolution = LcdModes[ModeNumber].HorizontalResolution;
304   (*Info)->VerticalResolution = LcdModes[ModeNumber].VerticalResolution;
305   (*Info)->PixelFormat = PixelBltOnly;
306 
307   return EFI_SUCCESS;
308 }
309 
310 EFI_STATUS
311 EFIAPI
LcdGraphicsSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber)312 LcdGraphicsSetMode (
313   IN EFI_GRAPHICS_OUTPUT_PROTOCOL   *This,
314   IN UINT32                         ModeNumber
315   )
316 {
317   LCD_INSTANCE  *Instance;
318 
319   Instance = LCD_INSTANCE_FROM_GOP_THIS(This);
320 
321   if (ModeNumber >= Instance->Mode.MaxMode) {
322     return EFI_UNSUPPORTED;
323   }
324 
325   if (!mDisplayInitialized) {
326     InitializeDisplay (Instance);
327   }
328 
329   DssSetMode((UINT32)Instance->Mode.FrameBufferBase, ModeNumber);
330 
331   Instance->Mode.Mode = ModeNumber;
332   Instance->ModeInfo.HorizontalResolution = LcdModes[ModeNumber].HorizontalResolution;
333   Instance->ModeInfo.VerticalResolution = LcdModes[ModeNumber].VerticalResolution;
334 
335   return EFI_SUCCESS;
336 }
337 
338 EFI_STATUS
339 EFIAPI
LcdGraphicsOutputDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)340 LcdGraphicsOutputDxeInitialize (
341   IN EFI_HANDLE         ImageHandle,
342   IN EFI_SYSTEM_TABLE   *SystemTable
343   )
344 {
345   EFI_STATUS Status = EFI_SUCCESS;
346   LCD_INSTANCE* Instance;
347 
348   Status = LcdInstanceContructor (&Instance);
349   if (EFI_ERROR(Status)) {
350     goto EXIT;
351   }
352 
353   // Install the Graphics Output Protocol and the Device Path
354   Status = gBS->InstallMultipleProtocolInterfaces(
355              &Instance->Handle,
356              &gEfiGraphicsOutputProtocolGuid, &Instance->Gop,
357              &gEfiDevicePathProtocolGuid,     &Instance->DevicePath,
358              NULL
359              );
360 
361   if (EFI_ERROR(Status)) {
362     DEBUG((DEBUG_ERROR, "GraphicsOutputDxeInitialize: Can not install the protocol. Exit Status=%r\n", Status));
363     goto EXIT;
364   }
365 
366   // Register for an ExitBootServicesEvent
367   // When ExitBootServices starts, this function here will make sure that the graphics driver will shut down properly,
368   // i.e. it will free up all allocated memory and perform any necessary hardware re-configuration.
369   /*Status = gBS->CreateEvent (
370                EVT_SIGNAL_EXIT_BOOT_SERVICES,
371                TPL_NOTIFY,
372                LcdGraphicsExitBootServicesEvent, NULL,
373                &Instance->ExitBootServicesEvent
374                );
375 
376   if (EFI_ERROR(Status)) {
377     DEBUG((DEBUG_ERROR, "GraphicsOutputDxeInitialize: Can not install the ExitBootServicesEvent handler. Exit Status=%r\n", Status));
378     goto EXIT_ERROR_UNINSTALL_PROTOCOL;
379   }*/
380 
381   // To get here, everything must be fine, so just exit
382   goto EXIT;
383 
384 //EXIT_ERROR_UNINSTALL_PROTOCOL:
385   /* The following function could return an error message,
386    * however, to get here something must have gone wrong already,
387    * so preserve the original error, i.e. don't change
388    * the Status variable, even it fails to uninstall the protocol.
389    */
390   /*  gBS->UninstallMultipleProtocolInterfaces (
391         Instance->Handle,
392         &gEfiGraphicsOutputProtocolGuid, &Instance->Gop, // Uninstall Graphics Output protocol
393         &gEfiDevicePathProtocolGuid,     &Instance->DevicePath,     // Uninstall device path
394         NULL
395         );*/
396 
397 EXIT:
398   return Status;
399 
400 }
401