VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxVgaDxe/Edid.c@ 37808

Last change on this file since 37808 was 29081, checked in by vboxsync, 15 years ago

more EFI exports to OSE

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