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