TianoCore EDK2 master
Loading...
Searching...
No Matches
PL011UartLib.c
Go to the documentation of this file.
1
11#include <Uefi.h>
12
13#include <Library/DebugLib.h>
14#include <Library/IoLib.h>
15#include <Library/PcdLib.h>
16
17#include <Protocol/SerialIo.h>
18
19#include "PL011Uart.h"
20
21#define FRACTION_PART_SIZE_IN_BITS 6
22#define FRACTION_PART_MASK ((1 << FRACTION_PART_SIZE_IN_BITS) - 1)
23
24//
25// Per UEFI spec, only these control bits are allowed to be set.
26//
27STATIC CONST UINT32 mAllowedControlBits =
28 EFI_SERIAL_REQUEST_TO_SEND |
29 EFI_SERIAL_DATA_TERMINAL_READY |
30 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE |
31 EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
32 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
33
34//
35// platform-specific bits that are not supported by this device.
36//
37STATIC CONST UINT32 mPlatformInvalidControlBits =
38 EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
39
74RETURN_STATUS
75EFIAPI
77 IN UINTN UartBase,
78 IN UINT32 UartClkInHz,
79 IN OUT UINT64 *BaudRate,
80 IN OUT UINT32 *ReceiveFifoDepth,
81 IN OUT EFI_PARITY_TYPE *Parity,
82 IN OUT UINT8 *DataBits,
83 IN OUT EFI_STOP_BITS_TYPE *StopBits
84 )
85{
86 UINT32 LineControl;
87 UINT32 Divisor;
88 UINT32 Integer;
89 UINT32 Fractional;
90 UINT32 HardwareFifoDepth;
91 UINT32 UartPid2;
92
93 HardwareFifoDepth = FixedPcdGet16 (PcdUartDefaultReceiveFifoDepth);
94 if (HardwareFifoDepth == 0) {
95 UartPid2 = MmioRead32 (UartBase + UARTPID2);
96 HardwareFifoDepth = (PL011_UARTPID2_VER (UartPid2) > PL011_VER_R1P4) ? 32 : 16;
97 }
98
99 // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept
100 // 1 char buffer as the minimum FIFO size. Because everything can be rounded
101 // down, there is no maximum FIFO size.
102 if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= HardwareFifoDepth)) {
103 // Enable FIFO
104 LineControl = PL011_UARTLCR_H_FEN;
105 *ReceiveFifoDepth = HardwareFifoDepth;
106 } else {
107 // Disable FIFO
108 LineControl = 0;
109 // Nothing else to do. 1 byte FIFO is default.
110 *ReceiveFifoDepth = 1;
111 }
112
113 //
114 // Parity
115 //
116 switch (*Parity) {
117 case DefaultParity:
118 *Parity = NoParity;
119 case NoParity:
120 // Nothing to do. Parity is disabled by default.
121 break;
122 case EvenParity:
123 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);
124 break;
125 case OddParity:
126 LineControl |= PL011_UARTLCR_H_PEN;
127 break;
128 case MarkParity:
129 LineControl |= (PL011_UARTLCR_H_PEN \
130 | PL011_UARTLCR_H_SPS \
131 | PL011_UARTLCR_H_EPS);
132 break;
133 case SpaceParity:
134 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);
135 break;
136 default:
138 }
139
140 //
141 // Data Bits
142 //
143 switch (*DataBits) {
144 case 0:
145 *DataBits = 8;
146 case 8:
147 LineControl |= PL011_UARTLCR_H_WLEN_8;
148 break;
149 case 7:
150 LineControl |= PL011_UARTLCR_H_WLEN_7;
151 break;
152 case 6:
153 LineControl |= PL011_UARTLCR_H_WLEN_6;
154 break;
155 case 5:
156 LineControl |= PL011_UARTLCR_H_WLEN_5;
157 break;
158 default:
160 }
161
162 //
163 // Stop Bits
164 //
165 switch (*StopBits) {
166 case DefaultStopBits:
167 *StopBits = OneStopBit;
168 case OneStopBit:
169 // Nothing to do. One stop bit is enabled by default.
170 break;
171 case TwoStopBits:
172 LineControl |= PL011_UARTLCR_H_STP2;
173 break;
174 case OneFiveStopBits:
175 // Only 1 or 2 stop bits are supported
176 default:
178 }
179
180 // Don't send the LineControl value to the PL011 yet,
181 // wait until after the Baud Rate setting.
182 // This ensures we do not mess up the UART settings halfway through
183 // in the rare case when there is an error with the Baud Rate.
184
185 //
186 // Baud Rate
187 //
188
189 // If PL011 Integer value has been defined then always ignore the BAUD rate
190 if (FixedPcdGet32 (PL011UartInteger) != 0) {
191 Integer = FixedPcdGet32 (PL011UartInteger);
192 Fractional = FixedPcdGet32 (PL011UartFractional);
193 } else {
194 // If BAUD rate is zero then replace it with the system default value
195 if (*BaudRate == 0) {
196 *BaudRate = FixedPcdGet32 (PcdSerialBaudRate);
197 if (*BaudRate == 0) {
199 }
200 }
201
202 if (0 == UartClkInHz) {
204 }
205
206 Divisor = (UINT32)((UartClkInHz * 4) / *BaudRate);
207 Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;
208 Fractional = Divisor & FRACTION_PART_MASK;
209 }
210
211 //
212 // If PL011 is already initialized, check the current settings
213 // and re-initialize only if the settings are different.
214 //
215 if (((MmioRead32 (UartBase + UARTCR) & PL011_UARTCR_UARTEN) != 0) &&
216 (MmioRead32 (UartBase + UARTLCR_H) == LineControl) &&
217 (MmioRead32 (UartBase + UARTIBRD) == Integer) &&
218 (MmioRead32 (UartBase + UARTFBRD) == Fractional))
219 {
220 // Nothing to do - already initialized with correct attributes
221 return RETURN_SUCCESS;
222 }
223
224 // Wait for the end of transmission
225 while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0) {
226 }
227
228 // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed
229 // when the UART is enabled"
230 MmioWrite32 (UartBase + UARTCR, 0);
231
232 // Set Baud Rate Registers
233 MmioWrite32 (UartBase + UARTIBRD, Integer);
234 MmioWrite32 (UartBase + UARTFBRD, Fractional);
235
236 // No parity, 1 stop, no fifo, 8 data bits
237 MmioWrite32 (UartBase + UARTLCR_H, LineControl);
238
239 // Clear any pending errors
240 MmioWrite32 (UartBase + UARTECR, 0);
241
242 // Enable Tx, Rx, and UART overall
244 UartBase + UARTCR,
245 PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN
246 );
247
248 return RETURN_SUCCESS;
249}
250
278RETURN_STATUS
279EFIAPI
281 IN UINTN UartBase,
282 IN UINT32 Control
283 )
284{
285 UINT32 Bits;
286
287 if ((Control & ~mAllowedControlBits) != 0) {
288 return RETURN_UNSUPPORTED;
289 }
290
291 if ((Control & mPlatformInvalidControlBits) != 0) {
292 return RETURN_UNSUPPORTED;
293 }
294
295 Bits = MmioRead32 (UartBase + UARTCR);
296
297 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) != 0) {
298 Bits |= PL011_UARTCR_RTS;
299 } else {
300 Bits &= ~PL011_UARTCR_RTS;
301 }
302
303 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) != 0) {
304 Bits |= PL011_UARTCR_DTR;
305 } else {
306 Bits &= ~PL011_UARTCR_DTR;
307 }
308
309 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) != 0) {
310 Bits |= PL011_UARTCR_LBE;
311 } else {
312 Bits &= ~PL011_UARTCR_LBE;
313 }
314
315 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) != 0) {
316 Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
317 } else {
318 Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
319 }
320
321 MmioWrite32 (UartBase + UARTCR, Bits);
322
323 return RETURN_SUCCESS;
324}
325
359RETURN_STATUS
360EFIAPI
362 IN UINTN UartBase,
363 OUT UINT32 *Control
364 )
365{
366 UINT32 FlagRegister;
367 UINT32 ControlRegister;
368
369 FlagRegister = MmioRead32 (UartBase + UARTFR);
370 ControlRegister = MmioRead32 (UartBase + UARTCR);
371
372 *Control = 0;
373
374 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
375 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
376 }
377
378 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
379 *Control |= EFI_SERIAL_DATA_SET_READY;
380 }
381
382 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
383 *Control |= EFI_SERIAL_RING_INDICATE;
384 }
385
386 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
387 *Control |= EFI_SERIAL_CARRIER_DETECT;
388 }
389
390 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
391 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
392 }
393
394 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
395 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
396 }
397
398 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
399 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
400 }
401
402 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
403 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
404 }
405
406 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
407 == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
408 {
409 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
410 }
411
412 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
413 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
414 }
415
416 return RETURN_SUCCESS;
417}
418
429UINTN
430EFIAPI
432 IN UINTN UartBase,
433 IN UINT8 *Buffer,
434 IN UINTN NumberOfBytes
435 )
436{
437 UINT8 *CONST Final = &Buffer[NumberOfBytes];
438
439 while (Buffer < Final) {
440 // Wait until UART able to accept another char
441 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK)) {
442 }
443
444 MmioWrite8 (UartBase + UARTDR, *Buffer++);
445 }
446
447 return NumberOfBytes;
448}
449
460UINTN
461EFIAPI
463 IN UINTN UartBase,
464 OUT UINT8 *Buffer,
465 IN UINTN NumberOfBytes
466 )
467{
468 UINTN Count;
469
470 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
471 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0) {
472 }
473
474 *Buffer = MmioRead8 (UartBase + UARTDR);
475 }
476
477 return NumberOfBytes;
478}
479
487BOOLEAN
488EFIAPI
490 IN UINTN UartBase
491 )
492{
493 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
494}
UINT64 UINTN
UINT8 EFIAPI MmioRead8(IN UINTN Address)
Definition: IoLib.c:82
UINT8 EFIAPI MmioWrite8(IN UINTN Address, IN UINT8 Value)
Definition: IoLib.c:126
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition: IoLib.c:262
UINT32 EFIAPI MmioWrite32(IN UINTN Address, IN UINT32 Value)
Definition: IoLib.c:309
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define RETURN_UNSUPPORTED
Definition: Base.h:1081
#define RETURN_SUCCESS
Definition: Base.h:1066
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define RETURN_INVALID_PARAMETER
Definition: Base.h:1076
RETURN_STATUS EFIAPI PL011UartInitializePort(IN UINTN UartBase, IN UINT32 UartClkInHz, IN OUT UINT64 *BaudRate, IN OUT UINT32 *ReceiveFifoDepth, IN OUT EFI_PARITY_TYPE *Parity, IN OUT UINT8 *DataBits, IN OUT EFI_STOP_BITS_TYPE *StopBits)
Definition: PL011UartLib.c:76
RETURN_STATUS EFIAPI PL011UartSetControl(IN UINTN UartBase, IN UINT32 Control)
Definition: PL011UartLib.c:280
UINTN EFIAPI PL011UartWrite(IN UINTN UartBase, IN UINT8 *Buffer, IN UINTN NumberOfBytes)
Definition: PL011UartLib.c:431
UINTN EFIAPI PL011UartRead(IN UINTN UartBase, OUT UINT8 *Buffer, IN UINTN NumberOfBytes)
Definition: PL011UartLib.c:462
BOOLEAN EFIAPI PL011UartPoll(IN UINTN UartBase)
Definition: PL011UartLib.c:489
RETURN_STATUS EFIAPI PL011UartGetControl(IN UINTN UartBase, OUT UINT32 *Control)
Definition: PL011UartLib.c:361
#define FixedPcdGet32(TokenName)
Definition: PcdLib.h:92
#define FixedPcdGet16(TokenName)
Definition: PcdLib.h:78
EFI_STOP_BITS_TYPE
Definition: SerialIo.h:53
EFI_PARITY_TYPE
Definition: SerialIo.h:41