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// 30STATIC 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**/ 66RETURN_STATUS 67EFIAPI 68PL011UartInitializePort ( 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**/ 261RETURN_STATUS 262EFIAPI 263PL011UartSetControl ( 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**/ 338RETURN_STATUS 339EFIAPI 340PL011UartGetControl ( 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**/ 408UINTN 409EFIAPI 410PL011UartWrite ( 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**/ 438UINTN 439EFIAPI 440PL011UartRead ( 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**/ 463BOOLEAN 464EFIAPI 465PL011UartPoll ( 466 IN UINTN UartBase 467 ) 468{ 469 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0); 470} 471