2 Serial I/O Port library functions with no library constructor/destructor
4 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
5 Copyright (c) 2011 - 2016, ARM Ltd. All rights reserved.<BR>
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
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.
17 #include <Library/DebugLib.h>
18 #include <Library/IoLib.h>
19 #include <Library/PcdLib.h>
21 #include <Drivers/PL011Uart.h>
23 #define FRACTION_PART_SIZE_IN_BITS 6
24 #define FRACTION_PART_MASK ((1 << FRACTION_PART_SIZE_IN_BITS) - 1)
27 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE is the only
28 // control bit that is not supported.
30 STATIC CONST UINT32 mInvalidControlBits
= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
;
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.
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
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.
60 @retval RETURN_SUCCESS All attributes were set correctly on the
62 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an
68 PL011UartInitializePort (
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
83 // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept
84 // 1 char buffer as the minimum FIFO size. Because everything can be rounded
85 // down, there is no maximum FIFO size.
86 if ((*ReceiveFifoDepth
== 0) || (*ReceiveFifoDepth
>= 32)) {
88 LineControl
= PL011_UARTLCR_H_FEN
;
89 if (PL011_UARTPID2_VER (MmioRead32 (UartBase
+ UARTPID2
)) > PL011_VER_R1P4
)
90 *ReceiveFifoDepth
= 32;
92 *ReceiveFifoDepth
= 16;
96 // Nothing else to do. 1 byte FIFO is default.
97 *ReceiveFifoDepth
= 1;
107 // Nothing to do. Parity is disabled by default.
110 LineControl
|= (PL011_UARTLCR_H_PEN
| PL011_UARTLCR_H_EPS
);
113 LineControl
|= PL011_UARTLCR_H_PEN
;
116 LineControl
|= ( PL011_UARTLCR_H_PEN \
117 | PL011_UARTLCR_H_SPS \
118 | PL011_UARTLCR_H_EPS
);
121 LineControl
|= (PL011_UARTLCR_H_PEN
| PL011_UARTLCR_H_SPS
);
124 return RETURN_INVALID_PARAMETER
;
134 LineControl
|= PL011_UARTLCR_H_WLEN_8
;
137 LineControl
|= PL011_UARTLCR_H_WLEN_7
;
140 LineControl
|= PL011_UARTLCR_H_WLEN_6
;
143 LineControl
|= PL011_UARTLCR_H_WLEN_5
;
146 return RETURN_INVALID_PARAMETER
;
153 case DefaultStopBits
:
154 *StopBits
= OneStopBit
;
156 // Nothing to do. One stop bit is enabled by default.
159 LineControl
|= PL011_UARTLCR_H_STP2
;
161 case OneFiveStopBits
:
162 // Only 1 or 2 stop bits are supported
164 return RETURN_INVALID_PARAMETER
;
167 // Don't send the LineControl value to the PL011 yet,
168 // wait until after the Baud Rate setting.
169 // This ensures we do not mess up the UART settings halfway through
170 // in the rare case when there is an error with the Baud Rate.
176 // If PL011 Integer value has been defined then always ignore the BAUD rate
177 if (FixedPcdGet32 (PL011UartInteger
) != 0) {
178 Integer
= FixedPcdGet32 (PL011UartInteger
);
179 Fractional
= FixedPcdGet32 (PL011UartFractional
);
181 // If BAUD rate is zero then replace it with the system default value
182 if (*BaudRate
== 0) {
183 *BaudRate
= FixedPcdGet32 (PcdSerialBaudRate
);
184 if (*BaudRate
== 0) {
185 return RETURN_INVALID_PARAMETER
;
188 if (0 == UartClkInHz
) {
189 return RETURN_INVALID_PARAMETER
;
192 Divisor
= (UartClkInHz
* 4) / *BaudRate
;
193 Integer
= Divisor
>> FRACTION_PART_SIZE_IN_BITS
;
194 Fractional
= Divisor
& FRACTION_PART_MASK
;
198 // If PL011 is already initialized, check the current settings
199 // and re-initialize only if the settings are different.
201 if (((MmioRead32 (UartBase
+ UARTCR
) & PL011_UARTCR_UARTEN
) != 0) &&
202 (MmioRead32 (UartBase
+ UARTLCR_H
) == LineControl
) &&
203 (MmioRead32 (UartBase
+ UARTIBRD
) == Integer
) &&
204 (MmioRead32 (UartBase
+ UARTFBRD
) == Fractional
)) {
205 // Nothing to do - already initialized with correct attributes
206 return RETURN_SUCCESS
;
209 // Wait for the end of transmission
210 while ((MmioRead32 (UartBase
+ UARTFR
) & PL011_UARTFR_TXFE
) == 0);
212 // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed
213 // when the UART is enabled"
214 MmioWrite32 (UartBase
+ UARTCR
, 0);
216 // Set Baud Rate Registers
217 MmioWrite32 (UartBase
+ UARTIBRD
, Integer
);
218 MmioWrite32 (UartBase
+ UARTFBRD
, Fractional
);
220 // No parity, 1 stop, no fifo, 8 data bits
221 MmioWrite32 (UartBase
+ UARTLCR_H
, LineControl
);
223 // Clear any pending errors
224 MmioWrite32 (UartBase
+ UARTECR
, 0);
226 // Enable Tx, Rx, and UART overall
227 MmioWrite32 (UartBase
+ UARTCR
,
228 PL011_UARTCR_RXE
| PL011_UARTCR_TXE
| PL011_UARTCR_UARTEN
);
230 return RETURN_SUCCESS
;
235 Assert or deassert the control signals on a serial port.
236 The following control signals are set according their bit settings :
238 . Data Terminal Ready
240 @param[in] UartBase UART registers base address
241 @param[in] Control The following bits are taken into account :
242 . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the
243 "Request To Send" control signal if this bit is
245 . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert
246 the "Data Terminal Ready" control signal if this
247 bit is equal to one/zero.
248 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable
249 the hardware loopback if this bit is equal to
251 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported.
252 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/
253 disable the hardware flow control based on CTS (Clear
254 To Send) and RTS (Ready To Send) control signals.
256 @retval RETURN_SUCCESS The new control bits were set on the device.
257 @retval RETURN_UNSUPPORTED The device does not support this operation.
262 PL011UartSetControl (
269 if (Control
& (mInvalidControlBits
)) {
270 return RETURN_UNSUPPORTED
;
273 Bits
= MmioRead32 (UartBase
+ UARTCR
);
275 if (Control
& EFI_SERIAL_REQUEST_TO_SEND
) {
276 Bits
|= PL011_UARTCR_RTS
;
278 Bits
&= ~PL011_UARTCR_RTS
;
281 if (Control
& EFI_SERIAL_DATA_TERMINAL_READY
) {
282 Bits
|= PL011_UARTCR_DTR
;
284 Bits
&= ~PL011_UARTCR_DTR
;
287 if (Control
& EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
) {
288 Bits
|= PL011_UARTCR_LBE
;
290 Bits
&= ~PL011_UARTCR_LBE
;
293 if (Control
& EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
) {
294 Bits
|= (PL011_UARTCR_CTSEN
| PL011_UARTCR_RTSEN
);
296 Bits
&= ~(PL011_UARTCR_CTSEN
| PL011_UARTCR_RTSEN
);
299 MmioWrite32 (UartBase
+ UARTCR
, Bits
);
301 return RETURN_SUCCESS
;
306 Retrieve the status of the control bits on a serial device.
308 @param[in] UartBase UART registers base address
309 @param[out] Control Status of the control bits on a serial device :
311 . EFI_SERIAL_DATA_CLEAR_TO_SEND,
312 EFI_SERIAL_DATA_SET_READY,
313 EFI_SERIAL_RING_INDICATE,
314 EFI_SERIAL_CARRIER_DETECT,
315 EFI_SERIAL_REQUEST_TO_SEND,
316 EFI_SERIAL_DATA_TERMINAL_READY
317 are all related to the DTE (Data Terminal Equipment)
318 and DCE (Data Communication Equipment) modes of
319 operation of the serial device.
320 . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the
321 receive buffer is empty, 0 otherwise.
322 . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the
323 transmit buffer is empty, 0 otherwise.
324 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if
325 the hardware loopback is enabled (the ouput feeds the
326 receive buffer), 0 otherwise.
327 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if
328 a loopback is accomplished by software, 0 otherwise.
329 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to
330 one if the hardware flow control based on CTS (Clear
331 To Send) and RTS (Ready To Send) control signals is
332 enabled, 0 otherwise.
334 @retval RETURN_SUCCESS The control bits were read from the serial device.
339 PL011UartGetControl (
345 UINT32 ControlRegister
;
348 FlagRegister
= MmioRead32 (UartBase
+ UARTFR
);
349 ControlRegister
= MmioRead32 (UartBase
+ UARTCR
);
353 if ((FlagRegister
& PL011_UARTFR_CTS
) == PL011_UARTFR_CTS
) {
354 *Control
|= EFI_SERIAL_CLEAR_TO_SEND
;
357 if ((FlagRegister
& PL011_UARTFR_DSR
) == PL011_UARTFR_DSR
) {
358 *Control
|= EFI_SERIAL_DATA_SET_READY
;
361 if ((FlagRegister
& PL011_UARTFR_RI
) == PL011_UARTFR_RI
) {
362 *Control
|= EFI_SERIAL_RING_INDICATE
;
365 if ((FlagRegister
& PL011_UARTFR_DCD
) == PL011_UARTFR_DCD
) {
366 *Control
|= EFI_SERIAL_CARRIER_DETECT
;
369 if ((ControlRegister
& PL011_UARTCR_RTS
) == PL011_UARTCR_RTS
) {
370 *Control
|= EFI_SERIAL_REQUEST_TO_SEND
;
373 if ((ControlRegister
& PL011_UARTCR_DTR
) == PL011_UARTCR_DTR
) {
374 *Control
|= EFI_SERIAL_DATA_TERMINAL_READY
;
377 if ((FlagRegister
& PL011_UARTFR_RXFE
) == PL011_UARTFR_RXFE
) {
378 *Control
|= EFI_SERIAL_INPUT_BUFFER_EMPTY
;
381 if ((FlagRegister
& PL011_UARTFR_TXFE
) == PL011_UARTFR_TXFE
) {
382 *Control
|= EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
385 if ((ControlRegister
& (PL011_UARTCR_CTSEN
| PL011_UARTCR_RTSEN
))
386 == (PL011_UARTCR_CTSEN
| PL011_UARTCR_RTSEN
)) {
387 *Control
|= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
;
390 if ((ControlRegister
& PL011_UARTCR_LBE
) == PL011_UARTCR_LBE
) {
391 *Control
|= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
;
394 return RETURN_SUCCESS
;
398 Write data to serial device.
400 @param Buffer Point of data buffer which need to be written.
401 @param NumberOfBytes Number of output bytes which are cached in Buffer.
403 @retval 0 Write data failed.
404 @retval !0 Actual number of bytes written to serial device.
412 IN UINTN NumberOfBytes
415 UINT8
* CONST Final
= &Buffer
[NumberOfBytes
];
417 while (Buffer
< Final
) {
418 // Wait until UART able to accept another char
419 while ((MmioRead32 (UartBase
+ UARTFR
) & UART_TX_FULL_FLAG_MASK
));
421 MmioWrite8 (UartBase
+ UARTDR
, *Buffer
++);
424 return NumberOfBytes
;
428 Read data from serial device and save the data in buffer.
430 @param Buffer Point of data buffer which need to be written.
431 @param NumberOfBytes Number of output bytes which are cached in Buffer.
433 @retval 0 Read data failed.
434 @retval !0 Actual number of bytes read from serial device.
442 IN UINTN NumberOfBytes
447 for (Count
= 0; Count
< NumberOfBytes
; Count
++, Buffer
++) {
448 while ((MmioRead32 (UartBase
+ UARTFR
) & UART_RX_EMPTY_FLAG_MASK
) != 0);
449 *Buffer
= MmioRead8 (UartBase
+ UARTDR
);
452 return NumberOfBytes
;
456 Check to see if any data is available to be read from the debug device.
458 @retval EFI_SUCCESS At least one byte of data is available to be read
459 @retval EFI_NOT_READY No data is available to be read
460 @retval EFI_DEVICE_ERROR The serial device is not functioning properly
469 return ((MmioRead32 (UartBase
+ UARTFR
) & UART_RX_EMPTY_FLAG_MASK
) == 0);