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