d4b3eafb273828ef4114d840f8f4cc21037089a9
[mirror_edk2.git] / OptionRomPkg / CirrusLogic5430Dxe / CirrusLogic5430GraphicsOutput.c
1 /** @file
2 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
3 This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
7
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11 Module Name:
12
13 UefiCirrusLogic5430GraphicsOutput.c
14
15 Abstract:
16
17 This file produces the graphics abstration of Graphics Output Protocol. It is called by
18 CirrusLogic5430.c file which deals with the EFI 1.1 driver model.
19 This file just does graphics.
20
21 **/
22 #include "CirrusLogic5430.h"
23 #include <IndustryStandard/Acpi.h>
24
25
26 STATIC
27 VOID
28 CirrusLogic5430CompleteModeInfo (
29 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info
30 )
31 {
32 Info->Version = 0;
33 Info->PixelFormat = PixelBitMask;
34 Info->PixelInformation.RedMask = PIXEL_RED_MASK;
35 Info->PixelInformation.GreenMask = PIXEL_GREEN_MASK;
36 Info->PixelInformation.BlueMask = PIXEL_BLUE_MASK;
37 Info->PixelInformation.ReservedMask = 0;
38 Info->PixelsPerScanLine = Info->HorizontalResolution;
39 }
40
41
42 STATIC
43 EFI_STATUS
44 CirrusLogic5430CompleteModeData (
45 IN CIRRUS_LOGIC_5430_PRIVATE_DATA *Private,
46 OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
47 )
48 {
49 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
50 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
51
52 Info = Mode->Info;
53 CirrusLogic5430CompleteModeInfo (Info);
54
55 Private->PciIo->GetBarAttributes (
56 Private->PciIo,
57 0,
58 NULL,
59 (VOID**) &FrameBufDesc
60 );
61
62 Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin;
63 Mode->FrameBufferSize = Info->HorizontalResolution * Info->VerticalResolution;
64
65 return EFI_SUCCESS;
66 }
67
68
69 //
70 // Graphics Output Protocol Member Functions
71 //
72 EFI_STATUS
73 EFIAPI
74 CirrusLogic5430GraphicsOutputQueryMode (
75 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
76 IN UINT32 ModeNumber,
77 OUT UINTN *SizeOfInfo,
78 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
79 )
80 /*++
81
82 Routine Description:
83
84 Graphics Output protocol interface to query video mode
85
86 Arguments:
87 This - Protocol instance pointer.
88 ModeNumber - The mode number to return information on.
89 Info - Caller allocated buffer that returns information about ModeNumber.
90 SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
91
92 Returns:
93 EFI_SUCCESS - Mode information returned.
94 EFI_BUFFER_TOO_SMALL - The Info buffer was too small.
95 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
96 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
97 EFI_INVALID_PARAMETER - One of the input args was NULL.
98
99 --*/
100 {
101 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private;
102
103 Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
104
105 if (Private->HardwareNeedsStarting) {
106 return EFI_NOT_STARTED;
107 }
108
109 if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
110 return EFI_INVALID_PARAMETER;
111 }
112
113 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
114 if (*Info == NULL) {
115 return EFI_OUT_OF_RESOURCES;
116 }
117
118 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
119
120 (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
121 (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution;
122 CirrusLogic5430CompleteModeInfo (*Info);
123
124 return EFI_SUCCESS;
125 }
126
127 EFI_STATUS
128 EFIAPI
129 CirrusLogic5430GraphicsOutputSetMode (
130 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
131 IN UINT32 ModeNumber
132 )
133 /*++
134
135 Routine Description:
136
137 Graphics Output protocol interface to set video mode
138
139 Arguments:
140 This - Protocol instance pointer.
141 ModeNumber - The mode number to be set.
142
143 Returns:
144 EFI_SUCCESS - Graphics mode was changed.
145 EFI_DEVICE_ERROR - The device had an error and could not complete the request.
146 EFI_UNSUPPORTED - ModeNumber is not supported by this device.
147
148 --*/
149 {
150 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private;
151 CIRRUS_LOGIC_5430_MODE_DATA *ModeData;
152
153 Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
154
155 if (ModeNumber >= This->Mode->MaxMode) {
156 return EFI_UNSUPPORTED;
157 }
158
159 ModeData = &Private->ModeData[ModeNumber];
160
161 if (Private->LineBuffer) {
162 gBS->FreePool (Private->LineBuffer);
163 }
164
165 Private->LineBuffer = NULL;
166 Private->LineBuffer = AllocatePool (ModeData->HorizontalResolution);
167 if (Private->LineBuffer == NULL) {
168 return EFI_OUT_OF_RESOURCES;
169 }
170
171 InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[ModeData->ModeNumber]);
172
173 This->Mode->Mode = ModeNumber;
174 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
175 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
176 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
177
178 CirrusLogic5430CompleteModeData (Private, This->Mode);
179
180 Private->HardwareNeedsStarting = FALSE;
181
182 return EFI_SUCCESS;
183 }
184
185 EFI_STATUS
186 EFIAPI
187 CirrusLogic5430GraphicsOutputBlt (
188 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
189 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
190 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
191 IN UINTN SourceX,
192 IN UINTN SourceY,
193 IN UINTN DestinationX,
194 IN UINTN DestinationY,
195 IN UINTN Width,
196 IN UINTN Height,
197 IN UINTN Delta
198 )
199 /*++
200
201 Routine Description:
202
203 Graphics Output protocol instance to block transfer for CirrusLogic device
204
205 Arguments:
206
207 This - Pointer to Graphics Output protocol instance
208 BltBuffer - The data to transfer to screen
209 BltOperation - The operation to perform
210 SourceX - The X coordinate of the source for BltOperation
211 SourceY - The Y coordinate of the source for BltOperation
212 DestinationX - The X coordinate of the destination for BltOperation
213 DestinationY - The Y coordinate of the destination for BltOperation
214 Width - The width of a rectangle in the blt rectangle in pixels
215 Height - The height of a rectangle in the blt rectangle in pixels
216 Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
217 If a Delta of 0 is used, the entire BltBuffer will be operated on.
218 If a subrectangle of the BltBuffer is used, then Delta represents
219 the number of bytes in a row of the BltBuffer.
220
221 Returns:
222
223 EFI_INVALID_PARAMETER - Invalid parameter passed in
224 EFI_SUCCESS - Blt operation success
225
226 --*/
227 {
228 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private;
229 EFI_TPL OriginalTPL;
230 UINTN DstY;
231 UINTN SrcY;
232 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
233 UINTN X;
234 UINT8 Pixel;
235 UINT32 WidePixel;
236 UINTN ScreenWidth;
237 UINTN Offset;
238 UINTN SourceOffset;
239 UINT32 CurrentMode;
240
241 Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
242
243 if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
244 return EFI_INVALID_PARAMETER;
245 }
246
247 if (Width == 0 || Height == 0) {
248 return EFI_INVALID_PARAMETER;
249 }
250
251 //
252 // If Delta is zero, then the entire BltBuffer is being used, so Delta
253 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
254 // the number of bytes in each row can be computed.
255 //
256 if (Delta == 0) {
257 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
258 }
259
260 //
261 // We need to fill the Virtual Screen buffer with the blt data.
262 // The virtual screen is upside down, as the first row is the bootom row of
263 // the image.
264 //
265
266 CurrentMode = This->Mode->Mode;
267 //
268 // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
269 // are valid for the operation and the current screen geometry.
270 //
271 if (BltOperation == EfiBltVideoToBltBuffer) {
272 //
273 // Video to BltBuffer: Source is Video, destination is BltBuffer
274 //
275 if (SourceY + Height > Private->ModeData[CurrentMode].VerticalResolution) {
276 return EFI_INVALID_PARAMETER;
277 }
278
279 if (SourceX + Width > Private->ModeData[CurrentMode].HorizontalResolution) {
280 return EFI_INVALID_PARAMETER;
281 }
282 } else {
283 //
284 // BltBuffer to Video: Source is BltBuffer, destination is Video
285 //
286 if (DestinationY + Height > Private->ModeData[CurrentMode].VerticalResolution) {
287 return EFI_INVALID_PARAMETER;
288 }
289
290 if (DestinationX + Width > Private->ModeData[CurrentMode].HorizontalResolution) {
291 return EFI_INVALID_PARAMETER;
292 }
293 }
294 //
295 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
296 // We would not want a timer based event (Cursor, ...) to come in while we are
297 // doing this operation.
298 //
299 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
300
301 switch (BltOperation) {
302 case EfiBltVideoToBltBuffer:
303 //
304 // Video to BltBuffer: Source is Video, destination is BltBuffer
305 //
306 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
307
308 Offset = (SrcY * Private->ModeData[CurrentMode].HorizontalResolution) + SourceX;
309 if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {
310 Private->PciIo->Mem.Read (
311 Private->PciIo,
312 EfiPciIoWidthUint32,
313 0,
314 Offset,
315 Width >> 2,
316 Private->LineBuffer
317 );
318 } else {
319 Private->PciIo->Mem.Read (
320 Private->PciIo,
321 EfiPciIoWidthUint8,
322 0,
323 Offset,
324 Width,
325 Private->LineBuffer
326 );
327 }
328
329 for (X = 0; X < Width; X++) {
330 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
331
332 Blt->Red = PIXEL_TO_RED_BYTE (Private->LineBuffer[X]);
333 Blt->Green = PIXEL_TO_GREEN_BYTE (Private->LineBuffer[X]);
334 Blt->Blue = PIXEL_TO_BLUE_BYTE (Private->LineBuffer[X]);
335 }
336 }
337 break;
338
339 case EfiBltVideoToVideo:
340 //
341 // Perform hardware acceleration for Video to Video operations
342 //
343 ScreenWidth = Private->ModeData[CurrentMode].HorizontalResolution;
344 SourceOffset = (SourceY * Private->ModeData[CurrentMode].HorizontalResolution) + (SourceX);
345 Offset = (DestinationY * Private->ModeData[CurrentMode].HorizontalResolution) + (DestinationX);
346
347 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0000);
348 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0010);
349 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0012);
350 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0014);
351
352 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0001);
353 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0011);
354 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0013);
355 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0015);
356
357 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Width << 8) & 0xff00) | 0x20));
358 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Width & 0xff00) | 0x21));
359 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Height << 8) & 0xff00) | 0x22));
360 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Height & 0xff00) | 0x23));
361 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x24));
362 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x25));
363 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x26));
364 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x27));
365 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) << 8) & 0xff00) | 0x28));
366 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 0) & 0xff00) | 0x29));
367 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 8) & 0xff00) | 0x2a));
368 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) << 8) & 0xff00) | 0x2c));
369 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 0) & 0xff00) | 0x2d));
370 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 8) & 0xff00) | 0x2e));
371 outw (Private, GRAPH_ADDRESS_REGISTER, 0x002f);
372 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0030);
373 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0d32);
374 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0033);
375 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0034);
376 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0035);
377
378 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0231);
379
380 outb (Private, GRAPH_ADDRESS_REGISTER, 0x31);
381 while ((inb (Private, GRAPH_DATA_REGISTER) & 0x01) == 0x01)
382 ;
383 break;
384
385 case EfiBltVideoFill:
386 Blt = BltBuffer;
387 Pixel = RGB_BYTES_TO_PIXEL (Blt->Red, Blt->Green, Blt->Blue);
388 WidePixel = (Pixel << 8) | Pixel;
389 WidePixel = (WidePixel << 16) | WidePixel;
390
391 if (DestinationX == 0 && Width == Private->ModeData[CurrentMode].HorizontalResolution) {
392 Offset = DestinationY * Private->ModeData[CurrentMode].HorizontalResolution;
393 if (((Offset & 0x03) == 0) && (((Width * Height) & 0x03) == 0)) {
394 Private->PciIo->Mem.Write (
395 Private->PciIo,
396 EfiPciIoWidthFillUint32,
397 0,
398 Offset,
399 (Width * Height) >> 2,
400 &WidePixel
401 );
402 } else {
403 Private->PciIo->Mem.Write (
404 Private->PciIo,
405 EfiPciIoWidthFillUint8,
406 0,
407 Offset,
408 Width * Height,
409 &Pixel
410 );
411 }
412 } else {
413 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
414 Offset = (DstY * Private->ModeData[CurrentMode].HorizontalResolution) + DestinationX;
415 if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {
416 Private->PciIo->Mem.Write (
417 Private->PciIo,
418 EfiPciIoWidthFillUint32,
419 0,
420 Offset,
421 Width >> 2,
422 &WidePixel
423 );
424 } else {
425 Private->PciIo->Mem.Write (
426 Private->PciIo,
427 EfiPciIoWidthFillUint8,
428 0,
429 Offset,
430 Width,
431 &Pixel
432 );
433 }
434 }
435 }
436 break;
437
438 case EfiBltBufferToVideo:
439 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
440
441 for (X = 0; X < Width; X++) {
442 Blt =
443 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (
444 (UINT8 *) BltBuffer +
445 (SrcY * Delta) +
446 ((SourceX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))
447 );
448 Private->LineBuffer[X] =
449 RGB_BYTES_TO_PIXEL (Blt->Red, Blt->Green, Blt->Blue);
450 }
451
452 Offset = (DstY * Private->ModeData[CurrentMode].HorizontalResolution) + DestinationX;
453
454 if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {
455 Private->PciIo->Mem.Write (
456 Private->PciIo,
457 EfiPciIoWidthUint32,
458 0,
459 Offset,
460 Width >> 2,
461 Private->LineBuffer
462 );
463 } else {
464 Private->PciIo->Mem.Write (
465 Private->PciIo,
466 EfiPciIoWidthUint8,
467 0,
468 Offset,
469 Width,
470 Private->LineBuffer
471 );
472 }
473 }
474 break;
475 default:
476 ASSERT (FALSE);
477 }
478
479 gBS->RestoreTPL (OriginalTPL);
480
481 return EFI_SUCCESS;
482 }
483
484 EFI_STATUS
485 CirrusLogic5430GraphicsOutputConstructor (
486 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private
487 )
488 {
489 EFI_STATUS Status;
490 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
491
492
493 GraphicsOutput = &Private->GraphicsOutput;
494 GraphicsOutput->QueryMode = CirrusLogic5430GraphicsOutputQueryMode;
495 GraphicsOutput->SetMode = CirrusLogic5430GraphicsOutputSetMode;
496 GraphicsOutput->Blt = CirrusLogic5430GraphicsOutputBlt;
497
498 //
499 // Initialize the private data
500 //
501 Status = gBS->AllocatePool (
502 EfiBootServicesData,
503 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
504 (VOID **) &Private->GraphicsOutput.Mode
505 );
506 if (EFI_ERROR (Status)) {
507 return Status;
508 }
509 Status = gBS->AllocatePool (
510 EfiBootServicesData,
511 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
512 (VOID **) &Private->GraphicsOutput.Mode->Info
513 );
514 if (EFI_ERROR (Status)) {
515 return Status;
516 }
517 Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;
518 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
519 Private->HardwareNeedsStarting = TRUE;
520 Private->LineBuffer = NULL;
521
522 //
523 // Initialize the hardware
524 //
525 GraphicsOutput->SetMode (GraphicsOutput, 0);
526 ASSERT (Private->GraphicsOutput.Mode->Mode < CIRRUS_LOGIC_5430_MODE_COUNT);
527 DrawLogo (
528 Private,
529 Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,
530 Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution
531 );
532
533 return EFI_SUCCESS;
534 }
535
536 EFI_STATUS
537 CirrusLogic5430GraphicsOutputDestructor (
538 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private
539 )
540 /*++
541
542 Routine Description:
543
544 Arguments:
545
546 Returns:
547
548 None
549
550 --*/
551 {
552 if (Private->GraphicsOutput.Mode != NULL) {
553 if (Private->GraphicsOutput.Mode->Info != NULL) {
554 gBS->FreePool (Private->GraphicsOutput.Mode->Info);
555 }
556 gBS->FreePool (Private->GraphicsOutput.Mode);
557 }
558
559 return EFI_SUCCESS;
560 }
561
562