/** @file\r
ConsoleOut Routines that speak VGA.\r
\r
-Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions\r
\r
UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };\r
\r
+//\r
+// Save controller attributes during first start\r
+//\r
+UINT64 mOriginalPciAttributes;\r
+BOOLEAN mPciAttributesSaved = FALSE;\r
+\r
EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor[] = {\r
{ 0x00, 0x00, 0x00, 0x00 },\r
{ 0x98, 0x00, 0x00, 0x00 },\r
//\r
if (Node->DevPath.Type != ACPI_DEVICE_PATH ||\r
Node->DevPath.SubType != ACPI_ADR_DP ||\r
- DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {\r
+ DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {\r
Status = EFI_UNSUPPORTED;\r
}\r
}\r
EFI_PCI_IO_PROTOCOL *PciIo;\r
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
UINTN Flags;\r
- UINT64 OriginalPciAttributes;\r
UINT64 Supports;\r
- BOOLEAN PciAttributesSaved;\r
\r
//\r
// Initialize local variables\r
return Status;\r
}\r
\r
- PciAttributesSaved = FALSE;\r
//\r
// Save original PCI attributes\r
//\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationGet,\r
- 0,\r
- &OriginalPciAttributes\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
+ if (!mPciAttributesSaved) {\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationGet,\r
+ 0,\r
+ &mOriginalPciAttributes\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ mPciAttributesSaved = TRUE;\r
}\r
- PciAttributesSaved = TRUE;\r
\r
//\r
// Get supported PCI attributes\r
PciIo,\r
LegacyBios,\r
ParentDevicePath,\r
- RemainingDevicePath,\r
- OriginalPciAttributes\r
+ RemainingDevicePath\r
);\r
\r
Done:\r
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,\r
ParentDevicePath\r
);\r
- if (PciAttributesSaved) {\r
- //\r
- // Restore original PCI attributes\r
- //\r
- PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSet,\r
- OriginalPciAttributes,\r
- NULL\r
- );\r
+ if (!HasChildHandle (Controller)) {\r
+ if (mPciAttributesSaved) {\r
+ //\r
+ // Restore original PCI attributes\r
+ //\r
+ PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ mOriginalPciAttributes,\r
+ NULL\r
+ );\r
+ }\r
}\r
//\r
// Release PCI I/O Protocols on the controller handle.\r
EFI_STATUS Status;\r
BOOLEAN AllChildrenStopped;\r
UINTN Index;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
\r
AllChildrenStopped = TRUE;\r
\r
return EFI_DEVICE_ERROR;\r
}\r
\r
+ if (!HasChildHandle (Controller)) {\r
+ if (mPciAttributesSaved) {\r
+ Status = gBS->HandleProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ //\r
+ // Restore original PCI attributes\r
+ //\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ mOriginalPciAttributes,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+\r
return EFI_SUCCESS;\r
}\r
\r
@param ParentLegacyBios Parent LegacyBios interface\r
@param ParentDevicePath Parent Device Path\r
@param RemainingDevicePath Remaining Device Path\r
- @param OriginalPciAttributes Original PCI Attributes\r
\r
@retval EFI_SUCCESS If a child handle was added\r
@retval other A child handle was not added\r
IN EFI_PCI_IO_PROTOCOL *ParentPciIo,\r
IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios,\r
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
- IN UINT64 OriginalPciAttributes\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
)\r
{\r
EFI_STATUS Status;\r
// When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally\r
//\r
BiosVideoPrivate->PciIo = ParentPciIo;\r
- BiosVideoPrivate->OriginalPciAttributes = OriginalPciAttributes;\r
\r
//\r
// Check for VESA BIOS Extensions for modes that are compatible with Graphics Output\r
Regs.H.BL = 0;\r
BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);\r
\r
- //\r
- // Restore original PCI attributes\r
- //\r
- Status = BiosVideoPrivate->PciIo->Attributes (\r
- BiosVideoPrivate->PciIo,\r
- EfiPciIoAttributeOperationSet,\r
- BiosVideoPrivate->OriginalPciAttributes,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
//\r
// Close PCI I/O protocol that opened by child handle\r
//\r
((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;\r
for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {\r
if ((TimingBits & 0x1) != 0) {\r
+ DEBUG ((EFI_D_INFO, "Established Timing: %d x %d\n",\r
+ mEstablishedEdidTiming[Index].HorizontalResolution, mEstablishedEdidTiming[Index].VerticalResolution));\r
ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);\r
ValidNumber ++;\r
}\r
TimingBits = TimingBits >> 1;\r
}\r
- } else {\r
+ }\r
+\r
+ //\r
+ // Parse the standard timing data\r
+ //\r
+ BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];\r
+ for (Index = 0; Index < 8; Index ++) {\r
//\r
- // If no Established timing data, read the standard timing data\r
+ // Check if this is a valid Standard Timing entry\r
+ // VESA documents unused fields should be set to 01h\r
//\r
- BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];\r
- for (Index = 0; Index < 8; Index ++) {\r
- if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){\r
- //\r
- // A valid Standard Timing\r
- //\r
- HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);\r
- AspectRatio = (UINT8) (BufferIndex[1] >> 6);\r
- switch (AspectRatio) {\r
- case 0:\r
- VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);\r
- break;\r
- case 1:\r
- VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
- break;\r
- case 2:\r
- VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);\r
- break;\r
- case 3:\r
- VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);\r
- break;\r
- default:\r
- VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
- break;\r
- }\r
- RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);\r
- TempTiming.HorizontalResolution = HorizontalResolution;\r
- TempTiming.VerticalResolution = VerticalResolution;\r
- TempTiming.RefreshRate = RefreshRate;\r
- ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);\r
- ValidNumber ++;\r
+ if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){\r
+ //\r
+ // A valid Standard Timing\r
+ //\r
+ HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);\r
+ AspectRatio = (UINT8) (BufferIndex[1] >> 6);\r
+ switch (AspectRatio) {\r
+ case 0:\r
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);\r
+ break;\r
+ case 1:\r
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
+ break;\r
+ case 2:\r
+ VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);\r
+ break;\r
+ case 3:\r
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);\r
+ break;\r
+ default:\r
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);\r
+ break;\r
}\r
- BufferIndex += 2;\r
+ RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);\r
+ DEBUG ((EFI_D_INFO, "Standard Timing: %d x %d\n", HorizontalResolution, VerticalResolution));\r
+ TempTiming.HorizontalResolution = HorizontalResolution;\r
+ TempTiming.VerticalResolution = VerticalResolution;\r
+ TempTiming.RefreshRate = RefreshRate;\r
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);\r
+ ValidNumber ++;\r
}\r
+ BufferIndex += 2;\r
+ }\r
+\r
+ //\r
+ // Parse the Detailed Timing data\r
+ //\r
+ BufferIndex = &EdidDataBlock->DetailedTimingDescriptions[0];\r
+ for (Index = 0; Index < 4; Index ++, BufferIndex += VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE) {\r
+ if ((BufferIndex[0] == 0x0) && (BufferIndex[1] == 0x0)) {\r
+ //\r
+ // Check if this is a valid Detailed Timing Descriptor\r
+ // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor\r
+ //\r
+ continue;\r
+ }\r
+ //\r
+ // Calculate Horizontal and Vertical resolution\r
+ //\r
+ TempTiming.HorizontalResolution = ((UINT16)(BufferIndex[4] & 0xF0) << 4) | (BufferIndex[2]);\r
+ TempTiming.VerticalResolution = ((UINT16)(BufferIndex[7] & 0xF0) << 4) | (BufferIndex[5]);\r
+ DEBUG ((EFI_D_INFO, "Detailed Timing %d: %d x %d\n",\r
+ Index, TempTiming.HorizontalResolution, TempTiming.VerticalResolution));\r
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);\r
+ ValidNumber ++;\r
}\r
\r
ValidEdidTiming->ValidNumber = ValidNumber;\r
return FALSE;\r
}\r
\r
+/**\r
+ Check if all video child handles have been uninstalled.\r
+\r
+ @param Controller Video controller handle\r
+\r
+ @return TRUE Child handles exist.\r
+ @return FALSE All video child handles have been uninstalled.\r
+\r
+**/\r
+BOOLEAN\r
+HasChildHandle (\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+ UINTN EntryCount;\r
+ BOOLEAN HasChild;\r
+ EFI_STATUS Status;\r
+\r
+ EntryCount = 0;\r
+ HasChild = FALSE;\r
+ Status = gBS->OpenProtocolInformation (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ &OpenInfoBuffer,\r
+ &EntryCount\r
+ );\r
+ for (Index = 0; Index < EntryCount; Index++) {\r
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+ HasChild = TRUE;\r
+ }\r
+ }\r
+ \r
+ return HasChild;\r
+}\r
\r
/**\r
Check for VBE device.\r
EFI_STATUS Status;\r
EFI_IA32_REGISTER_SET Regs;\r
UINT16 *ModeNumberPtr;\r
+ UINT16 VbeModeNumber;\r
BOOLEAN ModeFound;\r
BOOLEAN EdidFound;\r
BIOS_VIDEO_MODE_DATA *ModeBuffer;\r
UINT8 *EdidOverrideDataBlock;\r
UINTN EdidActiveDataSize;\r
UINT8 *EdidActiveDataBlock;\r
+ UINT32 HighestHorizontalResolution;\r
+ UINT32 HighestVerticalResolution;\r
+ UINTN HighestResolutionMode;\r
\r
EdidFound = TRUE;\r
EdidOverrideFound = FALSE;\r
EdidOverrideDataBlock = NULL;\r
EdidActiveDataSize = 0;\r
EdidActiveDataBlock = NULL;\r
+ HighestHorizontalResolution = 0;\r
+ HighestVerticalResolution = 0;\r
+ HighestResolutionMode = 0;\r
\r
//\r
// Allocate buffer under 1MB for VBE data structures\r
//\r
// Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow\r
//\r
- EdidOverrideDataBlock = AllocatePool (sizeof (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2));\r
+ EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2);\r
if (NULL == EdidOverrideDataBlock) {\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\r
\r
PreferMode = 0;\r
ModeNumber = 0;\r
-\r
- for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) {\r
+ \r
+ //\r
+ // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.\r
+ //\r
+ for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr);\r
+ VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST;\r
+ VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) {\r
//\r
// Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.\r
//\r
- if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {\r
+ if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {\r
continue;\r
}\r
//\r
//\r
gBS->SetMem (&Regs, sizeof (Regs), 0);\r
Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;\r
- Regs.X.CX = *ModeNumberPtr;\r
+ Regs.X.CX = VbeModeNumber;\r
gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);\r
Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);\r
Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);\r
continue;\r
}\r
\r
+ DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n",\r
+ VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution));\r
+\r
if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {\r
//\r
// EDID exist, check whether this mode match with any mode in EDID\r
Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {\r
+ //\r
+ // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,\r
+ // but INT10 can support these modes, we add them into GOP mode.\r
+ //\r
+ if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) &&\r
+ !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) &&\r
+ !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) &&\r
+ !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) {\r
continue;\r
+ }\r
}\r
}\r
\r
continue;\r
}\r
\r
+ //\r
+ // Record the highest resolution mode to set later\r
+ //\r
+ if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) ||\r
+ ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) && \r
+ (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) {\r
+ HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
+ HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
+ HighestResolutionMode = ModeNumber;\r
+ }\r
+\r
//\r
// Add mode to the list of available modes\r
//\r
}\r
\r
CurrentModeData = &ModeBuffer[ModeNumber - 1];\r
- CurrentModeData->VbeModeNumber = *ModeNumberPtr;\r
+ CurrentModeData->VbeModeNumber = VbeModeNumber;\r
if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {\r
CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;\r
CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;\r
CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;\r
CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;\r
CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;\r
- CurrentModeData->FrameBufferSize = BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024;\r
\r
CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;\r
CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;\r
CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;\r
\r
CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;\r
-\r
+ CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;\r
+ //\r
+ // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.\r
+ //\r
+ ASSERT (CurrentModeData->FrameBufferSize <= (UINTN)(BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024));\r
+ \r
BiosVideoPrivate->ModeData = ModeBuffer;\r
}\r
//\r
//\r
// Find the best mode to initialize\r
//\r
+ if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) {\r
+ DEBUG_CODE (\r
+ BIOS_VIDEO_MODE_DATA *ModeData;\r
+ ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode];\r
+ DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n",\r
+ ModeData->HorizontalResolution, ModeData->VerticalResolution));\r
+ );\r
+ PreferMode = HighestResolutionMode;\r
+ }\r
Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);\r
if (EFI_ERROR (Status)) {\r
for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {\r
CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));\r
This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;\r
This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
-\r
- //\r
- // Frame BufferSize remain unchanged\r
- //\r
- This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;\r
This->Mode->FrameBufferSize = ModeData->FrameBufferSize;\r
+ This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;\r
\r
BiosVideoPrivate->HardwareNeedsStarting = FALSE;\r
\r