]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuVideoDxe/Driver.c
OvmfPkg: Add QemuVideoDxe driver
[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 "Qemu.h"
18
19 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
20 QemuVideoControllerDriverSupported,
21 QemuVideoControllerDriverStart,
22 QemuVideoControllerDriverStop,
23 0x10,
24 NULL,
25 NULL
26 };
27
28 /**
29 Check if this device is supported.
30
31 @param This The driver binding protocol.
32 @param Controller The controller handle to check.
33 @param RemainingDevicePath The remaining device path.
34
35 @retval EFI_SUCCESS The bus supports this controller.
36 @retval EFI_UNSUPPORTED This device isn't supported.
37
38 **/
39 EFI_STATUS
40 EFIAPI
41 QemuVideoControllerDriverSupported (
42 IN EFI_DRIVER_BINDING_PROTOCOL *This,
43 IN EFI_HANDLE Controller,
44 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
45 )
46 {
47 EFI_STATUS Status;
48 EFI_PCI_IO_PROTOCOL *PciIo;
49 PCI_TYPE00 Pci;
50 EFI_DEV_PATH *Node;
51
52 //
53 // Open the PCI I/O Protocol
54 //
55 Status = gBS->OpenProtocol (
56 Controller,
57 &gEfiPciIoProtocolGuid,
58 (VOID **) &PciIo,
59 This->DriverBindingHandle,
60 Controller,
61 EFI_OPEN_PROTOCOL_BY_DRIVER
62 );
63 if (EFI_ERROR (Status)) {
64 return Status;
65 }
66
67 //
68 // Read the PCI Configuration Header from the PCI Device
69 //
70 Status = PciIo->Pci.Read (
71 PciIo,
72 EfiPciIoWidthUint32,
73 0,
74 sizeof (Pci) / sizeof (UINT32),
75 &Pci
76 );
77 if (EFI_ERROR (Status)) {
78 goto Done;
79 }
80
81 Status = EFI_UNSUPPORTED;
82 //
83 // See if the I/O enable is on. Most systems only allow one VGA device to be turned on
84 // at a time, so see if this is one that is turned on.
85 //
86 // if (((Pci.Hdr.Command & 0x01) == 0x01)) {
87 //
88 // See if this is a Cirrus Logic PCI controller
89 //
90 if (Pci.Hdr.VendorId == CIRRUS_LOGIC_VENDOR_ID) {
91 //
92 // See if this is a 5430 or a 5446 PCI controller
93 //
94 if (Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_DEVICE_ID ||
95 Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID ||
96 Pci.Hdr.DeviceId == CIRRUS_LOGIC_5446_DEVICE_ID) {
97
98 Status = EFI_SUCCESS;
99 //
100 // If this is an Intel 945 graphics controller,
101 // go further check RemainingDevicePath validation
102 //
103 if (RemainingDevicePath != NULL) {
104 Node = (EFI_DEV_PATH *) RemainingDevicePath;
105 //
106 // Check if RemainingDevicePath is the End of Device Path Node,
107 // if yes, return EFI_SUCCESS
108 //
109 if (!IsDevicePathEnd (Node)) {
110 //
111 // If RemainingDevicePath isn't the End of Device Path Node,
112 // check its validation
113 //
114 if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
115 Node->DevPath.SubType != ACPI_ADR_DP ||
116 DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {
117 Status = EFI_UNSUPPORTED;
118 }
119 }
120 }
121 }
122 }
123
124 Done:
125 //
126 // Close the PCI I/O Protocol
127 //
128 gBS->CloseProtocol (
129 Controller,
130 &gEfiPciIoProtocolGuid,
131 This->DriverBindingHandle,
132 Controller
133 );
134
135 return Status;
136 }
137
138 /**
139 Start to process the controller.
140
141 @param This The USB bus driver binding instance.
142 @param Controller The controller to check.
143 @param RemainingDevicePath The remaining device patch.
144
145 @retval EFI_SUCCESS The controller is controlled by the usb bus.
146 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
147 bus.
148 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
149
150 **/
151 EFI_STATUS
152 EFIAPI
153 QemuVideoControllerDriverStart (
154 IN EFI_DRIVER_BINDING_PROTOCOL *This,
155 IN EFI_HANDLE Controller,
156 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
157 )
158 {
159 EFI_STATUS Status;
160 QEMU_VIDEO_PRIVATE_DATA *Private;
161 BOOLEAN PciAttributesSaved;
162 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
163 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
164
165 PciAttributesSaved = FALSE;
166 //
167 // Allocate Private context data for GOP inteface.
168 //
169 Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
170 if (Private == NULL) {
171 Status = EFI_OUT_OF_RESOURCES;
172 goto Error;
173 }
174
175 //
176 // Set up context record
177 //
178 Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
179 Private->Handle = NULL;
180
181 //
182 // Open PCI I/O Protocol
183 //
184 Status = gBS->OpenProtocol (
185 Controller,
186 &gEfiPciIoProtocolGuid,
187 (VOID **) &Private->PciIo,
188 This->DriverBindingHandle,
189 Controller,
190 EFI_OPEN_PROTOCOL_BY_DRIVER
191 );
192 if (EFI_ERROR (Status)) {
193 goto Error;
194 }
195
196 //
197 // Save original PCI attributes
198 //
199 Status = Private->PciIo->Attributes (
200 Private->PciIo,
201 EfiPciIoAttributeOperationGet,
202 0,
203 &Private->OriginalPciAttributes
204 );
205
206 if (EFI_ERROR (Status)) {
207 goto Error;
208 }
209 PciAttributesSaved = TRUE;
210
211 Status = Private->PciIo->Attributes (
212 Private->PciIo,
213 EfiPciIoAttributeOperationEnable,
214 EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
215 NULL
216 );
217 if (EFI_ERROR (Status)) {
218 goto Error;
219 }
220
221 //
222 // Get ParentDevicePath
223 //
224 Status = gBS->HandleProtocol (
225 Controller,
226 &gEfiDevicePathProtocolGuid,
227 (VOID **) &ParentDevicePath
228 );
229 if (EFI_ERROR (Status)) {
230 goto Error;
231 }
232
233 //
234 // Set Gop Device Path
235 //
236 if (RemainingDevicePath == NULL) {
237 ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
238 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
239 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
240 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
241 SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
242
243 Private->GopDevicePath = AppendDevicePathNode (
244 ParentDevicePath,
245 (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
246 );
247 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
248 //
249 // If RemainingDevicePath isn't the End of Device Path Node,
250 // only scan the specified device by RemainingDevicePath
251 //
252 Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
253 } else {
254 //
255 // If RemainingDevicePath is the End of Device Path Node,
256 // don't create child device and return EFI_SUCCESS
257 //
258 Private->GopDevicePath = NULL;
259 }
260
261 if (Private->GopDevicePath != NULL) {
262 //
263 // Creat child handle and device path protocol firstly
264 //
265 Private->Handle = NULL;
266 Status = gBS->InstallMultipleProtocolInterfaces (
267 &Private->Handle,
268 &gEfiDevicePathProtocolGuid,
269 Private->GopDevicePath,
270 NULL
271 );
272 }
273
274 //
275 // Construct video mode buffer
276 //
277 Status = QemuVideoVideoModeSetup (Private);
278 if (EFI_ERROR (Status)) {
279 goto Error;
280 }
281
282 if (Private->GopDevicePath == NULL) {
283 //
284 // If RemainingDevicePath is the End of Device Path Node,
285 // don't create child device and return EFI_SUCCESS
286 //
287 Status = EFI_SUCCESS;
288 } else {
289
290 //
291 // Start the GOP software stack.
292 //
293 Status = QemuVideoGraphicsOutputConstructor (Private);
294 ASSERT_EFI_ERROR (Status);
295
296 Status = gBS->InstallMultipleProtocolInterfaces (
297 &Private->Handle,
298 &gEfiGraphicsOutputProtocolGuid,
299 &Private->GraphicsOutput,
300 NULL
301 );
302 }
303
304 Error:
305 if (EFI_ERROR (Status)) {
306 if (Private) {
307 if (Private->PciIo) {
308 if (PciAttributesSaved == TRUE) {
309 //
310 // Restore original PCI attributes
311 //
312 Private->PciIo->Attributes (
313 Private->PciIo,
314 EfiPciIoAttributeOperationSet,
315 Private->OriginalPciAttributes,
316 NULL
317 );
318 }
319 //
320 // Close the PCI I/O Protocol
321 //
322 gBS->CloseProtocol (
323 Private->Handle,
324 &gEfiPciIoProtocolGuid,
325 This->DriverBindingHandle,
326 Private->Handle
327 );
328 }
329
330 gBS->FreePool (Private);
331 }
332 }
333
334 return Status;
335 }
336
337 /**
338 Stop this device
339
340 @param This The USB bus driver binding protocol.
341 @param Controller The controller to release.
342 @param NumberOfChildren The number of children of this device that
343 opened the controller BY_CHILD.
344 @param ChildHandleBuffer The array of child handle.
345
346 @retval EFI_SUCCESS The controller or children are stopped.
347 @retval EFI_DEVICE_ERROR Failed to stop the driver.
348
349 **/
350 EFI_STATUS
351 EFIAPI
352 QemuVideoControllerDriverStop (
353 IN EFI_DRIVER_BINDING_PROTOCOL *This,
354 IN EFI_HANDLE Controller,
355 IN UINTN NumberOfChildren,
356 IN EFI_HANDLE *ChildHandleBuffer
357 )
358 {
359 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
360
361 EFI_STATUS Status;
362 QEMU_VIDEO_PRIVATE_DATA *Private;
363
364 Status = gBS->OpenProtocol (
365 Controller,
366 &gEfiGraphicsOutputProtocolGuid,
367 (VOID **) &GraphicsOutput,
368 This->DriverBindingHandle,
369 Controller,
370 EFI_OPEN_PROTOCOL_GET_PROTOCOL
371 );
372 if (EFI_ERROR (Status)) {
373 return Status;
374 }
375
376 //
377 // Get our private context information
378 //
379 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
380
381 QemuVideoGraphicsOutputDestructor (Private);
382 //
383 // Remove the GOP protocol interface from the system
384 //
385 Status = gBS->UninstallMultipleProtocolInterfaces (
386 Private->Handle,
387 &gEfiGraphicsOutputProtocolGuid,
388 &Private->GraphicsOutput,
389 NULL
390 );
391
392 if (EFI_ERROR (Status)) {
393 return Status;
394 }
395
396 //
397 // Restore original PCI attributes
398 //
399 Private->PciIo->Attributes (
400 Private->PciIo,
401 EfiPciIoAttributeOperationSet,
402 Private->OriginalPciAttributes,
403 NULL
404 );
405
406 //
407 // Close the PCI I/O Protocol
408 //
409 gBS->CloseProtocol (
410 Controller,
411 &gEfiPciIoProtocolGuid,
412 This->DriverBindingHandle,
413 Controller
414 );
415
416 //
417 // Free our instance data
418 //
419 gBS->FreePool (Private);
420
421 return EFI_SUCCESS;
422 }
423
424 /**
425 TODO: Add function description
426
427 @param Private TODO: add argument description
428 @param Address TODO: add argument description
429 @param Data TODO: add argument description
430
431 TODO: add return values
432
433 **/
434 VOID
435 outb (
436 QEMU_VIDEO_PRIVATE_DATA *Private,
437 UINTN Address,
438 UINT8 Data
439 )
440 {
441 Private->PciIo->Io.Write (
442 Private->PciIo,
443 EfiPciIoWidthUint8,
444 EFI_PCI_IO_PASS_THROUGH_BAR,
445 Address,
446 1,
447 &Data
448 );
449 }
450
451 /**
452 TODO: Add function description
453
454 @param Private TODO: add argument description
455 @param Address TODO: add argument description
456 @param Data TODO: add argument description
457
458 TODO: add return values
459
460 **/
461 VOID
462 outw (
463 QEMU_VIDEO_PRIVATE_DATA *Private,
464 UINTN Address,
465 UINT16 Data
466 )
467 {
468 Private->PciIo->Io.Write (
469 Private->PciIo,
470 EfiPciIoWidthUint16,
471 EFI_PCI_IO_PASS_THROUGH_BAR,
472 Address,
473 1,
474 &Data
475 );
476 }
477
478 /**
479 TODO: Add function description
480
481 @param Private TODO: add argument description
482 @param Address TODO: add argument description
483
484 TODO: add return values
485
486 **/
487 UINT8
488 inb (
489 QEMU_VIDEO_PRIVATE_DATA *Private,
490 UINTN Address
491 )
492 {
493 UINT8 Data;
494
495 Private->PciIo->Io.Read (
496 Private->PciIo,
497 EfiPciIoWidthUint8,
498 EFI_PCI_IO_PASS_THROUGH_BAR,
499 Address,
500 1,
501 &Data
502 );
503 return Data;
504 }
505
506 /**
507 TODO: Add function description
508
509 @param Private TODO: add argument description
510 @param Address TODO: add argument description
511
512 TODO: add return values
513
514 **/
515 UINT16
516 inw (
517 QEMU_VIDEO_PRIVATE_DATA *Private,
518 UINTN Address
519 )
520 {
521 UINT16 Data;
522
523 Private->PciIo->Io.Read (
524 Private->PciIo,
525 EfiPciIoWidthUint16,
526 EFI_PCI_IO_PASS_THROUGH_BAR,
527 Address,
528 1,
529 &Data
530 );
531 return Data;
532 }
533
534 /**
535 TODO: Add function description
536
537 @param Private TODO: add argument description
538 @param Index TODO: add argument description
539 @param Red TODO: add argument description
540 @param Green TODO: add argument description
541 @param Blue TODO: add argument description
542
543 TODO: add return values
544
545 **/
546 VOID
547 SetPaletteColor (
548 QEMU_VIDEO_PRIVATE_DATA *Private,
549 UINTN Index,
550 UINT8 Red,
551 UINT8 Green,
552 UINT8 Blue
553 )
554 {
555 outb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);
556 outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
557 outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
558 outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
559 }
560
561 /**
562 TODO: Add function description
563
564 @param Private TODO: add argument description
565
566 TODO: add return values
567
568 **/
569 VOID
570 SetDefaultPalette (
571 QEMU_VIDEO_PRIVATE_DATA *Private
572 )
573 {
574 UINTN Index;
575 UINTN RedIndex;
576 UINTN GreenIndex;
577 UINTN BlueIndex;
578
579 Index = 0;
580 for (RedIndex = 0; RedIndex < 8; RedIndex++) {
581 for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
582 for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
583 SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));
584 Index++;
585 }
586 }
587 }
588 }
589
590 /**
591 TODO: Add function description
592
593 @param Private TODO: add argument description
594
595 TODO: add return values
596
597 **/
598 VOID
599 ClearScreen (
600 QEMU_VIDEO_PRIVATE_DATA *Private
601 )
602 {
603 UINT32 Color;
604
605 Color = 0;
606 Private->PciIo->Mem.Write (
607 Private->PciIo,
608 EfiPciIoWidthFillUint32,
609 0,
610 0,
611 0x400000 >> 2,
612 &Color
613 );
614 }
615
616 /**
617 TODO: Add function description
618
619 @param Private TODO: add argument description
620
621 TODO: add return values
622
623 **/
624 VOID
625 DrawLogo (
626 QEMU_VIDEO_PRIVATE_DATA *Private,
627 UINTN ScreenWidth,
628 UINTN ScreenHeight
629 )
630 {
631 }
632
633 /**
634 TODO: Add function description
635
636 @param Private TODO: add argument description
637 @param ModeData TODO: add argument description
638
639 TODO: add return values
640
641 **/
642 VOID
643 InitializeGraphicsMode (
644 QEMU_VIDEO_PRIVATE_DATA *Private,
645 QEMU_VIDEO_VIDEO_MODES *ModeData
646 )
647 {
648 UINT8 Byte;
649 UINTN Index;
650 UINT16 DeviceId;
651 EFI_STATUS Status;
652
653 Status = Private->PciIo->Pci.Read (
654 Private->PciIo,
655 EfiPciIoWidthUint16,
656 PCI_DEVICE_ID_OFFSET,
657 1,
658 &DeviceId
659 );
660 //
661 // Read the PCI Configuration Header from the PCI Device
662 //
663 ASSERT_EFI_ERROR (Status);
664
665 outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
666 outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
667
668 for (Index = 0; Index < 15; Index++) {
669 outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
670 }
671
672 if (DeviceId != CIRRUS_LOGIC_5446_DEVICE_ID) {
673 outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
674 Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
675 outb (Private, SEQ_DATA_REGISTER, Byte);
676 }
677
678 outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
679 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);
680 outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);
681 outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
682
683 for (Index = 0; Index < 28; Index++) {
684 outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));
685 }
686
687 for (Index = 0; Index < 9; Index++) {
688 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));
689 }
690
691 inb (Private, INPUT_STATUS_1_REGISTER);
692
693 for (Index = 0; Index < 21; Index++) {
694 outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);
695 outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
696 }
697
698 outb (Private, ATT_ADDRESS_REGISTER, 0x20);
699
700 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);
701 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);
702 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);
703 outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);
704
705 SetDefaultPalette (Private);
706 ClearScreen (Private);
707 }
708
709 EFI_STATUS
710 EFIAPI
711 InitializeQemuVideo (
712 IN EFI_HANDLE ImageHandle,
713 IN EFI_SYSTEM_TABLE *SystemTable
714 )
715 {
716 EFI_STATUS Status;
717
718 Status = EfiLibInstallDriverBindingComponentName2 (
719 ImageHandle,
720 SystemTable,
721 &gQemuVideoDriverBinding,
722 ImageHandle,
723 &gQemuVideoComponentName,
724 &gQemuVideoComponentName2
725 );
726 ASSERT_EFI_ERROR (Status);
727
728 //
729 // Install EFI Driver Supported EFI Version Protocol required for
730 // EFI drivers that are on PCI and other plug in cards.
731 //
732 gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
733 Status = gBS->InstallMultipleProtocolInterfaces (
734 &ImageHandle,
735 &gEfiDriverSupportedEfiVersionProtocolGuid,
736 &gQemuVideoDriverSupportedEfiVersion,
737 NULL
738 );
739 ASSERT_EFI_ERROR (Status);
740
741 return Status;
742 }