2 This driver is a sample implementation of the Graphics Output Protocol for
3 the QEMU (Cirrus Logic 5446) video controller.
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
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
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.
18 #include <IndustryStandard/Acpi.h>
20 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding
= {
21 QemuVideoControllerDriverSupported
,
22 QemuVideoControllerDriverStart
,
23 QemuVideoControllerDriverStop
,
29 QEMU_VIDEO_CARD gQemuVideoCardList
[] = {
31 CIRRUS_LOGIC_VENDOR_ID
,
32 CIRRUS_LOGIC_5430_DEVICE_ID
,
33 QEMU_VIDEO_CIRRUS_5430
,
36 CIRRUS_LOGIC_VENDOR_ID
,
37 CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID
,
38 QEMU_VIDEO_CIRRUS_5430
,
41 CIRRUS_LOGIC_VENDOR_ID
,
42 CIRRUS_LOGIC_5446_DEVICE_ID
,
43 QEMU_VIDEO_CIRRUS_5446
,
48 QEMU_VIDEO_BOCHS_MMIO
,
60 static QEMU_VIDEO_CARD
*
68 while (gQemuVideoCardList
[Index
].VendorId
!= 0) {
69 if (gQemuVideoCardList
[Index
].VendorId
== VendorId
&&
70 gQemuVideoCardList
[Index
].DeviceId
== DeviceId
) {
71 return gQemuVideoCardList
+ Index
;
79 Check if this device is supported.
81 @param This The driver binding protocol.
82 @param Controller The controller handle to check.
83 @param RemainingDevicePath The remaining device path.
85 @retval EFI_SUCCESS The bus supports this controller.
86 @retval EFI_UNSUPPORTED This device isn't supported.
91 QemuVideoControllerDriverSupported (
92 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
93 IN EFI_HANDLE Controller
,
94 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
98 EFI_PCI_IO_PROTOCOL
*PciIo
;
101 QEMU_VIDEO_CARD
*Card
;
104 // Open the PCI I/O Protocol
106 Status
= gBS
->OpenProtocol (
108 &gEfiPciIoProtocolGuid
,
110 This
->DriverBindingHandle
,
112 EFI_OPEN_PROTOCOL_BY_DRIVER
114 if (EFI_ERROR (Status
)) {
119 // Read the PCI Configuration Header from the PCI Device
121 Status
= PciIo
->Pci
.Read (
125 sizeof (Pci
) / sizeof (UINT32
),
128 if (EFI_ERROR (Status
)) {
132 Status
= EFI_UNSUPPORTED
;
134 // See if the I/O enable is on. Most systems only allow one VGA device to be turned on
135 // at a time, so see if this is one that is turned on.
137 // if (((Pci.Hdr.Command & 0x01) == 0x01)) {
139 // See if this is a Cirrus Logic PCI controller
141 Card
= QemuVideoDetect(Pci
.Hdr
.VendorId
, Pci
.Hdr
.DeviceId
);
143 DEBUG ((EFI_D_INFO
, "QemuVideo: %s detected\n", Card
->Name
));
144 Status
= EFI_SUCCESS
;
146 // If this is an Intel 945 graphics controller,
147 // go further check RemainingDevicePath validation
149 if (RemainingDevicePath
!= NULL
) {
150 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
152 // Check if RemainingDevicePath is the End of Device Path Node,
153 // if yes, return EFI_SUCCESS
155 if (!IsDevicePathEnd (Node
)) {
157 // If RemainingDevicePath isn't the End of Device Path Node,
158 // check its validation
160 if (Node
->DevPath
.Type
!= ACPI_DEVICE_PATH
||
161 Node
->DevPath
.SubType
!= ACPI_ADR_DP
||
162 DevicePathNodeLength(&Node
->DevPath
) != sizeof(ACPI_ADR_DEVICE_PATH
)) {
163 Status
= EFI_UNSUPPORTED
;
171 // Close the PCI I/O Protocol
175 &gEfiPciIoProtocolGuid
,
176 This
->DriverBindingHandle
,
184 Start to process the controller.
186 @param This The USB bus driver binding instance.
187 @param Controller The controller to check.
188 @param RemainingDevicePath The remaining device patch.
190 @retval EFI_SUCCESS The controller is controlled by the usb bus.
191 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
193 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
198 QemuVideoControllerDriverStart (
199 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
200 IN EFI_HANDLE Controller
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
205 QEMU_VIDEO_PRIVATE_DATA
*Private
;
206 BOOLEAN PciAttributesSaved
;
207 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
208 ACPI_ADR_DEVICE_PATH AcpiDeviceNode
;
210 QEMU_VIDEO_CARD
*Card
;
211 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*MmioDesc
;
213 PciAttributesSaved
= FALSE
;
215 // Allocate Private context data for GOP inteface.
217 Private
= AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA
));
218 if (Private
== NULL
) {
219 Status
= EFI_OUT_OF_RESOURCES
;
224 // Set up context record
226 Private
->Signature
= QEMU_VIDEO_PRIVATE_DATA_SIGNATURE
;
227 Private
->Handle
= NULL
;
230 // Open PCI I/O Protocol
232 Status
= gBS
->OpenProtocol (
234 &gEfiPciIoProtocolGuid
,
235 (VOID
**) &Private
->PciIo
,
236 This
->DriverBindingHandle
,
238 EFI_OPEN_PROTOCOL_BY_DRIVER
240 if (EFI_ERROR (Status
)) {
245 // Read the PCI Configuration Header from the PCI Device
247 Status
= Private
->PciIo
->Pci
.Read (
251 sizeof (Pci
) / sizeof (UINT32
),
254 if (EFI_ERROR (Status
)) {
258 Card
= QemuVideoDetect(Pci
.Hdr
.VendorId
, Pci
.Hdr
.DeviceId
);
260 Status
= EFI_DEVICE_ERROR
;
263 Private
->Variant
= Card
->Variant
;
266 // Save original PCI attributes
268 Status
= Private
->PciIo
->Attributes (
270 EfiPciIoAttributeOperationGet
,
272 &Private
->OriginalPciAttributes
275 if (EFI_ERROR (Status
)) {
278 PciAttributesSaved
= TRUE
;
280 Status
= Private
->PciIo
->Attributes (
282 EfiPciIoAttributeOperationEnable
,
283 EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
| EFI_PCI_IO_ATTRIBUTE_VGA_IO
,
286 if (EFI_ERROR (Status
)) {
291 // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
293 if (Private
->Variant
== QEMU_VIDEO_BOCHS_MMIO
) {
294 Status
= Private
->PciIo
->GetBarAttributes (
300 if (EFI_ERROR (Status
) ||
301 MmioDesc
->ResType
!= ACPI_ADDRESS_SPACE_TYPE_MEM
) {
302 DEBUG ((EFI_D_INFO
, "QemuVideo: No mmio bar, fallback to port io\n"));
303 Private
->Variant
= QEMU_VIDEO_BOCHS
;
305 DEBUG ((EFI_D_INFO
, "QemuVideo: Using mmio bar @ 0x%lx\n",
306 MmioDesc
->AddrRangeMin
));
309 if (!EFI_ERROR (Status
)) {
315 // Check if accessing the bochs interface works.
317 if (Private
->Variant
== QEMU_VIDEO_BOCHS_MMIO
||
318 Private
->Variant
== QEMU_VIDEO_BOCHS
) {
320 BochsId
= BochsRead(Private
, VBE_DISPI_INDEX_ID
);
321 if ((BochsId
& 0xFFF0) != VBE_DISPI_ID0
) {
322 DEBUG ((EFI_D_INFO
, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId
));
323 Status
= EFI_DEVICE_ERROR
;
329 // Get ParentDevicePath
331 Status
= gBS
->HandleProtocol (
333 &gEfiDevicePathProtocolGuid
,
334 (VOID
**) &ParentDevicePath
336 if (EFI_ERROR (Status
)) {
341 // Set Gop Device Path
343 if (RemainingDevicePath
== NULL
) {
344 ZeroMem (&AcpiDeviceNode
, sizeof (ACPI_ADR_DEVICE_PATH
));
345 AcpiDeviceNode
.Header
.Type
= ACPI_DEVICE_PATH
;
346 AcpiDeviceNode
.Header
.SubType
= ACPI_ADR_DP
;
347 AcpiDeviceNode
.ADR
= ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA
, 0, 0);
348 SetDevicePathNodeLength (&AcpiDeviceNode
.Header
, sizeof (ACPI_ADR_DEVICE_PATH
));
350 Private
->GopDevicePath
= AppendDevicePathNode (
352 (EFI_DEVICE_PATH_PROTOCOL
*) &AcpiDeviceNode
354 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
356 // If RemainingDevicePath isn't the End of Device Path Node,
357 // only scan the specified device by RemainingDevicePath
359 Private
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
, RemainingDevicePath
);
362 // If RemainingDevicePath is the End of Device Path Node,
363 // don't create child device and return EFI_SUCCESS
365 Private
->GopDevicePath
= NULL
;
368 if (Private
->GopDevicePath
!= NULL
) {
370 // Creat child handle and device path protocol firstly
372 Private
->Handle
= NULL
;
373 Status
= gBS
->InstallMultipleProtocolInterfaces (
375 &gEfiDevicePathProtocolGuid
,
376 Private
->GopDevicePath
,
382 // Construct video mode buffer
384 switch (Private
->Variant
) {
385 case QEMU_VIDEO_CIRRUS_5430
:
386 case QEMU_VIDEO_CIRRUS_5446
:
387 Status
= QemuVideoCirrusModeSetup (Private
);
389 case QEMU_VIDEO_BOCHS_MMIO
:
390 case QEMU_VIDEO_BOCHS
:
391 Status
= QemuVideoBochsModeSetup (Private
);
395 Status
= EFI_DEVICE_ERROR
;
398 if (EFI_ERROR (Status
)) {
402 if (Private
->GopDevicePath
== NULL
) {
404 // If RemainingDevicePath is the End of Device Path Node,
405 // don't create child device and return EFI_SUCCESS
407 Status
= EFI_SUCCESS
;
411 // Start the GOP software stack.
413 Status
= QemuVideoGraphicsOutputConstructor (Private
);
414 ASSERT_EFI_ERROR (Status
);
416 Status
= gBS
->InstallMultipleProtocolInterfaces (
418 &gEfiGraphicsOutputProtocolGuid
,
419 &Private
->GraphicsOutput
,
425 if (EFI_ERROR (Status
)) {
427 if (Private
->PciIo
) {
428 if (PciAttributesSaved
== TRUE
) {
430 // Restore original PCI attributes
432 Private
->PciIo
->Attributes (
434 EfiPciIoAttributeOperationSet
,
435 Private
->OriginalPciAttributes
,
440 // Close the PCI I/O Protocol
444 &gEfiPciIoProtocolGuid
,
445 This
->DriverBindingHandle
,
450 gBS
->FreePool (Private
);
460 @param This The USB bus driver binding protocol.
461 @param Controller The controller to release.
462 @param NumberOfChildren The number of children of this device that
463 opened the controller BY_CHILD.
464 @param ChildHandleBuffer The array of child handle.
466 @retval EFI_SUCCESS The controller or children are stopped.
467 @retval EFI_DEVICE_ERROR Failed to stop the driver.
472 QemuVideoControllerDriverStop (
473 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
474 IN EFI_HANDLE Controller
,
475 IN UINTN NumberOfChildren
,
476 IN EFI_HANDLE
*ChildHandleBuffer
479 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
;
482 QEMU_VIDEO_PRIVATE_DATA
*Private
;
484 Status
= gBS
->OpenProtocol (
486 &gEfiGraphicsOutputProtocolGuid
,
487 (VOID
**) &GraphicsOutput
,
488 This
->DriverBindingHandle
,
490 EFI_OPEN_PROTOCOL_GET_PROTOCOL
492 if (EFI_ERROR (Status
)) {
497 // Get our private context information
499 Private
= QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput
);
501 QemuVideoGraphicsOutputDestructor (Private
);
503 // Remove the GOP protocol interface from the system
505 Status
= gBS
->UninstallMultipleProtocolInterfaces (
507 &gEfiGraphicsOutputProtocolGuid
,
508 &Private
->GraphicsOutput
,
512 if (EFI_ERROR (Status
)) {
517 // Restore original PCI attributes
519 Private
->PciIo
->Attributes (
521 EfiPciIoAttributeOperationSet
,
522 Private
->OriginalPciAttributes
,
527 // Close the PCI I/O Protocol
531 &gEfiPciIoProtocolGuid
,
532 This
->DriverBindingHandle
,
537 // Free our instance data
539 gBS
->FreePool (Private
);
545 TODO: Add function description
547 @param Private TODO: add argument description
548 @param Address TODO: add argument description
549 @param Data TODO: add argument description
551 TODO: add return values
556 QEMU_VIDEO_PRIVATE_DATA
*Private
,
561 Private
->PciIo
->Io
.Write (
564 EFI_PCI_IO_PASS_THROUGH_BAR
,
572 TODO: Add function description
574 @param Private TODO: add argument description
575 @param Address TODO: add argument description
576 @param Data TODO: add argument description
578 TODO: add return values
583 QEMU_VIDEO_PRIVATE_DATA
*Private
,
588 Private
->PciIo
->Io
.Write (
591 EFI_PCI_IO_PASS_THROUGH_BAR
,
599 TODO: Add function description
601 @param Private TODO: add argument description
602 @param Address TODO: add argument description
604 TODO: add return values
609 QEMU_VIDEO_PRIVATE_DATA
*Private
,
615 Private
->PciIo
->Io
.Read (
618 EFI_PCI_IO_PASS_THROUGH_BAR
,
627 TODO: Add function description
629 @param Private TODO: add argument description
630 @param Address TODO: add argument description
632 TODO: add return values
637 QEMU_VIDEO_PRIVATE_DATA
*Private
,
643 Private
->PciIo
->Io
.Read (
646 EFI_PCI_IO_PASS_THROUGH_BAR
,
655 TODO: Add function description
657 @param Private TODO: add argument description
658 @param Index TODO: add argument description
659 @param Red TODO: add argument description
660 @param Green TODO: add argument description
661 @param Blue TODO: add argument description
663 TODO: add return values
668 QEMU_VIDEO_PRIVATE_DATA
*Private
,
675 VgaOutb (Private
, PALETTE_INDEX_REGISTER
, (UINT8
) Index
);
676 VgaOutb (Private
, PALETTE_DATA_REGISTER
, (UINT8
) (Red
>> 2));
677 VgaOutb (Private
, PALETTE_DATA_REGISTER
, (UINT8
) (Green
>> 2));
678 VgaOutb (Private
, PALETTE_DATA_REGISTER
, (UINT8
) (Blue
>> 2));
682 TODO: Add function description
684 @param Private TODO: add argument description
686 TODO: add return values
691 QEMU_VIDEO_PRIVATE_DATA
*Private
700 for (RedIndex
= 0; RedIndex
< 8; RedIndex
++) {
701 for (GreenIndex
= 0; GreenIndex
< 8; GreenIndex
++) {
702 for (BlueIndex
= 0; BlueIndex
< 4; BlueIndex
++) {
703 SetPaletteColor (Private
, Index
, (UINT8
) (RedIndex
<< 5), (UINT8
) (GreenIndex
<< 5), (UINT8
) (BlueIndex
<< 6));
711 TODO: Add function description
713 @param Private TODO: add argument description
715 TODO: add return values
720 QEMU_VIDEO_PRIVATE_DATA
*Private
726 Private
->PciIo
->Mem
.Write (
728 EfiPciIoWidthFillUint32
,
737 TODO: Add function description
739 @param Private TODO: add argument description
741 TODO: add return values
746 QEMU_VIDEO_PRIVATE_DATA
*Private
,
754 TODO: Add function description
756 @param Private TODO: add argument description
757 @param ModeData TODO: add argument description
759 TODO: add return values
763 InitializeCirrusGraphicsMode (
764 QEMU_VIDEO_PRIVATE_DATA
*Private
,
765 QEMU_VIDEO_CIRRUS_MODES
*ModeData
771 outw (Private
, SEQ_ADDRESS_REGISTER
, 0x1206);
772 outw (Private
, SEQ_ADDRESS_REGISTER
, 0x0012);
774 for (Index
= 0; Index
< 15; Index
++) {
775 outw (Private
, SEQ_ADDRESS_REGISTER
, ModeData
->SeqSettings
[Index
]);
778 if (Private
->Variant
== QEMU_VIDEO_CIRRUS_5430
) {
779 outb (Private
, SEQ_ADDRESS_REGISTER
, 0x0f);
780 Byte
= (UINT8
) ((inb (Private
, SEQ_DATA_REGISTER
) & 0xc7) ^ 0x30);
781 outb (Private
, SEQ_DATA_REGISTER
, Byte
);
784 outb (Private
, MISC_OUTPUT_REGISTER
, ModeData
->MiscSetting
);
785 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x0506);
786 outw (Private
, SEQ_ADDRESS_REGISTER
, 0x0300);
787 outw (Private
, CRTC_ADDRESS_REGISTER
, 0x2011);
789 for (Index
= 0; Index
< 28; Index
++) {
790 outw (Private
, CRTC_ADDRESS_REGISTER
, (UINT16
) ((ModeData
->CrtcSettings
[Index
] << 8) | Index
));
793 for (Index
= 0; Index
< 9; Index
++) {
794 outw (Private
, GRAPH_ADDRESS_REGISTER
, (UINT16
) ((GraphicsController
[Index
] << 8) | Index
));
797 inb (Private
, INPUT_STATUS_1_REGISTER
);
799 for (Index
= 0; Index
< 21; Index
++) {
800 outb (Private
, ATT_ADDRESS_REGISTER
, (UINT8
) Index
);
801 outb (Private
, ATT_ADDRESS_REGISTER
, AttributeController
[Index
]);
804 outb (Private
, ATT_ADDRESS_REGISTER
, 0x20);
806 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x0009);
807 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x000a);
808 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x000b);
809 outb (Private
, DAC_PIXEL_MASK_REGISTER
, 0xff);
811 SetDefaultPalette (Private
);
812 ClearScreen (Private
);
817 QEMU_VIDEO_PRIVATE_DATA
*Private
,
824 if (Private
->Variant
== QEMU_VIDEO_BOCHS_MMIO
) {
825 Status
= Private
->PciIo
->Mem
.Write (
833 ASSERT_EFI_ERROR (Status
);
835 outw (Private
, VBE_DISPI_IOPORT_INDEX
, Reg
);
836 outw (Private
, VBE_DISPI_IOPORT_DATA
, Data
);
842 QEMU_VIDEO_PRIVATE_DATA
*Private
,
849 if (Private
->Variant
== QEMU_VIDEO_BOCHS_MMIO
) {
850 Status
= Private
->PciIo
->Mem
.Read (
858 ASSERT_EFI_ERROR (Status
);
860 outw (Private
, VBE_DISPI_IOPORT_INDEX
, Reg
);
861 Data
= inw (Private
, VBE_DISPI_IOPORT_DATA
);
868 QEMU_VIDEO_PRIVATE_DATA
*Private
,
875 if (Private
->Variant
== QEMU_VIDEO_BOCHS_MMIO
) {
876 Status
= Private
->PciIo
->Mem
.Write (
884 ASSERT_EFI_ERROR (Status
);
886 outb (Private
, Reg
, Data
);
891 InitializeBochsGraphicsMode (
892 QEMU_VIDEO_PRIVATE_DATA
*Private
,
893 QEMU_VIDEO_BOCHS_MODES
*ModeData
896 DEBUG ((EFI_D_INFO
, "InitializeBochsGraphicsMode: %dx%d @ %d\n",
897 ModeData
->Width
, ModeData
->Height
, ModeData
->ColorDepth
));
900 VgaOutb (Private
, ATT_ADDRESS_REGISTER
, 0x20);
902 BochsWrite (Private
, VBE_DISPI_INDEX_ENABLE
, 0);
903 BochsWrite (Private
, VBE_DISPI_INDEX_BANK
, 0);
904 BochsWrite (Private
, VBE_DISPI_INDEX_X_OFFSET
, 0);
905 BochsWrite (Private
, VBE_DISPI_INDEX_Y_OFFSET
, 0);
907 BochsWrite (Private
, VBE_DISPI_INDEX_BPP
, (UINT16
) ModeData
->ColorDepth
);
908 BochsWrite (Private
, VBE_DISPI_INDEX_XRES
, (UINT16
) ModeData
->Width
);
909 BochsWrite (Private
, VBE_DISPI_INDEX_VIRT_WIDTH
, (UINT16
) ModeData
->Width
);
910 BochsWrite (Private
, VBE_DISPI_INDEX_YRES
, (UINT16
) ModeData
->Height
);
911 BochsWrite (Private
, VBE_DISPI_INDEX_VIRT_HEIGHT
, (UINT16
) ModeData
->Height
);
913 BochsWrite (Private
, VBE_DISPI_INDEX_ENABLE
,
914 VBE_DISPI_ENABLED
| VBE_DISPI_LFB_ENABLED
);
916 SetDefaultPalette (Private
);
917 ClearScreen (Private
);
922 InitializeQemuVideo (
923 IN EFI_HANDLE ImageHandle
,
924 IN EFI_SYSTEM_TABLE
*SystemTable
929 Status
= EfiLibInstallDriverBindingComponentName2 (
932 &gQemuVideoDriverBinding
,
934 &gQemuVideoComponentName
,
935 &gQemuVideoComponentName2
937 ASSERT_EFI_ERROR (Status
);
940 // Install EFI Driver Supported EFI Version Protocol required for
941 // EFI drivers that are on PCI and other plug in cards.
943 gQemuVideoDriverSupportedEfiVersion
.FirmwareVersion
= PcdGet32 (PcdDriverSupportedEfiVersion
);
944 Status
= gBS
->InstallMultipleProtocolInterfaces (
946 &gEfiDriverSupportedEfiVersionProtocolGuid
,
947 &gQemuVideoDriverSupportedEfiVersion
,
950 ASSERT_EFI_ERROR (Status
);