]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: BaseSerialPortLib16550 library to support PCI UART device.
authorGao, Liming <liming.gao@intel.com>
Mon, 11 Aug 2014 06:38:28 +0000 (06:38 +0000)
committerlgao4 <lgao4@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 11 Aug 2014 06:38:28 +0000 (06:38 +0000)
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Gao, Liming <liming.gao@intel.com>
Reviewed-by: Kinney, Michael D <michael.d.kinney@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15783 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec

index 2fc6031ab74d1eb0e38e08c03343fa7c4fa8dfe8..190740c0bb7363652525d8db1e05aac1e2e5d187 100644 (file)
 **/\r
 \r
 #include <Base.h>\r
 **/\r
 \r
 #include <Base.h>\r
+#include <IndustryStandard/Pci.h>\r
 #include <Library/SerialPortLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/IoLib.h>\r
 #include <Library/SerialPortLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
 #include <Library/PlatformHookLib.h>\r
 #include <Library/PlatformHookLib.h>\r
+#include <Library/BaseLib.h>\r
+\r
+//\r
+// PCI Defintions.\r
+//\r
+#define PCI_BRIDGE_32_BIT_IO_SPACE              0x01\r
 \r
 //\r
 // 16550 UART register offsets and bitfields\r
 \r
 //\r
 // 16550 UART register offsets and bitfields\r
 #define   B_UART_MSR_CTS      BIT4\r
 #define   B_UART_MSR_DSR      BIT5\r
 \r
 #define   B_UART_MSR_CTS      BIT4\r
 #define   B_UART_MSR_DSR      BIT5\r
 \r
+//\r
+// 4-byte structure for each PCI node in PcdSerialPciDeviceInfo\r
+//\r
+typedef struct {\r
+  UINT8   Device;\r
+  UINT8   Function;\r
+  UINT16  PowerManagementStatusAndControlRegister;\r
+} PCI_UART_DEVICE_INFO;\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
 /**\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
 **/\r
 UINT8\r
 SerialPortReadRegister (\r
 **/\r
 UINT8\r
 SerialPortReadRegister (\r
+  UINTN  Base,\r
   UINTN  Offset\r
   )\r
 {\r
   if (PcdGetBool (PcdSerialUseMmio)) {\r
   UINTN  Offset\r
   )\r
 {\r
   if (PcdGetBool (PcdSerialUseMmio)) {\r
-    return MmioRead8 ((UINTN)PcdGet64 (PcdSerialRegisterBase) + Offset);\r
+    return MmioRead8 (Base + Offset);\r
   } else {\r
   } else {\r
-    return IoRead8 ((UINT16)PcdGet64 (PcdSerialRegisterBase) + Offset);\r
+    return IoRead8 (Base + Offset);\r
   }\r
 }\r
 \r
   }\r
 }\r
 \r
