460 lines
12 KiB
C
460 lines
12 KiB
C
/** @file
|
|
This driver will install CRPolicy protocol for reference.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2013, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "PciHsUartDxe.h"
|
|
|
|
#define PCI_HSU_DEVICE_NAME_SIZE 50
|
|
#define PCI_HSU_DEVICE_NAME L"PCI_HS_UART"
|
|
#define PCI_HSU_REGISTER_BYTE_WIDTH sizeof(UINT32)
|
|
#define PCI_HSU_FIFO_DEPTH 16
|
|
#define PCI_HS_UART_DEVICE_DATA_SIGNATURE SIGNATURE_32 ('P','I','U','R')
|
|
#define PCI_HS_UART_DEVICE_DATA_FROM_THIS(This) CR (This, PCI_HS_UART_DEVICE_DATA, U16550Access, PCI_HS_UART_DEVICE_DATA_SIGNATURE)
|
|
|
|
//
|
|
// data type definitions
|
|
//
|
|
typedef struct {
|
|
UINT32 Signature;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UART_16550_DEVICE_INFO DeviceInfo;
|
|
H2O_UART_16550_ACCESS_PROTOCOL U16550Access;
|
|
} PCI_HS_UART_DEVICE_DATA;
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gHsUartControllerDriver = {
|
|
PciHsUartControllerDriverSupport,
|
|
PciHsUartControllerDriverStart,
|
|
PciHsUartControllerDriverStop,
|
|
0x0A,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
extern EFI_COMPONENT_NAME_PROTOCOL gPciHsUartComponentName;
|
|
extern EFI_COMPONENT_NAME2_PROTOCOL gPciHsUartComponentName2;
|
|
|
|
EFI_STATUS
|
|
PciHsUartControllerDriverSupport (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
PCI_TYPE00 PciHeader;
|
|
PCI_HSUART_LIST *DevList;
|
|
UINTN Seg;
|
|
UINTN Bus;
|
|
UINTN Dev;
|
|
UINTN Fun;
|
|
|
|
//
|
|
// Test the PciIo Protocol is not be open by driver.
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
&PciIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Fun);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Read Pci configuration to Identication the high speed UART
|
|
//
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0,
|
|
sizeof (PciHeader),
|
|
&PciHeader
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Check Device ID & PFA support
|
|
//
|
|
DevList = FixedPcdGetPtr (PcdH2OCrPciHsUartDeviceList);
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
while (DevList->VenderID != 0xFFFF) {
|
|
|
|
if (DevList->Bus != 0 || DevList->Device != 0 || DevList->Function != 0) {
|
|
//
|
|
// Check PFA
|
|
//
|
|
if (DevList->Bus == Bus && DevList->Device == Dev && DevList->Function == Fun) {
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
DevList++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (DevList->DeviceID != 0 || DevList->VenderID != 0) {
|
|
//
|
|
// Check Device ID and Vender ID
|
|
//
|
|
if ((DevList->DeviceID == PciHeader.Hdr.DeviceId) && (DevList->VenderID == PciHeader.Hdr.VendorId)) {
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
DevList++;
|
|
};
|
|
|
|
Exit:
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
InitPciHsUartDeviceData (
|
|
PCI_HS_UART_DEVICE_DATA *HsUartDev,
|
|
EFI_PCI_IO_PROTOCOL *PciIo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UART_16550_DEVICE_INFO *DevInfo;
|
|
PCI_TYPE00 PciHeader;
|
|
UINTN Segment;
|
|
UINTN Bus;
|
|
UINTN Device;
|
|
UINTN Function;
|
|
UINTN NameSize;
|
|
CHAR16 *Name;
|
|
UINT16 UID;
|
|
UINTN BaseAddress;
|
|
|
|
//
|
|
// Read pci configuration space for setting some field.
|
|
//
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0,
|
|
sizeof(PciHeader),
|
|
&PciHeader
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if ((PciHeader.Device.Bar[0] & BIT0) == 1) {
|
|
//
|
|
// IO port address
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
} else {
|
|
//
|
|
// 32bit Memory mapping IO address
|
|
//
|
|
BaseAddress = PciHeader.Device.Bar[0] & 0xFFFFFFF0;
|
|
}
|
|
//
|
|
// Convert PCI location to UID
|
|
//
|
|
Status = PciIo->GetLocation (
|
|
PciIo,
|
|
&Segment,
|
|
&Bus,
|
|
&Device,
|
|
&Function
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
UID = (UINT16)CREATE_UID (Bus, Device, Function);
|
|
|
|
//
|
|
// Set Device Name
|
|
//
|
|
NameSize = PCI_HSU_DEVICE_NAME_SIZE;
|
|
Name = AllocateZeroPool (NameSize);
|
|
|
|
UnicodeSPrint (
|
|
Name,
|
|
NameSize,
|
|
L"%s (0x%x,0x%x)",
|
|
PCI_HSU_DEVICE_NAME,
|
|
Device,
|
|
Function
|
|
);
|
|
//
|
|
// Initialize PCI_HS_UART_DEVICE_DATA structure
|
|
//
|
|
HsUartDev->Signature = PCI_HS_UART_DEVICE_DATA_SIGNATURE;
|
|
HsUartDev->PciIo = PciIo;
|
|
|
|
DevInfo = &HsUartDev->DeviceInfo;
|
|
DevInfo->DeviceName = Name;
|
|
DevInfo->DeviceType = PCI_HS_SERIAL_DEVICE;
|
|
DevInfo->UID = UID;
|
|
DevInfo->RegisterByteWidth = PCI_HSU_REGISTER_BYTE_WIDTH;
|
|
DevInfo->BaseAddressType = UBAT_MEMORY;
|
|
DevInfo->BaseAddress = BaseAddress;
|
|
DevInfo->FifoSize = PCI_HSU_FIFO_DEPTH;
|
|
DevInfo->SerialClockFreq = (UINTN)FixedPcdGet32(PcdH2OCrHsUartSerialClock);
|
|
DevInfo->SampleRate = FixedPcdGet16(PcdH2OCrHsUartSampleRate);
|
|
DevInfo->LegacySupport = TRUE;
|
|
|
|
HsUartDev->U16550Access.RegRead = PciHsUartRegRead;
|
|
HsUartDev->U16550Access.RegWrite = PciHsUartRegWrite;
|
|
HsUartDev->U16550Access.DeviceInfo = DevInfo;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PciHsUartControllerDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
PCI_HS_UART_DEVICE_DATA *HsUartDev;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
&PciIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for device Private data
|
|
//
|
|
HsUartDev = AllocateZeroPool(sizeof(PCI_HS_UART_DEVICE_DATA));
|
|
if (HsUartDev == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
SetMem (HsUartDev, 0, sizeof (PCI_HS_UART_DEVICE_DATA));
|
|
|
|
//
|
|
// Initialize the device Private data
|
|
//
|
|
Status = InitPciHsUartDeviceData (HsUartDev, PciIo);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Install Uart16550Access protocol on the contorller handle
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Controller,
|
|
&gH2OCrUart16550AccessProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&HsUartDev->U16550Access
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
Error:
|
|
|
|
if (HsUartDev != NULL) {
|
|
FreePool (HsUartDev);
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PciHsUartControllerDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *Protocol;
|
|
PCI_HS_UART_DEVICE_DATA *UartDevData;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gH2OCrUart16550AccessProtocolGuid,
|
|
(VOID**)&Protocol,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
UartDevData = PCI_HS_UART_DEVICE_DATA_FROM_THIS (Protocol);
|
|
Status = gBS->UninstallProtocolInterface (
|
|
Controller,
|
|
&gH2OCrUart16550AccessProtocolGuid,
|
|
&UartDevData->U16550Access
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
gBS->FreePool (UartDevData);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Install Driver to produce UART_16550_ACCESS protocol.
|
|
|
|
@param ImageHandle
|
|
@param SystemTable
|
|
|
|
@retval EFI_SUCCESS CrPolicy protocol installed
|
|
@return Other No protocol installed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
PciHsUartRegRead (
|
|
H2O_UART_16550_ACCESS_PROTOCOL *This,
|
|
UINT16 Index,
|
|
UINT8 *Data
|
|
)
|
|
{
|
|
PCI_HS_UART_DEVICE_DATA *DevData;
|
|
UINT32 *Register;
|
|
UINT8 Width;
|
|
|
|
Width = This->DeviceInfo->RegisterByteWidth;
|
|
DevData = PCI_HS_UART_DEVICE_DATA_FROM_THIS (This);
|
|
|
|
Register = (UINT32 *)(UINTN)(DevData->DeviceInfo.BaseAddress + Index * Width);
|
|
|
|
*Data = (UINT8) *Register;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Install Driver to produce UART_16550_ACCESS protocol.
|
|
|
|
@param ImageHandle
|
|
@param SystemTable
|
|
|
|
@retval EFI_SUCCESS CrPolicy protocol installed
|
|
@return Other No protocol installed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
PciHsUartRegWrite (
|
|
H2O_UART_16550_ACCESS_PROTOCOL *This,
|
|
UINT16 Index,
|
|
UINT8 Data
|
|
)
|
|
{
|
|
PCI_HS_UART_DEVICE_DATA *DevData;
|
|
UINT32 *Register;
|
|
UINT8 Width;
|
|
|
|
Width = This->DeviceInfo->RegisterByteWidth;
|
|
DevData = PCI_HS_UART_DEVICE_DATA_FROM_THIS (This);
|
|
|
|
Register = (UINT32 *)(UINTN)(DevData->DeviceInfo.BaseAddress + Index * Width);
|
|
|
|
*Register = Data;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Install Driver to produce UART_16550_ACCESS protocol.
|
|
|
|
@param ImageHandle
|
|
@param SystemTable
|
|
|
|
@retval EFI_SUCCESS CrPolicy protocol installed
|
|
@return Other No protocol installed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PciHsUartEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gHsUartControllerDriver,
|
|
ImageHandle,
|
|
&gPciHsUartComponentName,
|
|
&gPciHsUartComponentName2
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|