From 467d15ae63fb9d36904f06f11cde6c4cd5c297a2 Mon Sep 17 00:00:00 2001 From: mdkinney Date: Sat, 18 Dec 2010 01:02:59 +0000 Subject: [PATCH] Add generic SerialPortLib instance for 16550 UARTs configured through PCDs. Depends on new library class called PlatformHookLib to perform platform specific initialization of the UART. Add PlatformHookLib.h that defines the PlatformHookLib class Add PlatformHookLibNull instance that is a Null implementation of the PlatformHookLib class git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11184 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Library/PlatformHookLib.h | 38 ++ .../BasePlatformHookLibNull.c | 37 ++ .../BasePlatformHookLibNull.inf | 34 ++ .../BaseSerialPortLib16550.c | 336 ++++++++++++++++++ .../BaseSerialPortLib16550.inf | 41 +++ MdeModulePkg/MdeModulePkg.dec | 38 ++ MdeModulePkg/MdeModulePkg.dsc | 2 + 7 files changed, 526 insertions(+) create mode 100644 MdeModulePkg/Include/Library/PlatformHookLib.h create mode 100644 MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c create mode 100644 MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf create mode 100644 MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c create mode 100644 MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf diff --git a/MdeModulePkg/Include/Library/PlatformHookLib.h b/MdeModulePkg/Include/Library/PlatformHookLib.h new file mode 100644 index 0000000000..0f265d49a3 --- /dev/null +++ b/MdeModulePkg/Include/Library/PlatformHookLib.h @@ -0,0 +1,38 @@ +/** @file + Platform hook library. Platform can provide an implementation of this + library class to provide hooks that may be required for some type of + platform initialization. + +Copyright (c) 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 that 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. + +**/ + +#ifndef __PLATFORM_HOOK_LIB__ +#define __PLATFORM_HOOK_LIB__ + +/** + Performs platform specific initialization required for the CPU to access + the hardware associated with a SerialPortLib instance. This function does + not intiailzie the serial port hardware itself. Instead, it initializes + hardware devices that are required for the CPU to access the serial port + hardware. This function may be called more than once. + + @retval RETURN_SUCCESS The platform specific initialization succeeded. + @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed. + +**/ +RETURN_STATUS +EFIAPI +PlatformHookSerialPortInitialize ( + VOID + ); + +#endif // __PLATFORM_HOOK_LIB__ + diff --git a/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c b/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c new file mode 100644 index 0000000000..bd1a31a36e --- /dev/null +++ b/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c @@ -0,0 +1,37 @@ +/** @file + Null Platform Hook Library instance. + + Copyright (c) 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. + +**/ + +#include +#include + +/** + Performs platform specific initialization required for the CPU to access + the hardware associated with a SerialPortLib instance. This function does + not intiailzie the serial port hardware itself. Instead, it initializes + hardware devices that are required for the CPU to access the serial port + hardware. This function may be called more than once. + + @retval RETURN_SUCCESS The platform specific initialization succeeded. + @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed. + +**/ +RETURN_STATUS +EFIAPI +PlatformHookSerialPortInitialize ( + VOID + ) +{ + return RETURN_SUCCESS; +} + diff --git a/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf b/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf new file mode 100644 index 0000000000..1166e29fd7 --- /dev/null +++ b/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf @@ -0,0 +1,34 @@ +## @file +# Null Platform Hook Library instance. +# +# Copyright (c) 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BasePlatformHookLibNull + FILE_GUID = EBC3AEAD-CC13-49b0-A678-5BED93956955 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformHookLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + BasePlatformHookLibNull.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec diff --git a/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c new file mode 100644 index 0000000000..dfccbc3847 --- /dev/null +++ b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c @@ -0,0 +1,336 @@ +/** @file + 16550 UART Serial Port library functions + + 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. + +**/ + +#include +#include +#include +#include +#include + +// +// 16550 UART register offsets and bitfields +// +#define R_UART_RXBUF 0 +#define R_UART_TXBUF 0 +#define R_UART_BAUD_LOW 0 +#define R_UART_BAUD_HIGH 1 +#define R_UART_FCR 2 +#define B_UART_FCR_FIFOE BIT0 +#define B_UART_FCR_FIFO64 BIT5 +#define R_UART_LCR 3 +#define B_UART_LCR_DLAB BIT7 +#define R_UART_MCR 4 +#define B_UART_MCR_RTS BIT1 +#define R_UART_LSR 5 +#define B_UART_LSR_RXRDY BIT0 +#define B_UART_LSR_TXRDY BIT5 +#define B_UART_LSR_TEMT BIT6 +#define R_UART_MSR 6 +#define B_UART_MSR_CTS BIT4 +#define B_UART_MSR_DCD BIT7 + +/** + Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from + MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The + parameter Offset is added to the base address of the 16550 registers that is specified + by PcdSerialRegisterBase. + + @param Offset The offset of the 16550 register to read. + + @return The value read from the 16550 register. + +**/ +UINT8 +SerialPortReadRegister ( + UINTN Offset + ) +{ + if (PcdGetBool (PcdSerialUseMmio)) { + return MmioRead8 ((UINTN)PcdGet64 (PcdSerialRegisterBase) + Offset); + } else { + return IoRead8 ((UINT16)PcdGet64 (PcdSerialRegisterBase) + Offset); + } +} + +/** + Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to + MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The + parameter Offset is added to the base address of the 16550 registers that is specified + by PcdSerialRegisterBase. + + @param Offset The offset of the 16550 register to read. + + @return The value written to the 16550 register. + +**/ +UINT8 +SerialPortWriteRegister ( + UINTN Offset, + UINT8 Value + ) +{ + if (PcdGetBool (PcdSerialUseMmio)) { + return MmioWrite8 ((UINTN)PcdGet64 (PcdSerialRegisterBase) + Offset, Value); + } else { + return IoWrite8 ((UINT16)PcdGet64 (PcdSerialRegisterBase) + Offset, Value); + } +} + +/** + Initialize the serial device hardware. + + If no initialization is required, then return RETURN_SUCCESS. + If the serial device was successfuly initialized, then return RETURN_SUCCESS. + If the serial device could not be initialized, then return RETURN_DEVICE_ERROR. + + @retval RETURN_SUCCESS The serial device was initialized. + @retval RETURN_DEVICE_ERROR The serial device could not be initialized. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + RETURN_STATUS Status; + UINTN Divisor; + BOOLEAN Initialized; + + // + // Perform platform specific initialization required to enable use of the 16550 device + // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase. + // + Status = PlatformHookSerialPortInitialize (); + if (RETURN_ERROR (Status)) { + return Status; + } + + // + // See if the serial port is already initialized + // + Initialized = TRUE; + if ((SerialPortReadRegister (R_UART_FCR) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)) != + (PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)) ) { + Initialized = FALSE; + } + if ((SerialPortReadRegister (R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) { + Initialized = FALSE; + } + SerialPortWriteRegister (R_UART_LCR, SerialPortReadRegister (R_UART_LCR) | B_UART_LCR_DLAB); + Divisor = (SerialPortReadRegister (R_UART_BAUD_HIGH) << 8) | SerialPortReadRegister (R_UART_BAUD_LOW); + SerialPortWriteRegister (R_UART_LCR, SerialPortReadRegister (R_UART_LCR) & ~B_UART_LCR_DLAB); + if (Divisor != 115200 / PcdGet32 (PcdSerialBaudRate)) { + Initialized = FALSE; + } + if (Initialized) { + return RETURN_SUCCESS; + } + + // + // Configure baud rate + // + Divisor = 115200 / PcdGet32 (PcdSerialBaudRate); + SerialPortWriteRegister (R_UART_LCR, B_UART_LCR_DLAB); + SerialPortWriteRegister (R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8)); + SerialPortWriteRegister (R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff)); + + // + // Clear DLAB and configure Data Bits, Parity, and Stop Bits. + // Strip reserved bits from PcdSerialLineControl + // + SerialPortWriteRegister (R_UART_LCR, PcdGet8 (PcdSerialLineControl) & 0x3F); + + // + // Enable and reset FIFOs + // Strip reserved bits from PcdSerialFifoControl + // + SerialPortWriteRegister (R_UART_FCR, PcdGet8 (PcdSerialFifoControl) & 0x17); + + // + // Put Modem Control Register(MCR) into its reset state of 0x00. + // + SerialPortWriteRegister (R_UART_MCR, 0x00); + + return RETURN_SUCCESS; +} + +/** + Write data from buffer to serial device. + + Writes NumberOfBytes data bytes from Buffer to the serial device. + The number of bytes actually written to the serial device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + + If Buffer is NULL, then ASSERT(). + + If NumberOfBytes is zero, then return 0. + + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the serial device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Result; + UINTN Index; + UINTN FifoSize; + + if (Buffer == NULL) { + return 0; + } + + // + // Compute the maximum size of the Tx FIFO + // + FifoSize = 1; + if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) { + if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) { + FifoSize = 16; + } else { + FifoSize = 64; + } + } + + Result = NumberOfBytes; + while (NumberOfBytes != 0) { + // + // Wait for the serial port to be ready, to make sure both the transmit FIFO + // and shift register empty. + // + while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_TEMT) == 0); + + // + // Fill then entire Tx FIFO + // + for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) { + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { + // + // Wait for notification from peer to send data + // + while ((SerialPortReadRegister (R_UART_MSR) & (B_UART_MSR_CTS | B_UART_MSR_DCD)) == B_UART_MSR_DCD); + } + + // + // Write byte to the transmit buffer. + // + SerialPortWriteRegister (R_UART_TXBUF, *Buffer); + } + } + return Result; +} + +/** + Reads data from a serial device into a buffer. + + @param Buffer Pointer to the data buffer to store the data read from the serial device. + @param NumberOfBytes Number of bytes to read from the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes read from the serial device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +SerialPortRead ( + OUT UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Result; + UINT8 Mcr; + + if (NULL == Buffer) { + return 0; + } + + Mcr = SerialPortReadRegister (R_UART_MCR) & ~B_UART_MCR_RTS; + + for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) { + // + // Wait for the serial port to have some data. + // + while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_RXRDY) == 0) { + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { + // + // Set RTS to let the peer send some data + // + SerialPortWriteRegister (R_UART_MCR, Mcr | B_UART_MCR_RTS); + } + } + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { + // + // Clear RTS to prevent peer from sending data + // + SerialPortWriteRegister (R_UART_MCR, Mcr); + } + + // + // Read byte from the receive buffer. + // + *Buffer = SerialPortReadRegister (R_UART_RXBUF); + } + + return Result; +} + +/** + Polls a serial device to see if there is any data waiting to be read. + + Polls aserial device to see if there is any data waiting to be read. + If there is data waiting to be read from the serial device, then TRUE is returned. + If there is no data waiting to be read from the serial device, then FALSE is returned. + + @retval TRUE Data is waiting to be read from the serial device. + @retval FALSE There is no data waiting to be read from the serial device. + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( + VOID + ) +{ + // + // Read the serial port status + // + if ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_RXRDY) != 0) { + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { + // + // Clear RTS to prevent peer from sending data + // + SerialPortWriteRegister (R_UART_MCR, SerialPortReadRegister (R_UART_MCR) & ~B_UART_MCR_RTS); + } + return TRUE; + } + + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { + // + // Set RTS to let the peer send some data + // + SerialPortWriteRegister (R_UART_MCR, SerialPortReadRegister (R_UART_MCR) | B_UART_MCR_RTS); + } + + return FALSE; +} diff --git a/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf new file mode 100644 index 0000000000..251f353884 --- /dev/null +++ b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf @@ -0,0 +1,41 @@ +## @file +# SerialPortLib instance for 16550 UART +# +# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseSerialPortLib16550 + FILE_GUID = 9E7C00CF-355A-4d4e-BF60-0428CFF95540 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + PcdLib + IoLib + PlatformHookLib + +[Sources] + BaseSerialPortLib16550.c + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 8cf4b75309..3a4b0aa2cc 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -82,6 +82,10 @@ # DebugAgentLib|Include/Library/DebugAgentLib.h + ## @libraryclass Provide platform specific hooks. + # + PlatformHookLib|Include/Library/PlatformHookLib.h + [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h @@ -394,6 +398,40 @@ ## RTC Update Timeout Value gEfiMdeModulePkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout|100000|UINT32|0x00010034 + ## If TRUE, then 16550 serial port registers are in MMIO space. + # If FALSE, then 16550 serial port registers are in I/O space. Default value. + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|FALSE|BOOLEAN|0x00020000 + + ## If TRUE, then the 16550 serial port hardware flow control is enabled. + # If FALSE, then the 16550 serial port hardware flow control is disabled. Default value. + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE|BOOLEAN|0x00020001 + + ## Base address of 16550 serial port registers in MMIO or I/O space. Default is 0x3F8. + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x03F8|UINT64|0x00020002 + + ## Baud rate for the 16550 serial port. Default is 115200 baud. + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate|115200|UINT32|0x00020003 + + ## Line Control Register (LCR) for the 16550 serial port. This encodes data bits, parity, and stop bits. + # BIT1..BIT0 - Data bits. 00b = 5 bits, 01b = 6 bits, 10b = 7 bits, 11b = 8 bits + # BIT2 - Stop Bits. 0 = 1 stop bit. 1 = 1.5 stop bits if 5 data bits selected, otherwise 2 stop bits. + # BIT5..BIT2 - Parity. xx0b = No Parity, 001b = Odd Parity, 011b = Even Parity, 101b = Mark Parity, 111b=Stick Parity + # BIT7..BIT6 - Reserved. Must be 0. + # + # Default is No Parity, 8 Data Bits, 1 Stop Bit. + # + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl|0x03|UINT8|0x00020004 + + ## FIFO Control Register (FCR) for the 16550 serial port. + # BIT0 - FIFO Enable. 0 = Disable FIFOs. 1 = Enable FIFOs. + # BIT1 - Clear receive FIFO. 1 = Clear FIFO. + # BIT2 - Clear transmit FIFO. 1 = Clear FIFO. + # BIT7..BIT3 - Reserved. Must be 0. + # + # Default is to enable and clear all FIFOs. + # + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x07|UINT8|0x00020005 + ## Maximum address that the DXE Core will allocate the EFI_SYSTEM_TABLE_POINTER # structure. The default value for this PCD is 0, which means that the DXE Core # will allocate the buffer from the EFI_SYSTEM_TABLE_POINTER structure on a 4MB diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index bcbfe30552..80ef479c3c 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -221,6 +221,8 @@ MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf + MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf + MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf