]> git.proxmox.com Git - mirror_edk2.git/blob - OptionRomPkg/CirrusLogic5430Dxe/Edid.c
ccf8584787c8be94e68b01679a6ed111edd859b7
[mirror_edk2.git] / OptionRomPkg / CirrusLogic5430Dxe / Edid.c
1 /** @file
2 Read EDID information and parse EDID information.
3
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
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 sizeof (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 (sizeof (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 }