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