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