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
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)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
PL011UartSetControl(IN UINTN UartBase,IN UINT32 Control)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
PL011UartGetControl(IN UINTN UartBase,OUT UINT32 * Control)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
PL011UartWrite(IN UINTN UartBase,IN UINT8 * Buffer,IN UINTN NumberOfBytes)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
PL011UartRead(IN UINTN UartBase,OUT UINT8 * Buffer,IN UINTN NumberOfBytes)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
PL011UartPoll(IN UINTN UartBase)465 PL011UartPoll (
466 IN UINTN UartBase
467 )
468 {
469 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
470 }
471