--- /dev/null
+/** @file\r
+ 16550 UART Serial Port library functions\r
+\r
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <Library/SerialPortLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PlatformHookLib.h>\r
+\r
+//\r
+// 16550 UART register offsets and bitfields\r
+//\r
+#define R_UART_RXBUF 0\r
+#define R_UART_TXBUF 0\r
+#define R_UART_BAUD_LOW 0\r
+#define R_UART_BAUD_HIGH 1\r
+#define R_UART_FCR 2\r
+#define B_UART_FCR_FIFOE BIT0\r
+#define B_UART_FCR_FIFO64 BIT5\r
+#define R_UART_LCR 3\r
+#define B_UART_LCR_DLAB BIT7\r
+#define R_UART_MCR 4\r
+#define B_UART_MCR_RTS BIT1\r
+#define R_UART_LSR 5\r
+#define B_UART_LSR_RXRDY BIT0\r
+#define B_UART_LSR_TXRDY BIT5\r
+#define B_UART_LSR_TEMT BIT6\r
+#define R_UART_MSR 6\r
+#define B_UART_MSR_CTS BIT4\r
+#define B_UART_MSR_DCD BIT7\r
+\r
+/**\r
+ Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from \r
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The\r
+ parameter Offset is added to the base address of the 16550 registers that is specified \r
+ by PcdSerialRegisterBase. \r
+ \r
+ @param Offset The offset of the 16550 register to read.\r
+\r
+ @return The value read from the 16550 register.\r
+\r
+**/\r
+UINT8\r
+SerialPortReadRegister (\r
+ UINTN Offset\r
+ )\r
+{\r
+ if (PcdGetBool (PcdSerialUseMmio)) {\r
+ return MmioRead8 ((UINTN)PcdGet64 (PcdSerialRegisterBase) + Offset);\r
+ } else {\r
+ return IoRead8 ((UINT16)PcdGet64 (PcdSerialRegisterBase) + Offset);\r
+ }\r
+}\r
+\r
+/**\r
+ Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to\r
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The\r
+ parameter Offset is added to the base address of the 16550 registers that is specified \r
+ by PcdSerialRegisterBase. \r
+ \r
+ @param Offset The offset of the 16550 register to read.\r
+\r
+ @return The value written to the 16550 register.\r
+\r
+**/\r
+UINT8\r
+SerialPortWriteRegister (\r
+ UINTN Offset,\r
+ UINT8 Value\r
+ )\r
+{\r
+ if (PcdGetBool (PcdSerialUseMmio)) {\r
+ return MmioWrite8 ((UINTN)PcdGet64 (PcdSerialRegisterBase) + Offset, Value);\r
+ } else {\r
+ return IoWrite8 ((UINT16)PcdGet64 (PcdSerialRegisterBase) + Offset, Value);\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize the serial device hardware.\r
+ \r
+ If no initialization is required, then return RETURN_SUCCESS.\r
+ If the serial device was successfuly initialized, then return RETURN_SUCCESS.\r
+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.\r
+ \r
+ @retval RETURN_SUCCESS The serial device was initialized.\r
+ @retval RETURN_DEVICE_ERROR The serial device could not be initialized.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+SerialPortInitialize (\r
+ VOID\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINTN Divisor;\r
+ BOOLEAN Initialized;\r
+\r
+ //\r
+ // Perform platform specific initialization required to enable use of the 16550 device\r
+ // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.\r
+ //\r
+ Status = PlatformHookSerialPortInitialize ();\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // See if the serial port is already initialized\r
+ //\r
+ Initialized = TRUE;\r
+ if ((SerialPortReadRegister (R_UART_FCR) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)) !=\r
+ (PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)) ) {\r
+ Initialized = FALSE;\r
+ }\r
+ if ((SerialPortReadRegister (R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {\r
+ Initialized = FALSE;\r
+ }\r
+ SerialPortWriteRegister (R_UART_LCR, SerialPortReadRegister (R_UART_LCR) | B_UART_LCR_DLAB);\r
+ Divisor = (SerialPortReadRegister (R_UART_BAUD_HIGH) << 8) | SerialPortReadRegister (R_UART_BAUD_LOW);\r
+ SerialPortWriteRegister (R_UART_LCR, SerialPortReadRegister (R_UART_LCR) & ~B_UART_LCR_DLAB);\r
+ if (Divisor != 115200 / PcdGet32 (PcdSerialBaudRate)) {\r
+ Initialized = FALSE;\r
+ }\r
+ if (Initialized) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+ \r
+ //\r
+ // Configure baud rate\r
+ //\r
+ Divisor = 115200 / PcdGet32 (PcdSerialBaudRate);\r
+ SerialPortWriteRegister (R_UART_LCR, B_UART_LCR_DLAB);\r
+ SerialPortWriteRegister (R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));\r
+ SerialPortWriteRegister (R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));\r
+\r
+ //\r
+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.\r
+ // Strip reserved bits from PcdSerialLineControl\r
+ //\r
+ SerialPortWriteRegister (R_UART_LCR, PcdGet8 (PcdSerialLineControl) & 0x3F);\r
+\r
+ //\r
+ // Enable and reset FIFOs\r
+ // Strip reserved bits from PcdSerialFifoControl\r
+ //\r
+ SerialPortWriteRegister (R_UART_FCR, PcdGet8 (PcdSerialFifoControl) & 0x17);\r
+\r
+ //\r
+ // Put Modem Control Register(MCR) into its reset state of 0x00.\r
+ // \r
+ SerialPortWriteRegister (R_UART_MCR, 0x00);\r
+ \r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write data from buffer to serial device. \r
+ \r
+ Writes NumberOfBytes data bytes from Buffer to the serial device. \r
+ The number of bytes actually written to the serial device is returned.\r
+ If the return value is less than NumberOfBytes, then the write operation failed.\r
+\r
+ If Buffer is NULL, then ASSERT(). \r
+\r
+ If NumberOfBytes is zero, then return 0.\r
+\r
+ @param Buffer Pointer to the data buffer to be written.\r
+ @param NumberOfBytes Number of bytes to written to the serial device.\r
+\r
+ @retval 0 NumberOfBytes is 0.\r
+ @retval >0 The number of bytes written to the serial device. \r
+ If this value is less than NumberOfBytes, then the read operation failed.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+SerialPortWrite (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN NumberOfBytes\r
+)\r
+{\r
+ UINTN Result;\r
+ UINTN Index;\r
+ UINTN FifoSize;\r
+\r
+ if (Buffer == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Compute the maximum size of the Tx FIFO\r
+ //\r
+ FifoSize = 1;\r
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {\r
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {\r
+ FifoSize = 16;\r
+ } else {\r
+ FifoSize = 64;\r
+ }\r
+ }\r
+ \r
+ Result = NumberOfBytes;\r
+ while (NumberOfBytes != 0) {\r
+ //\r
+ // Wait for the serial port to be ready, to make sure both the transmit FIFO\r
+ // and shift register empty.\r
+ //\r
+ while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_TEMT) == 0);\r
+\r
+ //\r
+ // Fill then entire Tx FIFO\r
+ //\r
+ for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {\r
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
+ //\r
+ // Wait for notification from peer to send data\r
+ //\r
+ while ((SerialPortReadRegister (R_UART_MSR) & (B_UART_MSR_CTS | B_UART_MSR_DCD)) == B_UART_MSR_DCD);\r
+ }\r
+ \r
+ //\r
+ // Write byte to the transmit buffer.\r
+ //\r
+ SerialPortWriteRegister (R_UART_TXBUF, *Buffer);\r
+ }\r
+ }\r
+ return Result;\r
+}\r
+\r
+/**\r
+ Reads data from a serial device into a buffer.\r
+\r
+ @param Buffer Pointer to the data buffer to store the data read from the serial device.\r
+ @param NumberOfBytes Number of bytes to read from the serial device.\r
+\r
+ @retval 0 NumberOfBytes is 0.\r
+ @retval >0 The number of bytes read from the serial device. \r
+ If this value is less than NumberOfBytes, then the read operation failed.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+SerialPortRead (\r
+ OUT UINT8 *Buffer,\r
+ IN UINTN NumberOfBytes\r
+)\r
+{\r
+ UINTN Result;\r
+ UINT8 Mcr;\r
+\r
+ if (NULL == Buffer) {\r
+ return 0;\r
+ }\r
+\r
+ Mcr = SerialPortReadRegister (R_UART_MCR) & ~B_UART_MCR_RTS;\r
+ \r
+ for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {\r
+ //\r
+ // Wait for the serial port to have some data.\r
+ //\r
+ while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {\r
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
+ //\r
+ // Set RTS to let the peer send some data\r
+ //\r
+ SerialPortWriteRegister (R_UART_MCR, Mcr | B_UART_MCR_RTS);\r
+ }\r
+ }\r
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
+ //\r
+ // Clear RTS to prevent peer from sending data\r
+ //\r
+ SerialPortWriteRegister (R_UART_MCR, Mcr);\r
+ }\r
+ \r
+ //\r
+ // Read byte from the receive buffer.\r
+ //\r
+ *Buffer = SerialPortReadRegister (R_UART_RXBUF);\r
+ }\r
+ \r
+ return Result;\r
+}\r
+\r
+/**\r
+ Polls a serial device to see if there is any data waiting to be read.\r
+\r
+ Polls aserial device to see if there is any data waiting to be read.\r
+ If there is data waiting to be read from the serial device, then TRUE is returned.\r
+ If there is no data waiting to be read from the serial device, then FALSE is returned.\r
+\r
+ @retval TRUE Data is waiting to be read from the serial device.\r
+ @retval FALSE There is no data waiting to be read from the serial device.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+SerialPortPoll (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Read the serial port status\r
+ //\r
+ if ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {\r
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
+ //\r
+ // Clear RTS to prevent peer from sending data\r
+ //\r
+ SerialPortWriteRegister (R_UART_MCR, SerialPortReadRegister (R_UART_MCR) & ~B_UART_MCR_RTS);\r
+ }\r
+ return TRUE;\r
+ } \r
+ \r
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
+ //\r
+ // Set RTS to let the peer send some data\r
+ //\r
+ SerialPortWriteRegister (R_UART_MCR, SerialPortReadRegister (R_UART_MCR) | B_UART_MCR_RTS);\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
#\r
DebugAgentLib|Include/Library/DebugAgentLib.h\r
\r
+ ## @libraryclass Provide platform specific hooks.\r
+ #\r
+ PlatformHookLib|Include/Library/PlatformHookLib.h\r
+ \r
[Guids]\r
## MdeModule package token space guid\r
# Include/Guid/MdeModulePkgTokenSpace.h\r
## RTC Update Timeout Value\r
gEfiMdeModulePkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout|100000|UINT32|0x00010034\r
\r
+ ## If TRUE, then 16550 serial port registers are in MMIO space. \r
+ # If FALSE, then 16550 serial port registers are in I/O space. Default value.\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|FALSE|BOOLEAN|0x00020000\r
+ \r
+ ## If TRUE, then the 16550 serial port hardware flow control is enabled.\r
+ # If FALSE, then the 16550 serial port hardware flow control is disabled. Default value.\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE|BOOLEAN|0x00020001\r
+\r
+ ## Base address of 16550 serial port registers in MMIO or I/O space. Default is 0x3F8.\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x03F8|UINT64|0x00020002\r
+\r
+ ## Baud rate for the 16550 serial port. Default is 115200 baud.\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate|115200|UINT32|0x00020003\r
+\r
+ ## Line Control Register (LCR) for the 16550 serial port. This encodes data bits, parity, and stop bits. \r
+ # BIT1..BIT0 - Data bits. 00b = 5 bits, 01b = 6 bits, 10b = 7 bits, 11b = 8 bits\r
+ # BIT2 - Stop Bits. 0 = 1 stop bit. 1 = 1.5 stop bits if 5 data bits selected, otherwise 2 stop bits.\r
+ # BIT5..BIT2 - Parity. xx0b = No Parity, 001b = Odd Parity, 011b = Even Parity, 101b = Mark Parity, 111b=Stick Parity\r
+ # BIT7..BIT6 - Reserved. Must be 0.\r
+ #\r
+ # Default is No Parity, 8 Data Bits, 1 Stop Bit.\r
+ #\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl|0x03|UINT8|0x00020004\r
+\r
+ ## FIFO Control Register (FCR) for the 16550 serial port. \r
+ # BIT0 - FIFO Enable. 0 = Disable FIFOs. 1 = Enable FIFOs.\r
+ # BIT1 - Clear receive FIFO. 1 = Clear FIFO.\r
+ # BIT2 - Clear transmit FIFO. 1 = Clear FIFO.\r
+ # BIT7..BIT3 - Reserved. Must be 0.\r
+ #\r
+ # Default is to enable and clear all FIFOs.\r
+ #\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x07|UINT8|0x00020005\r
+\r
## Maximum address that the DXE Core will allocate the EFI_SYSTEM_TABLE_POINTER\r
# structure. The default value for this PCD is 0, which means that the DXE Core\r
# will allocate the buffer from the EFI_SYSTEM_TABLE_POINTER structure on a 4MB\r