2 Graphics Output Protocol functions for the QEMU video controller.
4 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 /// Generic Attribute Controller Register Settings
15 UINT8 AttributeController
[21] = {
16 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
17 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
18 0x41, 0x00, 0x0F, 0x00, 0x00
22 /// Generic Graphics Controller Register Settings
24 UINT8 GraphicsController
[9] = {
25 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF
29 // 640 x 480 x 256 color @ 60 Hertz
31 UINT8 Crtc_640_480_256_60
[28] = {
32 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
33 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34 0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3,
35 0xff, 0x00, 0x00, 0x22
38 UINT8 Crtc_640_480_32bpp_60
[28] = {
39 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
40 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 0xe1, 0x83, 0xdf, 0x40, 0x00, 0xe7, 0x04, 0xe3,
42 0xff, 0x00, 0x00, 0x32
45 UINT16 Seq_640_480_256_60
[15] = {
46 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
47 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
50 UINT16 Seq_640_480_32bpp_60
[15] = {
51 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
52 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
56 // 800 x 600 x 256 color @ 60 Hertz
58 UINT8 Crtc_800_600_256_60
[28] = {
59 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
60 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3,
62 0xFF, 0x00, 0x00, 0x22
65 UINT8 Crtc_800_600_32bpp_60
[28] = {
66 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
67 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x58, 0x8C, 0x57, 0x90, 0x00, 0x5F, 0x91, 0xE3,
69 0xFF, 0x00, 0x00, 0x32
72 UINT16 Seq_800_600_256_60
[15] = {
73 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
74 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
77 UINT16 Seq_800_600_32bpp_60
[15] = {
78 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
79 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
82 UINT8 Crtc_960_720_32bpp_60
[28] = {
83 0xA3, 0x77, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
84 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x02, 0x88, 0xCF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
86 0xFF, 0x4A, 0x00, 0x32
89 UINT16 Seq_960_720_32bpp_60
[15] = {
90 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
91 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
95 // 1024 x 768 x 256 color @ 60 Hertz
97 UINT8 Crtc_1024_768_256_60
[28] = {
98 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
99 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
101 0xFF, 0x4A, 0x00, 0x22
104 UINT16 Seq_1024_768_256_60
[15] = {
105 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
106 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
110 // 1024 x 768 x 24-bit color @ 60 Hertz
112 UINT8 Crtc_1024_768_24bpp_60
[28] = {
113 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
114 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
116 0xFF, 0x4A, 0x00, 0x32
119 UINT16 Seq_1024_768_24bpp_60
[15] = {
120 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1507, 0x0008, 0x4a0b,
121 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
124 UINT8 Crtc_1024_768_32bpp_60
[28] = {
125 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
126 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x02, 0x88, 0xFF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
128 0xFF, 0x4A, 0x00, 0x32
131 UINT16 Seq_1024_768_32bpp_60
[15] = {
132 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
133 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
137 /// Table of supported video modes
139 QEMU_VIDEO_CIRRUS_MODES QemuVideoCirrusModes
[] = {
140 // { 640, 480, 8, Crtc_640_480_256_60, Seq_640_480_256_60, 0xe3 },
141 // { 800, 600, 8, Crtc_800_600_256_60, Seq_800_600_256_60, 0xef },
142 { 640, 480, 32, Crtc_640_480_32bpp_60
, Seq_640_480_32bpp_60
, 0xef },
143 { 800, 600, 32, Crtc_800_600_32bpp_60
, Seq_800_600_32bpp_60
, 0xef },
144 // { 1024, 768, 8, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef }
145 { 1024, 768, 24, Crtc_1024_768_24bpp_60
, Seq_1024_768_24bpp_60
, 0xef }
146 // { 1024, 768, 32, Crtc_1024_768_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
147 // { 960, 720, 32, Crtc_960_720_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
150 #define QEMU_VIDEO_CIRRUS_MODE_COUNT \
151 (ARRAY_SIZE (QemuVideoCirrusModes))
154 Construct the valid video modes for QemuVideo.
158 QemuVideoCirrusModeSetup (
159 QEMU_VIDEO_PRIVATE_DATA
*Private
163 QEMU_VIDEO_MODE_DATA
*ModeData
;
164 QEMU_VIDEO_CIRRUS_MODES
*VideoMode
;
169 Private
->ModeData
= AllocatePool (
170 sizeof (Private
->ModeData
[0]) * QEMU_VIDEO_CIRRUS_MODE_COUNT
172 if (Private
->ModeData
== NULL
) {
173 return EFI_OUT_OF_RESOURCES
;
176 ModeData
= Private
->ModeData
;
177 VideoMode
= &QemuVideoCirrusModes
[0];
178 for (Index
= 0; Index
< QEMU_VIDEO_CIRRUS_MODE_COUNT
; Index
++) {
179 ModeData
->InternalModeIndex
= Index
;
180 ModeData
->HorizontalResolution
= VideoMode
->Width
;
181 ModeData
->VerticalResolution
= VideoMode
->Height
;
182 ModeData
->ColorDepth
= VideoMode
->ColorDepth
;
185 "Adding Mode %d as Cirrus Internal Mode %d: %dx%d, %d-bit\n",
186 (INT32
)(ModeData
- Private
->ModeData
),
187 ModeData
->InternalModeIndex
,
188 ModeData
->HorizontalResolution
,
189 ModeData
->VerticalResolution
,
197 Private
->MaxMode
= ModeData
- Private
->ModeData
;
203 /// Table of supported video modes
205 STATIC QEMU_VIDEO_BOCHS_MODES QemuVideoBochsModes
[] = {
245 #define QEMU_VIDEO_BOCHS_MODE_COUNT \
246 (ARRAY_SIZE (QemuVideoBochsModes))
250 QemuVideoBochsAddMode (
251 QEMU_VIDEO_PRIVATE_DATA
*Private
,
252 UINT32 AvailableFbSize
,
257 QEMU_VIDEO_MODE_DATA
*ModeData
= Private
->ModeData
+ Private
->MaxMode
;
258 UINTN RequiredFbSize
;
260 RequiredFbSize
= (UINTN
)Width
* Height
* 4;
261 if (RequiredFbSize
> AvailableFbSize
) {
264 "Skipping Bochs Mode %dx%d, 32-bit (not enough vram)\n",
271 ModeData
->InternalModeIndex
= (UINT32
)Private
->MaxMode
;
272 ModeData
->HorizontalResolution
= Width
;
273 ModeData
->VerticalResolution
= Height
;
274 ModeData
->ColorDepth
= 32;
277 "Adding Bochs Internal Mode %d: %dx%d, %d-bit\n",
278 ModeData
->InternalModeIndex
,
279 ModeData
->HorizontalResolution
,
280 ModeData
->VerticalResolution
,
290 QEMU_VIDEO_PRIVATE_DATA
*Private
,
297 if (Private
->Variant
!= QEMU_VIDEO_BOCHS_MMIO
) {
301 Status
= Private
->PciIo
->Mem
.Read (
306 sizeof (Private
->Edid
),
309 if (Status
!= EFI_SUCCESS
) {
312 "%a: mmio read failed\n",
318 if ((Private
->Edid
[0] != 0x00) ||
319 (Private
->Edid
[1] != 0xff))
323 "%a: magic check failed\n",
331 "%a: blob found (extensions: %d)\n",
336 if ((Private
->Edid
[54] == 0x00) &&
337 (Private
->Edid
[55] == 0x00))
341 "%a: no detailed timing descriptor\n",
347 *XRes
= Private
->Edid
[56] | ((Private
->Edid
[58] & 0xf0) << 4);
348 *YRes
= Private
->Edid
[59] | ((Private
->Edid
[61] & 0xf0) << 4);
351 "%a: default resolution: %dx%d\n",
357 if (PcdGet8 (PcdVideoResolutionSource
) == 0) {
358 Status
= PcdSet32S (PcdVideoHorizontalResolution
, *XRes
);
359 ASSERT_RETURN_ERROR (Status
);
360 Status
= PcdSet32S (PcdVideoVerticalResolution
, *YRes
);
361 ASSERT_RETURN_ERROR (Status
);
362 Status
= PcdSet8S (PcdVideoResolutionSource
, 2);
363 ASSERT_RETURN_ERROR (Status
);
366 // TODO: register edid as gEfiEdidDiscoveredProtocolGuid ?
370 QemuVideoBochsModeSetup (
371 QEMU_VIDEO_PRIVATE_DATA
*Private
,
375 UINT32 AvailableFbSize
;
376 UINT32 Index
, XRes
= 0, YRes
= 0;
379 // Fetch the available framebuffer size.
381 // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the
382 // drawable framebuffer. Up to and including qemu-2.1 however it used to
383 // return the size of PCI BAR 0 (ie. the full video RAM size).
385 // On stdvga the two concepts coincide with each other; the full memory size
386 // is usable for drawing.
388 // On QXL however, only a leading segment, "surface 0", can be used for
389 // drawing; the rest of the video memory is used for the QXL guest-host
390 // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of
391 // "surface 0", but since it doesn't (up to and including qemu-2.1), we
392 // retrieve the size of the drawable portion from a field in the QXL ROM BAR,
393 // where it is also available.
400 DrawStart
= 0xFFFFFFFF;
403 Private
->PciIo
->Mem
.Read (
412 (Signature
!= SIGNATURE_32 ('Q', 'X', 'R', 'O')) ||
414 Private
->PciIo
->Mem
.Read (
425 Private
->PciIo
->Mem
.Read (
437 "%a: can't read size of drawable buffer from QXL "
441 return EFI_NOT_FOUND
;
444 AvailableFbSize
= BochsRead (Private
, VBE_DISPI_INDEX_VIDEO_MEMORY_64K
);
445 AvailableFbSize
*= SIZE_64KB
;
450 "%a: AvailableFbSize=0x%x\n",
458 Private
->ModeData
= AllocatePool (
459 sizeof (Private
->ModeData
[0]) * (QEMU_VIDEO_BOCHS_MODE_COUNT
+1)
461 if (Private
->ModeData
== NULL
) {
462 return EFI_OUT_OF_RESOURCES
;
465 QemuVideoBochsEdid (Private
, &XRes
, &YRes
);
467 QemuVideoBochsAddMode (
475 for (Index
= 0; Index
< QEMU_VIDEO_BOCHS_MODE_COUNT
; Index
++) {
476 if ((QemuVideoBochsModes
[Index
].Width
== XRes
) &&
477 (QemuVideoBochsModes
[Index
].Height
== YRes
))
479 continue; // duplicate with edid resolution
482 QemuVideoBochsAddMode (
485 QemuVideoBochsModes
[Index
].Width
,
486 QemuVideoBochsModes
[Index
].Height