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