1 /** @file 2 Copyright (c) 2007 - 2012, 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 ((UINT32)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 563