@@ -77,17 +95,319 @@ SerialPortReadRegister (
 **/\r
 UINT8\r
 SerialPortWriteRegister (\r
 **/\r
 UINT8\r
 SerialPortWriteRegister (\r
+  UINTN  Base,\r
   UINTN  Offset,\r
   UINT8  Value\r
   )\r
 {\r
   if (PcdGetBool (PcdSerialUseMmio)) {\r
   UINTN  Offset,\r
   UINT8  Value\r
   )\r
 {\r
   if (PcdGetBool (PcdSerialUseMmio)) {\r
-    return MmioWrite8 ((UINTN)PcdGet64 (PcdSerialRegisterBase) + Offset, Value);\r
+    return MmioWrite8 (Base + Offset, Value);\r
   } else {\r
   } else {\r
-    return IoWrite8 ((UINT16)PcdGet64 (PcdSerialRegisterBase) + Offset, Value);\r
+    return IoWrite8 (Base + Offset, Value);\r
   }\r
 }\r
 \r
   }\r
 }\r
 \r
+/**\r
+  Update the value of an 16-bit PCI configuration register in a PCI device.  If the  \r
+  PCI Configuration register specified by PciAddress is already programmed with a \r
+  non-zero value, then return the current value.  Otherwise update the PCI configuration \r
+  register specified by PciAddress with the value specified by Value and return the\r
+  value programmed into the PCI configuration register.  All values must be masked \r
+  using the bitmask specified by Mask.\r
+\r
+  @param  PciAddress  PCI Library address of the PCI Configuration register to update.\r
+  @param  Value       The value to program into the PCI Configuration Register.\r
+  @param  Mask        Bitmask of the bits to check and update in the PCI configuration register.\r
+\r
+**/\r
+UINT16\r
+SerialPortLibUpdatePciRegister16 (\r
+  UINTN   PciAddress,\r
+  UINT16  Value,\r
+  UINT16  Mask\r
+  )\r
+{\r
+  UINT16  CurrentValue;\r
+  \r
+  CurrentValue = PciRead16 (PciAddress) & Mask;\r
+  if (CurrentValue != 0) {\r
+    return CurrentValue;\r
+  }\r
+  return PciWrite16 (PciAddress, Value & Mask);\r
+}\r
+\r
+/**\r
+  Update the value of an 32-bit PCI configuration register in a PCI device.  If the  \r
+  PCI Configuration register specified by PciAddress is already programmed with a \r
+  non-zero value, then return the current value.  Otherwise update the PCI configuration \r
+  register specified by PciAddress with the value specified by Value and return the\r
+  value programmed into the PCI configuration register.  All values must be masked \r
+  using the bitmask specified by Mask.\r
+\r
+  @param  PciAddress  PCI Library address of the PCI Configuration register to update.\r
+  @param  Value       The value to program into the PCI Configuration Register.\r
+  @param  Mask        Bitmask of the bits to check and update in the PCI configuration register.\r
+\r
+  @return  The Secondary bus number that is actually programed into the PCI to PCI Bridge device.\r
+\r
+**/\r
+UINT32\r
+SerialPortLibUpdatePciRegister32 (\r
+  UINTN   PciAddress,\r
+  UINT32  Value,\r
+  UINT32  Mask\r
+  )\r
+{\r
+  UINT32  CurrentValue;\r
+  \r
+  CurrentValue = PciRead32 (PciAddress) & Mask;\r
+  if (CurrentValue != 0) {\r
+    return CurrentValue;\r
+  }\r
+  return PciWrite32 (PciAddress, Value & Mask);\r
+}\r
+\r
+/**\r
+  Retrieve the I/O or MMIO base address register for the PCI UART device. \r
+  \r
+  This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART \r
+  Device if they are not already enabled. \r
+  \r
+  @return  The base address register of the PCI UART device.\r
+\r
+**/\r
+UINTN\r
+GetSerialRegisterBase (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                 PciLibAddress;\r
+  UINTN                 PrimaryBusNumber;\r
+  UINTN                 BusNumber;\r
+  UINTN                 SubordinateBusNumber;\r
+  UINT32                ParentIoBase;\r
+  UINT32                ParentIoLimit;\r
+  UINT16                ParentMemoryBase;\r
+  UINT16                ParentMemoryLimit;\r
+  UINT32                IoBase;\r
+  UINT32                IoLimit;\r
+  UINT16                MemoryBase;\r
+  UINT16                MemoryLimit;\r
+  UINTN                 SerialRegisterBase;\r
+  UINTN                 BarIndex;\r
+  UINT32                RegisterBaseMask;\r
+  PCI_UART_DEVICE_INFO  *DeviceInfo;\r
+\r
+  //\r
+  // Get PCI Device Info\r
+  //\r
+  DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);\r
+  \r
+  //\r
+  // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase\r
+  //  \r
+  if (DeviceInfo->Device == 0xff) {\r
+    return (UINTN)PcdGet64 (PcdSerialRegisterBase);\r
+  }\r
+\r
+  //\r
+  // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB\r
+  //\r
+  ParentMemoryBase  = 0 >> 16;\r
+  ParentMemoryLimit = 0xfff00000 >> 16;\r
+  ParentIoBase      = 0 >> 12;\r
+  ParentIoLimit     = 0xf000 >> 12;\r
+  \r
+  //\r
+  // Enable I/O and MMIO in PCI Bridge\r
+  // Assume Root Bus Numer is Zero. \r
+  //\r
+  for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {\r
+    //\r
+    // Compute PCI Lib Address to PCI to PCI Bridge\r
+    //\r
+    PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);\r
+    \r
+    //\r
+    // Retrieve and verify the bus numbers in the PCI to PCI Bridge\r
+    //\r
+    PrimaryBusNumber     = PciRead8 (PciLibAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);\r
+    BusNumber            = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);\r
+    SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);\r
+    if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {\r
+      return 0;\r
+    }\r
+\r
+    //\r
+    // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge\r
+    //\r
+    if (PcdGetBool (PcdSerialUseMmio)) {\r
+      MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_BRIDGE_CONTROL_REGISTER, MemoryLimit)) & 0xfff0;\r
+      MemoryBase  = PciRead16 (PciLibAddress + OFFSET_OF (PCI_BRIDGE_CONTROL_REGISTER, MemoryBase))  & 0xfff0;\r
+\r
+      //\r
+      // If PCI Bridge MMIO window is disabled, then return 0\r
+      //\r
+      if (MemoryLimit < MemoryBase) {\r
+        return 0;\r
+      }\r
+      \r
+      //\r
+      // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0\r
+      //  \r
+      if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {\r
+        return 0;\r
+      }\r
+      ParentMemoryBase  = MemoryBase;\r
+      ParentMemoryLimit = MemoryLimit;\r
+    } else {\r
+      IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_BRIDGE_CONTROL_REGISTER, IoLimit));\r
+      if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {\r
+        IoLimit = IoLimit >> 4;\r
+      } else {\r
+        IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_BRIDGE_CONTROL_REGISTER, IoLimitUpper16)) << 4) | (IoLimit >> 4);\r
+      }\r
+      IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_BRIDGE_CONTROL_REGISTER, IoBase));\r
+      if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {\r
+        IoBase = IoBase >> 4;\r
+      } else {\r
+        IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_BRIDGE_CONTROL_REGISTER, IoBaseUpper16)) << 4) | (IoBase >> 4);\r
+      }\r
+      \r
+      //\r
+      // If PCI Bridge I/O window is disabled, then return 0\r
+      //\r
+      if (IoLimit < IoBase) {\r
+        return 0;\r
+      }\r
+      \r
+      //\r
+      // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0\r
+      //  \r
+      if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {\r
+        return 0;\r
+      }\r
+      ParentIoBase  = IoBase;\r
+      ParentIoLimit = IoLimit;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Compute PCI Lib Address to PCI UART\r
+  //\r
+  PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);\r
+  \r
+  //\r
+  // Find the first IO or MMIO BAR\r
+  //\r
+  RegisterBaseMask = 0xFFFFFFF0;\r
+  for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {\r
+    SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);\r
+    if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {\r
+      //\r
+      // MMIO BAR is found\r
+      //\r
+      RegisterBaseMask = 0xFFFFFFF0;\r
+      break;\r
+    }\r
+\r
+    if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {\r
+      //\r
+      // IO BAR is found\r
+      //\r
+      RegisterBaseMask = 0xFFFFFFF8;\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // MMIO or IO BAR is not found.\r
+  //\r
+  if (BarIndex == PCI_MAX_BAR) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Program UART BAR\r
+  //  \r
+  SerialRegisterBase = SerialPortLibUpdatePciRegister32 (\r
+                         PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,\r
+                         (UINT32)PcdGet64 (PcdSerialRegisterBase), \r
+                         RegisterBaseMask\r
+                         );\r
+\r
+  //\r
+  // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge\r
+  //  \r
+  if (PcdGetBool (PcdSerialUseMmio)) {\r
+    if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {\r
+      return 0;\r
+    }\r
+  } else {\r
+    if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {\r
+      return 0;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Enable I/O and MMIO in PCI UART Device if they are not already enabled\r
+  //\r
+  PciOr16 (\r
+    PciLibAddress + PCI_COMMAND_OFFSET,\r
+    PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE\r
+    );\r
+\r
+  //\r
+  // Force D0 state if a Power Management and Status Register is specified\r
+  //\r
+  if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {\r
+    if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {\r
+      PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));\r
+      //\r
+      // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs\r
+      //\r
+      SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Get PCI Device Info\r
+  //\r
+  DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);\r
+\r
+  //\r
+  // Enable I/O or MMIO in PCI Bridge\r
+  // Assume Root Bus Numer is Zero. \r
+  //\r
+  for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {\r
+    //\r
+    // Compute PCI Lib Address to PCI to PCI Bridge\r
+    //\r
+    PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);\r
+    \r
+    //\r
+    // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge\r
+    //\r
+    PciOr16 (\r
+      PciLibAddress + PCI_COMMAND_OFFSET, \r
+      PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE\r
+      );\r
+      \r
+    //\r
+    // Force D0 state if a Power Management and Status Register is specified\r
+    //\r
+    if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {\r
+      if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {\r
+        PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));\r
+      }\r
+    }\r
+      \r
+    BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);\r
+  }\r
+  \r
+  return SerialRegisterBase;\r
+}\r
+\r
 /**\r
   Return whether the hardware flow control signal allows writing.\r
 \r
 /**\r
   Return whether the hardware flow control signal allows writing.\r
 \r
@@ -96,7 +416,7 @@ SerialPortWriteRegister (
 **/\r
 BOOLEAN\r
 SerialPortWritable (\r
 **/\r
 BOOLEAN\r
 SerialPortWritable (\r
-  VOID\r
+  UINTN  SerialRegisterBase\r
   )\r
 {\r
   if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
   )\r
 {\r
   if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
@@ -113,7 +433,7 @@ SerialPortWritable (
       //    1    0   Cable connected, but not clear to send.   Wait\r
       //    1    1   Cable connected, and clear to send.       Transmit\r
       //\r
       //    1    0   Cable connected, but not clear to send.   Wait\r
       //    1    1   Cable connected, and clear to send.       Transmit\r
       //\r
-      return (BOOLEAN) ((SerialPortReadRegister (R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));\r
+      return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));\r
     } else {\r
       //\r
       // Wait for both DSR and CTS to be set OR for DSR to be clear.  \r
     } else {\r
       //\r
       // Wait for both DSR and CTS to be set OR for DSR to be clear.  \r
@@ -127,7 +447,7 @@ SerialPortWritable (
       //    1    0   Cable connected, but not clear to send.   Wait\r
       //    1    1   Cable connected, and clar to send.        Transmit\r
       //\r
       //    1    0   Cable connected, but not clear to send.   Wait\r
       //    1    1   Cable connected, and clar to send.        Transmit\r
       //\r
-      return (BOOLEAN) ((SerialPortReadRegister (R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));\r
+      return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));\r
     }\r
   }\r
 \r
     }\r
   }\r
 \r
