]> git.proxmox.com Git - mirror_edk2.git/blobdiff - CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.c
Pkg-Module: CorebootPayloadPkg
[mirror_edk2.git] / CorebootPayloadPkg / Library / SerialPortLib / SerialPortLib.c
diff --git a/CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.c b/CorebootPayloadPkg/Library/SerialPortLib/SerialPortLib.c
new file mode 100644 (file)
index 0000000..0d87e62
--- /dev/null
@@ -0,0 +1,316 @@
+/** @file\r
+  SerialPortLib instance for UART device upon coreboot\r
+\r
+  Copyright (c) 2014, 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 <Uefi/UefiBaseType.h>\r
+#include <Library/SerialPortLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/CbParseLib.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_DSR      BIT5\r
+\r
+UINT32 mSerialRegBase = 0;\r
+UINT32 mSerialRegAccessType = 0;\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 (mSerialRegAccessType == 2) { //MMIO\r
+    return MmioRead8 (mSerialRegBase + Offset);\r
+  } else { //IO\r
+    return IoRead8 ((UINT16)mSerialRegBase + 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 write.\r
+  @param  Value   The value to write to the 16550 register specified by Offset.\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 (mSerialRegAccessType == 2) { //MMIO\r
+    return MmioWrite8 (mSerialRegBase + Offset, Value);\r
+  } else {// IO\r
+    return IoWrite8 ((UINT16)mSerialRegBase + 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 successfully 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
+  Status = CbParseSerialInfo (&mSerialRegBase, &mSerialRegAccessType, NULL);\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
+\r
+  if ((SerialPortReadRegister (R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {\r
+    Initialized = FALSE;\r
+  }\r
+  SerialPortWriteRegister (R_UART_LCR, (UINT8)(SerialPortReadRegister (R_UART_LCR) | B_UART_LCR_DLAB));\r
+  Divisor =  SerialPortReadRegister (R_UART_BAUD_HIGH) << 8;\r
+  Divisor |= SerialPortReadRegister (R_UART_BAUD_LOW);\r
+  SerialPortWriteRegister (R_UART_LCR, (UINT8)(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, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));\r
+\r
+  //\r
+  // Enable and reset FIFOs\r
+  // Strip reserved bits from PcdSerialFifoControl\r
+  //\r
+  SerialPortWriteRegister (R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & 0x27));\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
+  if (NumberOfBytes == 0) {\r
+    //\r
+    // Flush the hardware\r
+    //\r
+\r
+    //\r
+    // Wait for both the transmit FIFO and shift register empty.\r
+    //\r
+    while ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_TEMT) == 0);\r
+\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
+\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
+\r
+  if (NULL == Buffer) {\r
+    return 0;\r
+  }\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
+        \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
+    return TRUE;\r
+  }  \r
+  \r
+  return FALSE;\r
+}\r