/*++ Copyright (c) 2006 - 2010 Intel Corporation. All rights reserved This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: Gop.c Abstract: GOP Controller Driver. This driver is a sample implementation of the Graphics Output Protocol for the Intel GMCH family of PCI video controllers. This driver is only usable in the EFI pre-boot environment. This sample is intended to show how the Graphics Output Protocol is able to function. Revision History: --*/ #include "Gop.h" #include "CpuSupport.h" EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { ControllerDriverSupported, ControllerDriverStart, ControllerDriverStop, 0x10, NULL, NULL }; INTEL_PRIVATE_DATA mGopPrivateDataTemplate = { INTEL_PRIVATE_DATA_SIGNATURE, // Signature (EFI_HANDLE) NULL, // Handle (EFI_PCI_IO_PROTOCOL *) NULL, // PciIo protocol (EFI_DEVICE_PATH_PROTOCOL *) NULL, // DevicePath protocol { GraphicsOutputQueryMode, GraphicsOutputSetMode, GraphicsOutputBitBlt }, // Graphics Output Protocol { 0, NULL //Edid Discovered Protocol }, { 0, NULL //Edid Active Protocol }, { SIZE_TO_PAGE(GTT_ALLOC_SIZE), // Number of pages of GTT buffer 0 // GTT base address }, { SIZE_TO_PAGE(FB_SIZE), // Number of pages of allocated memory 0 // Frame buffer }, 0, // Frame buffer offset }; EFI_STATUS ControllerChildHandleUninstall ( EFI_DRIVER_BINDING_PROTOCOL *This, EFI_HANDLE Controller, EFI_HANDLE Handle ); UINT32 GetUmaSize ( EFI_PCI_IO_PROTOCOL *PciIo ); UINT32 GetUmaBase ( EFI_PCI_IO_PROTOCOL *PciIo ); // // GOP Driver Entry point // //EFI_DRIVER_ENTRY_POINT (GraphicsOutputDriverEntryPoint) EFI_STATUS EFIAPI GraphicsOutputDriverEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: Entrypoint of the GOP driver Arguments: ImageHandle - Driver image handle SystemTable - Pointer to system table Returns: EFI_SUCCESS - GOP driver finished initialize --*/ { EFI_STATUS Status; Status = EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, &gDriverBinding, ImageHandle, &gComponentName, &gComponentName2 ); ASSERT_EFI_ERROR (Status); return Status; /* return EfiLibInstallAllDriverProtocols2 ( ImageHandle, SystemTable, &gDriverBinding, ImageHandle, &gComponentName, NULL, NULL ); */ } EFI_STATUS EFIAPI ControllerDriverSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) /*++ Routine Description: The function test whether or not GOP driver support the Controller. Arguments: This - Driver Binding Protocol instance Controller - Pointer to controller Handle RemainingDevicePath - Remaining Device Path Returns: EFI_SUCCESS - Successfully support this controller --*/ { EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE00 Pci; // // Open the PCI I/O Protocol // Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { return Status; } // // Read the PCI Configuration Header from the PCI Device // Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci); if (EFI_ERROR (Status)) { goto Done; } Status = EFI_UNSUPPORTED; // // See if this is a graphics controller // if (Pci.Hdr.VendorId == INTEL_VENDOR_ID && ( (Pci.Hdr.DeviceId == INTEL_GMA_DEVICE_ID) || (Pci.Hdr.DeviceId == INTEL_GOP_DEVICE_ID) || (Pci.Hdr.DeviceId == INTEL_X3100_DEVICE_ID) )) { //Slice Status = EFI_SUCCESS; } Done: // // Close the PCI I/O Protocol // gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); return Status; } EFI_STATUS EFIAPI ControllerDriverStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) /*++ Routine Description: GOP driver start entrypoint. Arguments: This - Driver Binding Protocol instance Controller - Pointer to controller Handle RemainingDevicePath - Remaining Device Path Returns: EFI_SUCCESS - Driver success to start --*/ { EFI_STATUS Status; INTEL_PRIVATE_DATA *Private; EFI_PCI_IO_PROTOCOL *PciIo; ACPI_ADR_DEVICE_PATH AcpiDevicePath; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; EFI_PHYSICAL_ADDRESS AllocateMemoryBase; UINTN PreAllocatedMemory; // // Prepare parent device path // Status = gBS->HandleProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath ); if (EFI_ERROR (Status)) { return Status; } // // Open PCI I/O Protocol and save pointer to open protocol // in private data area. // Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { return Status; } // // Allocate Private context data for Graphics Output inteface. // Private = AllocateCopyPool ( sizeof (INTEL_PRIVATE_DATA), &mGopPrivateDataTemplate ); if (Private == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ErrorExit; } Private->PciIo = PciIo; // // Check UMA size // if (GetUmaSize(PciIo) < PREALLOCATED_SIZE) { // // if UMA == 1, or 0, then we allocate BootServices buffer // and not expose it // Private->PixelFormat = PixelBltOnly; // // Allocate the frame buffer // AllocateMemoryBase = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiBootServicesData, Private->AllocatedMemory.Pages, &AllocateMemoryBase ); if (EFI_ERROR (Status)) { goto ErrorExit; } Private->AllocatedMemory.BaseAddress = (UINTN)AllocateMemoryBase; ZeroMem ((VOID *) Private->AllocatedMemory.BaseAddress, MEM_ALLOC_SIZE); FlushDataCache (Private->AllocatedMemory.BaseAddress, MEM_ALLOC_SIZE); // // Allocate GTT buffer // AllocateMemoryBase = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateAnyPages, EfiBootServicesData, Private->GTTBaseAddress.Pages, &AllocateMemoryBase ); if (EFI_ERROR (Status)) { goto ErrorExit; } Private->GTTBaseAddress.BaseAddress = (UINTN)AllocateMemoryBase; ZeroMem ((VOID *) Private->GTTBaseAddress.BaseAddress, GTT_ALLOC_SIZE); FlushDataCache (Private->GTTBaseAddress.BaseAddress, GTT_ALLOC_SIZE); // // Create ExitBootServiceEvent to clear Gfx Controller // Status = gBS->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, ClearGfxController, Private, &Private->ExitBootServiceEvent ); } else { // // if UMA == 8, then we use UMA and expose it // Private->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; PreAllocatedMemory = (UINTN)GetUmaBase (PciIo); // // Use pre-allocated memory // Private->AllocatedMemory.BaseAddress = PreAllocatedMemory; Private->GTTBaseAddress.BaseAddress = PreAllocatedMemory + MEM_ALLOC_SIZE; ZeroMem ((VOID *) PreAllocatedMemory, PREALLOCATED_SIZE); FlushDataCache (PreAllocatedMemory, PREALLOCATED_SIZE); } // // Start the Graphics Output software stack. // The Graphics Output constructor requires that the MMIO BAR be enabled. // Status = GraphicsOutputConstructor (Private); if (EFI_ERROR (Status)) { goto ErrorExit; } if (RemainingDevicePath == NULL) { // // If ACPI_ADR is not specified, use default // ZeroMem (&AcpiDevicePath, sizeof (ACPI_ADR_DEVICE_PATH)); AcpiDevicePath.Header.Type = ACPI_DEVICE_PATH; AcpiDevicePath.Header.SubType = ACPI_ADR_DP; AcpiDevicePath.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0); SetDevicePathNodeLength (&AcpiDevicePath.Header, sizeof (ACPI_ADR_DEVICE_PATH)); Private->DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDevicePath); } else { Private->DevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath); } // // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol // Private->Handle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &Private->Handle, &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput, &gEfiEdidDiscoveredProtocolGuid, &Private->EdidDiscovered, &gEfiEdidActiveProtocolGuid, &Private->EdidActive, NULL ); if (!EFI_ERROR (Status)) { // // Open the Parent Handle for the child // Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &Private->PciIo, This->DriverBindingHandle, Private->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); if (EFI_ERROR (Status)) { goto ErrorExit; } } ErrorExit: if (EFI_ERROR (Status)) { // // Free all allocated memory if there is any // if (Private != NULL) { if (Private->PixelFormat == PixelBltOnly) { if (Private->AllocatedMemory.BaseAddress) { gBS->FreePages ( (EFI_PHYSICAL_ADDRESS)Private->AllocatedMemory.BaseAddress, Private->AllocatedMemory.Pages ); } if (Private->GTTBaseAddress.BaseAddress) { gBS->FreePages ( (EFI_PHYSICAL_ADDRESS)Private->GTTBaseAddress.BaseAddress, Private->GTTBaseAddress.Pages ); } } Private->GTTBaseAddress.BaseAddress = 0; Private->AllocatedMemory.BaseAddress = 0; if (Private->ExitBootServiceEvent != NULL) { gBS->CloseEvent (Private->ExitBootServiceEvent); Private->ExitBootServiceEvent = NULL; } gBS->FreePool (Private); } // // Close the PCI I/O Protocol // gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); } return Status; } EFI_STATUS EFIAPI ControllerDriverStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) /*++ Routine Description: GOP driver stop entrypoint Arguments: This - Driver Binding Protocol instance Controller - Controller Handle NumberOfChildren - Child number ChildHandleBuffer - A buffer that contain childern handles Returns: EFI_SUCCESS - GOP driver successfully Stop --*/ { EFI_STATUS Status; BOOLEAN AllChildrenStopped; UINTN Index; if (NumberOfChildren == 0) { // // Close PCI I/O protocol on the controller handle // gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index ++) { Status = ControllerChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]); if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } EFI_STATUS ControllerChildHandleUninstall ( EFI_DRIVER_BINDING_PROTOCOL *This, EFI_HANDLE Controller, EFI_HANDLE Handle ) /*++ Routine Description: Deregister an video child handle and free resources Arguments: This - Protocol instance pointer. Controller - Video controller handle Handle - Video child handle Returns: EFI_STATUS --*/ { EFI_STATUS Status; INTEL_PRIVATE_DATA *Private; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; // // There is only one child handle // Status = gBS->OpenProtocol ( Handle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return Status; } // // Get our private context information // Private = INTEL_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput); // // Shutdown the hardware // GraphicsOutputDestructor (Private); if (Private->PixelFormat == PixelBltOnly) { // // Free our instance data // if (Private->AllocatedMemory.BaseAddress) { gBS->FreePages ( (EFI_PHYSICAL_ADDRESS)Private->AllocatedMemory.BaseAddress, Private->AllocatedMemory.Pages ); } if (Private->GTTBaseAddress.BaseAddress) { gBS->FreePages ( (EFI_PHYSICAL_ADDRESS)Private->GTTBaseAddress.BaseAddress, Private->GTTBaseAddress.Pages ); } } Private->GTTBaseAddress.BaseAddress = 0; Private->AllocatedMemory.BaseAddress = 0; if (Private->ExitBootServiceEvent != NULL) { gBS->CloseEvent (Private->ExitBootServiceEvent); Private->ExitBootServiceEvent = NULL; } // // Close PCI I/O protocol that opened by child handle // gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Handle ); // // Remove the Graphics Output interface from the system // Status = gBS->UninstallMultipleProtocolInterfaces ( Private->Handle, &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput, &gEfiEdidDiscoveredProtocolGuid, &Private->EdidDiscovered, &gEfiEdidActiveProtocolGuid, &Private->EdidActive, NULL ); if (EFI_ERROR (Status)) { gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &Private->PciIo, This->DriverBindingHandle, Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); return Status; } // // Free our instance data // gBS->FreePool (Private); return EFI_SUCCESS; } UINT32 GetUmaSize ( EFI_PCI_IO_PROTOCOL *PciIo ) { EFI_STATUS Status; UINT16 GCC; UINT32 UmaSize; Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint16, IGD_GGC_OFFSET, 1, &GCC ); if (EFI_ERROR(Status)) { return 0; } switch (GCC & B_GMS) { case V_GMS_8MB: UmaSize = 8 * 1024 * 1024; break; case V_GMS_1MB: UmaSize = 1 * 1024 * 1024; break; default: UmaSize = 0; break; }; return UmaSize; } UINT32 GetUmaBase ( EFI_PCI_IO_PROTOCOL *PciIo ) { EFI_STATUS Status; UINT32 BSM; Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, IGD_BSM_OFFSET, 1, &BSM ); if (EFI_ERROR(Status)) { return 0; } return (BSM & 0xFFF00000); }