@@ -152,7 +472,9 @@ SerialPortInitialize (
   )\r
 {\r
   RETURN_STATUS  Status;\r
   )\r
 {\r
   RETURN_STATUS  Status;\r
-  UINTN          Divisor;\r
+  UINTN          SerialRegisterBase;\r
+  UINT32         Divisor;\r
+  UINT32         CurrentDivisor;  \r
   BOOLEAN        Initialized;\r
 \r
   //\r
   BOOLEAN        Initialized;\r
 \r
   //\r
@@ -164,59 +486,78 @@ SerialPortInitialize (
     return Status;\r
   }\r
 \r
     return Status;\r
   }\r
 \r
+  //\r
+  // Calculate divisor for baud generator\r
+  //    Ref_Clk_Rate / Baud_Rate / 16\r
+  //\r
+  Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);\r
+  if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {\r
+    Divisor++;\r
+  }\r
+\r
+  //\r
+  // Get the base address of the serial port in either I/O or MMIO space\r
+  //\r
+  SerialRegisterBase = GetSerialRegisterBase ();\r
+  if (SerialRegisterBase ==0) {\r
+    return RETURN_DEVICE_ERROR;\r
+  }\r
+\r
   //\r
   // See if the serial port is already initialized\r
   //\r
   Initialized = TRUE;\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
