alder_lake_bios/Insyde/InsydeCrPkg/Uart16550Devices/PciHsUartDxe/PciHsUartDxe.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;
}