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
ReadEdidData(CIRRUS_LOGIC_5430_PRIVATE_DATA * Private,UINT8 ** EdidDataBlock,UINTN * EdidSize)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
CalculateEdidKey(EDID_TIMING * EdidTiming)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
SearchEdidTiming(VALID_EDID_TIMING * ValidEdidTiming,EDID_TIMING * EdidTiming)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
ParseEdidData(UINT8 * EdidBuffer,VALID_EDID_TIMING * ValidEdidTiming)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
CirrusLogic5430VideoModeSetup(CIRRUS_LOGIC_5430_PRIVATE_DATA * Private)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