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"
16 #include "CirrusLogic5430I2c.h"
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
;
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
52 #define EDID_BLOCK_SIZE 128
53 #define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
56 UINT16 HorizontalResolution
;
57 UINT16 VerticalResolution
;
63 UINT32 Key
[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER
];
67 // Standard timing defined by VESA EDID
69 EDID_TIMING mVbeEstablishedEdidTiming
[] = {
71 // Established Timing I
82 // Established Timing II
93 // Established Timing III
99 Read EDID information from I2C Bus on CirrusLogic.
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.
105 @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, (UINT8
)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.
169 EDID_TIMING
*EdidTiming
175 // Be sure no conflicts for all standard timing defined by VESA.
177 Key
= (EdidTiming
->HorizontalResolution
* 2) + EdidTiming
->VerticalResolution
;
182 Search a specified Timing in all the valid EDID timings.
184 @param ValidEdidTiming All valid EDID timing information.
185 @param EdidTiming The Timing to search for.
188 @retval FALSE Not found.
193 VALID_EDID_TIMING
*ValidEdidTiming
,
194 EDID_TIMING
*EdidTiming
200 Key
= CalculateEdidKey (EdidTiming
);
202 for (Index
= 0; Index
< ValidEdidTiming
->ValidNumber
; Index
++) {
203 if (Key
== ValidEdidTiming
->Key
[Index
]) {
212 Parse the Established Timing and Standard Timing in EDID data block.
214 @param EdidBuffer Pointer to EDID data block
215 @param ValidEdidTiming Valid EDID timing information
217 @retval TRUE The EDID data is valid.
218 @retval FALSE The EDID data is invalid.
224 VALID_EDID_TIMING
*ValidEdidTiming
232 UINT16 HorizontalResolution
;
233 UINT16 VerticalResolution
;
236 EDID_TIMING TempTiming
;
237 EDID_BLOCK
*EdidDataBlock
;
239 EdidDataBlock
= (EDID_BLOCK
*) EdidBuffer
;
242 // Check the checksum of EDID data
245 for (Index
= 0; Index
< EDID_BLOCK_SIZE
; Index
++) {
246 CheckSum
= (UINT8
) (CheckSum
+ EdidBuffer
[Index
]);
253 SetMem (ValidEdidTiming
, sizeof (VALID_EDID_TIMING
), 0);
255 if ((EdidDataBlock
->EstablishedTimings
[0] != 0) ||
256 (EdidDataBlock
->EstablishedTimings
[1] != 0) ||
257 (EdidDataBlock
->EstablishedTimings
[2] != 0)
260 // Established timing data
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
]);
270 TimingBits
= TimingBits
>> 1;
274 // If no Established timing data, read the standard timing data
276 BufferIndex
= &EdidDataBlock
->StandardTimingIdentification
[0];
277 for (Index
= 0; Index
< 8; Index
++) {
278 if ((BufferIndex
[0] != 0x1) && (BufferIndex
[1] != 0x1)){
280 // A valid Standard Timing
282 HorizontalResolution
= (UINT16
) (BufferIndex
[0] * 8 + 248);
283 AspectRatio
= (UINT8
) (BufferIndex
[1] >> 6);
284 switch (AspectRatio
) {
286 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 10);
289 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
292 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 5 * 4);
295 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 9);
298 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
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
);
312 ValidEdidTiming
->ValidNumber
= ValidNumber
;
317 Construct the valid video modes for CirrusLogic5430.
321 CirrusLogic5430VideoModeSetup (
322 CIRRUS_LOGIC_5430_PRIVATE_DATA
*Private
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
;
341 CIRRUS_LOGIC_5430_VIDEO_MODES
*VideoMode
;
342 EDID_TIMING TempTiming
;
345 // setup EDID information
347 Private
->EdidDiscovered
.Edid
= NULL
;
348 Private
->EdidDiscovered
.SizeOfEdid
= 0;
349 Private
->EdidActive
.Edid
= NULL
;
350 Private
->EdidActive
.SizeOfEdid
= 0;
353 EdidOverrideFound
= FALSE
;
354 EdidAttributes
= 0xff;
355 EdidOverrideDataSize
= 0;
356 EdidOverrideDataBlock
= NULL
;
357 EdidActiveDataSize
= 0;
358 EdidActiveDataBlock
= NULL
;
359 EdidDiscoveredDataBlock
= NULL
;
362 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
364 Status
= gBS
->LocateProtocol (
365 &gEfiEdidOverrideProtocolGuid
,
367 (VOID
**) &EdidOverride
369 if (!EFI_ERROR (Status
)) {
371 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
373 EdidOverrideDataBlock
= AllocatePool (sizeof (EDID_BLOCK_SIZE
* 2));
374 if (NULL
== EdidOverrideDataBlock
) {
375 Status
= EFI_OUT_OF_RESOURCES
;
379 Status
= EdidOverride
->GetEdid (
383 &EdidOverrideDataSize
,
384 (UINT8
**) &EdidOverrideDataBlock
386 if (!EFI_ERROR (Status
) &&
387 EdidAttributes
== 0 &&
388 EdidOverrideDataSize
!= 0) {
390 // Succeeded to get EDID Override Data
392 EdidOverrideFound
= TRUE
;
396 if (EdidOverrideFound
!= TRUE
|| EdidAttributes
== EFI_EDID_OVERRIDE_DONT_OVERRIDE
) {
398 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
399 // read EDID information through I2C Bus
401 if (ReadEdidData (Private
, &EdidDiscoveredDataBlock
, &EdidDiscoveredDataSize
) == EFI_SUCCESS
) {
402 Private
->EdidDiscovered
.SizeOfEdid
= (UINT32
) EdidDiscoveredDataSize
;
403 Private
->EdidDiscovered
.Edid
= (UINT8
*) AllocateCopyPool (
404 EdidDiscoveredDataSize
,
405 EdidDiscoveredDataBlock
408 if (NULL
== Private
->EdidDiscovered
.Edid
) {
409 Status
= EFI_OUT_OF_RESOURCES
;
413 EdidActiveDataSize
= Private
->EdidDiscovered
.SizeOfEdid
;
414 EdidActiveDataBlock
= Private
->EdidDiscovered
.Edid
;
420 if (EdidFound
!= TRUE
&& EdidOverrideFound
== TRUE
) {
421 EdidActiveDataSize
= EdidOverrideDataSize
;
422 EdidActiveDataBlock
= EdidOverrideDataBlock
;
426 if (EdidFound
== TRUE
) {
428 // Parse EDID data structure to retrieve modes supported by monitor
430 if (ParseEdidData ((UINT8
*) EdidActiveDataBlock
, &ValidEdidTiming
) == TRUE
) {
432 // Copy EDID Override Data to EDID Active Data
434 Private
->EdidActive
.SizeOfEdid
= (UINT32
) EdidActiveDataSize
;
435 Private
->EdidActive
.Edid
= (UINT8
*) AllocateCopyPool (
439 if (NULL
== Private
->EdidActive
.Edid
) {
440 Status
= EFI_OUT_OF_RESOURCES
;
445 Private
->EdidActive
.SizeOfEdid
= 0;
446 Private
->EdidActive
.Edid
= NULL
;
452 // Initialize the private mode data with the supported modes.
455 ModeData
= &Private
->ModeData
[0];
456 VideoMode
= &CirrusLogic5430VideoModes
[0];
457 for (Index
= 0; Index
< CIRRUS_LOGIC_5430_MODE_COUNT
; Index
++) {
462 // Check whether match with CirrusLogic5430 video mode
464 TempTiming
.HorizontalResolution
= (UINT16
) VideoMode
->Width
;
465 TempTiming
.VerticalResolution
= (UINT16
) VideoMode
->Height
;
466 TempTiming
.RefreshRate
= (UINT16
) VideoMode
->RefreshRate
;
467 if (SearchEdidTiming (&ValidEdidTiming
, &TempTiming
) != TRUE
) {
472 // Not export Mode 0x0 as GOP mode, this is not defined in spec.
474 if ((VideoMode
->Width
== 0) || (VideoMode
->Height
== 0)) {
479 ModeData
->ModeNumber
= Index
;
480 ModeData
->HorizontalResolution
= VideoMode
->Width
;
481 ModeData
->VerticalResolution
= VideoMode
->Height
;
482 ModeData
->ColorDepth
= VideoMode
->ColorDepth
;
483 ModeData
->RefreshRate
= VideoMode
->RefreshRate
;
492 Private
->MaxMode
= ValidModeCount
;
496 // If EDID information wasn't found
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
;
510 Private
->MaxMode
= CIRRUS_LOGIC_5430_MODE_COUNT
;
513 if (EdidOverrideDataBlock
!= NULL
) {
514 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
;