1 /** @file
2   Graphics Output Protocol functions for the QEMU video controller.
3 
4   Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution. The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "Qemu.h"
17 
18 
19 ///
20 /// Generic Attribute Controller Register Settings
21 ///
22 UINT8  AttributeController[21] = {
23   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
24   0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
25   0x41, 0x00, 0x0F, 0x00, 0x00
26 };
27 
28 ///
29 /// Generic Graphics Controller Register Settings
30 ///
31 UINT8 GraphicsController[9] = {
32   0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF
33 };
34 
35 //
36 // 640 x 480 x 256 color @ 60 Hertz
37 //
38 UINT8 Crtc_640_480_256_60[28] = {
39   0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
40   0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41   0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3,
42   0xff, 0x00, 0x00, 0x22
43 };
44 
45 UINT8 Crtc_640_480_32bpp_60[28] = {
46   0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
47   0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48   0xe1, 0x83, 0xdf, 0x40, 0x00, 0xe7, 0x04, 0xe3,
49   0xff, 0x00, 0x00, 0x32
50 };
51 
52 UINT16 Seq_640_480_256_60[15] = {
53   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
54   0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
55 };
56 
57 UINT16 Seq_640_480_32bpp_60[15] = {
58   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
59   0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
60 };
61 
62 //
63 // 800 x 600 x 256 color @ 60 Hertz
64 //
65 UINT8 Crtc_800_600_256_60[28] = {
66   0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
67   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68   0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3,
69   0xFF, 0x00, 0x00, 0x22
70 };
71 
72 UINT8 Crtc_800_600_32bpp_60[28] = {
73   0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
74   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75   0x58, 0x8C, 0x57, 0x90, 0x00, 0x5F, 0x91, 0xE3,
76   0xFF, 0x00, 0x00, 0x32
77 };
78 
79 UINT16 Seq_800_600_256_60[15] = {
80   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
81   0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
82 };
83 
84 UINT16 Seq_800_600_32bpp_60[15] = {
85   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
86   0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
87 };
88 
89 UINT8 Crtc_960_720_32bpp_60[28] = {
90   0xA3, 0x77, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
91   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92   0x02, 0x88, 0xCF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
93   0xFF, 0x4A, 0x00, 0x32
94 };
95 
96 UINT16 Seq_960_720_32bpp_60[15] = {
97   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
98   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
99 };
100 
101 //
102 // 1024 x 768 x 256 color @ 60 Hertz
103 //
104 UINT8 Crtc_1024_768_256_60[28] = {
105   0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
106   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107   0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
108   0xFF, 0x4A, 0x00, 0x22
109 };
110 
111 UINT16 Seq_1024_768_256_60[15] = {
112   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
113   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
114 };
115 
116 //
117 // 1024 x 768 x 24-bit color @ 60 Hertz
118 //
119 UINT8 Crtc_1024_768_24bpp_60[28] = {
120   0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
121   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122   0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
123   0xFF, 0x4A, 0x00, 0x32
124 };
125 
126 UINT16 Seq_1024_768_24bpp_60[15] = {
127   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1507, 0x0008, 0x4a0b,
128   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
129 };
130 
131 UINT8 Crtc_1024_768_32bpp_60[28] = {
132   0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
133   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134   0x02, 0x88, 0xFF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
135   0xFF, 0x4A, 0x00, 0x32
136 };
137 
138 UINT16 Seq_1024_768_32bpp_60[15] = {
139   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
140   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
141 };
142 
143 ///
144 /// Table of supported video modes
145 ///
146 QEMU_VIDEO_CIRRUS_MODES  QemuVideoCirrusModes[] = {
147 //  {  640, 480, 8, 60, Crtc_640_480_256_60,  Seq_640_480_256_60,  0xe3 },
148 //  {  800, 600, 8, 60, Crtc_800_600_256_60,  Seq_800_600_256_60,  0xef },
149   {  640, 480, 32, 60, Crtc_640_480_32bpp_60,  Seq_640_480_32bpp_60,  0xef },
150   {  800, 600, 32, 60, Crtc_800_600_32bpp_60,  Seq_800_600_32bpp_60,  0xef },
151 //  { 1024, 768, 8, 60, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef }
152   { 1024, 768, 24, 60, Crtc_1024_768_24bpp_60, Seq_1024_768_24bpp_60, 0xef }
153 //  { 1024, 768, 32, 60, Crtc_1024_768_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
154 //  { 960, 720, 32, 60, Crtc_960_720_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
155 };
156 
157 #define QEMU_VIDEO_CIRRUS_MODE_COUNT \
158   (sizeof (QemuVideoCirrusModes) / sizeof (QemuVideoCirrusModes[0]))
159 
160 /**
161   Construct the valid video modes for QemuVideo.
162 
163 **/
164 EFI_STATUS
QemuVideoCirrusModeSetup(QEMU_VIDEO_PRIVATE_DATA * Private)165 QemuVideoCirrusModeSetup (
166   QEMU_VIDEO_PRIVATE_DATA  *Private
167   )
168 {
169   UINT32                                 Index;
170   QEMU_VIDEO_MODE_DATA                   *ModeData;
171   QEMU_VIDEO_CIRRUS_MODES                *VideoMode;
172 
173   //
174   // Setup Video Modes
175   //
176   Private->ModeData = AllocatePool (
177                         sizeof (Private->ModeData[0]) * QEMU_VIDEO_CIRRUS_MODE_COUNT
178                         );
179   if (Private->ModeData == NULL) {
180     return EFI_OUT_OF_RESOURCES;
181   }
182   ModeData = Private->ModeData;
183   VideoMode = &QemuVideoCirrusModes[0];
184   for (Index = 0; Index < QEMU_VIDEO_CIRRUS_MODE_COUNT; Index ++) {
185     ModeData->InternalModeIndex = Index;
186     ModeData->HorizontalResolution          = VideoMode->Width;
187     ModeData->VerticalResolution            = VideoMode->Height;
188     ModeData->ColorDepth                    = VideoMode->ColorDepth;
189     ModeData->RefreshRate                   = VideoMode->RefreshRate;
190     DEBUG ((EFI_D_INFO,
191       "Adding Mode %d as Cirrus Internal Mode %d: %dx%d, %d-bit, %d Hz\n",
192       (INT32) (ModeData - Private->ModeData),
193       ModeData->InternalModeIndex,
194       ModeData->HorizontalResolution,
195       ModeData->VerticalResolution,
196       ModeData->ColorDepth,
197       ModeData->RefreshRate
198       ));
199 
200     ModeData ++ ;
201     VideoMode ++;
202   }
203   Private->MaxMode = ModeData - Private->ModeData;
204 
205   return EFI_SUCCESS;
206 }
207 
208 ///
209 /// Table of supported video modes
210 ///
211 QEMU_VIDEO_BOCHS_MODES  QemuVideoBochsModes[] = {
212   {  640,  480, 32 },
213   {  800,  480, 32 },
214   {  800,  600, 32 },
215   {  832,  624, 32 },
216   {  960,  640, 32 },
217   { 1024,  600, 32 },
218   { 1024,  768, 32 },
219   { 1152,  864, 32 },
220   { 1152,  870, 32 },
221   { 1280,  720, 32 },
222   { 1280,  760, 32 },
223   { 1280,  768, 32 },
224   { 1280,  800, 32 },
225   { 1280,  960, 32 },
226   { 1280, 1024, 32 },
227   { 1360,  768, 32 },
228   { 1366,  768, 32 },
229   { 1400, 1050, 32 },
230   { 1440,  900, 32 },
231   { 1600,  900, 32 },
232   { 1600, 1200, 32 },
233   { 1680, 1050, 32 },
234   { 1920, 1080, 32 },
235   { 1920, 1200, 32 },
236   { 1920, 1440, 32 },
237   { 2000, 2000, 32 },
238   { 2048, 1536, 32 },
239   { 2048, 2048, 32 },
240   { 2560, 1440, 32 },
241   { 2560, 1600, 32 },
242   { 2560, 2048, 32 },
243   { 2800, 2100, 32 },
244   { 3200, 2400, 32 },
245   { 3840, 2160, 32 },
246   { 4096, 2160, 32 },
247   { 7680, 4320, 32 },
248   { 8192, 4320, 32 }
249 };
250 
251 #define QEMU_VIDEO_BOCHS_MODE_COUNT \
252   (sizeof (QemuVideoBochsModes) / sizeof (QemuVideoBochsModes[0]))
253 
254 EFI_STATUS
QemuVideoBochsModeSetup(QEMU_VIDEO_PRIVATE_DATA * Private,BOOLEAN IsQxl)255 QemuVideoBochsModeSetup (
256   QEMU_VIDEO_PRIVATE_DATA  *Private,
257   BOOLEAN                  IsQxl
258   )
259 {
260   UINT32                                 AvailableFbSize;
261   UINT32                                 Index;
262   QEMU_VIDEO_MODE_DATA                   *ModeData;
263   QEMU_VIDEO_BOCHS_MODES                 *VideoMode;
264 
265   //
266   // Fetch the available framebuffer size.
267   //
268   // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the
269   // drawable framebuffer. Up to and including qemu-2.1 however it used to
270   // return the size of PCI BAR 0 (ie. the full video RAM size).
271   //
272   // On stdvga the two concepts coincide with each other; the full memory size
273   // is usable for drawing.
274   //
275   // On QXL however, only a leading segment, "surface 0", can be used for
276   // drawing; the rest of the video memory is used for the QXL guest-host
277   // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of
278   // "surface 0", but since it doesn't (up to and including qemu-2.1), we
279   // retrieve the size of the drawable portion from a field in the QXL ROM BAR,
280   // where it is also available.
281   //
282   if (IsQxl) {
283     UINT32 Signature;
284     UINT32 DrawStart;
285 
286     Signature = 0;
287     DrawStart = 0xFFFFFFFF;
288     AvailableFbSize = 0;
289     if (EFI_ERROR (
290           Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
291                                 PCI_BAR_IDX2, 0, 1, &Signature)) ||
292         Signature != SIGNATURE_32 ('Q', 'X', 'R', 'O') ||
293         EFI_ERROR (
294           Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
295                                 PCI_BAR_IDX2, 36, 1, &DrawStart)) ||
296         DrawStart != 0 ||
297         EFI_ERROR (
298           Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
299                                 PCI_BAR_IDX2, 40, 1, &AvailableFbSize))) {
300       DEBUG ((EFI_D_ERROR, "%a: can't read size of drawable buffer from QXL "
301         "ROM\n", __FUNCTION__));
302       return EFI_NOT_FOUND;
303     }
304   } else {
305     AvailableFbSize  = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
306     AvailableFbSize *= SIZE_64KB;
307   }
308   DEBUG ((EFI_D_VERBOSE, "%a: AvailableFbSize=0x%x\n", __FUNCTION__,
309     AvailableFbSize));
310 
311   //
312   // Setup Video Modes
313   //
314   Private->ModeData = AllocatePool (
315                         sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
316                         );
317   if (Private->ModeData == NULL) {
318     return EFI_OUT_OF_RESOURCES;
319   }
320   ModeData = Private->ModeData;
321   VideoMode = &QemuVideoBochsModes[0];
322   for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index ++) {
323     UINTN RequiredFbSize;
324 
325     ASSERT (VideoMode->ColorDepth % 8 == 0);
326     RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height *
327                      (VideoMode->ColorDepth / 8);
328     if (RequiredFbSize <= AvailableFbSize) {
329       ModeData->InternalModeIndex    = Index;
330       ModeData->HorizontalResolution = VideoMode->Width;
331       ModeData->VerticalResolution   = VideoMode->Height;
332       ModeData->ColorDepth           = VideoMode->ColorDepth;
333       ModeData->RefreshRate          = 60;
334       DEBUG ((EFI_D_INFO,
335         "Adding Mode %d as Bochs Internal Mode %d: %dx%d, %d-bit, %d Hz\n",
336         (INT32) (ModeData - Private->ModeData),
337         ModeData->InternalModeIndex,
338         ModeData->HorizontalResolution,
339         ModeData->VerticalResolution,
340         ModeData->ColorDepth,
341         ModeData->RefreshRate
342         ));
343 
344       ModeData ++ ;
345     }
346     VideoMode ++;
347   }
348   Private->MaxMode = ModeData - Private->ModeData;
349 
350   return EFI_SUCCESS;
351 }
352 
353