VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c@ 48674

Last change on this file since 48674 was 48674, checked in by vboxsync, 11 years ago

EFI: Export newly imported tinaocore UEFI sources to OSE.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette