]> git.proxmox.com Git - mirror_edk2.git/blob - OptionRomPkg/CirrusLogic5430Dxe/Edid.c
1. add DxeI2c Library in OptionRomPkg.
[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 STATIC
109 EFI_STATUS
110 ReadEdidData (
111 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private,
112 UINT8 **EdidDataBlock,
113 UINTN *EdidSize
114 )
115 {
116 UINT8 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, 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 STATIC
168 UINT32
169 CalculateEdidKey (
170 EDID_TIMING *EdidTiming
171 )
172 {
173 UINT32 Key;
174
175 //
176 // Be sure no conflicts for all standard timing defined by VESA.
177 //
178 Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
179 return Key;
180 }
181
182 /**
183 Search a specified Timing in all the valid EDID timings.
184
185 @param ValidEdidTiming All valid EDID timing information.
186 @param EdidTiming The Timing to search for.
187
188 @retval TRUE Found.
189 @retval FALSE Not found.
190
191 **/
192 STATIC
193 BOOLEAN
194 SearchEdidTiming (
195 VALID_EDID_TIMING *ValidEdidTiming,
196 EDID_TIMING *EdidTiming
197 )
198 {
199 UINT32 Index;
200 UINT32 Key;
201
202 Key = CalculateEdidKey (EdidTiming);
203
204 for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
205 if (Key == ValidEdidTiming->Key[Index]) {
206 return TRUE;
207 }
208 }
209
210 return FALSE;
211 }
212
213 /**
214 Parse the Established Timing and Standard Timing in EDID data block.
215
216 @param EdidBuffer Pointer to EDID data block
217 @param ValidEdidTiming Valid EDID timing information
218
219 @retval TRUE The EDID data is valid.
220 @retval FALSE The EDID data is invalid.
221
222 **/
223 STATIC
224 BOOLEAN
225 ParseEdidData (
226 UINT8 *EdidBuffer,
227 VALID_EDID_TIMING *ValidEdidTiming
228 )
229 {
230 UINT8 CheckSum;
231 UINT32 Index;
232 UINT32 ValidNumber;
233 UINT32 TimingBits;
234 UINT8 *BufferIndex;
235 UINT16 HorizontalResolution;
236 UINT16 VerticalResolution;
237 UINT8 AspectRatio;
238 UINT8 RefreshRate;
239 EDID_TIMING TempTiming;
240 EDID_BLOCK *EdidDataBlock;
241
242 EdidDataBlock = (EDID_BLOCK *) EdidBuffer;
243
244 //
245 // Check the checksum of EDID data
246 //
247 CheckSum = 0;
248 for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {
249 CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
250 }
251 if (CheckSum != 0) {
252 return FALSE;
253 }
254
255 ValidNumber = 0;
256 SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);
257
258 if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
259 (EdidDataBlock->EstablishedTimings[1] != 0) ||
260 (EdidDataBlock->EstablishedTimings[2] != 0)
261 ) {
262 //
263 // Established timing data
264 //
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]);
271 ValidNumber ++;
272 }
273 TimingBits = TimingBits >> 1;
274 }
275 } else {
276 //
277 // If no Established timing data, read the standard timing data
278 //
279 BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
280 for (Index = 0; Index < 8; Index ++) {
281 if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
282 //
283 // A valid Standard Timing
284 //
285 HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
286 AspectRatio = (UINT8) (BufferIndex[1] >> 6);
287 switch (AspectRatio) {
288 case 0:
289 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
290 break;
291 case 1:
292 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
293 break;
294 case 2:
295 VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
296 break;
297 case 3:
298 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
299 break;
300 default:
301 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
302 break;
303 }
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);
309 ValidNumber ++;
310 }
311 BufferIndex += 2;
312 }
313 }
314
315 ValidEdidTiming->ValidNumber = ValidNumber;
316 return TRUE;
317 }
318
319 /**
320 Construct the valid video modes for CirrusLogic5430.
321
322 **/
323 EFI_STATUS
324 CirrusLogic5430VideoModeSetup (
325 CIRRUS_LOGIC_5430_PRIVATE_DATA *Private
326 )
327 {
328 EFI_STATUS Status;
329 UINT32 Index;
330 BOOLEAN EdidFound;
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;
343 BOOLEAN TimingMatch;
344 CIRRUS_LOGIC_5430_VIDEO_MODES *VideoMode;
345 EDID_TIMING TempTiming;
346
347 //
348 // setup EDID information
349 //
350 Private->EdidDiscovered.Edid = NULL;
351 Private->EdidDiscovered.SizeOfEdid = 0;
352 Private->EdidActive.Edid = NULL;
353 Private->EdidActive.SizeOfEdid = 0;
354
355 EdidFound = FALSE;
356 EdidOverrideFound = FALSE;
357 EdidAttributes = 0xff;
358 EdidOverrideDataSize = 0;
359 EdidOverrideDataBlock = NULL;
360 EdidActiveDataSize = 0;
361 EdidActiveDataBlock = NULL;
362 EdidDiscoveredDataBlock = NULL;
363
364 //
365 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
366 //
367 Status = gBS->LocateProtocol (
368 &gEfiEdidOverrideProtocolGuid,
369 NULL,
370 (VOID **) &EdidOverride
371 );
372 if (!EFI_ERROR (Status)) {
373 //
374 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
375 //
376 EdidOverrideDataBlock = AllocatePool (sizeof (EDID_BLOCK_SIZE * 2));
377 if (NULL == EdidOverrideDataBlock) {
378 Status = EFI_OUT_OF_RESOURCES;
379 goto Done;
380 }
381
382 Status = EdidOverride->GetEdid (
383 EdidOverride,
384 Private->Handle,
385 &EdidAttributes,
386 &EdidOverrideDataSize,
387 (UINT8 **) &EdidOverrideDataBlock
388 );
389 if (!EFI_ERROR (Status) &&
390 EdidAttributes == 0 &&
391 EdidOverrideDataSize != 0) {
392 //
393 // Succeeded to get EDID Override Data
394 //
395 EdidOverrideFound = TRUE;
396 }
397 }
398
399 if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
400 //
401 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
402 // read EDID information through I2C Bus
403 //
404 if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {;
405 Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;
406 Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
407 EdidDiscoveredDataSize,
408 EdidDiscoveredDataBlock
409 );
410
411 if (NULL == Private->EdidDiscovered.Edid) {
412 Status = EFI_OUT_OF_RESOURCES;
413 goto Done;
414 }
415
416 EdidActiveDataSize = Private->EdidDiscovered.SizeOfEdid;
417 EdidActiveDataBlock = Private->EdidDiscovered.Edid;
418
419 EdidFound = TRUE;
420 }
421 }
422
423 if (EdidFound != TRUE && EdidOverrideFound == TRUE) {
424 EdidActiveDataSize = EdidOverrideDataSize;
425 EdidActiveDataBlock = EdidOverrideDataBlock;
426 EdidFound = TRUE;
427 }
428
429 if (EdidFound == TRUE) {
430 //
431 // Parse EDID data structure to retrieve modes supported by monitor
432 //
433 if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {
434 //
435 // Copy EDID Override Data to EDID Active Data
436 //
437 Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
438 Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
439 EdidActiveDataSize,
440 EdidActiveDataBlock
441 );
442 if (NULL == Private->EdidActive.Edid) {
443 Status = EFI_OUT_OF_RESOURCES;
444 goto Done;
445 }
446 }
447 } else {
448 Private->EdidActive.SizeOfEdid = 0;
449 Private->EdidActive.Edid = NULL;
450 EdidFound = FALSE;
451 }
452
453 if (EdidFound) {
454 //
455 // Initialize the private mode data with the supported modes.
456 //
457 ValidModeCount = 0;
458 ModeData = &Private->ModeData[0];
459 VideoMode = &CirrusLogic5430VideoModes[0];
460 for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index++) {
461
462 TimingMatch = TRUE;
463
464 //
465 // Check whether match with CirrusLogic5430 video mode
466 //
467 TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;
468 TempTiming.VerticalResolution = (UINT16) VideoMode->Height;
469 TempTiming.RefreshRate = (UINT16) VideoMode->RefreshRate;
470 if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {
471 TimingMatch = FALSE;
472 }
473
474 //
475 // Not export Mode 0x0 as GOP mode, this is not defined in spec.
476 //
477 if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
478 TimingMatch = FALSE;
479 }
480
481 if (TimingMatch) {
482 ModeData->ModeNumber = Index;
483 ModeData->HorizontalResolution = VideoMode->Width;
484 ModeData->VerticalResolution = VideoMode->Height;
485 ModeData->ColorDepth = VideoMode->ColorDepth;
486 ModeData->RefreshRate = VideoMode->RefreshRate;
487
488 ModeData ++;
489 ValidModeCount ++;
490 }
491
492 VideoMode ++;
493 }
494
495 Private->MaxMode = ValidModeCount;
496
497 } else {
498 //
499 // If EDID information wasn't found
500 //
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;
509
510 ModeData ++ ;
511 VideoMode ++;
512 }
513 Private->MaxMode = CIRRUS_LOGIC_5430_MODE_COUNT;
514 }
515
516 FreePool (EdidOverrideDataBlock);
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 }