]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuVideoDxe/Driver.c
OvmfPkg/QemuVideoDxe: Add SubClass field to QEMU_VIDEO_CARD
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Driver.c
1 /** @file
2 This driver is a sample implementation of the Graphics Output Protocol for
3 the QEMU (Cirrus Logic 5446) video controller.
4
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <IndustryStandard/VmwareSvga.h>
18 #include <IndustryStandard/Acpi.h>
19 #include "Qemu.h"
20 #include "UnalignedIoInternal.h"
21
22 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
23 QemuVideoControllerDriverSupported,
24 QemuVideoControllerDriverStart,
25 QemuVideoControllerDriverStop,
26 0x10,
27 NULL,
28 NULL
29 };
30
31 QEMU_VIDEO_CARD gQemuVideoCardList[] = {
32 {
33 PCI_CLASS_DISPLAY_VGA,
34 CIRRUS_LOGIC_VENDOR_ID,
35 CIRRUS_LOGIC_5430_DEVICE_ID,
36 QEMU_VIDEO_CIRRUS_5430,
37 L"Cirrus 5430"
38 },{
39 PCI_CLASS_DISPLAY_VGA,
40 CIRRUS_LOGIC_VENDOR_ID,
41 CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,
42 QEMU_VIDEO_CIRRUS_5430,
43 L"Cirrus 5430"
44 },{
45 PCI_CLASS_DISPLAY_VGA,
46 CIRRUS_LOGIC_VENDOR_ID,
47 CIRRUS_LOGIC_5446_DEVICE_ID,
48 QEMU_VIDEO_CIRRUS_5446,
49 L"Cirrus 5446"
50 },{
51 PCI_CLASS_DISPLAY_VGA,
52 0x1234,
53 0x1111,
54 QEMU_VIDEO_BOCHS_MMIO,
55 L"QEMU Standard VGA"
56 },{
57 PCI_CLASS_DISPLAY_VGA,
58 0x1b36,
59 0x0100,
60 QEMU_VIDEO_BOCHS,
61 L"QEMU QXL VGA"
62 },{
63 PCI_CLASS_DISPLAY_VGA,
64 0x1af4,
65 0x1050,
66 QEMU_VIDEO_BOCHS_MMIO,
67 L"QEMU VirtIO VGA"
68 },{
69 PCI_CLASS_DISPLAY_VGA,
70 VMWARE_PCI_VENDOR_ID_VMWARE,
71 VMWARE_PCI_DEVICE_ID_VMWARE_SVGA2,
72 QEMU_VIDEO_VMWARE_SVGA,
73 L"QEMU VMWare SVGA"
74 },{
75 0 /* end of list */
76 }
77 };
78
79 static QEMU_VIDEO_CARD*
80 QemuVideoDetect(
81 IN UINT8 SubClass,
82 IN UINT16 VendorId,
83 IN UINT16 DeviceId
84 )
85 {
86 UINTN Index = 0;
87
88 while (gQemuVideoCardList[Index].VendorId != 0) {
89 if (gQemuVideoCardList[Index].SubClass == SubClass &&
90 gQemuVideoCardList[Index].VendorId == VendorId &&
91 gQemuVideoCardList[Index].DeviceId == DeviceId) {
92 return gQemuVideoCardList + Index;
93 }
94 Index++;
95 }
96 return NULL;
97 }
98
99 /**
100 Check if this device is supported.
101
102 @param This The driver binding protocol.
103 @param Controller The controller handle to check.
104 @param RemainingDevicePath The remaining device path.
105
106 @retval EFI_SUCCESS The bus supports this controller.
107 @retval EFI_UNSUPPORTED This device isn't supported.
108
109 **/
110 EFI_STATUS
111 EFIAPI
112 QemuVideoControllerDriverSupported (
113 IN EFI_DRIVER_BINDING_PROTOCOL *This,
114 IN EFI_HANDLE Controller,
115 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
116 )
117 {
118 EFI_STATUS Status;
119 EFI_PCI_IO_PROTOCOL *PciIo;
120 PCI_TYPE00 Pci;
121 QEMU_VIDEO_CARD *Card;
122
123 //
124 // Open the PCI I/O Protocol
125 //
126 Status = gBS->OpenProtocol (
127 Controller,
128 &gEfiPciIoProtocolGuid,
129 (VOID **) &PciIo,
130 This->DriverBindingHandle,
131 Controller,
132 EFI_OPEN_PROTOCOL_BY_DRIVER
133 );
134 if (EFI_ERROR (Status)) {
135 return Status;
136 }
137
138 //
139 // Read the PCI Configuration Header from the PCI Device
140 //
141 Status = PciIo->Pci.Read (
142 PciIo,
143 EfiPciIoWidthUint32,
144 0,
145 sizeof (Pci) / sizeof (UINT32),
146 &Pci
147 );
148 if (EFI_ERROR (Status)) {
149 goto Done;
150 }
151
152 Status = EFI_UNSUPPORTED;
153 if (!IS_PCI_DISPLAY (&Pci)) {
154 goto Done;
155 }
156 Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
157 if (Card != NULL) {
158 DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));
159 Status = EFI_SUCCESS;
160 }
161
162 Done:
163 //
164 // Close the PCI I/O Protocol
165 //
166 gBS->CloseProtocol (
167 Controller,
168 &gEfiPciIoProtocolGuid,
169 This->DriverBindingHandle,
170 Controller
171 );
172
173 return Status;
174 }
175
176 /**
177 Start to process the controller.
178
179 @param This The USB bus driver binding instance.
180 @param Controller The controller to check.
181 @param RemainingDevicePath The remaining device patch.
182
183 @retval EFI_SUCCESS The controller is controlled by the usb bus.
184 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
185 bus.
186 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
187
188 **/
189 EFI_STATUS
190 EFIAPI
191 QemuVideoControllerDriverStart (
192 IN EFI_DRIVER_BINDING_PROTOCOL *This,
193 IN EFI_HANDLE Controller,
194 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
195 )
196 {
197 EFI_TPL OldTpl;
198 EFI_STATUS Status;
199 QEMU_VIDEO_PRIVATE_DATA *Private;
200 BOOLEAN IsQxl;
201 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
202 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
203 PCI_TYPE00 Pci;
204 QEMU_VIDEO_CARD *Card;
205 EFI_PCI_IO_PROTOCOL *ChildPciIo;
206
207 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
208
209 //
210 // Allocate Private context data for GOP inteface.
211 //
212 Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
213 if (Private == NULL) {
214 Status = EFI_OUT_OF_RESOURCES;
215 goto RestoreTpl;
216 }
217
218 //
219 // Set up context record
220 //
221 Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
222
223 //
224 // Open PCI I/O Protocol
225 //
226 Status = gBS->OpenProtocol (
227 Controller,
228 &gEfiPciIoProtocolGuid,
229 (VOID **) &Private->PciIo,
230 This->DriverBindingHandle,
231 Controller,
232 EFI_OPEN_PROTOCOL_BY_DRIVER
233 );
234 if (EFI_ERROR (Status)) {
235 goto FreePrivate;
236 }
237
238 //
239 // Read the PCI Configuration Header from the PCI Device
240 //
241 Status = Private->PciIo->Pci.Read (
242 Private->PciIo,
243 EfiPciIoWidthUint32,
244 0,
245 sizeof (Pci) / sizeof (UINT32),
246 &Pci
247 );
248 if (EFI_ERROR (Status)) {
249 goto ClosePciIo;
250 }
251
252 //
253 // Determine card variant.
254 //
255 Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
256 if (Card == NULL) {
257 Status = EFI_DEVICE_ERROR;
258 goto ClosePciIo;
259 }
260 Private->Variant = Card->Variant;
261 Private->FrameBufferVramBarIndex = PCI_BAR_IDX0;
262
263 //
264 // IsQxl is based on the detected Card->Variant, which at a later point might
265 // not match Private->Variant.
266 //
267 IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);
268
269 //
270 // Save original PCI attributes
271 //
272 Status = Private->PciIo->Attributes (
273 Private->PciIo,
274 EfiPciIoAttributeOperationGet,
275 0,
276 &Private->OriginalPciAttributes
277 );
278
279 if (EFI_ERROR (Status)) {
280 goto ClosePciIo;
281 }
282
283 //
284 // Set new PCI attributes
285 //
286 Status = Private->PciIo->Attributes (
287 Private->PciIo,
288 EfiPciIoAttributeOperationEnable,
289 EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
290 NULL
291 );
292 if (EFI_ERROR (Status)) {
293 goto ClosePciIo;
294 }
295
296 //
297 // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
298 //
299 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
300 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
301
302 Status = Private->PciIo->GetBarAttributes (
303 Private->PciIo,
304 PCI_BAR_IDX2,
305 NULL,
306 (VOID**) &MmioDesc
307 );
308 if (EFI_ERROR (Status) ||
309 MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
310 DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
311 Private->Variant = QEMU_VIDEO_BOCHS;
312 } else {
313 DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
314 MmioDesc->AddrRangeMin));
315 }
316
317 if (!EFI_ERROR (Status)) {
318 FreePool (MmioDesc);
319 }
320 }
321
322 //
323 // Check if accessing the bochs interface works.
324 //
325 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
326 Private->Variant == QEMU_VIDEO_BOCHS) {
327 UINT16 BochsId;
328 BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID);
329 if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {
330 DEBUG ((EFI_D_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));
331 Status = EFI_DEVICE_ERROR;
332 goto RestoreAttributes;
333 }
334 }
335
336 //
337 // Check if accessing Vmware SVGA interface works
338 //
339 if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
340 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *IoDesc;
341 UINT32 TargetId;
342 UINT32 SvgaIdRead;
343
344 IoDesc = NULL;
345 Status = Private->PciIo->GetBarAttributes (
346 Private->PciIo,
347 PCI_BAR_IDX0,
348 NULL,
349 (VOID**) &IoDesc
350 );
351 if (EFI_ERROR (Status) ||
352 IoDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_IO ||
353 IoDesc->AddrRangeMin > MAX_UINT16 + 1 - (VMWARE_SVGA_VALUE_PORT + 4)) {
354 if (IoDesc != NULL) {
355 FreePool (IoDesc);
356 }
357 Status = EFI_DEVICE_ERROR;
358 goto RestoreAttributes;
359 }
360 Private->VmwareSvgaBasePort = (UINT16) IoDesc->AddrRangeMin;
361 FreePool (IoDesc);
362
363 TargetId = VMWARE_SVGA_ID_2;
364 while (TRUE) {
365 VmwareSvgaWrite (Private, VmwareSvgaRegId, TargetId);
366 SvgaIdRead = VmwareSvgaRead (Private, VmwareSvgaRegId);
367 if ((SvgaIdRead == TargetId) || (TargetId <= VMWARE_SVGA_ID_0)) {
368 break;
369 }
370 TargetId--;
371 }
372
373 if (SvgaIdRead != TargetId) {
374 DEBUG ((
375 DEBUG_ERROR,
376 "QemuVideo: QEMU_VIDEO_VMWARE_SVGA ID mismatch "
377 "(got 0x%x, base address 0x%x)\n",
378 SvgaIdRead,
379 Private->VmwareSvgaBasePort
380 ));
381 Status = EFI_DEVICE_ERROR;
382 goto RestoreAttributes;
383 }
384
385 Private->FrameBufferVramBarIndex = PCI_BAR_IDX1;
386 }
387
388 //
389 // Get ParentDevicePath
390 //
391 Status = gBS->HandleProtocol (
392 Controller,
393 &gEfiDevicePathProtocolGuid,
394 (VOID **) &ParentDevicePath
395 );
396 if (EFI_ERROR (Status)) {
397 goto RestoreAttributes;
398 }
399
400 //
401 // Set Gop Device Path
402 //
403 ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
404 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
405 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
406 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
407 SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
408
409 Private->GopDevicePath = AppendDevicePathNode (
410 ParentDevicePath,
411 (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
412 );
413 if (Private->GopDevicePath == NULL) {
414 Status = EFI_OUT_OF_RESOURCES;
415 goto RestoreAttributes;
416 }
417
418 //
419 // Create new child handle and install the device path protocol on it.
420 //
421 Status = gBS->InstallMultipleProtocolInterfaces (
422 &Private->Handle,
423 &gEfiDevicePathProtocolGuid,
424 Private->GopDevicePath,
425 NULL
426 );
427 if (EFI_ERROR (Status)) {
428 goto FreeGopDevicePath;
429 }
430
431 //
432 // Construct video mode buffer
433 //
434 switch (Private->Variant) {
435 case QEMU_VIDEO_CIRRUS_5430:
436 case QEMU_VIDEO_CIRRUS_5446:
437 Status = QemuVideoCirrusModeSetup (Private);
438 break;
439 case QEMU_VIDEO_BOCHS_MMIO:
440 case QEMU_VIDEO_BOCHS:
441 Status = QemuVideoBochsModeSetup (Private, IsQxl);
442 break;
443 case QEMU_VIDEO_VMWARE_SVGA:
444 Status = QemuVideoVmwareSvgaModeSetup (Private);
445 break;
446 default:
447 ASSERT (FALSE);
448 Status = EFI_DEVICE_ERROR;
449 break;
450 }
451 if (EFI_ERROR (Status)) {
452 goto UninstallGopDevicePath;
453 }
454
455 //
456 // Start the GOP software stack.
457 //
458 Status = QemuVideoGraphicsOutputConstructor (Private);
459 if (EFI_ERROR (Status)) {
460 goto FreeModeData;
461 }
462
463 Status = gBS->InstallMultipleProtocolInterfaces (
464 &Private->Handle,
465 &gEfiGraphicsOutputProtocolGuid,
466 &Private->GraphicsOutput,
467 NULL
468 );
469 if (EFI_ERROR (Status)) {
470 goto DestructQemuVideoGraphics;
471 }
472
473 //
474 // Reference parent handle from child handle.
475 //
476 Status = gBS->OpenProtocol (
477 Controller,
478 &gEfiPciIoProtocolGuid,
479 (VOID **) &ChildPciIo,
480 This->DriverBindingHandle,
481 Private->Handle,
482 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
483 );
484 if (EFI_ERROR (Status)) {
485 goto UninstallGop;
486 }
487
488 #if defined MDE_CPU_IA32 || defined MDE_CPU_X64
489 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
490 Private->Variant == QEMU_VIDEO_BOCHS) {
491 InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);
492 }
493 #endif
494
495 gBS->RestoreTPL (OldTpl);
496 return EFI_SUCCESS;
497
498 UninstallGop:
499 gBS->UninstallProtocolInterface (Private->Handle,
500 &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput);
501
502 DestructQemuVideoGraphics:
503 QemuVideoGraphicsOutputDestructor (Private);
504
505 FreeModeData:
506 FreePool (Private->ModeData);
507 if (Private->VmwareSvgaModeInfo != NULL) {
508 FreePool (Private->VmwareSvgaModeInfo);
509 }
510
511 UninstallGopDevicePath:
512 gBS->UninstallProtocolInterface (Private->Handle,
513 &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
514
515 FreeGopDevicePath:
516 FreePool (Private->GopDevicePath);
517
518 RestoreAttributes:
519 Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet,
520 Private->OriginalPciAttributes, NULL);
521
522 ClosePciIo:
523 gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,
524 This->DriverBindingHandle, Controller);
525
526 FreePrivate:
527 FreePool (Private);
528
529 RestoreTpl:
530 gBS->RestoreTPL (OldTpl);
531
532 return Status;
533 }
534
535 /**
536 Stop this device
537
538 @param This The USB bus driver binding protocol.
539 @param Controller The controller to release.
540 @param NumberOfChildren The number of children of this device that
541 opened the controller BY_CHILD.
542 @param ChildHandleBuffer The array of child handle.
543
544 @retval EFI_SUCCESS The controller or children are stopped.
545 @retval EFI_DEVICE_ERROR Failed to stop the driver.
546
547 **/
548 EFI_STATUS
549 EFIAPI
550 QemuVideoControllerDriverStop (
551 IN EFI_DRIVER_BINDING_PROTOCOL *This,
552 IN EFI_HANDLE Controller,
553 IN UINTN NumberOfChildren,
554 IN EFI_HANDLE *ChildHandleBuffer
555 )
556 {
557 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
558
559 EFI_STATUS Status;
560 QEMU_VIDEO_PRIVATE_DATA *Private;
561
562 if (NumberOfChildren == 0) {
563 //
564 // Close the PCI I/O Protocol
565 //
566 gBS->CloseProtocol (
567 Controller,
568 &gEfiPciIoProtocolGuid,
569 This->DriverBindingHandle,
570 Controller
571 );
572 return EFI_SUCCESS;
573 }
574
575 //
576 // free all resources for whose access we need the child handle, because the
577 // child handle is going away
578 //
579 ASSERT (NumberOfChildren == 1);
580 Status = gBS->OpenProtocol (
581 ChildHandleBuffer[0],
582 &gEfiGraphicsOutputProtocolGuid,
583 (VOID **) &GraphicsOutput,
584 This->DriverBindingHandle,
585 Controller,
586 EFI_OPEN_PROTOCOL_GET_PROTOCOL
587 );
588 if (EFI_ERROR (Status)) {
589 return Status;
590 }
591
592 //
593 // Get our private context information
594 //
595 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
596 ASSERT (Private->Handle == ChildHandleBuffer[0]);
597
598 QemuVideoGraphicsOutputDestructor (Private);
599 //
600 // Remove the GOP protocol interface from the system
601 //
602 Status = gBS->UninstallMultipleProtocolInterfaces (
603 Private->Handle,
604 &gEfiGraphicsOutputProtocolGuid,
605 &Private->GraphicsOutput,
606 NULL
607 );
608
609 if (EFI_ERROR (Status)) {
610 return Status;
611 }
612
613 //
614 // Restore original PCI attributes
615 //
616 Private->PciIo->Attributes (
617 Private->PciIo,
618 EfiPciIoAttributeOperationSet,
619 Private->OriginalPciAttributes,
620 NULL
621 );
622
623 gBS->CloseProtocol (
624 Controller,
625 &gEfiPciIoProtocolGuid,
626 This->DriverBindingHandle,
627 Private->Handle
628 );
629
630 FreePool (Private->ModeData);
631 if (Private->VmwareSvgaModeInfo != NULL) {
632 FreePool (Private->VmwareSvgaModeInfo);
633 }
634 gBS->UninstallProtocolInterface (Private->Handle,
635 &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
636 FreePool (Private->GopDevicePath);
637
638 //
639 // Free our instance data
640 //
641 gBS->FreePool (Private);
642
643 return EFI_SUCCESS;
644 }
645
646 /**
647 TODO: Add function description
648
649 @param Private TODO: add argument description
650 @param Address TODO: add argument description
651 @param Data TODO: add argument description
652
653 TODO: add return values
654
655 **/
656 VOID
657 outb (
658 QEMU_VIDEO_PRIVATE_DATA *Private,
659 UINTN Address,
660 UINT8 Data
661 )
662 {
663 Private->PciIo->Io.Write (
664 Private->PciIo,
665 EfiPciIoWidthUint8,
666 EFI_PCI_IO_PASS_THROUGH_BAR,
667 Address,
668 1,
669 &Data
670 );
671 }
672
673 /**
674 TODO: Add function description
675
676 @param Private TODO: add argument description
677 @param Address TODO: add argument description
678 @param Data TODO: add argument description
679
680 TODO: add return values
681
682 **/
683 VOID
684 outw (
685 QEMU_VIDEO_PRIVATE_DATA *Private,
686 UINTN Address,
687 UINT16 Data
688 )
689 {
690 Private->PciIo->Io.Write (
691 Private->PciIo,
692 EfiPciIoWidthUint16,
693 EFI_PCI_IO_PASS_THROUGH_BAR,
694 Address,
695 1,
696 &Data
697 );
698 }
699
700 /**
701 TODO: Add function description
702
703 @param Private TODO: add argument description
704 @param Address TODO: add argument description
705
706 TODO: add return values
707
708 **/
709 UINT8
710 inb (
711 QEMU_VIDEO_PRIVATE_DATA *Private,
712 UINTN Address
713 )
714 {
715 UINT8 Data;
716
717 Private->PciIo->Io.Read (
718 Private->PciIo,
719 EfiPciIoWidthUint8,
720 EFI_PCI_IO_PASS_THROUGH_BAR,
721 Address,
722 1,
723 &Data
724 );
725 return Data;
726 }
727
728 /**
729 TODO: Add function description
730
731 @param Private TODO: add argument description
732 @param Address TODO: add argument description
733
734 TODO: add return values
735
736 **/
737 UINT16
738 inw (
739 QEMU_VIDEO_PRIVATE_DATA *Private,
740 UINTN Address
741 )
742 {
743 UINT16 Data;
744
745 Private->PciIo->Io.Read (
746 Private->PciIo,
747 EfiPciIoWidthUint16,
748 EFI_PCI_IO_PASS_THROUGH_BAR,
749 Address,
750 1,
751 &Data
752 );
753 return Data;
754 }
755
756 /**
757 TODO: Add function description
758
759 @param Private TODO: add argument description
760 @param Index TODO: add argument description
761 @param Red TODO: add argument description
762 @param Green TODO: add argument description
763 @param Blue TODO: add argument description
764
765 TODO: add return values
766
767 **/
768 VOID
769 SetPaletteColor (
770 QEMU_VIDEO_PRIVATE_DATA *Private,
771 UINTN Index,
772 UINT8 Red,
773 UINT8 Green,
774 UINT8 Blue
775 )
776 {
777 VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);
778 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
779 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
780 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
781 }
782
783 /**
784 TODO: Add function description
785
786 @param Private TODO: add argument description
787
788 TODO: add return values
789
790 **/
791 VOID
792 SetDefaultPalette (
793 QEMU_VIDEO_PRIVATE_DATA *Private
794 )
795 {
796 UINTN Index;
797 UINTN RedIndex;
798 UINTN GreenIndex;
799 UINTN BlueIndex;
800
801 Index = 0;
802 for (RedIndex = 0; RedIndex < 8; RedIndex++) {
803 for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
804 for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
805 SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));
806 Index++;
807 }
808 }
809 }
810 }
811
812 /**
813 TODO: Add function description
814
815 @param Private TODO: add argument description
816
817 TODO: add return values
818
819 **/
820 VOID
821 ClearScreen (
822 QEMU_VIDEO_PRIVATE_DATA *Private
823 )
824 {
825 UINT32 Color;
826
827 Color = 0;
828 Private->PciIo->Mem.Write (
829 Private->PciIo,
830 EfiPciIoWidthFillUint32,
831 Private->FrameBufferVramBarIndex,
832 0,
833 0x400000 >> 2,
834 &Color
835 );
836 }
837
838 /**
839 TODO: Add function description
840
841 @param Private TODO: add argument description
842
843 TODO: add return values
844
845 **/
846 VOID
847 DrawLogo (
848 QEMU_VIDEO_PRIVATE_DATA *Private,
849 UINTN ScreenWidth,
850 UINTN ScreenHeight
851 )
852 {
853 }
854
855 /**
856 TODO: Add function description
857
858 @param Private TODO: add argument description
859 @param ModeData TODO: add argument description
860
861 TODO: add return values
862
863 **/
864 VOID
865 InitializeCirrusGraphicsMode (
866 QEMU_VIDEO_PRIVATE_DATA *Private,
867 QEMU_VIDEO_CIRRUS_MODES *ModeData
868 )
869 {
870 UINT8 Byte;
871 UINTN Index;
872
873 outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
874 outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
875
876 for (Index = 0; Index < 15; Index++) {
877 outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
878 }
879
880 if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
881 outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
882 Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
883 outb (Private, SEQ_DATA_REGISTER, Byte);
884 }
885
886 outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
887 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);
888 outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);
889 outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
890
891 for (Index = 0; Index < 28; Index++) {
892 outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));
893 }
894
895 for (Index = 0; Index < 9; Index++) {
896 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));
897 }
898
899 inb (Private, INPUT_STATUS_1_REGISTER);
900
901 for (Index = 0; Index < 21; Index++) {
902 outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);
903 outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
904 }
905
906 outb (Private, ATT_ADDRESS_REGISTER, 0x20);
907
908 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);
909 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);
910 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);
911 outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);
912
913 SetDefaultPalette (Private);
914 ClearScreen (Private);
915 }
916
917 VOID
918 BochsWrite (
919 QEMU_VIDEO_PRIVATE_DATA *Private,
920 UINT16 Reg,
921 UINT16 Data
922 )
923 {
924 EFI_STATUS Status;
925
926 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
927 Status = Private->PciIo->Mem.Write (
928 Private->PciIo,
929 EfiPciIoWidthUint16,
930 PCI_BAR_IDX2,
931 0x500 + (Reg << 1),
932 1,
933 &Data
934 );
935 ASSERT_EFI_ERROR (Status);
936 } else {
937 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
938 outw (Private, VBE_DISPI_IOPORT_DATA, Data);
939 }
940 }
941
942 UINT16
943 BochsRead (
944 QEMU_VIDEO_PRIVATE_DATA *Private,
945 UINT16 Reg
946 )
947 {
948 EFI_STATUS Status;
949 UINT16 Data;
950
951 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
952 Status = Private->PciIo->Mem.Read (
953 Private->PciIo,
954 EfiPciIoWidthUint16,
955 PCI_BAR_IDX2,
956 0x500 + (Reg << 1),
957 1,
958 &Data
959 );
960 ASSERT_EFI_ERROR (Status);
961 } else {
962 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
963 Data = inw (Private, VBE_DISPI_IOPORT_DATA);
964 }
965 return Data;
966 }
967
968 VOID
969 VmwareSvgaWrite (
970 QEMU_VIDEO_PRIVATE_DATA *Private,
971 UINT16 Register,
972 UINT32 Value
973 )
974 {
975 UnalignedIoWrite32 (
976 Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,
977 Register
978 );
979 UnalignedIoWrite32 (
980 Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT,
981 Value
982 );
983 }
984
985 UINT32
986 VmwareSvgaRead (
987 QEMU_VIDEO_PRIVATE_DATA *Private,
988 UINT16 Register
989 )
990 {
991 UnalignedIoWrite32 (
992 Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,
993 Register
994 );
995 return UnalignedIoRead32 (
996 Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT
997 );
998 }
999
1000 VOID
1001 VgaOutb (
1002 QEMU_VIDEO_PRIVATE_DATA *Private,
1003 UINTN Reg,
1004 UINT8 Data
1005 )
1006 {
1007 EFI_STATUS Status;
1008
1009 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
1010 Status = Private->PciIo->Mem.Write (
1011 Private->PciIo,
1012 EfiPciIoWidthUint8,
1013 PCI_BAR_IDX2,
1014 0x400 - 0x3c0 + Reg,
1015 1,
1016 &Data
1017 );
1018 ASSERT_EFI_ERROR (Status);
1019 } else {
1020 outb (Private, Reg, Data);
1021 }
1022 }
1023
1024 VOID
1025 InitializeBochsGraphicsMode (
1026 QEMU_VIDEO_PRIVATE_DATA *Private,
1027 QEMU_VIDEO_BOCHS_MODES *ModeData
1028 )
1029 {
1030 DEBUG ((EFI_D_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n",
1031 ModeData->Width, ModeData->Height, ModeData->ColorDepth));
1032
1033 /* unblank */
1034 VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);
1035
1036 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0);
1037 BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0);
1038 BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0);
1039 BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0);
1040
1041 BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16) ModeData->ColorDepth);
1042 BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16) ModeData->Width);
1043 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16) ModeData->Width);
1044 BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16) ModeData->Height);
1045 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height);
1046
1047 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,
1048 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1049
1050 SetDefaultPalette (Private);
1051 ClearScreen (Private);
1052 }
1053
1054 VOID
1055 InitializeVmwareSvgaGraphicsMode (
1056 QEMU_VIDEO_PRIVATE_DATA *Private,
1057 QEMU_VIDEO_BOCHS_MODES *ModeData
1058 )
1059 {
1060 UINT32 Capabilities;
1061
1062 VmwareSvgaWrite (Private, VmwareSvgaRegWidth, ModeData->Width);
1063 VmwareSvgaWrite (Private, VmwareSvgaRegHeight, ModeData->Height);
1064
1065 Capabilities = VmwareSvgaRead (
1066 Private,
1067 VmwareSvgaRegCapabilities
1068 );
1069 if ((Capabilities & VMWARE_SVGA_CAP_8BIT_EMULATION) != 0) {
1070 VmwareSvgaWrite (
1071 Private,
1072 VmwareSvgaRegBitsPerPixel,
1073 ModeData->ColorDepth
1074 );
1075 }
1076
1077 VmwareSvgaWrite (Private, VmwareSvgaRegEnable, 1);
1078
1079 SetDefaultPalette (Private);
1080 ClearScreen (Private);
1081 }
1082
1083 EFI_STATUS
1084 EFIAPI
1085 InitializeQemuVideo (
1086 IN EFI_HANDLE ImageHandle,
1087 IN EFI_SYSTEM_TABLE *SystemTable
1088 )
1089 {
1090 EFI_STATUS Status;
1091
1092 Status = EfiLibInstallDriverBindingComponentName2 (
1093 ImageHandle,
1094 SystemTable,
1095 &gQemuVideoDriverBinding,
1096 ImageHandle,
1097 &gQemuVideoComponentName,
1098 &gQemuVideoComponentName2
1099 );
1100 ASSERT_EFI_ERROR (Status);
1101
1102 //
1103 // Install EFI Driver Supported EFI Version Protocol required for
1104 // EFI drivers that are on PCI and other plug in cards.
1105 //
1106 gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
1107 Status = gBS->InstallMultipleProtocolInterfaces (
1108 &ImageHandle,
1109 &gEfiDriverSupportedEfiVersionProtocolGuid,
1110 &gQemuVideoDriverSupportedEfiVersion,
1111 NULL
1112 );
1113 ASSERT_EFI_ERROR (Status);
1114
1115 return Status;
1116 }