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