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
111 CIRRUS_LOGIC_5430_PRIVATE_DATA
*Private
,
112 UINT8
**EdidDataBlock
,
117 UINT8 EdidData
[EDID_BLOCK_SIZE
* 2];
121 for (Index
= 0; Index
< EDID_BLOCK_SIZE
* 2; Index
++) {
122 I2cReadByte (Private
->PciIo
, 0xa0, Index
, &EdidData
[Index
]);
126 // Search for the EDID signature
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) {
138 // No EDID signature found
140 return EFI_UNSUPPORTED
;
143 *EdidDataBlock
= AllocateCopyPool (
144 sizeof (EDID_BLOCK_SIZE
),
147 if (*EdidDataBlock
== NULL
) {
148 return EFI_OUT_OF_RESOURCES
;
152 // Currently only support EDID 1.x
154 *EdidSize
= EDID_BLOCK_SIZE
;
160 Generate a search key for a specified timing data.
162 @param EdidTiming Pointer to EDID timing
164 @return The 32 bit unique key for search.
170 EDID_TIMING
*EdidTiming
176 // Be sure no conflicts for all standard timing defined by VESA.
178 Key
= (EdidTiming
->HorizontalResolution
* 2) + EdidTiming
->VerticalResolution
;
183 Search a specified Timing in all the valid EDID timings.
185 @param ValidEdidTiming All valid EDID timing information.
186 @param EdidTiming The Timing to search for.
189 @retval FALSE Not found.
195 VALID_EDID_TIMING
*ValidEdidTiming
,
196 EDID_TIMING
*EdidTiming
202 Key
= CalculateEdidKey (EdidTiming
);
204 for (Index
= 0; Index
< ValidEdidTiming
->ValidNumber
; Index
++) {
205 if (Key
== ValidEdidTiming
->Key
[Index
]) {
214 Parse the Established Timing and Standard Timing in EDID data block.
216 @param EdidBuffer Pointer to EDID data block
217 @param ValidEdidTiming Valid EDID timing information
219 @retval TRUE The EDID data is valid.
220 @retval FALSE The EDID data is invalid.
227 VALID_EDID_TIMING
*ValidEdidTiming
235 UINT16 HorizontalResolution
;
236 UINT16 VerticalResolution
;
239 EDID_TIMING TempTiming
;
240 EDID_BLOCK
*EdidDataBlock
;
242 EdidDataBlock
= (EDID_BLOCK
*) EdidBuffer
;
245 // Check the checksum of EDID data
248 for (Index
= 0; Index
< EDID_BLOCK_SIZE
; Index
++) {
249 CheckSum
= (UINT8
) (CheckSum
+ EdidBuffer
[Index
]);
256 SetMem (ValidEdidTiming
, sizeof (VALID_EDID_TIMING
), 0);
258 if ((EdidDataBlock
->EstablishedTimings
[0] != 0) ||
259 (EdidDataBlock
->EstablishedTimings
[1] != 0) ||
260 (EdidDataBlock
->EstablishedTimings
[2] != 0)
263 // Established timing data
265 TimingBits
= EdidDataBlock
->EstablishedTimings
[0] |
266 (EdidDataBlock
->EstablishedTimings
[1] << 8) |
267 ((EdidDataBlock
->EstablishedTimings
[2] & 0x80) << 9) ;
268 for (Index
= 0; Index
< VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER
; Index
++) {
269 if (TimingBits
& 0x1) {
270 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&mVbeEstablishedEdidTiming
[Index
]);
273 TimingBits
= TimingBits
>> 1;
277 // If no Established timing data, read the standard timing data
279 BufferIndex
= &EdidDataBlock
->StandardTimingIdentification
[0];
280 for (Index
= 0; Index
< 8; Index
++) {
281 if ((BufferIndex
[0] != 0x1) && (BufferIndex
[1] != 0x1)){
283 // A valid Standard Timing
285 HorizontalResolution
= (UINT16
) (BufferIndex
[0] * 8 + 248);
286 AspectRatio
= (UINT8
) (BufferIndex
[1] >> 6);
287 switch (AspectRatio
) {
289 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 10);
292 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
295 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 5 * 4);
298 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 9);
301 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
304 RefreshRate
= (UINT8
) ((BufferIndex
[1] & 0x1f) + 60);
305 TempTiming
.HorizontalResolution
= HorizontalResolution
;
306 TempTiming
.VerticalResolution
= VerticalResolution
;
307 TempTiming
.RefreshRate
= RefreshRate
;
308 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&TempTiming
);
315 ValidEdidTiming
->ValidNumber
= ValidNumber
;
320 Construct the valid video modes for CirrusLogic5430.
324 CirrusLogic5430VideoModeSetup (
325 CIRRUS_LOGIC_5430_PRIVATE_DATA
*Private
331 EFI_EDID_OVERRIDE_PROTOCOL
*EdidOverride
;
332 UINT32 EdidAttributes
;
333 BOOLEAN EdidOverrideFound
;
334 UINTN EdidOverrideDataSize
;
335 UINT8
*EdidOverrideDataBlock
;
336 UINTN EdidDiscoveredDataSize
;
337 UINT8
*EdidDiscoveredDataBlock
;
338 UINTN EdidActiveDataSize
;
339 UINT8
*EdidActiveDataBlock
;
340 VALID_EDID_TIMING ValidEdidTiming
;
341 UINT32 ValidModeCount
;
342 CIRRUS_LOGIC_5430_MODE_DATA
*ModeData
;
344 CIRRUS_LOGIC_5430_VIDEO_MODES
*VideoMode
;
345 EDID_TIMING TempTiming
;
348 // setup EDID information
350 Private
->EdidDiscovered
.Edid
= NULL
;
351 Private
->EdidDiscovered
.SizeOfEdid
= 0;
352 Private
->EdidActive
.Edid
= NULL
;
353 Private
->EdidActive
.SizeOfEdid
= 0;
356 EdidOverrideFound
= FALSE
;
357 EdidAttributes
= 0xff;
358 EdidOverrideDataSize
= 0;
359 EdidOverrideDataBlock
= NULL
;
360 EdidActiveDataSize
= 0;
361 EdidActiveDataBlock
= NULL
;
362 EdidDiscoveredDataBlock
= NULL
;
365 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
367 Status
= gBS
->LocateProtocol (
368 &gEfiEdidOverrideProtocolGuid
,
370 (VOID
**) &EdidOverride
372 if (!EFI_ERROR (Status
)) {
374 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
376 EdidOverrideDataBlock
= AllocatePool (sizeof (EDID_BLOCK_SIZE
* 2));
377 if (NULL
== EdidOverrideDataBlock
) {
378 Status
= EFI_OUT_OF_RESOURCES
;
382 Status
= EdidOverride
->GetEdid (
386 &EdidOverrideDataSize
,
387 (UINT8
**) &EdidOverrideDataBlock
389 if (!EFI_ERROR (Status
) &&
390 EdidAttributes
== 0 &&
391 EdidOverrideDataSize
!= 0) {
393 // Succeeded to get EDID Override Data
395 EdidOverrideFound
= TRUE
;
399 if (EdidOverrideFound
!= TRUE
|| EdidAttributes
== EFI_EDID_OVERRIDE_DONT_OVERRIDE
) {
401 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
402 // read EDID information through I2C Bus
404 if (ReadEdidData (Private
, &EdidDiscoveredDataBlock
, &EdidDiscoveredDataSize
) == EFI_SUCCESS
) {;
405 Private
->EdidDiscovered
.SizeOfEdid
= (UINT32
) EdidDiscoveredDataSize
;
406 Private
->EdidDiscovered
.Edid
= (UINT8
*) AllocateCopyPool (
407 EdidDiscoveredDataSize
,
408 EdidDiscoveredDataBlock
411 if (NULL
== Private
->EdidDiscovered
.Edid
) {
412 Status
= EFI_OUT_OF_RESOURCES
;
416 EdidActiveDataSize
= Private
->EdidDiscovered
.SizeOfEdid
;
417 EdidActiveDataBlock
= Private
->EdidDiscovered
.Edid
;
423 if (EdidFound
!= TRUE
&& EdidOverrideFound
== TRUE
) {
424 EdidActiveDataSize
= EdidOverrideDataSize
;
425 EdidActiveDataBlock
= EdidOverrideDataBlock
;
429 if (EdidFound
== TRUE
) {
431 // Parse EDID data structure to retrieve modes supported by monitor
433 if (ParseEdidData ((UINT8
*) EdidActiveDataBlock
, &ValidEdidTiming
) == TRUE
) {
435 // Copy EDID Override Data to EDID Active Data
437 Private
->EdidActive
.SizeOfEdid
= (UINT32
) EdidActiveDataSize
;
438 Private
->EdidActive
.Edid
= (UINT8
*) AllocateCopyPool (
442 if (NULL
== Private
->EdidActive
.Edid
) {
443 Status
= EFI_OUT_OF_RESOURCES
;
448 Private
->EdidActive
.SizeOfEdid
= 0;
449 Private
->EdidActive
.Edid
= NULL
;
455 // Initialize the private mode data with the supported modes.
458 ModeData
= &Private
->ModeData
[0];
459 VideoMode
= &CirrusLogic5430VideoModes
[0];
460 for (Index
= 0; Index
< CIRRUS_LOGIC_5430_MODE_COUNT
; Index
++) {
465 // Check whether match with CirrusLogic5430 video mode
467 TempTiming
.HorizontalResolution
= (UINT16
) VideoMode
->Width
;
468 TempTiming
.VerticalResolution
= (UINT16
) VideoMode
->Height
;
469 TempTiming
.RefreshRate
= (UINT16
) VideoMode
->RefreshRate
;
470 if (SearchEdidTiming (&ValidEdidTiming
, &TempTiming
) != TRUE
) {
475 // Not export Mode 0x0 as GOP mode, this is not defined in spec.
477 if ((VideoMode
->Width
== 0) || (VideoMode
->Height
== 0)) {
482 ModeData
->ModeNumber
= Index
;
483 ModeData
->HorizontalResolution
= VideoMode
->Width
;
484 ModeData
->VerticalResolution
= VideoMode
->Height
;
485 ModeData
->ColorDepth
= VideoMode
->ColorDepth
;
486 ModeData
->RefreshRate
= VideoMode
->RefreshRate
;
495 Private
->MaxMode
= ValidModeCount
;
499 // If EDID information wasn't found
501 ModeData
= &Private
->ModeData
[0];
502 VideoMode
= &CirrusLogic5430VideoModes
[0];
503 for (Index
= 0; Index
< CIRRUS_LOGIC_5430_MODE_COUNT
; Index
++) {
504 ModeData
->ModeNumber
= Index
;
505 ModeData
->HorizontalResolution
= VideoMode
->Width
;
506 ModeData
->VerticalResolution
= VideoMode
->Height
;
507 ModeData
->ColorDepth
= VideoMode
->ColorDepth
;
508 ModeData
->RefreshRate
= VideoMode
->RefreshRate
;
513 Private
->MaxMode
= CIRRUS_LOGIC_5430_MODE_COUNT
;
516 FreePool (EdidOverrideDataBlock
);
520 if (EdidOverrideDataBlock
!= NULL
) {
521 FreePool (EdidOverrideDataBlock
);
523 if (Private
->EdidDiscovered
.Edid
!= NULL
) {
524 FreePool (Private
->EdidDiscovered
.Edid
);
526 if (Private
->EdidDiscovered
.Edid
!= NULL
) {
527 FreePool (Private
->EdidActive
.Edid
);
530 return EFI_DEVICE_ERROR
;