123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- /** @file
- Read EDID information and parse EDID information.
- Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "CirrusLogic5430.h"
- #include "CirrusLogic5430I2c.h"
- //
- // EDID block
- //
- typedef struct {
- UINT8 Header[8]; //EDID header "00 FF FF FF FF FF FF 00"
- UINT16 ManufactureName; //EISA 3-character ID
- UINT16 ProductCode; //Vendor assigned code
- UINT32 SerialNumber; //32-bit serial number
- UINT8 WeekOfManufacture; //Week number
- UINT8 YearOfManufacture; //Year
- UINT8 EdidVersion; //EDID Structure Version
- UINT8 EdidRevision; //EDID Structure Revision
- UINT8 VideoInputDefinition;
- UINT8 MaxHorizontalImageSize; //cm
- UINT8 MaxVerticalImageSize; //cm
- UINT8 DisplayTransferCharacteristic;
- UINT8 FeatureSupport;
- UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
- UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
- UINT8 RedX; //Red-x Bits 9 - 2
- UINT8 RedY; //Red-y Bits 9 - 2
- UINT8 GreenX; //Green-x Bits 9 - 2
- UINT8 GreenY; //Green-y Bits 9 - 2
- UINT8 BlueX; //Blue-x Bits 9 - 2
- UINT8 BlueY; //Blue-y Bits 9 - 2
- UINT8 WhiteX; //White-x Bits 9 - 2
- UINT8 WhiteY; //White-x Bits 9 - 2
- UINT8 EstablishedTimings[3];
- UINT8 StandardTimingIdentification[16];
- UINT8 DetailedTimingDescriptions[72];
- UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
- UINT8 Checksum;
- } EDID_BLOCK;
- #define EDID_BLOCK_SIZE 128
- #define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
- typedef struct {
- UINT16 HorizontalResolution;
- UINT16 VerticalResolution;
- UINT16 RefreshRate;
- } EDID_TIMING;
- typedef struct {
- UINT32 ValidNumber;
- UINT32 Key[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER];
- } VALID_EDID_TIMING;
- //
- // Standard timing defined by VESA EDID
- //
- EDID_TIMING mVbeEstablishedEdidTiming[] = {
- //
- // Established Timing I
- //
- {800, 600, 60},
- {800, 600, 56},
- {640, 480, 75},
- {640, 480, 72},
- {640, 480, 67},
- {640, 480, 60},
- {720, 400, 88},
- {720, 400, 70},
- //
- // Established Timing II
- //
- {1280, 1024, 75},
- {1024, 768, 75},
- {1024, 768, 70},
- {1024, 768, 60},
- {1024, 768, 87},
- {832, 624, 75},
- {800, 600, 75},
- {800, 600, 72},
- //
- // Established Timing III
- //
- {1152, 870, 75}
- };
- /**
- Read EDID information from I2C Bus on CirrusLogic.
- @param Private Pointer to CIRRUS_LOGIC_5430_PRIVATE_DATA.
- @param EdidDataBlock Pointer to EDID data block.
- @param EdidSize Returned EDID block size.
- @retval EFI_UNSUPPORTED
- @retval EFI_SUCCESS
- **/
- EFI_STATUS
- ReadEdidData (
- CIRRUS_LOGIC_5430_PRIVATE_DATA *Private,
- UINT8 **EdidDataBlock,
- UINTN *EdidSize
- )
- {
- UINTN Index;
- UINT8 EdidData[EDID_BLOCK_SIZE * 2];
- UINT8 *ValidEdid;
- UINT64 Signature;
- for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++) {
- I2cReadByte (Private->PciIo, 0xa0, (UINT8)Index, &EdidData[Index]);
- }
- //
- // Search for the EDID signature
- //
- ValidEdid = &EdidData[0];
- Signature = 0x00ffffffffffff00ull;
- for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++, ValidEdid ++) {
- if (CompareMem (ValidEdid, &Signature, 8) == 0) {
- break;
- }
- }
- if (Index == 256) {
- //
- // No EDID signature found
- //
- return EFI_UNSUPPORTED;
- }
- *EdidDataBlock = AllocateCopyPool (
- EDID_BLOCK_SIZE,
- ValidEdid
- );
- if (*EdidDataBlock == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Currently only support EDID 1.x
- //
- *EdidSize = EDID_BLOCK_SIZE;
- return EFI_SUCCESS;
- }
- /**
- Generate a search key for a specified timing data.
- @param EdidTiming Pointer to EDID timing
- @return The 32 bit unique key for search.
- **/
- UINT32
- CalculateEdidKey (
- EDID_TIMING *EdidTiming
- )
- {
- UINT32 Key;
- //
- // Be sure no conflicts for all standard timing defined by VESA.
- //
- Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
- return Key;
- }
- /**
- Search a specified Timing in all the valid EDID timings.
- @param ValidEdidTiming All valid EDID timing information.
- @param EdidTiming The Timing to search for.
- @retval TRUE Found.
- @retval FALSE Not found.
- **/
- BOOLEAN
- SearchEdidTiming (
- VALID_EDID_TIMING *ValidEdidTiming,
- EDID_TIMING *EdidTiming
- )
- {
- UINT32 Index;
- UINT32 Key;
- Key = CalculateEdidKey (EdidTiming);
- for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
- if (Key == ValidEdidTiming->Key[Index]) {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- Parse the Established Timing and Standard Timing in EDID data block.
- @param EdidBuffer Pointer to EDID data block
- @param ValidEdidTiming Valid EDID timing information
- @retval TRUE The EDID data is valid.
- @retval FALSE The EDID data is invalid.
- **/
- BOOLEAN
- ParseEdidData (
- UINT8 *EdidBuffer,
- VALID_EDID_TIMING *ValidEdidTiming
- )
- {
- UINT8 CheckSum;
- UINT32 Index;
- UINT32 ValidNumber;
- UINT32 TimingBits;
- UINT8 *BufferIndex;
- UINT16 HorizontalResolution;
- UINT16 VerticalResolution;
- UINT8 AspectRatio;
- UINT8 RefreshRate;
- EDID_TIMING TempTiming;
- EDID_BLOCK *EdidDataBlock;
- EdidDataBlock = (EDID_BLOCK *) EdidBuffer;
- //
- // Check the checksum of EDID data
- //
- CheckSum = 0;
- for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {
- CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
- }
- if (CheckSum != 0) {
- return FALSE;
- }
- ValidNumber = 0;
- SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);
- if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
- (EdidDataBlock->EstablishedTimings[1] != 0) ||
- (EdidDataBlock->EstablishedTimings[2] != 0)
- ) {
- //
- // Established timing data
- //
- TimingBits = EdidDataBlock->EstablishedTimings[0] |
- (EdidDataBlock->EstablishedTimings[1] << 8) |
- ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
- for (Index = 0; Index < VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
- if (TimingBits & 0x1) {
- ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mVbeEstablishedEdidTiming[Index]);
- ValidNumber ++;
- }
- TimingBits = TimingBits >> 1;
- }
- } else {
- //
- // If no Established timing data, read the standard timing data
- //
- BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
- for (Index = 0; Index < 8; Index ++) {
- if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
- //
- // A valid Standard Timing
- //
- HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
- AspectRatio = (UINT8) (BufferIndex[1] >> 6);
- switch (AspectRatio) {
- case 0:
- VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
- break;
- case 1:
- VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
- break;
- case 2:
- VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
- break;
- case 3:
- VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
- break;
- default:
- VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
- break;
- }
- RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
- TempTiming.HorizontalResolution = HorizontalResolution;
- TempTiming.VerticalResolution = VerticalResolution;
- TempTiming.RefreshRate = RefreshRate;
- ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
- ValidNumber ++;
- }
- BufferIndex += 2;
- }
- }
- ValidEdidTiming->ValidNumber = ValidNumber;
- return TRUE;
- }
- /**
- Construct the valid video modes for CirrusLogic5430.
- **/
- EFI_STATUS
- CirrusLogic5430VideoModeSetup (
- CIRRUS_LOGIC_5430_PRIVATE_DATA *Private
- )
- {
- EFI_STATUS Status;
- UINT32 Index;
- BOOLEAN EdidFound;
- EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
- UINT32 EdidAttributes;
- BOOLEAN EdidOverrideFound;
- UINTN EdidOverrideDataSize;
- UINT8 *EdidOverrideDataBlock;
- UINTN EdidDiscoveredDataSize;
- UINT8 *EdidDiscoveredDataBlock;
- UINTN EdidActiveDataSize;
- UINT8 *EdidActiveDataBlock;
- VALID_EDID_TIMING ValidEdidTiming;
- UINT32 ValidModeCount;
- CIRRUS_LOGIC_5430_MODE_DATA *ModeData;
- BOOLEAN TimingMatch;
- CIRRUS_LOGIC_5430_VIDEO_MODES *VideoMode;
- EDID_TIMING TempTiming;
- //
- // setup EDID information
- //
- Private->EdidDiscovered.Edid = NULL;
- Private->EdidDiscovered.SizeOfEdid = 0;
- Private->EdidActive.Edid = NULL;
- Private->EdidActive.SizeOfEdid = 0;
- EdidFound = FALSE;
- EdidOverrideFound = FALSE;
- EdidAttributes = 0xff;
- EdidOverrideDataSize = 0;
- EdidOverrideDataBlock = NULL;
- EdidActiveDataSize = 0;
- EdidActiveDataBlock = NULL;
- EdidDiscoveredDataBlock = NULL;
- //
- // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
- //
- Status = gBS->LocateProtocol (
- &gEfiEdidOverrideProtocolGuid,
- NULL,
- (VOID **) &EdidOverride
- );
- if (!EFI_ERROR (Status)) {
- //
- // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
- //
- EdidOverrideDataBlock = AllocatePool (EDID_BLOCK_SIZE * 2);
- if (NULL == EdidOverrideDataBlock) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- Status = EdidOverride->GetEdid (
- EdidOverride,
- Private->Handle,
- &EdidAttributes,
- &EdidOverrideDataSize,
- (UINT8 **) &EdidOverrideDataBlock
- );
- if (!EFI_ERROR (Status) &&
- EdidAttributes == 0 &&
- EdidOverrideDataSize != 0) {
- //
- // Succeeded to get EDID Override Data
- //
- EdidOverrideFound = TRUE;
- }
- }
- if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
- //
- // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
- // read EDID information through I2C Bus
- //
- if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {
- Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;
- Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
- EdidDiscoveredDataSize,
- EdidDiscoveredDataBlock
- );
- if (NULL == Private->EdidDiscovered.Edid) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- EdidActiveDataSize = Private->EdidDiscovered.SizeOfEdid;
- EdidActiveDataBlock = Private->EdidDiscovered.Edid;
- EdidFound = TRUE;
- }
- }
- if (EdidFound != TRUE && EdidOverrideFound == TRUE) {
- EdidActiveDataSize = EdidOverrideDataSize;
- EdidActiveDataBlock = EdidOverrideDataBlock;
- EdidFound = TRUE;
- }
- if (EdidFound == TRUE) {
- //
- // Parse EDID data structure to retrieve modes supported by monitor
- //
- if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {
- //
- // Copy EDID Override Data to EDID Active Data
- //
- Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
- Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
- EdidActiveDataSize,
- EdidActiveDataBlock
- );
- if (NULL == Private->EdidActive.Edid) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- }
- } else {
- Private->EdidActive.SizeOfEdid = 0;
- Private->EdidActive.Edid = NULL;
- EdidFound = FALSE;
- }
- if (EdidFound) {
- //
- // Initialize the private mode data with the supported modes.
- //
- ValidModeCount = 0;
- ModeData = &Private->ModeData[0];
- VideoMode = &CirrusLogic5430VideoModes[0];
- for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index++) {
- TimingMatch = TRUE;
- //
- // Check whether match with CirrusLogic5430 video mode
- //
- TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;
- TempTiming.VerticalResolution = (UINT16) VideoMode->Height;
- TempTiming.RefreshRate = (UINT16) VideoMode->RefreshRate;
- if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {
- TimingMatch = FALSE;
- }
- //
- // Not export Mode 0x0 as GOP mode, this is not defined in spec.
- //
- if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
- TimingMatch = FALSE;
- }
- if (TimingMatch) {
- ModeData->ModeNumber = Index;
- ModeData->HorizontalResolution = VideoMode->Width;
- ModeData->VerticalResolution = VideoMode->Height;
- ModeData->ColorDepth = VideoMode->ColorDepth;
- ModeData->RefreshRate = VideoMode->RefreshRate;
- ModeData ++;
- ValidModeCount ++;
- }
- VideoMode ++;
- }
- Private->MaxMode = ValidModeCount;
- } else {
- //
- // If EDID information wasn't found
- //
- ModeData = &Private->ModeData[0];
- VideoMode = &CirrusLogic5430VideoModes[0];
- for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index ++) {
- ModeData->ModeNumber = Index;
- ModeData->HorizontalResolution = VideoMode->Width;
- ModeData->VerticalResolution = VideoMode->Height;
- ModeData->ColorDepth = VideoMode->ColorDepth;
- ModeData->RefreshRate = VideoMode->RefreshRate;
- ModeData ++ ;
- VideoMode ++;
- }
- Private->MaxMode = CIRRUS_LOGIC_5430_MODE_COUNT;
- }
- if (EdidOverrideDataBlock != NULL) {
- FreePool (EdidOverrideDataBlock);
- }
- return EFI_SUCCESS;
- Done:
- if (EdidOverrideDataBlock != NULL) {
- FreePool (EdidOverrideDataBlock);
- }
- if (Private->EdidDiscovered.Edid != NULL) {
- FreePool (Private->EdidDiscovered.Edid);
- }
- if (Private->EdidDiscovered.Edid != NULL) {
- FreePool (Private->EdidActive.Edid);
- }
- return EFI_DEVICE_ERROR;
- }
|