Edid.c 16 KB

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