281 lines
7.2 KiB
C
281 lines
7.2 KiB
C
/** @file
|
|
High Speed Uart 16550 Compatible hardware driver
|
|
|
|
;******************************************************************************
|
|
;* 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 "PchHsUartDxe.h"
|
|
|
|
#define PCH_HS_UART_DEVICE_NAME_SIZE 30
|
|
#define PCH_HS_UART_DEVICE_NAME L"PCH_HS_UART"
|
|
#define PCH_HS_UART_FIFO_DEPTH 16
|
|
|
|
#define HS_UART_DEVICE_DATA_SIGNATURE SIGNATURE_32 ('H','S','U','R')
|
|
#define HS_UART_DEVICE_DATA_FROM_THIS(This) CR (This, PCH_HS_UART_DEVICE_DATA, U16550Access, HS_UART_DEVICE_DATA_SIGNATURE)
|
|
|
|
MMIO_ADDR *gPchBaseAddr;
|
|
|
|
PCH_HS_UART_DEVICE_DATA mHsUartTemplate[] = {
|
|
HS_UART_DEVICE_DATA_SIGNATURE,
|
|
NULL, // Handle
|
|
{ // DeviceInfo
|
|
0
|
|
},
|
|
{ // DevicePath
|
|
{ // HS_Uart_device_path Node
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
sizeof (HS_UART_DEVICE_PATH_NODE),
|
|
0,
|
|
UART_16550_COMPATIBLE_HW_GUID, //GUID
|
|
0, //BaseAddress
|
|
0 //UID
|
|
},
|
|
{ //End_of_Device_path_Node
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
sizeof (EFI_DEVICE_PATH),
|
|
0
|
|
}
|
|
},
|
|
{ // Uart16550AccessProtocol
|
|
HsUartRegRead,
|
|
HsUartRegWrite,
|
|
0
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
Returns UART's currently active access mode, 8 or 32 bit
|
|
|
|
@param[in] UartNumber Selects Serial IO UART device (0-2)
|
|
@retval AccessMode8bit
|
|
@retval AccessMode32bit
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
InternalDetectAccessMode (
|
|
IN UINT16 UartNumber
|
|
)
|
|
{
|
|
UINT32 Address;
|
|
UINT32 ByteMode;
|
|
|
|
Address = FixedPcdGet32(PcdH2OCrSerialIoPchPcrAddress);
|
|
|
|
if (Address <= 1) {
|
|
ByteMode = Address;
|
|
//
|
|
// Some platform didn't support PchPcrAddress.
|
|
// Set 1 = Access8bit
|
|
// Set 0 = Access32bit
|
|
//
|
|
if (ByteMode == 1) {
|
|
return Access8bit;
|
|
} else {
|
|
return Access32bit;
|
|
}
|
|
|
|
} else {
|
|
ByteMode = MmioRead32 (Address);
|
|
|
|
if ((ByteMode>>UartNumber) & 0x1) {
|
|
return Access8bit;
|
|
} else {
|
|
return Access32bit;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
InitHsUartDeviceData (
|
|
IN PCH_HS_UART_DEVICE_DATA *PchHsUartDev
|
|
)
|
|
{
|
|
UINT16 UID;
|
|
CHAR16 *Name;
|
|
|
|
UID = PchHsUartDev->DeviceInfo.UID;
|
|
|
|
//
|
|
// Set Device Name
|
|
//
|
|
Name = AllocateZeroPool (PCH_HS_UART_DEVICE_NAME_SIZE);
|
|
|
|
UnicodeSPrint (
|
|
Name,
|
|
PCH_HS_UART_DEVICE_NAME_SIZE,
|
|
L"%s %d",
|
|
PCH_HS_UART_DEVICE_NAME,
|
|
UID
|
|
);
|
|
|
|
//
|
|
// Initialize HS_UART_DEVICE_DATA structure
|
|
//
|
|
PchHsUartDev->DeviceInfo.DeviceName = Name;
|
|
PchHsUartDev->DeviceInfo.DeviceType = PCH_HS_SERIAL_DEVICE;
|
|
PchHsUartDev->DeviceInfo.RegisterByteWidth = InternalDetectAccessMode (UID);
|
|
PchHsUartDev->DeviceInfo.BaseAddressType = UBAT_MEMORY;
|
|
PchHsUartDev->DeviceInfo.BaseAddress = (UINTN)(gPchBaseAddr[UID].BaseAddr) ;
|
|
PchHsUartDev->DeviceInfo.DevIRQ = gPchBaseAddr[UID].Irq;
|
|
PchHsUartDev->DeviceInfo.FifoSize = PCH_HS_UART_FIFO_DEPTH;
|
|
PchHsUartDev->DeviceInfo.SerialClockFreq = (UINTN)FixedPcdGet32(PcdH2OCrHsUartSerialClock);
|
|
PchHsUartDev->DeviceInfo.SampleRate = FixedPcdGet16(PcdH2OCrHsUartSampleRate);
|
|
PchHsUartDev->DeviceInfo.LegacySupport = TRUE;
|
|
|
|
PchHsUartDev->DevicePath.HsUartNode.BaseAddress = (UINTN)gPchBaseAddr[UID].BaseAddr;
|
|
PchHsUartDev->DevicePath.HsUartNode.UID = UID;
|
|
PchHsUartDev->U16550Access.DeviceInfo = &(PchHsUartDev->DeviceInfo);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Read data from HsUart register.
|
|
|
|
@param This The H2O_UART_16550_ACCESS_PROTOCOL.
|
|
@param Index Reg offset.
|
|
@param Data Write data.
|
|
|
|
@retval EFI_SUCCESS CrPolicy protocol installed
|
|
@return Other No protocol installed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
HsUartRegRead (
|
|
H2O_UART_16550_ACCESS_PROTOCOL *This,
|
|
UINT16 Index,
|
|
UINT8 *Data
|
|
)
|
|
{
|
|
UINTN BaseAddress;
|
|
UINT8 RegisterWidth;
|
|
|
|
BaseAddress = This->DeviceInfo->BaseAddress;
|
|
RegisterWidth = This->DeviceInfo->RegisterByteWidth;
|
|
|
|
if (RegisterWidth == Access32bit) {
|
|
*Data = (UINT8) (0xFF & MmioRead32 (BaseAddress + 4 * Index));
|
|
} else {
|
|
*Data = MmioRead8 (BaseAddress + Index);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Write data to HsUart register.
|
|
|
|
@param This The H2O_UART_16550_ACCESS_PROTOCOL.
|
|
@param Index Reg offset.
|
|
@param Data Write data.
|
|
|
|
@retval EFI_SUCCESS CrPolicy protocol installed
|
|
@return Other No protocol installed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
HsUartRegWrite (
|
|
IN H2O_UART_16550_ACCESS_PROTOCOL *This,
|
|
IN UINT16 Index,
|
|
IN UINT8 Data
|
|
)
|
|
{
|
|
UINTN BaseAddress;
|
|
UINT8 RegisterWidth;
|
|
|
|
BaseAddress = This->DeviceInfo->BaseAddress;
|
|
RegisterWidth = This->DeviceInfo->RegisterByteWidth;
|
|
|
|
if (RegisterWidth == Access32bit) {
|
|
MmioWrite32 (BaseAddress + 4 * Index, Data);
|
|
} else {
|
|
MmioWrite8 (BaseAddress + Index, Data);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsHsUartEnable (
|
|
IN UINT8 Index
|
|
)
|
|
{
|
|
return gPchBaseAddr[Index].Enable == 0x01 ? TRUE : FALSE;
|
|
}
|
|
|
|
/**
|
|
Install Driver to produce UART_16550_ACCESS protocol.
|
|
|
|
@param ImageHandle
|
|
@param SystemTable
|
|
|
|
@retval EFI_SUCCESS HsUart installed
|
|
@return Other Install HsUart fail.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
HsUartEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
PCH_HS_UART_DEVICE_DATA *PchHsUartDev;
|
|
UINT8 Index;
|
|
|
|
Index = 0;
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
gPchBaseAddr = FixedPcdGetPtr(PcdH2OCrPchHsUartMmioAddress);
|
|
|
|
while (gPchBaseAddr[Index].Enable != 0xFF) {
|
|
if (!IsHsUartEnable(Index)) {
|
|
Index++;
|
|
continue;
|
|
}
|
|
|
|
PchHsUartDev = AllocateCopyPool (sizeof(PCH_HS_UART_DEVICE_DATA), &mHsUartTemplate);
|
|
if (PchHsUartDev == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
PchHsUartDev->DeviceInfo.UID = Index;
|
|
|
|
//
|
|
// Initialize the device Private data
|
|
//
|
|
InitHsUartDeviceData (PchHsUartDev);
|
|
|
|
//
|
|
// Install Uart16550Access protocol on the contorller handle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&PchHsUartDev->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&PchHsUartDev->DevicePath,
|
|
&gH2OCrUart16550AccessProtocolGuid,
|
|
&PchHsUartDev->U16550Access,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
Index ++;
|
|
}
|
|
return Status;
|
|
}
|
|
|