]> git.proxmox.com Git - mirror_edk2.git/blob - OptionRomPkg/CirrusLogic5430Dxe/Edid.c
Resolve a bug where the initial ReadEdidData 'for' loop would loop
[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
17 //
18 // EDID block
19 //
20 typedef struct {
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;
33 UINT8 FeatureSupport;
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
48 UINT8 Checksum;
49 } EDID_BLOCK;
50
51 #define EDID_BLOCK_SIZE 128
52 #define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
53
54 typedef struct {
55 UINT16 HorizontalResolution;
56 UINT16 VerticalResolution;
57 UINT16 RefreshRate;
58 } EDID_TIMING;
59
60 typedef struct {
61 UINT32 ValidNumber;
62 UINT32 Key[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER];
63 } VALID_EDID_TIMING;
64
65 //
66 // Standard timing defined by VESA EDID
67 //
68 EDID_TIMING mVbeEstablishedEdidTiming[] = {
69 //
70 // Established Timing I
71 //
72 {800, 600, 60},
73 {800, 600, 56},
74 {640, 480, 75},
75 {640, 480, 72},
76 {640, 480, 67},
77 {640, 480, 60},
78 {720, 400, 88},
79 {720, 400, 70},
80 //
81 // Established Timing II
82 //
83 {1280, 1024, 75},
84 {1024, 768, 75},
85 {1024, 768, 70},
86 {1024, 768, 60},
87 {1024, 768, 87},
88 {832, 624, 75},
89 {800, 600, 75},
90 {800, 600, 72},
91 //
92 // Established Timing III
93 //
94 {1152, 870, 75}
95 };
96
97 /**
98 Read EDID information from I2C Bus on CirrusLogic.
99
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.
103
104 @retval EFI_UNSUPPORTED
105 @retval EFI_SUCCESS
106
107 **/
108 EFI_STATUS
109 ReadEdidData (
110 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private,
111 UINT8 **EdidDataBlock,
112 UINTN *EdidSize
113 )
114 {
115 UINTN Index;
116 UINT8 EdidData[EDID_BLOCK_SIZE * 2];
117 UINT8 *ValidEdid;
118 UINT64 Signature;
119
120 for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++) {
121 I2cReadByte (Private->PciIo, 0xa0, Index, &EdidData[Index]);
122 }
123
124 //
125 // Search for the EDID signature
126 //
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) {
131 break;
132 }
133 }
134
135 if (Index == 256) {
136 //
137 // No EDID signature found
138 //
139 return EFI_UNSUPPORTED;
140 }
141
142 *EdidDataBlock = AllocateCopyPool (
143 sizeof (EDID_BLOCK_SIZE),
144 ValidEdid
145 );
146 if (*EdidDataBlock == NULL) {
147 return EFI_OUT_OF_RESOURCES;
148 }
149
150 //
151 // Currently only support EDID 1.x
152 //
153 *EdidSize = EDID_BLOCK_SIZE;
154
155 return EFI_SUCCESS;
156 }
157
158 /**
159 Generate a search key for a specified timing data.
160
161 @param EdidTiming Pointer to EDID timing
162
163 @return The 32 bit unique key for search.
164
165 **/
166 UINT32
167 CalculateEdidKey (
168 EDID_TIMING *EdidTiming
169 )
170 {
171 UINT32 Key;
172
173 //
174 // Be sure no conflicts for all standard timing defined by VESA.
175 //
176 Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
177 return Key;
178 }
179
180 /**
181 Search a specified Timing in all the valid EDID timings.
182
183 @param ValidEdidTiming All valid EDID timing information.
184 @param EdidTiming The Timing to search for.
185
186 @retval TRUE Found.
187 @retval FALSE Not found.
188
189 **/
190 BOOLEAN
191 SearchEdidTiming (
192 VALID_EDID_TIMING *ValidEdidTiming,
193 EDID_TIMING *EdidTiming
194 )
195 {
196 UINT32 Index;
197 UINT32 Key;
198
199 Key = CalculateEdidKey (EdidTiming);
200
201 for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
202 if (Key == ValidEdidTiming->Key[Index]) {
203 return TRUE;
204 }
205 }
206
207 return FALSE;
208 }
209
210 /**
211 Parse the Established Timing and Standard Timing in EDID data block.
212
213 @param EdidBuffer Pointer to EDID data block
214 @param ValidEdidTiming Valid EDID timing information
215
216 @retval TRUE The EDID data is valid.
217 @retval FALSE The EDID data is invalid.
218
219 **/
220 BOOLEAN
221 ParseEdidData (
222 UINT8 *EdidBuffer,
223 VALID_EDID_TIMING *ValidEdidTiming
224 )
225 {
226 UINT8 CheckSum;
227 UINT32 Index;
228 UINT32 ValidNumber;
229 UINT32 TimingBits;
230 UINT8 *BufferIndex;
231 UINT16 HorizontalResolution;
232 UINT16 VerticalResolution;
233 UINT8 AspectRatio;
234 UINT8 RefreshRate;
235 EDID_TIMING TempTiming;
236 EDID_BLOCK *EdidDataBlock;
237
238 EdidDataBlock = (EDID_BLOCK *) EdidBuffer;
239
240 //
241 // Check the checksum of EDID data
242 //
243 CheckSum = 0;
244 for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {
245 CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
246 }
247 if (CheckSum != 0) {
248 return FALSE;
249 }
250
251 ValidNumber = 0;
252 SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);
253
254 if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
255 (EdidDataBlock->EstablishedTimings[1] != 0) ||
256 (EdidDataBlock->EstablishedTimings[2] != 0)
257 ) {
258 //
259 // Established timing data
260 //
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]);
267 ValidNumber ++;
268 }
269 TimingBits = TimingBits >> 1;
270 }
271 } else {
272 //
273 // If no Established timing data, read the standard timing data
274 //
275 BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
276 for (Index = 0; Index < 8; Index ++) {
277 if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
278 //
279 // A valid Standard Timing
280 //
281 HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
282 AspectRatio = (UINT8) (BufferIndex[1] >> 6);
283 switch (AspectRatio) {
284 case 0:
285 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
286 break;
287 case 1:
288 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
289 break;
290 case 2:
291 VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
292 break;
293 case 3:
294 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
295 break;
296 default:
297 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
298 break;
299 }
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);
305 ValidNumber ++;
306 }
307 BufferIndex += 2;
308 }
309 }
310
311 ValidEdidTiming->ValidNumber = ValidNumber;
312 return TRUE;
313 }
314
315 /**
316 Construct the valid video modes for CirrusLogic5430.
317
318 **/
319 EFI_STATUS
320 CirrusLogic5430VideoModeSetup (
321 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private
322 )
323 {
324 EFI_STATUS Status;
325 UINT32 Index;
326 BOOLEAN EdidFound;
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;
339 BOOLEAN TimingMatch;
340 CIRRUS_LOGIC_5430_VIDEO_MODES *VideoMode;
341 EDID_TIMING TempTiming;
342
343 //
344 // setup EDID information
345 //
346 Private->EdidDiscovered.Edid = NULL;
347 Private->EdidDiscovered.SizeOfEdid = 0;
348 Private->EdidActive.Edid = NULL;
349 Private->EdidActive.SizeOfEdid = 0;
350
351 EdidFound = FALSE;
352 EdidOverrideFound = FALSE;
353 EdidAttributes = 0xff;
354 EdidOverrideDataSize = 0;
355 EdidOverrideDataBlock = NULL;
356 EdidActiveDataSize = 0;
357 EdidActiveDataBlock = NULL;
358 EdidDiscoveredDataBlock = NULL;
359
360 //
361 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
362 //
363 Status = gBS->LocateProtocol (
364 &gEfiEdidOverrideProtocolGuid,
365 NULL,
366 (VOID **) &EdidOverride
367 );
368 if (!EFI_ERROR (Status)) {
369 //
370 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
371 //
372 EdidOverrideDataBlock = AllocatePool (sizeof (EDID_BLOCK_SIZE * 2));
373 if (NULL == EdidOverrideDataBlock) {
374 Status = EFI_OUT_OF_RESOURCES;
375 goto Done;
376 }
377
378 Status = EdidOverride->GetEdid (
379 EdidOverride,
380 Private->Handle,
381 &EdidAttributes,
382 &EdidOverrideDataSize,
383 (UINT8 **) &EdidOverrideDataBlock
384 );
385 if (!EFI_ERROR (Status) &&
386 EdidAttributes == 0 &&
387 EdidOverrideDataSize != 0) {
388 //
389 // Succeeded to get EDID Override Data
390 //
391 EdidOverrideFound = TRUE;
392 }
393 }
394
395 if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
396 //
397 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
398 // read EDID information through I2C Bus
399 //
400 if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {
401 Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;
402 Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
403 EdidDiscoveredDataSize,
404 EdidDiscoveredDataBlock
405 );
406
407 if (NULL == Private->EdidDiscovered.Edid) {
408 Status = EFI_OUT_OF_RESOURCES;
409 goto Done;
410 }
411
412 EdidActiveDataSize = Private->EdidDiscovered.SizeOfEdid;
413 EdidActiveDataBlock = Private->EdidDiscovered.Edid;
414
415 EdidFound = TRUE;
416 }
417 }
418
419 if (EdidFound != TRUE && EdidOverrideFound == TRUE) {
420 EdidActiveDataSize = EdidOverrideDataSize;
421 EdidActiveDataBlock = EdidOverrideDataBlock;
422 EdidFound = TRUE;
423 }
424
425 if (EdidFound == TRUE) {
426 //
427 // Parse EDID data structure to retrieve modes supported by monitor
428 //
429 if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {
430 //
431 // Copy EDID Override Data to EDID Active Data
432 //
433 Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
434 Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
435 EdidActiveDataSize,
436 EdidActiveDataBlock
437 );
438 if (NULL == Private->EdidActive.Edid) {
439 Status = EFI_OUT_OF_RESOURCES;
440 goto Done;
441 }
442 }
443 } else {
444 Private->EdidActive.SizeOfEdid = 0;
445 Private->EdidActive.Edid = NULL;
446 EdidFound = FALSE;
447 }
448
449 if (EdidFound) {
450 //
451 // Initialize the private mode data with the supported modes.
452 //
453 ValidModeCount = 0;
454 ModeData = &Private->ModeData[0];
455 VideoMode = &CirrusLogic5430VideoModes[0];
456 for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index++) {
457
458 TimingMatch = TRUE;
459
460 //
461 // Check whether match with CirrusLogic5430 video mode
462 //
463 TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;
464 TempTiming.VerticalResolution = (UINT16) VideoMode->Height;
465 TempTiming.RefreshRate = (UINT16) VideoMode->RefreshRate;
466 if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {
467 TimingMatch = FALSE;
468 }
469
470 //
471 // Not export Mode 0x0 as GOP mode, this is not defined in spec.
472 //
473 if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
474 TimingMatch = FALSE;
475 }
476
477 if (TimingMatch) {
478 ModeData->ModeNumber = Index;
479 ModeData->HorizontalResolution = VideoMode->Width;
480 ModeData->VerticalResolution = VideoMode->Height;
481 ModeData->ColorDepth = VideoMode->ColorDepth;
482 ModeData->RefreshRate = VideoMode->RefreshRate;
483
484 ModeData ++;
485 ValidModeCount ++;
486 }
487
488 VideoMode ++;
489 }
490
491 Private->MaxMode = ValidModeCount;
492
493 } else {
494 //
495 // If EDID information wasn't found
496 //
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;
505
506 ModeData ++ ;
507 VideoMode ++;
508 }
509 Private->MaxMode = CIRRUS_LOGIC_5430_MODE_COUNT;
510 }
511
512 if (EdidOverrideDataBlock != NULL) {
513 FreePool (EdidOverrideDataBlock);
514 }
515
516 return EFI_SUCCESS;
517
518 Done:
519 if (EdidOverrideDataBlock != NULL) {
520 FreePool (EdidOverrideDataBlock);
521 }
522 if (Private->EdidDiscovered.Edid != NULL) {
523 FreePool (Private->EdidDiscovered.Edid);
524 }
525 if (Private->EdidDiscovered.Edid != NULL) {
526 FreePool (Private->EdidActive.Edid);
527 }
528
529 return EFI_DEVICE_ERROR;
530 }