+  if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {\r
     Initialized = FALSE;\r
   }\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 |= (UINTN)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
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));\r
+  CurrentDivisor =  SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;\r
+  CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));\r
+  if (CurrentDivisor != Divisor) {\r
     Initialized = FALSE;\r
   }\r
   if (Initialized) {\r
     return RETURN_SUCCESS;\r
   }\r
     Initialized = FALSE;\r
   }\r
   if (Initialized) {\r
     return RETURN_SUCCESS;\r
   }\r
+\r
+  //\r
+  // Wait for the serial port to be ready.\r
+  // Verify that both the transmit FIFO and the shift register are empty.\r
+  //\r
+  while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));\r
   \r
   //\r
   // Configure baud rate\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
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));\r
+  SerialPortWriteRegister (SerialRegisterBase, 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
 \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
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));\r
 \r
   //\r
   // Enable and reset FIFOs\r
   // Strip reserved bits from PcdSerialFifoControl\r
   //\r
 \r
   //\r
   // Enable and reset FIFOs\r
   // Strip reserved bits from PcdSerialFifoControl\r
   //\r
-  SerialPortWriteRegister (R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & 0x27));\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);\r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));\r
 \r
   //\r
   // Put Modem Control Register(MCR) into its reset state of 0x00.\r
   //  \r
 \r
   //\r
   // Put Modem Control Register(MCR) into its reset state of 0x00.\r
   //  \r
