Home | History | Annotate | Download | only in CirrusLogic5430Dxe
      1 /** @file
      2   Read EDID information and parse EDID information.
      3 
      4   Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "CirrusLogic5430.h"
     16 #include "CirrusLogic5430I2c.h"
     17 
     18 //
     19 // EDID block
     20 //
     21 typedef struct {
     22   UINT8   Header[8];                        //EDID header "00 FF FF FF FF FF FF 00"
     23   UINT16  ManufactureName;                  //EISA 3-character ID
     24   UINT16  ProductCode;                      //Vendor assigned code
     25   UINT32  SerialNumber;                     //32-bit serial number
     26   UINT8   WeekOfManufacture;                //Week number
     27   UINT8   YearOfManufacture;                //Year
     28   UINT8   EdidVersion;                      //EDID Structure Version
     29   UINT8   EdidRevision;                     //EDID Structure Revision
     30   UINT8   VideoInputDefinition;
     31   UINT8   MaxHorizontalImageSize;           //cm
     32   UINT8   MaxVerticalImageSize;             //cm
     33   UINT8   DisplayTransferCharacteristic;
     34   UINT8   FeatureSupport;
     35   UINT8   RedGreenLowBits;                  //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
     36   UINT8   BlueWhiteLowBits;                 //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
     37   UINT8   RedX;                             //Red-x Bits 9 - 2
     38   UINT8   RedY;                             //Red-y Bits 9 - 2
     39   UINT8   GreenX;                           //Green-x Bits 9 - 2
     40   UINT8   GreenY;                           //Green-y Bits 9 - 2
     41   UINT8   BlueX;                            //Blue-x Bits 9 - 2
     42   UINT8   BlueY;                            //Blue-y Bits 9 - 2
     43   UINT8   WhiteX;                           //White-x Bits 9 - 2
     44   UINT8   WhiteY;                           //White-x Bits 9 - 2
     45   UINT8   EstablishedTimings[3];
     46   UINT8   StandardTimingIdentification[16];
     47   UINT8   DetailedTimingDescriptions[72];
     48   UINT8   ExtensionFlag;                    //Number of (optional) 128-byte EDID extension blocks to follow
     49   UINT8   Checksum;
     50 } EDID_BLOCK;
     51 
     52 #define EDID_BLOCK_SIZE                        128
     53 #define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
     54 
     55 typedef struct {
     56   UINT16  HorizontalResolution;
     57   UINT16  VerticalResolution;
     58   UINT16  RefreshRate;
     59 } EDID_TIMING;
     60 
     61 typedef struct {
     62   UINT32  ValidNumber;
     63   UINT32  Key[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER];
     64 } VALID_EDID_TIMING;
     65 
     66 //
     67 // Standard timing defined by VESA EDID
     68 //
     69 EDID_TIMING mVbeEstablishedEdidTiming[] = {
     70   //
     71   // Established Timing I
     72   //
     73   {800, 600, 60},
     74   {800, 600, 56},
     75   {640, 480, 75},
     76   {640, 480, 72},
     77   {640, 480, 67},
     78   {640, 480, 60},
     79   {720, 400, 88},
     80   {720, 400, 70},
     81   //
     82   // Established Timing II
     83   //
     84   {1280, 1024, 75},
     85   {1024,  768, 75},
     86   {1024,  768, 70},
     87   {1024,  768, 60},
     88   {1024,  768, 87},
     89   {832,   624, 75},
     90   {800,   600, 75},
     91   {800,   600, 72},
     92   //
     93   // Established Timing III
     94   //
     95   {1152, 870, 75}
     96 };
     97 
     98 /**
     99   Read EDID information from I2C Bus on CirrusLogic.
    100 
    101   @param  Private             Pointer to CIRRUS_LOGIC_5430_PRIVATE_DATA.
    102   @param  EdidDataBlock       Pointer to EDID data block.
    103   @param  EdidSize            Returned EDID block size.
    104 
    105   @retval EFI_UNSUPPORTED
    106   @retval EFI_SUCCESS
    107 
    108 **/
    109 EFI_STATUS
    110 ReadEdidData (
    111   CIRRUS_LOGIC_5430_PRIVATE_DATA     *Private,
    112   UINT8                              **EdidDataBlock,
    113   UINTN                              *EdidSize
    114   )
    115 {
    116   UINTN             Index;
    117   UINT8             EdidData[EDID_BLOCK_SIZE * 2];
    118   UINT8             *ValidEdid;
    119   UINT64            Signature;
    120 
    121   for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++) {
    122     I2cReadByte (Private->PciIo, 0xa0, (UINT8)Index, &EdidData[Index]);
    123   }
    124 
    125   //
    126   // Search for the EDID signature
    127   //
    128   ValidEdid = &EdidData[0];
    129   Signature = 0x00ffffffffffff00ull;
    130   for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++, ValidEdid ++) {
    131     if (CompareMem (ValidEdid, &Signature, 8) == 0) {
    132       break;
    133     }
    134   }
    135 
    136   if (Index == 256) {
    137     //
    138     // No EDID signature found
    139     //
    140     return EFI_UNSUPPORTED;
    141   }
    142 
    143   *EdidDataBlock = AllocateCopyPool (
    144                      EDID_BLOCK_SIZE,
    145                      ValidEdid
    146                      );
    147   if (*EdidDataBlock == NULL) {
    148     return EFI_OUT_OF_RESOURCES;
    149   }
    150 
    151   //
    152   // Currently only support EDID 1.x
    153   //
    154   *EdidSize = EDID_BLOCK_SIZE;
    155 
    156   return EFI_SUCCESS;
    157 }
    158 
    159 /**
    160   Generate a search key for a specified timing data.
    161 
    162   @param  EdidTiming             Pointer to EDID timing
    163 
    164   @return The 32 bit unique key for search.
    165 
    166 **/
    167 UINT32
    168 CalculateEdidKey (
    169   EDID_TIMING       *EdidTiming
    170   )
    171 {
    172   UINT32 Key;
    173 
    174   //
    175   // Be sure no conflicts for all standard timing defined by VESA.
    176   //
    177   Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
    178   return Key;
    179 }
    180 
    181 /**
    182   Search a specified Timing in all the valid EDID timings.
    183 
    184   @param  ValidEdidTiming        All valid EDID timing information.
    185   @param  EdidTiming             The Timing to search for.
    186 
    187   @retval TRUE                   Found.
    188   @retval FALSE                  Not found.
    189 
    190 **/
    191 BOOLEAN
    192 SearchEdidTiming (
    193   VALID_EDID_TIMING *ValidEdidTiming,
    194   EDID_TIMING       *EdidTiming
    195   )
    196 {
    197   UINT32 Index;
    198   UINT32 Key;
    199 
    200   Key = CalculateEdidKey (EdidTiming);
    201 
    202   for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
    203     if (Key == ValidEdidTiming->Key[Index]) {
    204       return TRUE;
    205     }
    206   }
    207 
    208   return FALSE;
    209 }
    210 
    211 /**
    212   Parse the Established Timing and Standard Timing in EDID data block.
    213 
    214   @param  EdidBuffer             Pointer to EDID data block
    215   @param  ValidEdidTiming        Valid EDID timing information
    216 
    217   @retval TRUE                   The EDID data is valid.
    218   @retval FALSE                  The EDID data is invalid.
    219 
    220 **/
    221 BOOLEAN
    222 ParseEdidData (
    223   UINT8                         *EdidBuffer,
    224   VALID_EDID_TIMING             *ValidEdidTiming
    225   )
    226 {
    227   UINT8        CheckSum;
    228   UINT32       Index;
    229   UINT32       ValidNumber;
    230   UINT32       TimingBits;
    231   UINT8        *BufferIndex;
    232   UINT16       HorizontalResolution;
    233   UINT16       VerticalResolution;
    234   UINT8        AspectRatio;
    235   UINT8        RefreshRate;
    236   EDID_TIMING  TempTiming;
    237   EDID_BLOCK   *EdidDataBlock;
    238 
    239   EdidDataBlock = (EDID_BLOCK *) EdidBuffer;
    240 
    241   //
    242   // Check the checksum of EDID data
    243   //
    244   CheckSum = 0;
    245   for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {
    246     CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
    247   }
    248   if (CheckSum != 0) {
    249     return FALSE;
    250   }
    251 
    252   ValidNumber = 0;
    253   SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);
    254 
    255   if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
    256       (EdidDataBlock->EstablishedTimings[1] != 0) ||
    257       (EdidDataBlock->EstablishedTimings[2] != 0)
    258       ) {
    259     //
    260     // Established timing data
    261     //
    262     TimingBits = EdidDataBlock->EstablishedTimings[0] |
    263                  (EdidDataBlock->EstablishedTimings[1] << 8) |
    264                  ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
    265     for (Index = 0; Index < VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
    266       if (TimingBits & 0x1) {
    267         ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mVbeEstablishedEdidTiming[Index]);
    268         ValidNumber ++;
    269       }
    270       TimingBits = TimingBits >> 1;
    271     }
    272   } else {
    273     //
    274     // If no Established timing data, read the standard timing data
    275     //
    276     BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
    277     for (Index = 0; Index < 8; Index ++) {
    278       if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
    279         //
    280         // A valid Standard Timing
    281         //
    282         HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
    283         AspectRatio = (UINT8) (BufferIndex[1] >> 6);
    284         switch (AspectRatio) {
    285           case 0:
    286             VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
    287             break;
    288           case 1:
    289             VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
    290             break;
    291           case 2:
    292             VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
    293             break;
    294           case 3:
    295             VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
    296             break;
    297           default:
    298             VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
    299             break;
    300         }
    301         RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
    302         TempTiming.HorizontalResolution = HorizontalResolution;
    303         TempTiming.VerticalResolution = VerticalResolution;
    304         TempTiming.RefreshRate = RefreshRate;
    305         ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
    306         ValidNumber ++;
    307       }
    308       BufferIndex += 2;
    309     }
    310   }
    311 
    312   ValidEdidTiming->ValidNumber = ValidNumber;
    313   return TRUE;
    314 }
    315 
    316 /**
    317   Construct the valid video modes for CirrusLogic5430.
    318 
    319 **/
    320 EFI_STATUS
    321 CirrusLogic5430VideoModeSetup (
    322   CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private
    323   )
    324 {
    325   EFI_STATUS                             Status;
    326   UINT32                                 Index;
    327   BOOLEAN                                EdidFound;
    328   EFI_EDID_OVERRIDE_PROTOCOL             *EdidOverride;
    329   UINT32                                 EdidAttributes;
    330   BOOLEAN                                EdidOverrideFound;
    331   UINTN                                  EdidOverrideDataSize;
    332   UINT8                                  *EdidOverrideDataBlock;
    333   UINTN                                  EdidDiscoveredDataSize;
    334   UINT8                                  *EdidDiscoveredDataBlock;
    335   UINTN                                  EdidActiveDataSize;
    336   UINT8                                  *EdidActiveDataBlock;
    337   VALID_EDID_TIMING                      ValidEdidTiming;
    338   UINT32                                 ValidModeCount;
    339   CIRRUS_LOGIC_5430_MODE_DATA            *ModeData;
    340   BOOLEAN                                TimingMatch;
    341   CIRRUS_LOGIC_5430_VIDEO_MODES          *VideoMode;
    342   EDID_TIMING                            TempTiming;
    343 
    344   //
    345   // setup EDID information
    346   //
    347   Private->EdidDiscovered.Edid       = NULL;
    348   Private->EdidDiscovered.SizeOfEdid = 0;
    349   Private->EdidActive.Edid           = NULL;
    350   Private->EdidActive.SizeOfEdid     = 0;
    351 
    352   EdidFound               = FALSE;
    353   EdidOverrideFound       = FALSE;
    354   EdidAttributes          = 0xff;
    355   EdidOverrideDataSize    = 0;
    356   EdidOverrideDataBlock   = NULL;
    357   EdidActiveDataSize      = 0;
    358   EdidActiveDataBlock     = NULL;
    359   EdidDiscoveredDataBlock = NULL;
    360 
    361   //
    362   // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
    363   //
    364   Status = gBS->LocateProtocol (
    365                    &gEfiEdidOverrideProtocolGuid,
    366                    NULL,
    367                    (VOID **) &EdidOverride
    368                    );
    369   if (!EFI_ERROR (Status)) {
    370     //
    371     // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
    372     //
    373     EdidOverrideDataBlock = AllocatePool (EDID_BLOCK_SIZE * 2);
    374     if (NULL == EdidOverrideDataBlock) {
    375   		Status = EFI_OUT_OF_RESOURCES;
    376       goto Done;
    377     }
    378 
    379     Status = EdidOverride->GetEdid (
    380                              EdidOverride,
    381                              Private->Handle,
    382                              &EdidAttributes,
    383                              &EdidOverrideDataSize,
    384                              (UINT8 **) &EdidOverrideDataBlock
    385                              );
    386     if (!EFI_ERROR (Status)  &&
    387          EdidAttributes == 0 &&
    388          EdidOverrideDataSize != 0) {
    389       //
    390       // Succeeded to get EDID Override Data
    391       //
    392       EdidOverrideFound = TRUE;
    393     }
    394   }
    395 
    396   if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
    397     //
    398     // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
    399     // read EDID information through I2C Bus
    400     //
    401     if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {
    402       Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;
    403      	Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
    404                                                           EdidDiscoveredDataSize,
    405                                                           EdidDiscoveredDataBlock
    406      																										  );
    407 
    408       if (NULL == Private->EdidDiscovered.Edid) {
    409      	  Status = EFI_OUT_OF_RESOURCES;
    410         goto Done;
    411       }
    412 
    413       EdidActiveDataSize  = Private->EdidDiscovered.SizeOfEdid;
    414       EdidActiveDataBlock = Private->EdidDiscovered.Edid;
    415 
    416       EdidFound = TRUE;
    417     }
    418   }
    419 
    420   if (EdidFound != TRUE && EdidOverrideFound == TRUE) {
    421     EdidActiveDataSize  = EdidOverrideDataSize;
    422     EdidActiveDataBlock = EdidOverrideDataBlock;
    423     EdidFound = TRUE;
    424  	}
    425 
    426  	if (EdidFound == TRUE) {
    427     //
    428     // Parse EDID data structure to retrieve modes supported by monitor
    429     //
    430     if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {
    431       //
    432       // Copy EDID Override Data to EDID Active Data
    433       //
    434       Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
    435       Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
    436                                              EdidActiveDataSize,
    437                                              EdidActiveDataBlock
    438                                              );
    439       if (NULL == Private->EdidActive.Edid) {
    440    		  Status = EFI_OUT_OF_RESOURCES;
    441         goto Done;
    442       }
    443     }
    444   } else {
    445     Private->EdidActive.SizeOfEdid = 0;
    446     Private->EdidActive.Edid = NULL;
    447     EdidFound = FALSE;
    448   }
    449 
    450   if (EdidFound) {
    451     //
    452     // Initialize the private mode data with the supported modes.
    453     //
    454     ValidModeCount = 0;
    455     ModeData = &Private->ModeData[0];
    456     VideoMode = &CirrusLogic5430VideoModes[0];
    457     for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index++) {
    458 
    459       TimingMatch = TRUE;
    460 
    461       //
    462       // Check whether match with CirrusLogic5430 video mode
    463       //
    464       TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;
    465       TempTiming.VerticalResolution   = (UINT16) VideoMode->Height;
    466       TempTiming.RefreshRate          = (UINT16) VideoMode->RefreshRate;
    467       if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {
    468         TimingMatch = FALSE;
    469       }
    470 
    471       //
    472       // Not export Mode 0x0 as GOP mode, this is not defined in spec.
    473       //
    474       if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
    475         TimingMatch = FALSE;
    476       }
    477 
    478       if (TimingMatch) {
    479         ModeData->ModeNumber = Index;
    480         ModeData->HorizontalResolution          = VideoMode->Width;
    481         ModeData->VerticalResolution            = VideoMode->Height;
    482         ModeData->ColorDepth                    = VideoMode->ColorDepth;
    483         ModeData->RefreshRate                   = VideoMode->RefreshRate;
    484 
    485         ModeData ++;
    486         ValidModeCount ++;
    487       }
    488 
    489       VideoMode ++;
    490     }
    491 
    492     Private->MaxMode = ValidModeCount;
    493 
    494   } else {
    495     //
    496     // If EDID information wasn't found
    497     //
    498     ModeData = &Private->ModeData[0];
    499     VideoMode = &CirrusLogic5430VideoModes[0];
    500     for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index ++) {
    501       ModeData->ModeNumber = Index;
    502       ModeData->HorizontalResolution          = VideoMode->Width;
    503       ModeData->VerticalResolution            = VideoMode->Height;
    504       ModeData->ColorDepth                    = VideoMode->ColorDepth;
    505       ModeData->RefreshRate                   = VideoMode->RefreshRate;
    506 
    507       ModeData ++ ;
    508       VideoMode ++;
    509     }
    510     Private->MaxMode = CIRRUS_LOGIC_5430_MODE_COUNT;
    511   }
    512 
    513   if (EdidOverrideDataBlock != NULL) {
    514     FreePool (EdidOverrideDataBlock);
    515   }
    516 
    517   return EFI_SUCCESS;
    518 
    519 Done:
    520   if (EdidOverrideDataBlock != NULL) {
    521     FreePool (EdidOverrideDataBlock);
    522   }
    523   if (Private->EdidDiscovered.Edid != NULL) {
    524     FreePool (Private->EdidDiscovered.Edid);
    525   }
    526   if (Private->EdidDiscovered.Edid != NULL) {
    527     FreePool (Private->EdidActive.Edid);
    528   }
    529 
    530   return EFI_DEVICE_ERROR;
    531 }
    532