CloverBootloader/Trash/IntelGmaDxe/Gop.c

708 lines
18 KiB
C

/*++
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);
}