-  SerialPortWriteRegister (R_UART_MCR, 0x00);\r
-  \r
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);\r
+\r
   return RETURN_SUCCESS;\r
 }\r
 \r
 /**\r
   Write data from buffer to serial device. \r
   return RETURN_SUCCESS;\r
 }\r
 \r
 /**\r
   Write data from buffer to serial device. \r
\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
   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
@@ -238,16 +579,22 @@ EFIAPI
 SerialPortWrite (\r
   IN UINT8     *Buffer,\r
   IN UINTN     NumberOfBytes\r
 SerialPortWrite (\r
   IN UINT8     *Buffer,\r
   IN UINTN     NumberOfBytes\r
-)\r
+  )\r
 {\r
 {\r
-  UINTN    Result;\r
-  UINTN    Index;\r
-  UINTN    FifoSize;\r
+  UINTN  SerialRegisterBase;\r
+  UINTN  Result;\r
+  UINTN  Index;\r
+  UINTN  FifoSize;\r
 \r
   if (Buffer == NULL) {\r
     return 0;\r
   }\r
 \r
 \r
   if (Buffer == NULL) {\r
     return 0;\r
   }\r
 \r
+  SerialRegisterBase = GetSerialRegisterBase ();\r
+  if (SerialRegisterBase ==0) {\r
+    return 0;\r
+  }\r
+  \r
   if (NumberOfBytes == 0) {\r
     //\r
     // Flush the hardware\r
   if (NumberOfBytes == 0) {\r
     //\r
     // Flush the hardware\r
@@ -256,12 +603,12 @@ SerialPortWrite (
     //\r
     // Wait for both the transmit FIFO and shift register empty.\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
+    while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));\r
 \r
     //\r
     // Wait for the hardware flow control signal\r
     //\r
 \r
     //\r
     // Wait for the hardware flow control signal\r
     //\r
-    while (!SerialPortWritable ());\r
+    while (!SerialPortWritable (SerialRegisterBase));\r
     return 0;\r
   }\r
 \r
     return 0;\r
   }\r
 \r
@@ -273,7 +620,7 @@ SerialPortWrite (
     if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {\r
       FifoSize = 16;\r
     } else {\r
     if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {\r
       FifoSize = 16;\r
     } else {\r
-      FifoSize = 64;\r
+      FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);\r
     }\r
   }\r
 \r
     }\r
   }\r
 \r
@@ -283,7 +630,7 @@ SerialPortWrite (
     // Wait for the serial port to be ready, to make sure both the transmit FIFO\r
     // and shift register empty.\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
+    while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_TEMT) == 0);\r
 \r
     //\r
     // Fill then entire Tx FIFO\r
 \r
     //\r
     // Fill then entire Tx FIFO\r
@@ -292,12 +639,12 @@ SerialPortWrite (
       //\r
       // Wait for the hardware flow control signal\r
       //\r
       //\r
       // Wait for the hardware flow control signal\r
       //\r
-      while (!SerialPortWritable ());\r
+      while (!SerialPortWritable (SerialRegisterBase));\r
 \r
       //\r
       // Write byte to the transmit buffer.\r
       //\r
 \r
       //\r
       // Write byte to the transmit buffer.\r
       //\r
-      SerialPortWriteRegister (R_UART_TXBUF, *Buffer);\r
+      SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);\r
     }\r
   }\r
   return Result;\r
     }\r
   }\r
   return Result;\r
@@ -319,8 +666,9 @@ EFIAPI
 SerialPortRead (\r
   OUT UINT8     *Buffer,\r
   IN  UINTN     NumberOfBytes\r
 SerialPortRead (\r
   OUT UINT8     *Buffer,\r
   IN  UINTN     NumberOfBytes\r
-)\r
+  )\r
 {\r
 {\r
+  UINTN  SerialRegisterBase;\r
   UINTN  Result;\r
   UINT8  Mcr;\r
 \r
   UINTN  Result;\r
   UINT8  Mcr;\r
 \r
@@ -328,36 +676,42 @@ SerialPortRead (
     return 0;\r
   }\r
 \r
     return 0;\r
   }\r
 \r
-  Mcr = (UINT8)(SerialPortReadRegister (R_UART_MCR) & ~B_UART_MCR_RTS);\r
+  SerialRegisterBase = GetSerialRegisterBase ();\r
+  if (SerialRegisterBase ==0) {\r
+    return 0;\r
+  }\r
+\r
+  Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, 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
   \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
+    while ((SerialPortReadRegister (SerialRegisterBase, 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
       if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
         //\r
         // Set RTS to let the peer send some data\r
         //\r
-        SerialPortWriteRegister (R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));\r
+        SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));\r
       }\r
     }\r
     if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
       //\r
       // Clear RTS to prevent peer from sending data\r
       //\r
       }\r
     }\r
     if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
       //\r
       // Clear RTS to prevent peer from sending data\r
       //\r
-      SerialPortWriteRegister (R_UART_MCR, Mcr);\r
+      SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);\r
     }\r
     \r
     //\r
     // Read byte from the receive buffer.\r
     //\r
     }\r
     \r
     //\r
     // Read byte from the receive buffer.\r
     //\r
-    *Buffer = SerialPortReadRegister (R_UART_RXBUF);\r
+    *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);\r
   }\r
   \r
   return Result;\r
 }\r
 \r
   }\r
   \r
   return Result;\r
 }\r
 \r
+\r
 /**\r
   Polls a serial device to see if there is any data waiting to be read.\r
 \r
 /**\r
   Polls a serial device to see if there is any data waiting to be read.\r
 \r
@@ -375,15 +729,22 @@ SerialPortPoll (
   VOID\r
   )\r
 {\r
   VOID\r
   )\r
 {\r
+  UINTN  SerialRegisterBase;\r
+  \r
+  SerialRegisterBase = GetSerialRegisterBase ();\r
+  if (SerialRegisterBase ==0) {\r
+    return FALSE;\r
+  }\r
+\r
   //\r
   // Read the serial port status\r
   //\r
   //\r
   // Read the serial port status\r
   //\r
-  if ((SerialPortReadRegister (R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {\r
+  if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {\r
     if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
       //\r
       // Clear RTS to prevent peer from sending data\r
       //\r
     if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
       //\r
       // Clear RTS to prevent peer from sending data\r
       //\r
-      SerialPortWriteRegister (R_UART_MCR, (UINT8)(SerialPortReadRegister (R_UART_MCR) & ~B_UART_MCR_RTS));\r
+      SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));\r
     }\r
     return TRUE;\r
   }    \r
     }\r
     return TRUE;\r
   }    \r
@@ -392,7 +753,7 @@ SerialPortPoll (
     //\r
     // Set RTS to let the peer send some data\r
     //\r
     //\r
     // Set RTS to let the peer send some data\r
     //\r
-    SerialPortWriteRegister (R_UART_MCR, (UINT8)(SerialPortReadRegister (R_UART_MCR) | B_UART_MCR_RTS));\r
+    SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));\r
   }\r
   \r
   return FALSE;\r
   }\r
   \r
   return FALSE;\r
index 3f223667c7a6b01a841a5de1f239919c8a207ada..ebbfa6e9a29cf82c6403d44e2c8d8d508fc8e063 100644 (file)
@@ -1,7 +1,7 @@
 ## @file\r
 ## @file\r
-#   SerialPortLib instance for 16550 UART\r
+#  SerialPortLib instance for 16550 UART.\r
 #\r
 #\r
-#  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2006 - 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
 #  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
@@ -15,6 +15,7 @@
 [Defines]\r
   INF_VERSION                    = 0x00010005\r
   BASE_NAME                      = BaseSerialPortLib16550\r
 [Defines]\r
   INF_VERSION                    = 0x00010005\r
   BASE_NAME                      = BaseSerialPortLib16550\r
+  MODULE_UNI_FILE                = BaseSerialPortLib16550.uni\r
   FILE_GUID                      = 9E7C00CF-355A-4d4e-BF60-0428CFF95540\r
   MODULE_TYPE                    = BASE\r
   VERSION_STRING                 = 1.0\r
   FILE_GUID                      = 9E7C00CF-355A-4d4e-BF60-0428CFF95540\r
   MODULE_TYPE                    = BASE\r
   VERSION_STRING                 = 1.0\r
   PcdLib\r
   IoLib\r
   PlatformHookLib\r
   PcdLib\r
   IoLib\r
   PlatformHookLib\r
+  PciLib\r
 \r
 [Sources]\r
   BaseSerialPortLib16550.c\r
   \r
 [Pcd]\r
 \r
 [Sources]\r
   BaseSerialPortLib16550.c\r
   \r
 [Pcd]\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio                 ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl  ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable             ## SOMETIMES_CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase            ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate                ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl             ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl             ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate                  ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo              ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize         ## CONSUMES\r
diff --git a/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni
new file mode 100644 (file)
index 0000000..98c5897
Binary files /dev/null and b/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni differ
index 87121a8d83703c7a40ed5de25cf4d2bd50b26e55..47d9fdda1a7b7493a8ec27511724be794abe5053 100644 (file)
   ## Default Creator Revision for ACPI table creation.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision|0x01000013|UINT32|0x30001038\r
 \r
   ## Default Creator Revision for ACPI table creation.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision|0x01000013|UINT32|0x30001038\r
 \r
+  ## UART clock frequency is for the baud rate configuration.\r
+  # @Prompt Serial Port Clock Rate\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200|UINT32|0x00010066\r
+  \r
+  ## PCI Serial Device Info. It is an array of Device, Function, and Power Management\r
+  #  information that describes the path that contains zero or more PCI to PCI briges \r
+  #  followed by a PCI serial device.  Each array entry is 4-bytes in length.  The \r
+  #  first byte is the PCI Device Number, then second byte is the PCI Function Number, \r
+  #  and the last two bytes are the offset to the PCI power management capabilities \r
+  #  register used to manage the D0-D3 states.  If a PCI power management capabilities \r
+  #  register is not present, then the last two bytes in the offset is set to 0.  The \r
+  #  array is terminated by an array entry with a PCI Device Number of 0xFF.  For a \r
+  #  non-PCI fixed address serial device, such as an ISA serial device, the value is 0xFF.\r
+  # @Prompt Pci Serial Device Info\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}|VOID*|0x00010067\r
+\r
+  ## Serial Port Extended Transmit FIFO Size.  The default is 64 bytes. \r
+  # @Prompt Pci Port Extended Transmit FIFO Size in Bytes\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize|64|UINT32|0x00010068\r
+  \r
 [PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]\r
   ## This PCD defines the Console output column and the default value is 25 according to UEFI spec.\r
   #  This PCD could be set to 0 then console output could be at max column and max row.\r
 [PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]\r
   ## This PCD defines the Console output column and the default value is 25 according to UEFI spec.\r
   #  This PCD could be set to 0 then console output could be at max column and max row.\r