Home | History | Annotate | Download | only in PL011Uart
      1 /** @file
      2   Serial I/O Port library functions with no library constructor/destructor
      3 
      4   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
      5   Copyright (c) 2011 - 2016, ARM Ltd. All rights reserved.<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include <Library/DebugLib.h>
     18 #include <Library/IoLib.h>
     19 #include <Library/PcdLib.h>
     20 
     21 #include <Drivers/PL011Uart.h>
     22 
     23 #define FRACTION_PART_SIZE_IN_BITS  6
     24 #define FRACTION_PART_MASK          ((1 << FRACTION_PART_SIZE_IN_BITS) - 1)
     25 
     26 //
     27 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE is the only
     28 // control bit that is not supported.
     29 //
     30 STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
     31 
     32 /**
     33 
     34   Initialise the serial port to the specified settings.
     35   The serial port is re-configured only if the specified settings
     36   are different from the current settings.
     37   All unspecified settings will be set to the default values.
     38 
     39   @param  UartBase                The base address of the serial device.
     40   @param  UartClkInHz             The clock in Hz for the serial device.
     41                                   Ignored if the PCD PL011UartInteger is not 0
     42   @param  BaudRate                The baud rate of the serial device. If the
     43                                   baud rate is not supported, the speed will be
     44                                   reduced to the nearest supported one and the
     45                                   variable's value will be updated accordingly.
     46   @param  ReceiveFifoDepth        The number of characters the device will
     47                                   buffer on input.  Value of 0 will use the
     48                                   device's default FIFO depth.
     49   @param  Parity                  If applicable, this is the EFI_PARITY_TYPE
     50                                   that is computed or checked as each character
     51                                   is transmitted or received. If the device
     52                                   does not support parity, the value is the
     53                                   default parity value.
     54   @param  DataBits                The number of data bits in each character.
     55   @param  StopBits                If applicable, the EFI_STOP_BITS_TYPE number
     56                                   of stop bits per character.
     57                                   If the device does not support stop bits, the
     58                                   value is the default stop bit value.
     59 
     60   @retval RETURN_SUCCESS            All attributes were set correctly on the
     61                                     serial device.
     62   @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an
     63                                     unsupported value.
     64 
     65 **/
     66 RETURN_STATUS
     67 EFIAPI
     68 PL011UartInitializePort (
     69   IN     UINTN               UartBase,
     70   IN     UINT32              UartClkInHz,
     71   IN OUT UINT64              *BaudRate,
     72   IN OUT UINT32              *ReceiveFifoDepth,
     73   IN OUT EFI_PARITY_TYPE     *Parity,
     74   IN OUT UINT8               *DataBits,
     75   IN OUT EFI_STOP_BITS_TYPE  *StopBits
     76   )
     77 {
     78   UINT32      LineControl;
     79   UINT32      Divisor;
     80   UINT32      Integer;
     81   UINT32      Fractional;
     82   UINT32      HardwareFifoDepth;
     83 
     84   HardwareFifoDepth = (PL011_UARTPID2_VER (MmioRead32 (UartBase + UARTPID2)) \
     85                        > PL011_VER_R1P4) \
     86                       ? 32 : 16 ;
     87   // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept
     88   // 1 char buffer as the minimum FIFO size. Because everything can be rounded
     89   // down, there is no maximum FIFO size.
     90   if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= HardwareFifoDepth)) {
     91     // Enable FIFO
     92     LineControl = PL011_UARTLCR_H_FEN;
     93     *ReceiveFifoDepth = HardwareFifoDepth;
     94   } else {
     95     // Disable FIFO
     96     LineControl = 0;
     97     // Nothing else to do. 1 byte FIFO is default.
     98     *ReceiveFifoDepth = 1;
     99   }
    100 
    101   //
    102   // Parity
    103   //
    104   switch (*Parity) {
    105   case DefaultParity:
    106     *Parity = NoParity;
    107   case NoParity:
    108     // Nothing to do. Parity is disabled by default.
    109     break;
    110   case EvenParity:
    111     LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);
    112     break;
    113   case OddParity:
    114     LineControl |= PL011_UARTLCR_H_PEN;
    115     break;
    116   case MarkParity:
    117     LineControl |= (  PL011_UARTLCR_H_PEN \
    118                     | PL011_UARTLCR_H_SPS \
    119                     | PL011_UARTLCR_H_EPS);
    120     break;
    121   case SpaceParity:
    122     LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);
    123     break;
    124   default:
    125     return RETURN_INVALID_PARAMETER;
    126   }
    127 
    128   //
    129   // Data Bits
    130   //
    131   switch (*DataBits) {
    132   case 0:
    133     *DataBits = 8;
    134   case 8:
    135     LineControl |= PL011_UARTLCR_H_WLEN_8;
    136     break;
    137   case 7:
    138     LineControl |= PL011_UARTLCR_H_WLEN_7;
    139     break;
    140   case 6:
    141     LineControl |= PL011_UARTLCR_H_WLEN_6;
    142     break;
    143   case 5:
    144     LineControl |= PL011_UARTLCR_H_WLEN_5;
    145     break;
    146   default:
    147     return RETURN_INVALID_PARAMETER;
    148   }
    149 
    150   //
    151   // Stop Bits
    152   //
    153   switch (*StopBits) {
    154   case DefaultStopBits:
    155     *StopBits = OneStopBit;
    156   case OneStopBit:
    157     // Nothing to do. One stop bit is enabled by default.
    158     break;
    159   case TwoStopBits:
    160     LineControl |= PL011_UARTLCR_H_STP2;
    161     break;
    162   case OneFiveStopBits:
    163     // Only 1 or 2 stop bits are supported
    164   default:
    165     return RETURN_INVALID_PARAMETER;
    166   }
    167 
    168   // Don't send the LineControl value to the PL011 yet,
    169   // wait until after the Baud Rate setting.
    170   // This ensures we do not mess up the UART settings halfway through
    171   // in the rare case when there is an error with the Baud Rate.
    172 
    173   //
    174   // Baud Rate
    175   //
    176 
    177   // If PL011 Integer value has been defined then always ignore the BAUD rate
    178   if (FixedPcdGet32 (PL011UartInteger) != 0) {
    179     Integer = FixedPcdGet32 (PL011UartInteger);
    180     Fractional = FixedPcdGet32 (PL011UartFractional);
    181   } else {
    182     // If BAUD rate is zero then replace it with the system default value
    183     if (*BaudRate == 0) {
    184       *BaudRate = FixedPcdGet32 (PcdSerialBaudRate);
    185       if (*BaudRate == 0) {
    186         return RETURN_INVALID_PARAMETER;
    187       }
    188     }
    189     if (0 == UartClkInHz) {
    190       return RETURN_INVALID_PARAMETER;
    191     }
    192 
    193     Divisor = (UartClkInHz * 4) / *BaudRate;
    194     Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;
    195     Fractional = Divisor & FRACTION_PART_MASK;
    196   }
    197 
    198   //
    199   // If PL011 is already initialized, check the current settings
    200   // and re-initialize only if the settings are different.
    201   //
    202   if (((MmioRead32 (UartBase + UARTCR) & PL011_UARTCR_UARTEN) != 0) &&
    203        (MmioRead32 (UartBase + UARTLCR_H) == LineControl) &&
    204        (MmioRead32 (UartBase + UARTIBRD) == Integer) &&
    205        (MmioRead32 (UartBase + UARTFBRD) == Fractional)) {
    206     // Nothing to do - already initialized with correct attributes
    207     return RETURN_SUCCESS;
    208   }
    209 
    210   // Wait for the end of transmission
    211   while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0);
    212 
    213   // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed
    214   // when the UART is enabled"
    215   MmioWrite32 (UartBase + UARTCR, 0);
    216 
    217   // Set Baud Rate Registers
    218   MmioWrite32 (UartBase + UARTIBRD, Integer);
    219   MmioWrite32 (UartBase + UARTFBRD, Fractional);
    220 
    221   // No parity, 1 stop, no fifo, 8 data bits
    222   MmioWrite32 (UartBase + UARTLCR_H, LineControl);
    223 
    224   // Clear any pending errors
    225   MmioWrite32 (UartBase + UARTECR, 0);
    226 
    227   // Enable Tx, Rx, and UART overall
    228   MmioWrite32 (UartBase + UARTCR,
    229                PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);
    230 
    231   return RETURN_SUCCESS;
    232 }
    233 
    234 /**
    235 
    236   Assert or deassert the control signals on a serial port.
    237   The following control signals are set according their bit settings :
    238   . Request to Send
    239   . Data Terminal Ready
    240 
    241   @param[in]  UartBase  UART registers base address
    242   @param[in]  Control   The following bits are taken into account :
    243                         . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the
    244                           "Request To Send" control signal if this bit is
    245                           equal to one/zero.
    246                         . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert
    247                           the "Data Terminal Ready" control signal if this
    248                           bit is equal to one/zero.
    249                         . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable
    250                           the hardware loopback if this bit is equal to
    251                           one/zero.
    252                         . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported.
    253                         . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/
    254                           disable the hardware flow control based on CTS (Clear
    255                           To Send) and RTS (Ready To Send) control signals.
    256 
    257   @retval  RETURN_SUCCESS      The new control bits were set on the device.
    258   @retval  RETURN_UNSUPPORTED  The device does not support this operation.
    259 
    260 **/
    261 RETURN_STATUS
    262 EFIAPI
    263 PL011UartSetControl (
    264     IN UINTN   UartBase,
    265     IN UINT32  Control
    266   )
    267 {
    268   UINT32  Bits;
    269 
    270   if (Control & (mInvalidControlBits)) {
    271     return RETURN_UNSUPPORTED;
    272   }
    273 
    274   Bits = MmioRead32 (UartBase + UARTCR);
    275 
    276   if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
    277     Bits |= PL011_UARTCR_RTS;
    278   } else {
    279     Bits &= ~PL011_UARTCR_RTS;
    280   }
    281 
    282   if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
    283     Bits |= PL011_UARTCR_DTR;
    284   } else {
    285     Bits &= ~PL011_UARTCR_DTR;
    286   }
    287 
    288   if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
    289     Bits |= PL011_UARTCR_LBE;
    290   } else {
    291     Bits &= ~PL011_UARTCR_LBE;
    292   }
    293 
    294   if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
    295     Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
    296   } else {
    297     Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
    298   }
    299 
    300   MmioWrite32 (UartBase + UARTCR, Bits);
    301 
    302   return RETURN_SUCCESS;
    303 }
    304 
    305 /**
    306 
    307   Retrieve the status of the control bits on a serial device.
    308 
    309   @param[in]   UartBase  UART registers base address
    310   @param[out]  Control   Status of the control bits on a serial device :
    311 
    312                          . EFI_SERIAL_DATA_CLEAR_TO_SEND,
    313                            EFI_SERIAL_DATA_SET_READY,
    314                            EFI_SERIAL_RING_INDICATE,
    315                            EFI_SERIAL_CARRIER_DETECT,
    316                            EFI_SERIAL_REQUEST_TO_SEND,
    317                            EFI_SERIAL_DATA_TERMINAL_READY
    318                            are all related to the DTE (Data Terminal Equipment)
    319                            and DCE (Data Communication Equipment) modes of
    320                            operation of the serial device.
    321                          . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the
    322                            receive buffer is empty, 0 otherwise.
    323                          . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the
    324                            transmit buffer is empty, 0 otherwise.
    325                          . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if
    326                            the hardware loopback is enabled (the ouput feeds the
    327                            receive buffer), 0 otherwise.
    328                          . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if
    329                            a loopback is accomplished by software, 0 otherwise.
    330                          . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to
    331                            one if the hardware flow control based on CTS (Clear
    332                            To Send) and RTS (Ready To Send) control signals is
    333                            enabled, 0 otherwise.
    334 
    335   @retval RETURN_SUCCESS  The control bits were read from the serial device.
    336 
    337 **/
    338 RETURN_STATUS
    339 EFIAPI
    340 PL011UartGetControl (
    341     IN UINTN     UartBase,
    342     OUT UINT32  *Control
    343   )
    344 {
    345   UINT32      FlagRegister;
    346   UINT32      ControlRegister;
    347 
    348 
    349   FlagRegister = MmioRead32 (UartBase + UARTFR);
    350   ControlRegister = MmioRead32 (UartBase + UARTCR);
    351 
    352   *Control = 0;
    353 
    354   if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
    355     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
    356   }
    357 
    358   if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
    359     *Control |= EFI_SERIAL_DATA_SET_READY;
    360   }
    361 
    362   if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
    363     *Control |= EFI_SERIAL_RING_INDICATE;
    364   }
    365 
    366   if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
    367     *Control |= EFI_SERIAL_CARRIER_DETECT;
    368   }
    369 
    370   if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
    371     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
    372   }
    373 
    374   if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
    375     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
    376   }
    377 
    378   if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
    379     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
    380   }
    381 
    382   if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
    383     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
    384   }
    385 
    386   if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
    387        == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {
    388     *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
    389   }
    390 
    391   if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
    392     *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
    393   }
    394 
    395   return RETURN_SUCCESS;
    396 }
    397 
    398 /**
    399   Write data to serial device.
    400 
    401   @param  Buffer           Point of data buffer which need to be written.
    402   @param  NumberOfBytes    Number of output bytes which are cached in Buffer.
    403 
    404   @retval 0                Write data failed.
    405   @retval !0               Actual number of bytes written to serial device.
    406 
    407 **/
    408 UINTN
    409 EFIAPI
    410 PL011UartWrite (
    411   IN  UINTN    UartBase,
    412   IN UINT8     *Buffer,
    413   IN UINTN     NumberOfBytes
    414   )
    415 {
    416   UINT8* CONST Final = &Buffer[NumberOfBytes];
    417 
    418   while (Buffer < Final) {
    419     // Wait until UART able to accept another char
    420     while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));
    421 
    422     MmioWrite8 (UartBase + UARTDR, *Buffer++);
    423   }
    424 
    425   return NumberOfBytes;
    426 }
    427 
    428 /**
    429   Read data from serial device and save the data in buffer.
    430 
    431   @param  Buffer           Point of data buffer which need to be written.
    432   @param  NumberOfBytes    Number of output bytes which are cached in Buffer.
    433 
    434   @retval 0                Read data failed.
    435   @retval !0               Actual number of bytes read from serial device.
    436 
    437 **/
    438 UINTN
    439 EFIAPI
    440 PL011UartRead (
    441   IN  UINTN     UartBase,
    442   OUT UINT8     *Buffer,
    443   IN  UINTN     NumberOfBytes
    444   )
    445 {
    446   UINTN   Count;
    447 
    448   for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
    449     while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);
    450     *Buffer = MmioRead8 (UartBase + UARTDR);
    451   }
    452 
    453   return NumberOfBytes;
    454 }
    455 
    456 /**
    457   Check to see if any data is available to be read from the debug device.
    458 
    459   @retval TRUE       At least one byte of data is available to be read
    460   @retval FALSE      No data is available to be read
    461 
    462 **/
    463 BOOLEAN
    464 EFIAPI
    465 PL011UartPoll (
    466   IN  UINTN     UartBase
    467   )
    468 {
    469   return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
    470 }
    471