2 Read EDID information and parse EDID information.
4 Copyright (c) 2008, Intel Corporation
5 All rights reserved. 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
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.
15 #include "CirrusLogic5430.h"
21 UINT8 Header
[8]; //EDID header "00 FF FF FF FF FF FF 00"
22 UINT16 ManufactureName
; //EISA 3-character ID
23 UINT16 ProductCode
; //Vendor assigned code
24 UINT32 SerialNumber
; //32-bit serial number
25 UINT8 WeekOfManufacture
; //Week number
26 UINT8 YearOfManufacture
; //Year
27 UINT8 EdidVersion
; //EDID Structure Version
28 UINT8 EdidRevision
; //EDID Structure Revision
29 UINT8 VideoInputDefinition
;
30 UINT8 MaxHorizontalImageSize
; //cm
31 UINT8 MaxVerticalImageSize
; //cm
32 UINT8 DisplayTransferCharacteristic
;
34 UINT8 RedGreenLowBits
; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
35 UINT8 BlueWhiteLowBits
; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
36 UINT8 RedX
; //Red-x Bits 9 - 2
37 UINT8 RedY
; //Red-y Bits 9 - 2
38 UINT8 GreenX
; //Green-x Bits 9 - 2
39 UINT8 GreenY
; //Green-y Bits 9 - 2
40 UINT8 BlueX
; //Blue-x Bits 9 - 2
41 UINT8 BlueY
; //Blue-y Bits 9 - 2
42 UINT8 WhiteX
; //White-x Bits 9 - 2
43 UINT8 WhiteY
; //White-x Bits 9 - 2
44 UINT8 EstablishedTimings
[3];
45 UINT8 StandardTimingIdentification
[16];
46 UINT8 DetailedTimingDescriptions
[72];
47 UINT8 ExtensionFlag
; //Number of (optional) 128-byte EDID extension blocks to follow
51 #define EDID_BLOCK_SIZE 128
52 #define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
55 UINT16 HorizontalResolution
;
56 UINT16 VerticalResolution
;
62 UINT32 Key
[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER
];
66 // Standard timing defined by VESA EDID
68 EDID_TIMING mVbeEstablishedEdidTiming
[] = {
70 // Established Timing I
81 // Established Timing II
92 // Established Timing III
98 Read EDID information from I2C Bus on CirrusLogic.
100 @param Private Pointer to CIRRUS_LOGIC_5430_PRIVATE_DATA.
101 @param EdidDataBlock Pointer to EDID data block.
102 @param EdidSize Returned EDID block size.
104 @retval EFI_UNSUPPORTED
110 CIRRUS_LOGIC_5430_PRIVATE_DATA
*Private
,
111 UINT8
**EdidDataBlock
,
116 UINT8 EdidData
[EDID_BLOCK_SIZE
* 2];
120 for (Index
= 0; Index
< EDID_BLOCK_SIZE
* 2; Index
++) {
121 I2cReadByte (Private
->PciIo
, 0xa0, Index
, &EdidData
[Index
]);
125 // Search for the EDID signature
127 ValidEdid
= &EdidData
[0];
128 Signature
= 0x00ffffffffffff00ull
;
129 for (Index
= 0; Index
< EDID_BLOCK_SIZE
* 2; Index
++, ValidEdid
++) {
130 if (CompareMem (ValidEdid
, &Signature
, 8) == 0) {
137 // No EDID signature found
139 return EFI_UNSUPPORTED
;
142 *EdidDataBlock
= AllocateCopyPool (
143 sizeof (EDID_BLOCK_SIZE
),
146 if (*EdidDataBlock
== NULL
) {
147 return EFI_OUT_OF_RESOURCES
;
151 // Currently only support EDID 1.x
153 *EdidSize
= EDID_BLOCK_SIZE
;
159 Generate a search key for a specified timing data.
161 @param EdidTiming Pointer to EDID timing
163 @return The 32 bit unique key for search.
168 EDID_TIMING
*EdidTiming
174 // Be sure no conflicts for all standard timing defined by VESA.
176 Key
= (EdidTiming
->HorizontalResolution
* 2) + EdidTiming
->VerticalResolution
;
181 Search a specified Timing in all the valid EDID timings.
183 @param ValidEdidTiming All valid EDID timing information.
184 @param EdidTiming The Timing to search for.
187 @retval FALSE Not found.
192 VALID_EDID_TIMING
*ValidEdidTiming
,
193 EDID_TIMING
*EdidTiming
199 Key
= CalculateEdidKey (EdidTiming
);
201 for (Index
= 0; Index
< ValidEdidTiming
->ValidNumber
; Index
++) {
202 if (Key
== ValidEdidTiming
->Key
[Index
]) {
211 Parse the Established Timing and Standard Timing in EDID data block.
213 @param EdidBuffer Pointer to EDID data block
214 @param ValidEdidTiming Valid EDID timing information
216 @retval TRUE The EDID data is valid.
217 @retval FALSE The EDID data is invalid.
223 VALID_EDID_TIMING
*ValidEdidTiming
231 UINT16 HorizontalResolution
;
232 UINT16 VerticalResolution
;
235 EDID_TIMING TempTiming
;
236 EDID_BLOCK
*EdidDataBlock
;
238 EdidDataBlock
= (EDID_BLOCK
*) EdidBuffer
;
241 // Check the checksum of EDID data
244 for (Index
= 0; Index
< EDID_BLOCK_SIZE
; Index
++) {
245 CheckSum
= (UINT8
) (CheckSum
+ EdidBuffer
[Index
]);
252 SetMem (ValidEdidTiming
, sizeof (VALID_EDID_TIMING
), 0);
254 if ((EdidDataBlock
->EstablishedTimings
[0] != 0) ||
255 (EdidDataBlock
->EstablishedTimings
[1] != 0) ||
256 (EdidDataBlock
->EstablishedTimings
[2] != 0)
259 // Established timing data
261 TimingBits
= EdidDataBlock
->EstablishedTimings
[0] |
262 (EdidDataBlock
->EstablishedTimings
[1] << 8) |
263 ((EdidDataBlock
->EstablishedTimings
[2] & 0x80) << 9) ;
264 for (Index
= 0; Index
< VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER
; Index
++) {
265 if (TimingBits
& 0x1) {
266 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&mVbeEstablishedEdidTiming
[Index
]);
269 TimingBits
= TimingBits
>> 1;
273 // If no Established timing data, read the standard timing data
275 BufferIndex
= &EdidDataBlock
->StandardTimingIdentification
[0];
276 for (Index
= 0; Index
< 8; Index
++) {
277 if ((BufferIndex
[0] != 0x1) && (BufferIndex
[1] != 0x1)){
279 // A valid Standard Timing
281 HorizontalResolution
= (UINT16
) (BufferIndex
[0] * 8 + 248);
282 AspectRatio
= (UINT8
) (BufferIndex
[1] >> 6);
283 switch (AspectRatio
) {
285 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 10);
288 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
291 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 5 * 4);
294 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 9);
297 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
300 RefreshRate
= (UINT8
) ((BufferIndex
[1] & 0x1f) + 60);
301 TempTiming
.HorizontalResolution
= HorizontalResolution
;
302 TempTiming
.VerticalResolution
= VerticalResolution
;
303 TempTiming
.RefreshRate
= RefreshRate
;
304 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&TempTiming
);
311 ValidEdidTiming
->ValidNumber
= ValidNumber
;
316 Construct the valid video modes for CirrusLogic5430.
320 CirrusLogic5430VideoModeSetup (
321 CIRRUS_LOGIC_5430_PRIVATE_DATA
*Private
327 EFI_EDID_OVERRIDE_PROTOCOL
*EdidOverride
;
328 UINT32 EdidAttributes
;
329 BOOLEAN EdidOverrideFound
;
330 UINTN EdidOverrideDataSize
;
331 UINT8
*EdidOverrideDataBlock
;
332 UINTN EdidDiscoveredDataSize
;
333 UINT8
*EdidDiscoveredDataBlock
;
334 UINTN EdidActiveDataSize
;
335 UINT8
*EdidActiveDataBlock
;
336 VALID_EDID_TIMING ValidEdidTiming
;
337 UINT32 ValidModeCount
;
338 CIRRUS_LOGIC_5430_MODE_DATA
*ModeData
;
340 CIRRUS_LOGIC_5430_VIDEO_MODES
*VideoMode
;
341 EDID_TIMING TempTiming
;
344 // setup EDID information
346 Private
->EdidDiscovered
.Edid
= NULL
;
347 Private
->EdidDiscovered
.SizeOfEdid
= 0;
348 Private
->EdidActive
.Edid
= NULL
;
349 Private
->EdidActive
.SizeOfEdid
= 0;
352 EdidOverrideFound
= FALSE
;
353 EdidAttributes
= 0xff;
354 EdidOverrideDataSize
= 0;
355 EdidOverrideDataBlock
= NULL
;
356 EdidActiveDataSize
= 0;
357 EdidActiveDataBlock
= NULL
;
358 EdidDiscoveredDataBlock
= NULL
;
361 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
363 Status
= gBS
->LocateProtocol (
364 &gEfiEdidOverrideProtocolGuid
,
366 (VOID
**) &EdidOverride
368 if (!EFI_ERROR (Status
)) {
370 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
372 EdidOverrideDataBlock
= AllocatePool (sizeof (EDID_BLOCK_SIZE
* 2));
373 if (NULL
== EdidOverrideDataBlock
) {
374 Status
= EFI_OUT_OF_RESOURCES
;
378 Status
= EdidOverride
->GetEdid (
382 &EdidOverrideDataSize
,
383 (UINT8
**) &EdidOverrideDataBlock
385 if (!EFI_ERROR (Status
) &&
386 EdidAttributes
== 0 &&
387 EdidOverrideDataSize
!= 0) {
389 // Succeeded to get EDID Override Data
391 EdidOverrideFound
= TRUE
;
395 if (EdidOverrideFound
!= TRUE
|| EdidAttributes
== EFI_EDID_OVERRIDE_DONT_OVERRIDE
) {
397 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
398 // read EDID information through I2C Bus
400 if (ReadEdidData (Private
, &EdidDiscoveredDataBlock
, &EdidDiscoveredDataSize
) == EFI_SUCCESS
) {;
401 Private
->EdidDiscovered
.SizeOfEdid
= (UINT32
) EdidDiscoveredDataSize
;
402 Private
->EdidDiscovered
.Edid
= (UINT8
*) AllocateCopyPool (
403 EdidDiscoveredDataSize
,
404 EdidDiscoveredDataBlock
407 if (NULL
== Private
->EdidDiscovered
.Edid
) {
408 Status
= EFI_OUT_OF_RESOURCES
;
412 EdidActiveDataSize
= Private
->EdidDiscovered
.SizeOfEdid
;
413 EdidActiveDataBlock
= Private
->EdidDiscovered
.Edid
;
419 if (EdidFound
!= TRUE
&& EdidOverrideFound
== TRUE
) {
420 EdidActiveDataSize
= EdidOverrideDataSize
;
421 EdidActiveDataBlock
= EdidOverrideDataBlock
;
425 if (EdidFound
== TRUE
) {
427 // Parse EDID data structure to retrieve modes supported by monitor
429 if (ParseEdidData ((UINT8
*) EdidActiveDataBlock
, &ValidEdidTiming
) == TRUE
) {
431 // Copy EDID Override Data to EDID Active Data
433 Private
->EdidActive
.SizeOfEdid
= (UINT32
) EdidActiveDataSize
;
434 Private
->EdidActive
.Edid
= (UINT8
*) AllocateCopyPool (
438 if (NULL
== Private
->EdidActive
.Edid
) {
439 Status
= EFI_OUT_OF_RESOURCES
;
444 Private
->EdidActive
.SizeOfEdid
= 0;
445 Private
->EdidActive
.Edid
= NULL
;
451 // Initialize the private mode data with the supported modes.
454 ModeData
= &Private
->ModeData
[0];
455 VideoMode
= &CirrusLogic5430VideoModes
[0];
456 for (Index
= 0; Index
< CIRRUS_LOGIC_5430_MODE_COUNT
; Index
++) {
461 // Check whether match with CirrusLogic5430 video mode
463 TempTiming
.HorizontalResolution
= (UINT16
) VideoMode
->Width
;
464 TempTiming
.VerticalResolution
= (UINT16
) VideoMode
->Height
;
465 TempTiming
.RefreshRate
= (UINT16
) VideoMode
->RefreshRate
;
466 if (SearchEdidTiming (&ValidEdidTiming
, &TempTiming
) != TRUE
) {
471 // Not export Mode 0x0 as GOP mode, this is not defined in spec.
473 if ((VideoMode
->Width
== 0) || (VideoMode
->Height
== 0)) {
478 ModeData
->ModeNumber
= Index
;
479 ModeData
->HorizontalResolution
= VideoMode
->Width
;
480 ModeData
->VerticalResolution
= VideoMode
->Height
;
481 ModeData
->ColorDepth
= VideoMode
->ColorDepth
;
482 ModeData
->RefreshRate
= VideoMode
->RefreshRate
;
491 Private
->MaxMode
= ValidModeCount
;
495 // If EDID information wasn't found
497 ModeData
= &Private
->ModeData
[0];
498 VideoMode
= &CirrusLogic5430VideoModes
[0];
499 for (Index
= 0; Index
< CIRRUS_LOGIC_5430_MODE_COUNT
; Index
++) {
500 ModeData
->ModeNumber
= Index
;
501 ModeData
->HorizontalResolution
= VideoMode
->Width
;
502 ModeData
->VerticalResolution
= VideoMode
->Height
;
503 ModeData
->ColorDepth
= VideoMode
->ColorDepth
;
504 ModeData
->RefreshRate
= VideoMode
->RefreshRate
;
509 Private
->MaxMode
= CIRRUS_LOGIC_5430_MODE_COUNT
;
512 FreePool (EdidOverrideDataBlock
);
516 if (EdidOverrideDataBlock
!= NULL
) {
517 FreePool (EdidOverrideDataBlock
);
519 if (Private
->EdidDiscovered
.Edid
!= NULL
) {
520 FreePool (Private
->EdidDiscovered
.Edid
);
522 if (Private
->EdidDiscovered
.Edid
!= NULL
) {
523 FreePool (Private
->EdidActive
.Edid
);
526 return EFI_DEVICE_ERROR
;