Home | History | Annotate | Download | only in BaseSerialPortLib16550
      1 /** @file
      2   16550 UART Serial Port library functions
      3 
      4   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <Base.h>
     17 #include <IndustryStandard/Pci.h>
     18 #include <Library/SerialPortLib.h>
     19 #include <Library/PcdLib.h>
     20 #include <Library/IoLib.h>
     21 #include <Library/PciLib.h>
     22 #include <Library/PlatformHookLib.h>
     23 #include <Library/BaseLib.h>
     24 
     25 //
     26 // PCI Defintions.
     27 //
     28 #define PCI_BRIDGE_32_BIT_IO_SPACE              0x01
     29 
     30 //
     31 // 16550 UART register offsets and bitfields
     32 //
     33 #define R_UART_RXBUF          0
     34 #define R_UART_TXBUF          0
     35 #define R_UART_BAUD_LOW       0
     36 #define R_UART_BAUD_HIGH      1
     37 #define R_UART_FCR            2
     38 #define   B_UART_FCR_FIFOE    BIT0
     39 #define   B_UART_FCR_FIFO64   BIT5
     40 #define R_UART_LCR            3
     41 #define   B_UART_LCR_DLAB     BIT7
     42 #define R_UART_MCR            4
     43 #define   B_UART_MCR_DTRC     BIT0
     44 #define   B_UART_MCR_RTS      BIT1
     45 #define R_UART_LSR            5
     46 #define   B_UART_LSR_RXRDY    BIT0
     47 #define   B_UART_LSR_TXRDY    BIT5
     48 #define   B_UART_LSR_TEMT     BIT6
     49 #define R_UART_MSR            6
     50 #define   B_UART_MSR_CTS      BIT4
     51 #define   B_UART_MSR_DSR      BIT5
     52 #define   B_UART_MSR_RI       BIT6
     53 #define   B_UART_MSR_DCD      BIT7
     54 
     55 //
     56 // 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
     57 //
     58 typedef struct {
     59   UINT8   Device;
     60   UINT8   Function;
     61   UINT16  PowerManagementStatusAndControlRegister;
     62 } PCI_UART_DEVICE_INFO;
     63 
     64 /**
     65   Read an 8-bit 16550 register.  If PcdSerialUseMmio is TRUE, then the value is read from
     66   MMIO space.  If PcdSerialUseMmio is FALSE, then the value is read from I/O space.  The
     67   parameter Offset is added to the base address of the 16550 registers that is specified
     68   by PcdSerialRegisterBase.
     69 
     70   @param  Base    The base address register of UART device.
     71   @param  Offset  The offset of the 16550 register to read.
     72 
     73   @return The value read from the 16550 register.
     74 
     75 **/
     76 UINT8
     77 SerialPortReadRegister (
     78   UINTN  Base,
     79   UINTN  Offset
     80   )
     81 {
     82   if (PcdGetBool (PcdSerialUseMmio)) {
     83     return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
     84   } else {
     85     return IoRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
     86   }
     87 }
     88 
     89 /**
     90   Write an 8-bit 16550 register.  If PcdSerialUseMmio is TRUE, then the value is written to
     91   MMIO space.  If PcdSerialUseMmio is FALSE, then the value is written to I/O space.  The
     92   parameter Offset is added to the base address of the 16550 registers that is specified
     93   by PcdSerialRegisterBase.
     94 
     95   @param  Base    The base address register of UART device.
     96   @param  Offset  The offset of the 16550 register to write.
     97   @param  Value   The value to write to the 16550 register specified by Offset.
     98 
     99   @return The value written to the 16550 register.
    100 
    101 **/
    102 UINT8
    103 SerialPortWriteRegister (
    104   UINTN  Base,
    105   UINTN  Offset,
    106   UINT8  Value
    107   )
    108 {
    109   if (PcdGetBool (PcdSerialUseMmio)) {
    110     return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
    111   } else {
    112     return IoWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
    113   }
    114 }
    115 
    116 /**
    117   Update the value of an 16-bit PCI configuration register in a PCI device.  If the
    118   PCI Configuration register specified by PciAddress is already programmed with a
    119   non-zero value, then return the current value.  Otherwise update the PCI configuration
    120   register specified by PciAddress with the value specified by Value and return the
    121   value programmed into the PCI configuration register.  All values must be masked
    122   using the bitmask specified by Mask.
    123 
    124   @param  PciAddress  PCI Library address of the PCI Configuration register to update.
    125   @param  Value       The value to program into the PCI Configuration Register.
    126   @param  Mask        Bitmask of the bits to check and update in the PCI configuration register.
    127 
    128 **/
    129 UINT16
    130 SerialPortLibUpdatePciRegister16 (
    131   UINTN   PciAddress,
    132   UINT16  Value,
    133   UINT16  Mask
    134   )
    135 {
    136   UINT16  CurrentValue;
    137 
    138   CurrentValue = PciRead16 (PciAddress) & Mask;
    139   if (CurrentValue != 0) {
    140     return CurrentValue;
    141   }
    142   return PciWrite16 (PciAddress, Value & Mask);
    143 }
    144 
    145 /**
    146   Update the value of an 32-bit PCI configuration register in a PCI device.  If the
    147   PCI Configuration register specified by PciAddress is already programmed with a
    148   non-zero value, then return the current value.  Otherwise update the PCI configuration
    149   register specified by PciAddress with the value specified by Value and return the
    150   value programmed into the PCI configuration register.  All values must be masked
    151   using the bitmask specified by Mask.
    152 
    153   @param  PciAddress  PCI Library address of the PCI Configuration register to update.
    154   @param  Value       The value to program into the PCI Configuration Register.
    155   @param  Mask        Bitmask of the bits to check and update in the PCI configuration register.
    156 
    157   @return  The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
    158 
    159 **/
    160 UINT32
    161 SerialPortLibUpdatePciRegister32 (
    162   UINTN   PciAddress,
    163   UINT32  Value,
    164   UINT32  Mask
    165   )
    166 {
    167   UINT32  CurrentValue;
    168 
    169   CurrentValue = PciRead32 (PciAddress) & Mask;
    170   if (CurrentValue != 0) {
    171     return CurrentValue;
    172   }
    173   return PciWrite32 (PciAddress, Value & Mask);
    174 }
    175 
    176 /**
    177   Retrieve the I/O or MMIO base address register for the PCI UART device.
    178 
    179   This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
    180   Device if they are not already enabled.
    181 
    182   @return  The base address register of the UART device.
    183 
    184 **/
    185 UINTN
    186 GetSerialRegisterBase (
    187   VOID
    188   )
    189 {
    190   UINTN                 PciLibAddress;
    191   UINTN                 BusNumber;
    192   UINTN                 SubordinateBusNumber;
    193   UINT32                ParentIoBase;
    194   UINT32                ParentIoLimit;
    195   UINT16                ParentMemoryBase;
    196   UINT16                ParentMemoryLimit;
    197   UINT32                IoBase;
    198   UINT32                IoLimit;
    199   UINT16                MemoryBase;
    200   UINT16                MemoryLimit;
    201   UINTN                 SerialRegisterBase;
    202   UINTN                 BarIndex;
    203   UINT32                RegisterBaseMask;
    204   PCI_UART_DEVICE_INFO  *DeviceInfo;
    205 
    206   //
    207   // Get PCI Device Info
    208   //
    209   DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
    210 
    211   //
    212   // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
    213   //
    214   if (DeviceInfo->Device == 0xff) {
    215     return (UINTN)PcdGet64 (PcdSerialRegisterBase);
    216   }
    217 
    218   //
    219   // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
    220   //
    221   ParentMemoryBase  = 0 >> 16;
    222   ParentMemoryLimit = 0xfff00000 >> 16;
    223   ParentIoBase      = 0 >> 12;
    224   ParentIoLimit     = 0xf000 >> 12;
    225 
    226   //
    227   // Enable I/O and MMIO in PCI Bridge
    228   // Assume Root Bus Numer is Zero.
    229   //
    230   for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
    231     //
    232     // Compute PCI Lib Address to PCI to PCI Bridge
    233     //
    234     PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
    235 
    236     //
    237     // Retrieve and verify the bus numbers in the PCI to PCI Bridge
    238     //
    239     BusNumber            = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
    240     SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
    241     if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {
    242       return 0;
    243     }
    244 
    245     //
    246     // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
    247     //
    248     if (PcdGetBool (PcdSerialUseMmio)) {
    249       MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xfff0;
    250       MemoryBase  = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase))  & 0xfff0;
    251 
    252       //
    253       // If PCI Bridge MMIO window is disabled, then return 0
    254       //
    255       if (MemoryLimit < MemoryBase) {
    256         return 0;
    257       }
    258 
    259       //
    260       // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
    261       //
    262       if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {
    263         return 0;
    264       }
    265       ParentMemoryBase  = MemoryBase;
    266       ParentMemoryLimit = MemoryLimit;
    267     } else {
    268       IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
    269       if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
    270         IoLimit = IoLimit >> 4;
    271       } else {
    272         IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimitUpper16)) << 4) | (IoLimit >> 4);
    273       }
    274       IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
    275       if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
    276         IoBase = IoBase >> 4;
    277       } else {
    278         IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16)) << 4) | (IoBase >> 4);
    279       }
    280 
    281       //
    282       // If PCI Bridge I/O window is disabled, then return 0
    283       //
    284       if (IoLimit < IoBase) {
    285         return 0;
    286       }
    287 
    288       //
    289       // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
    290       //
    291       if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {
    292         return 0;
    293       }
    294       ParentIoBase  = IoBase;
    295       ParentIoLimit = IoLimit;
    296     }
    297   }
    298 
    299   //
    300   // Compute PCI Lib Address to PCI UART
    301   //
    302   PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
    303 
    304   //
    305   // Find the first IO or MMIO BAR
    306   //
    307   RegisterBaseMask = 0xFFFFFFF0;
    308   for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {
    309     SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);
    310     if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {
    311       //
    312       // MMIO BAR is found
    313       //
    314       RegisterBaseMask = 0xFFFFFFF0;
    315       break;
    316     }
    317 
    318     if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {
    319       //
    320       // IO BAR is found
    321       //
    322       RegisterBaseMask = 0xFFFFFFF8;
    323       break;
    324     }
    325   }
    326 
    327   //
    328   // MMIO or IO BAR is not found.
    329   //
    330   if (BarIndex == PCI_MAX_BAR) {
    331     return 0;
    332   }
    333 
    334   //
    335   // Program UART BAR
    336   //
    337   SerialRegisterBase = SerialPortLibUpdatePciRegister32 (
    338                          PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,
    339                          (UINT32)PcdGet64 (PcdSerialRegisterBase),
    340                          RegisterBaseMask
    341                          );
    342 
    343   //
    344   // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
    345   //
    346   if (PcdGetBool (PcdSerialUseMmio)) {
    347     if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {
    348       return 0;
    349     }
    350   } else {
    351     if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {
    352       return 0;
    353     }
    354   }
    355 
    356   //
    357   // Enable I/O and MMIO in PCI UART Device if they are not already enabled
    358   //
    359   PciOr16 (
    360     PciLibAddress + PCI_COMMAND_OFFSET,
    361     PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
    362     );
    363 
    364   //
    365   // Force D0 state if a Power Management and Status Register is specified
    366   //
    367   if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
    368     if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
    369       PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
    370       //
    371       // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
    372       //
    373       SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
    374     }
    375   }
    376 
    377   //
    378   // Get PCI Device Info
    379   //
    380   DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
    381 
    382   //
    383   // Enable I/O or MMIO in PCI Bridge
    384   // Assume Root Bus Numer is Zero.
    385   //
    386   for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
    387     //
    388     // Compute PCI Lib Address to PCI to PCI Bridge
    389     //
    390     PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
    391 
    392     //
    393     // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
    394     //
    395     PciOr16 (
    396       PciLibAddress + PCI_COMMAND_OFFSET,
    397       PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
    398       );
    399 
    400     //
    401     // Force D0 state if a Power Management and Status Register is specified
    402     //
    403     if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
    404       if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
    405         PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
    406       }
    407     }
    408 
    409     BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
    410   }
    411 
    412   return SerialRegisterBase;
    413 }
    414 
    415 /**
    416   Return whether the hardware flow control signal allows writing.
    417 
    418   @param  SerialRegisterBase The base address register of UART device.
    419 
    420   @retval TRUE  The serial port is writable.
    421   @retval FALSE The serial port is not writable.
    422 **/
    423 BOOLEAN
    424 SerialPortWritable (
    425   UINTN  SerialRegisterBase
    426   )
    427 {
    428   if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
    429     if (PcdGetBool (PcdSerialDetectCable)) {
    430       //
    431       // Wait for both DSR and CTS to be set
    432       //   DSR is set if a cable is connected.
    433       //   CTS is set if it is ok to transmit data
    434       //
    435       //   DSR  CTS  Description                               Action
    436       //   ===  ===  ========================================  ========
    437       //    0    0   No cable connected.                       Wait
    438       //    0    1   No cable connected.                       Wait
    439       //    1    0   Cable connected, but not clear to send.   Wait
    440       //    1    1   Cable connected, and clear to send.       Transmit
    441       //
    442       return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));
    443     } else {
    444       //
    445       // Wait for both DSR and CTS to be set OR for DSR to be clear.
    446       //   DSR is set if a cable is connected.
    447       //   CTS is set if it is ok to transmit data
    448       //
    449       //   DSR  CTS  Description                               Action
    450       //   ===  ===  ========================================  ========
    451       //    0    0   No cable connected.                       Transmit
    452       //    0    1   No cable connected.                       Transmit
    453       //    1    0   Cable connected, but not clear to send.   Wait
    454       //    1    1   Cable connected, and clar to send.        Transmit
    455       //
    456       return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));
    457     }
    458   }
    459 
    460   return TRUE;
    461 }
    462 
    463 /**
    464   Initialize the serial device hardware.
    465 
    466   If no initialization is required, then return RETURN_SUCCESS.
    467   If the serial device was successfully initialized, then return RETURN_SUCCESS.
    468   If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
    469 
    470   @retval RETURN_SUCCESS        The serial device was initialized.
    471   @retval RETURN_DEVICE_ERROR   The serial device could not be initialized.
    472 
    473 **/
    474 RETURN_STATUS
    475 EFIAPI
    476 SerialPortInitialize (
    477   VOID
    478   )
    479 {
    480   RETURN_STATUS  Status;
    481   UINTN          SerialRegisterBase;
    482   UINT32         Divisor;
    483   UINT32         CurrentDivisor;
    484   BOOLEAN        Initialized;
    485 
    486   //
    487   // Perform platform specific initialization required to enable use of the 16550 device
    488   // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
    489   //
    490   Status = PlatformHookSerialPortInitialize ();
    491   if (RETURN_ERROR (Status)) {
    492     return Status;
    493   }
    494 
    495   //
    496   // Calculate divisor for baud generator
    497   //    Ref_Clk_Rate / Baud_Rate / 16
    498   //
    499   Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);
    500   if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {
    501     Divisor++;
    502   }
    503 
    504   //
    505   // Get the base address of the serial port in either I/O or MMIO space
    506   //
    507   SerialRegisterBase = GetSerialRegisterBase ();
    508   if (SerialRegisterBase ==0) {
    509     return RETURN_DEVICE_ERROR;
    510   }
    511 
    512   //
    513   // See if the serial port is already initialized
    514   //
    515   Initialized = TRUE;
    516   if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {
    517     Initialized = FALSE;
    518   }
    519   SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));
    520   CurrentDivisor =  SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;
    521   CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);
    522   SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));
    523   if (CurrentDivisor != Divisor) {
    524     Initialized = FALSE;
    525   }
    526   if (Initialized) {
    527     return RETURN_SUCCESS;
    528   }
    529 
    530   //
    531   // Wait for the serial port to be ready.
    532   // Verify that both the transmit FIFO and the shift register are empty.
    533   //
    534   while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
    535 
    536   //
    537   // Configure baud rate
    538   //
    539   SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
    540   SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
    541   SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
    542 
    543   //
    544   // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
    545   // Strip reserved bits from PcdSerialLineControl
    546   //
    547   SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));
    548 
    549   //
    550   // Enable and reset FIFOs
    551   // Strip reserved bits from PcdSerialFifoControl
    552   //
    553   SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);
    554   SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
    555 
    556   //
    557   // Put Modem Control Register(MCR) into its reset state of 0x00.
    558   //
    559   SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);
    560 
    561   return RETURN_SUCCESS;
    562 }
    563 
    564 /**
    565   Write data from buffer to serial device.
    566 
    567   Writes NumberOfBytes data bytes from Buffer to the serial device.
    568   The number of bytes actually written to the serial device is returned.
    569   If the return value is less than NumberOfBytes, then the write operation failed.
    570 
    571   If Buffer is NULL, then ASSERT().
    572 
    573   If NumberOfBytes is zero, then return 0.
    574 
    575   @param  Buffer           Pointer to the data buffer to be written.
    576   @param  NumberOfBytes    Number of bytes to written to the serial device.
    577 
    578   @retval 0                NumberOfBytes is 0.
    579   @retval >0               The number of bytes written to the serial device.
    580                            If this value is less than NumberOfBytes, then the write operation failed.
    581 
    582 **/
    583 UINTN
    584 EFIAPI
    585 SerialPortWrite (
    586   IN UINT8     *Buffer,
    587   IN UINTN     NumberOfBytes
    588   )
    589 {
    590   UINTN  SerialRegisterBase;
    591   UINTN  Result;
    592   UINTN  Index;
    593   UINTN  FifoSize;
    594 
    595   if (Buffer == NULL) {
    596     return 0;
    597   }
    598 
    599   SerialRegisterBase = GetSerialRegisterBase ();
    600   if (SerialRegisterBase ==0) {
    601     return 0;
    602   }
    603 
    604   if (NumberOfBytes == 0) {
    605     //
    606     // Flush the hardware
    607     //
    608 
    609     //
    610     // Wait for both the transmit FIFO and shift register empty.
    611     //
    612     while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
    613 
    614     //
    615     // Wait for the hardware flow control signal
    616     //
    617     while (!SerialPortWritable (SerialRegisterBase));
    618     return 0;
    619   }
    620 
    621   //
    622   // Compute the maximum size of the Tx FIFO
    623   //
    624   FifoSize = 1;
    625   if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {
    626     if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {
    627       FifoSize = 16;
    628     } else {
    629       FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);
    630     }
    631   }
    632 
    633   Result = NumberOfBytes;
    634   while (NumberOfBytes != 0) {
    635     //
    636     // Wait for the serial port to be ready, to make sure both the transmit FIFO
    637     // and shift register empty.
    638     //
    639     while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_TEMT) == 0);
    640 
    641     //
    642     // Fill then entire Tx FIFO
    643     //
    644     for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {
    645       //
    646       // Wait for the hardware flow control signal
    647       //
    648       while (!SerialPortWritable (SerialRegisterBase));
    649 
    650       //
    651       // Write byte to the transmit buffer.
    652       //
    653       SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);
    654     }
    655   }
    656   return Result;
    657 }
    658 
    659 /**
    660   Reads data from a serial device into a buffer.
    661 
    662   @param  Buffer           Pointer to the data buffer to store the data read from the serial device.
    663   @param  NumberOfBytes    Number of bytes to read from the serial device.
    664 
    665   @retval 0                NumberOfBytes is 0.
    666   @retval >0               The number of bytes read from the serial device.
    667                            If this value is less than NumberOfBytes, then the read operation failed.
    668 
    669 **/
    670 UINTN
    671 EFIAPI
    672 SerialPortRead (
    673   OUT UINT8     *Buffer,
    674   IN  UINTN     NumberOfBytes
    675   )
    676 {
    677   UINTN  SerialRegisterBase;
    678   UINTN  Result;
    679   UINT8  Mcr;
    680 
    681   if (NULL == Buffer) {
    682     return 0;
    683   }
    684 
    685   SerialRegisterBase = GetSerialRegisterBase ();
    686   if (SerialRegisterBase ==0) {
    687     return 0;
    688   }
    689 
    690   Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);
    691 
    692   for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {
    693     //
    694     // Wait for the serial port to have some data.
    695     //
    696     while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {
    697       if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
    698         //
    699         // Set RTS to let the peer send some data
    700         //
    701         SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));
    702       }
    703     }
    704     if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
    705       //
    706       // Clear RTS to prevent peer from sending data
    707       //
    708       SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
    709     }
    710 
    711     //
    712     // Read byte from the receive buffer.
    713     //
    714     *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);
    715   }
    716 
    717   return Result;
    718 }
    719 
    720 
    721 /**
    722   Polls a serial device to see if there is any data waiting to be read.
    723 
    724   Polls aserial device to see if there is any data waiting to be read.
    725   If there is data waiting to be read from the serial device, then TRUE is returned.
    726   If there is no data waiting to be read from the serial device, then FALSE is returned.
    727 
    728   @retval TRUE             Data is waiting to be read from the serial device.
    729   @retval FALSE            There is no data waiting to be read from the serial device.
    730 
    731 **/
    732 BOOLEAN
    733 EFIAPI
    734 SerialPortPoll (
    735   VOID
    736   )
    737 {
    738   UINTN  SerialRegisterBase;
    739 
    740   SerialRegisterBase = GetSerialRegisterBase ();
    741   if (SerialRegisterBase ==0) {
    742     return FALSE;
    743   }
    744 
    745   //
    746   // Read the serial port status
    747   //
    748   if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {
    749     if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
    750       //
    751       // Clear RTS to prevent peer from sending data
    752       //
    753       SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));
    754     }
    755     return TRUE;
    756   }
    757 
    758   if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
    759     //
    760     // Set RTS to let the peer send some data
    761     //
    762     SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));
    763   }
    764 
    765   return FALSE;
    766 }
    767 
    768 /**
    769   Sets the control bits on a serial device.
    770 
    771   @param Control                Sets the bits of Control that are settable.
    772 
    773   @retval RETURN_SUCCESS        The new control bits were set on the serial device.
    774   @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
    775   @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
    776 
    777 **/
    778 RETURN_STATUS
    779 EFIAPI
    780 SerialPortSetControl (
    781   IN UINT32 Control
    782   )
    783 {
    784   UINTN SerialRegisterBase;
    785   UINT8 Mcr;
    786 
    787   //
    788   // First determine the parameter is invalid.
    789   //
    790   if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
    791                     EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
    792     return RETURN_UNSUPPORTED;
    793   }
    794 
    795   SerialRegisterBase = GetSerialRegisterBase ();
    796   if (SerialRegisterBase ==0) {
    797     return RETURN_UNSUPPORTED;
    798   }
    799 
    800   //
    801   // Read the Modem Control Register.
    802   //
    803   Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
    804   Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));
    805 
    806   if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
    807     Mcr |= B_UART_MCR_DTRC;
    808   }
    809 
    810   if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
    811     Mcr |= B_UART_MCR_RTS;
    812   }
    813 
    814   //
    815   // Write the Modem Control Register.
    816   //
    817   SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
    818 
    819   return RETURN_SUCCESS;
    820 }
    821 
    822 /**
    823   Retrieve the status of the control bits on a serial device.
    824 
    825   @param Control                A pointer to return the current control signals from the serial device.
    826 
    827   @retval RETURN_SUCCESS        The control bits were read from the serial device.
    828   @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
    829   @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
    830 
    831 **/
    832 RETURN_STATUS
    833 EFIAPI
    834 SerialPortGetControl (
    835   OUT UINT32 *Control
    836   )
    837 {
    838   UINTN SerialRegisterBase;
    839   UINT8 Msr;
    840   UINT8 Mcr;
    841   UINT8 Lsr;
    842 
    843   SerialRegisterBase = GetSerialRegisterBase ();
    844   if (SerialRegisterBase ==0) {
    845     return RETURN_UNSUPPORTED;
    846   }
    847 
    848   *Control = 0;
    849 
    850   //
    851   // Read the Modem Status Register.
    852   //
    853   Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);
    854 
    855   if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {
    856     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
    857   }
    858 
    859   if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {
    860     *Control |= EFI_SERIAL_DATA_SET_READY;
    861   }
    862 
    863   if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {
    864     *Control |= EFI_SERIAL_RING_INDICATE;
    865   }
    866 
    867   if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {
    868     *Control |= EFI_SERIAL_CARRIER_DETECT;
    869   }
    870 
    871   //
    872   // Read the Modem Control Register.
    873   //
    874   Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
    875 
    876   if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {
    877     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
    878   }
    879 
    880   if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {
    881     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
    882   }
    883 
    884   if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
    885     *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
    886   }
    887 
    888   //
    889   // Read the Line Status Register.
    890   //
    891   Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);
    892 
    893   if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
    894     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
    895   }
    896 
    897   if ((Lsr & B_UART_LSR_RXRDY) == 0) {
    898     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
    899   }
    900 
    901   return RETURN_SUCCESS;
    902 }
    903 
    904 /**
    905   Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
    906   data bits, and stop bits on a serial device.
    907 
    908   @param BaudRate           The requested baud rate. A BaudRate value of 0 will use the
    909                             device's default interface speed.
    910                             On output, the value actually set.
    911   @param ReveiveFifoDepth   The requested depth of the FIFO on the receive side of the
    912                             serial interface. A ReceiveFifoDepth value of 0 will use
    913                             the device's default FIFO depth.
    914                             On output, the value actually set.
    915   @param Timeout            The requested time out for a single character in microseconds.
    916                             This timeout applies to both the transmit and receive side of the
    917                             interface. A Timeout value of 0 will use the device's default time
    918                             out value.
    919                             On output, the value actually set.
    920   @param Parity             The type of parity to use on this serial device. A Parity value of
    921                             DefaultParity will use the device's default parity value.
    922                             On output, the value actually set.
    923   @param DataBits           The number of data bits to use on the serial device. A DataBits
    924                             vaule of 0 will use the device's default data bit setting.
    925                             On output, the value actually set.
    926   @param StopBits           The number of stop bits to use on this serial device. A StopBits
    927                             value of DefaultStopBits will use the device's default number of
    928                             stop bits.
    929                             On output, the value actually set.
    930 
    931   @retval RETURN_SUCCESS            The new attributes were set on the serial device.
    932   @retval RETURN_UNSUPPORTED        The serial device does not support this operation.
    933   @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an unsupported value.
    934   @retval RETURN_DEVICE_ERROR       The serial device is not functioning correctly.
    935 
    936 **/
    937 RETURN_STATUS
    938 EFIAPI
    939 SerialPortSetAttributes (
    940   IN OUT UINT64             *BaudRate,
    941   IN OUT UINT32             *ReceiveFifoDepth,
    942   IN OUT UINT32             *Timeout,
    943   IN OUT EFI_PARITY_TYPE    *Parity,
    944   IN OUT UINT8              *DataBits,
    945   IN OUT EFI_STOP_BITS_TYPE *StopBits
    946   )
    947 {
    948   UINTN     SerialRegisterBase;
    949   UINT32    SerialBaudRate;
    950   UINTN     Divisor;
    951   UINT8     Lcr;
    952   UINT8     LcrData;
    953   UINT8     LcrParity;
    954   UINT8     LcrStop;
    955 
    956   SerialRegisterBase = GetSerialRegisterBase ();
    957   if (SerialRegisterBase ==0) {
    958     return RETURN_UNSUPPORTED;
    959   }
    960 
    961   //
    962   // Check for default settings and fill in actual values.
    963   //
    964   if (*BaudRate == 0) {
    965     *BaudRate = PcdGet32 (PcdSerialBaudRate);
    966   }
    967   SerialBaudRate = (UINT32) *BaudRate;
    968 
    969   if (*DataBits == 0) {
    970     LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);
    971     *DataBits = LcrData + 5;
    972   } else {
    973     if ((*DataBits < 5) || (*DataBits > 8)) {
    974       return RETURN_INVALID_PARAMETER;
    975     }
    976     //
    977     // Map 5..8 to 0..3
    978     //
    979     LcrData = (UINT8) (*DataBits - (UINT8) 5);
    980   }
    981 
    982   if (*Parity == DefaultParity) {
    983     LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);
    984     switch (LcrParity) {
    985       case 0:
    986         *Parity = NoParity;
    987         break;
    988 
    989       case 3:
    990         *Parity = EvenParity;
    991         break;
    992 
    993       case 1:
    994         *Parity = OddParity;
    995         break;
    996 
    997       case 7:
    998         *Parity = SpaceParity;
    999         break;
   1000 
   1001       case 5:
   1002         *Parity = MarkParity;
   1003         break;
   1004 
   1005       default:
   1006         break;
   1007     }
   1008   } else {
   1009     switch (*Parity) {
   1010       case NoParity:
   1011         LcrParity = 0;
   1012         break;
   1013 
   1014       case EvenParity:
   1015         LcrParity = 3;
   1016         break;
   1017 
   1018       case OddParity:
   1019         LcrParity = 1;
   1020         break;
   1021 
   1022       case SpaceParity:
   1023         LcrParity = 7;
   1024         break;
   1025 
   1026       case MarkParity:
   1027         LcrParity = 5;
   1028         break;
   1029 
   1030       default:
   1031         return RETURN_INVALID_PARAMETER;
   1032     }
   1033   }
   1034 
   1035   if (*StopBits == DefaultStopBits) {
   1036     LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);
   1037     switch (LcrStop) {
   1038       case 0:
   1039         *StopBits = OneStopBit;
   1040         break;
   1041 
   1042       case 1:
   1043         if (*DataBits == 5) {
   1044           *StopBits = OneFiveStopBits;
   1045         } else {
   1046           *StopBits = TwoStopBits;
   1047         }
   1048         break;
   1049 
   1050       default:
   1051         break;
   1052     }
   1053   } else {
   1054     switch (*StopBits) {
   1055       case OneStopBit:
   1056         LcrStop = 0;
   1057         break;
   1058 
   1059       case OneFiveStopBits:
   1060       case TwoStopBits:
   1061         LcrStop = 1;
   1062         break;
   1063 
   1064       default:
   1065         return RETURN_INVALID_PARAMETER;
   1066     }
   1067   }
   1068 
   1069   //
   1070   // Calculate divisor for baud generator
   1071   //    Ref_Clk_Rate / Baud_Rate / 16
   1072   //
   1073   Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16);
   1074   if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) {
   1075     Divisor++;
   1076   }
   1077 
   1078   //
   1079   // Configure baud rate
   1080   //
   1081   SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
   1082   SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
   1083   SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
   1084 
   1085   //
   1086   // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
   1087   // Strip reserved bits from line control value
   1088   //
   1089   Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);
   1090   SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));
   1091 
   1092   return RETURN_SUCCESS;
   1093 }
   1094 
   1095