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// EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE is the only
26// control bit that is not supported.
27//
28STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
29
64RETURN_STATUS
65EFIAPI
67 IN UINTN UartBase,
68 IN UINT32 UartClkInHz,
69 IN OUT UINT64 *BaudRate,
70 IN OUT UINT32 *ReceiveFifoDepth,
71 IN OUT EFI_PARITY_TYPE *Parity,
72 IN OUT UINT8 *DataBits,
73 IN OUT EFI_STOP_BITS_TYPE *StopBits
74 )
75{
76 UINT32 LineControl;
77 UINT32 Divisor;
78 UINT32 Integer;
79 UINT32 Fractional;
80 UINT32 HardwareFifoDepth;
81 UINT32 UartPid2;
82
83 HardwareFifoDepth = FixedPcdGet16 (PcdUartDefaultReceiveFifoDepth);
84 if (HardwareFifoDepth == 0) {
85 UartPid2 = MmioRead32 (UartBase + UARTPID2);
86 HardwareFifoDepth = (PL011_UARTPID2_VER (UartPid2) > PL011_VER_R1P4) ? 32 : 16;
87 }
88
89 // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept
90 // 1 char buffer as the minimum FIFO size. Because everything can be rounded
91 // down, there is no maximum FIFO size.
92 if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= HardwareFifoDepth)) {
93 // Enable FIFO
94 LineControl = PL011_UARTLCR_H_FEN;
95 *ReceiveFifoDepth = HardwareFifoDepth;
96 } else {
97 // Disable FIFO
98 LineControl = 0;
99 // Nothing else to do. 1 byte FIFO is default.
100 *ReceiveFifoDepth = 1;
101 }
102
103 //
104 // Parity
105 //
106 switch (*Parity) {
107 case DefaultParity:
108 *Parity = NoParity;
109 case NoParity:
110 // Nothing to do. Parity is disabled by default.
111 break;
112 case EvenParity:
113 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);
114 break;
115 case OddParity:
116 LineControl |= PL011_UARTLCR_H_PEN;
117 break;
118 case MarkParity:
119 LineControl |= (PL011_UARTLCR_H_PEN \
120 | PL011_UARTLCR_H_SPS \
121 | PL011_UARTLCR_H_EPS);
122 break;
123 case SpaceParity:
124 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);
125 break;
126 default:
128 }
129
130 //
131 // Data Bits
132 //
133 switch (*DataBits) {
134 case 0:
135 *DataBits = 8;
136 case 8:
137 LineControl |= PL011_UARTLCR_H_WLEN_8;
138 break;
139 case 7:
140 LineControl |= PL011_UARTLCR_H_WLEN_7;
141 break;
142 case 6:
143 LineControl |= PL011_UARTLCR_H_WLEN_6;
144 break;
145 case 5:
146 LineControl |= PL011_UARTLCR_H_WLEN_5;
147 break;
148 default:
150 }
151
152 //
153 // Stop Bits
154 //
155 switch (*StopBits) {
156 case DefaultStopBits:
157 *StopBits = OneStopBit;
158 case OneStopBit:
159 // Nothing to do. One stop bit is enabled by default.
160 break;
161 case TwoStopBits:
162 LineControl |= PL011_UARTLCR_H_STP2;
163 break;
164 case OneFiveStopBits:
165 // Only 1 or 2 stop bits are supported
166 default:
168 }
169
170 // Don't send the LineControl value to the PL011 yet,
171 // wait until after the Baud Rate setting.
172 // This ensures we do not mess up the UART settings halfway through
173 // in the rare case when there is an error with the Baud Rate.
174
175 //
176 // Baud Rate
177 //
178
179 // If PL011 Integer value has been defined then always ignore the BAUD rate
180 if (FixedPcdGet32 (PL011UartInteger) != 0) {
181 Integer = FixedPcdGet32 (PL011UartInteger);
182 Fractional = FixedPcdGet32 (PL011UartFractional);
183 } else {
184 // If BAUD rate is zero then replace it with the system default value
185 if (*BaudRate == 0) {
186 *BaudRate = FixedPcdGet32 (PcdSerialBaudRate);
187 if (*BaudRate == 0) {
189 }
190 }
191
192 if (0 == UartClkInHz) {
194 }
195
196 Divisor = (UartClkInHz * 4) / *BaudRate;
197 Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;
198 Fractional = Divisor & FRACTION_PART_MASK;
199 }
200
201 //
202 // If PL011 is already initialized, check the current settings
203 // and re-initialize only if the settings are different.
204 //
205 if (((MmioRead32 (UartBase + UARTCR) & PL011_UARTCR_UARTEN) != 0) &&
206 (MmioRead32 (UartBase + UARTLCR_H) == LineControl) &&
207 (MmioRead32 (UartBase + UARTIBRD) == Integer) &&
208 (MmioRead32 (UartBase + UARTFBRD) == Fractional))
209 {
210 // Nothing to do - already initialized with correct attributes
211 return RETURN_SUCCESS;
212 }
213
214 // Wait for the end of transmission
215 while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0) {
216 }
217
218 // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed
219 // when the UART is enabled"
220 MmioWrite32 (UartBase + UARTCR, 0);
221
222 // Set Baud Rate Registers
223 MmioWrite32 (UartBase + UARTIBRD, Integer);
224 MmioWrite32 (UartBase + UARTFBRD, Fractional);
225
226 // No parity, 1 stop, no fifo, 8 data bits
227 MmioWrite32 (UartBase + UARTLCR_H, LineControl);
228
229 // Clear any pending errors
230 MmioWrite32 (UartBase + UARTECR, 0);
231
232 // Enable Tx, Rx, and UART overall
234 UartBase + UARTCR,
235 PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN
236 );
237
238 return RETURN_SUCCESS;
239}
240
268RETURN_STATUS
269EFIAPI
271 IN UINTN UartBase,
272 IN UINT32 Control
273 )
274{
275 UINT32 Bits;
276
277 if ((Control & mInvalidControlBits) != 0) {
278 return RETURN_UNSUPPORTED;
279 }
280
281 Bits = MmioRead32 (UartBase + UARTCR);
282
283 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) != 0) {
284 Bits |= PL011_UARTCR_RTS;
285 } else {
286 Bits &= ~PL011_UARTCR_RTS;
287 }
288
289 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) != 0) {
290 Bits |= PL011_UARTCR_DTR;
291 } else {
292 Bits &= ~PL011_UARTCR_DTR;
293 }
294
295 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) != 0) {
296 Bits |= PL011_UARTCR_LBE;
297 } else {
298 Bits &= ~PL011_UARTCR_LBE;
299 }
300
301 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) != 0) {
302 Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
303 } else {
304 Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
305 }
306
307 MmioWrite32 (UartBase + UARTCR, Bits);
308
309 return RETURN_SUCCESS;
310}
311
345RETURN_STATUS
346EFIAPI
348 IN UINTN UartBase,
349 OUT UINT32 *Control
350 )
351{
352 UINT32 FlagRegister;
353 UINT32 ControlRegister;
354
355 FlagRegister = MmioRead32 (UartBase + UARTFR);
356 ControlRegister = MmioRead32 (UartBase + UARTCR);
357
358 *Control = 0;
359
360 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
361 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
362 }
363
364 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
365 *Control |= EFI_SERIAL_DATA_SET_READY;
366 }
367
368 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
369 *Control |= EFI_SERIAL_RING_INDICATE;
370 }
371
372 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
373 *Control |= EFI_SERIAL_CARRIER_DETECT;
374 }
375
376 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
377 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
378 }
379
380 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
381 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
382 }
383
384 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
385 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
386 }
387
388 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
389 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
390 }
391
392 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
393 == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
394 {
395 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
396 }
397
398 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
399 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
400 }
401
402 return RETURN_SUCCESS;
403}
404
415UINTN
416EFIAPI
418 IN UINTN UartBase,
419 IN UINT8 *Buffer,
420 IN UINTN NumberOfBytes
421 )
422{
423 UINT8 *CONST Final = &Buffer[NumberOfBytes];
424
425 while (Buffer < Final) {
426 // Wait until UART able to accept another char
427 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK)) {
428 }
429
430 MmioWrite8 (UartBase + UARTDR, *Buffer++);
431 }
432
433 return NumberOfBytes;
434}
435
446UINTN
447EFIAPI
449 IN UINTN UartBase,
450 OUT UINT8 *Buffer,
451 IN UINTN NumberOfBytes
452 )
453{
454 UINTN Count;
455
456 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
457 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0) {
458 }
459
460 *Buffer = MmioRead8 (UartBase + UARTDR);
461 }
462
463 return NumberOfBytes;
464}
465
473BOOLEAN
474EFIAPI
476 IN UINTN UartBase
477 )
478{
479 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
480}
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:66
RETURN_STATUS EFIAPI PL011UartSetControl(IN UINTN UartBase, IN UINT32 Control)
Definition: PL011UartLib.c:270
UINTN EFIAPI PL011UartWrite(IN UINTN UartBase, IN UINT8 *Buffer, IN UINTN NumberOfBytes)
Definition: PL011UartLib.c:417
UINTN EFIAPI PL011UartRead(IN UINTN UartBase, OUT UINT8 *Buffer, IN UINTN NumberOfBytes)
Definition: PL011UartLib.c:448
BOOLEAN EFIAPI PL011UartPoll(IN UINTN UartBase)
Definition: PL011UartLib.c:475
RETURN_STATUS EFIAPI PL011UartGetControl(IN UINTN UartBase, OUT UINT32 *Control)
Definition: PL011UartLib.c:347
#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