]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
3748972acbfc80f1077b9b928756a72cc77b5c75
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL011Uart / PL011Uart.c
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
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
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)) {
87 // Enable FIFO
88 LineControl = PL011_UARTLCR_H_FEN;
89 if (PL011_UARTPID2_VER (MmioRead32 (UartBase + UARTPID2)) > PL011_VER_R1P4)
90 *ReceiveFifoDepth = 32;
91 else
92 *ReceiveFifoDepth = 16;
93 } else {
94 // Disable FIFO
95 LineControl = 0;
96 // Nothing else to do. 1 byte FIFO is default.
97 *ReceiveFifoDepth = 1;
98 }
99
100 //
101 // Parity
102 //
103 switch (*Parity) {
104 case DefaultParity:
105 *Parity = NoParity;
106 case NoParity:
107 // Nothing to do. Parity is disabled by default.
108 break;
109 case EvenParity:
110 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);
111 break;
112 case OddParity:
113 LineControl |= PL011_UARTLCR_H_PEN;
114 break;
115 case MarkParity:
116 LineControl |= ( PL011_UARTLCR_H_PEN \
117 | PL011_UARTLCR_H_SPS \
118 | PL011_UARTLCR_H_EPS);
119 break;
120 case SpaceParity:
121 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);
122 break;
123 default:
124 return RETURN_INVALID_PARAMETER;
125 }
126
127 //
128 // Data Bits
129 //
130 switch (*DataBits) {
131 case 0:
132 *DataBits = 8;
133 case 8:
134 LineControl |= PL011_UARTLCR_H_WLEN_8;
135 break;
136 case 7:
137 LineControl |= PL011_UARTLCR_H_WLEN_7;
138 break;
139 case 6:
140 LineControl |= PL011_UARTLCR_H_WLEN_6;
141 break;
142 case 5:
143 LineControl |= PL011_UARTLCR_H_WLEN_5;
144 break;
145 default:
146 return RETURN_INVALID_PARAMETER;
147 }
148
149 //
150 // Stop Bits
151 //
152 switch (*StopBits) {
153 case DefaultStopBits:
154 *StopBits = OneStopBit;
155 case OneStopBit:
156 // Nothing to do. One stop bit is enabled by default.
157 break;
158 case TwoStopBits:
159 LineControl |= PL011_UARTLCR_H_STP2;
160 break;
161 case OneFiveStopBits:
162 // Only 1 or 2 stop bits are supported
163 default:
164 return RETURN_INVALID_PARAMETER;
165 }
166
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.
171
172 //
173 // Baud Rate
174 //
175
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);
180 } else {
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;
186 }
187 }
188 if (0 == UartClkInHz) {
189 return RETURN_INVALID_PARAMETER;
190 }
191
192 Divisor = (UartClkInHz * 4) / *BaudRate;
193 Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;
194 Fractional = Divisor & FRACTION_PART_MASK;
195 }
196
197 //
198 // If PL011 is already initialized, check the current settings
199 // and re-initialize only if the settings are different.
200 //
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;
207 }
208
209 // Wait for the end of transmission
210 while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0);
211
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);
215
216 // Set Baud Rate Registers
217 MmioWrite32 (UartBase + UARTIBRD, Integer);
218 MmioWrite32 (UartBase + UARTFBRD, Fractional);
219
220 // No parity, 1 stop, no fifo, 8 data bits
221 MmioWrite32 (UartBase + UARTLCR_H, LineControl);
222
223 // Clear any pending errors
224 MmioWrite32 (UartBase + UARTECR, 0);
225
226 // Enable Tx, Rx, and UART overall
227 MmioWrite32 (UartBase + UARTCR,
228 PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);
229
230 return RETURN_SUCCESS;
231 }
232
233 /**
234
235 Assert or deassert the control signals on a serial port.
236 The following control signals are set according their bit settings :
237 . Request to Send
238 . Data Terminal Ready
239
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
244 equal to one/zero.
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
250 one/zero.
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.
255
256 @retval RETURN_SUCCESS The new control bits were set on the device.
257 @retval RETURN_UNSUPPORTED The device does not support this operation.
258
259 **/
260 RETURN_STATUS
261 EFIAPI
262 PL011UartSetControl (
263 IN UINTN UartBase,
264 IN UINT32 Control
265 )
266 {
267 UINT32 Bits;
268
269 if (Control & (mInvalidControlBits)) {
270 return RETURN_UNSUPPORTED;
271 }
272
273 Bits = MmioRead32 (UartBase + UARTCR);
274
275 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
276 Bits |= PL011_UARTCR_RTS;
277 } else {
278 Bits &= ~PL011_UARTCR_RTS;
279 }
280
281 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
282 Bits |= PL011_UARTCR_DTR;
283 } else {
284 Bits &= ~PL011_UARTCR_DTR;
285 }
286
287 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
288 Bits |= PL011_UARTCR_LBE;
289 } else {
290 Bits &= ~PL011_UARTCR_LBE;
291 }
292
293 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
294 Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
295 } else {
296 Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
297 }
298
299 MmioWrite32 (UartBase + UARTCR, Bits);
300
301 return RETURN_SUCCESS;
302 }
303
304 /**
305
306 Retrieve the status of the control bits on a serial device.
307
308 @param[in] UartBase UART registers base address
309 @param[out] Control Status of the control bits on a serial device :
310
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.
333
334 @retval RETURN_SUCCESS The control bits were read from the serial device.
335
336 **/
337 RETURN_STATUS
338 EFIAPI
339 PL011UartGetControl (
340 IN UINTN UartBase,
341 OUT UINT32 *Control
342 )
343 {
344 UINT32 FlagRegister;
345 UINT32 ControlRegister;
346
347
348 FlagRegister = MmioRead32 (UartBase + UARTFR);
349 ControlRegister = MmioRead32 (UartBase + UARTCR);
350
351 *Control = 0;
352
353 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
354 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
355 }
356
357 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
358 *Control |= EFI_SERIAL_DATA_SET_READY;
359 }
360
361 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
362 *Control |= EFI_SERIAL_RING_INDICATE;
363 }
364
365 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
366 *Control |= EFI_SERIAL_CARRIER_DETECT;
367 }
368
369 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
370 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
371 }
372
373 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
374 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
375 }
376
377 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
378 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
379 }
380
381 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
382 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
383 }
384
385 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
386 == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {
387 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
388 }
389
390 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
391 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
392 }
393
394 return RETURN_SUCCESS;
395 }
396
397 /**
398 Write data to serial device.
399
400 @param Buffer Point of data buffer which need to be written.
401 @param NumberOfBytes Number of output bytes which are cached in Buffer.
402
403 @retval 0 Write data failed.
404 @retval !0 Actual number of bytes written to serial device.
405
406 **/
407 UINTN
408 EFIAPI
409 PL011UartWrite (
410 IN UINTN UartBase,
411 IN UINT8 *Buffer,
412 IN UINTN NumberOfBytes
413 )
414 {
415 UINT8* CONST Final = &Buffer[NumberOfBytes];
416
417 while (Buffer < Final) {
418 // Wait until UART able to accept another char
419 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));
420
421 MmioWrite8 (UartBase + UARTDR, *Buffer++);
422 }
423
424 return NumberOfBytes;
425 }
426
427 /**
428 Read data from serial device and save the data in buffer.
429
430 @param Buffer Point of data buffer which need to be written.
431 @param NumberOfBytes Number of output bytes which are cached in Buffer.
432
433 @retval 0 Read data failed.
434 @retval !0 Actual number of bytes read from serial device.
435
436 **/
437 UINTN
438 EFIAPI
439 PL011UartRead (
440 IN UINTN UartBase,
441 OUT UINT8 *Buffer,
442 IN UINTN NumberOfBytes
443 )
444 {
445 UINTN Count;
446
447 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
448 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);
449 *Buffer = MmioRead8 (UartBase + UARTDR);
450 }
451
452 return NumberOfBytes;
453 }
454
455 /**
456 Check to see if any data is available to be read from the debug device.
457
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
461
462 **/
463 BOOLEAN
464 EFIAPI
465 PL011UartPoll (
466 IN UINTN UartBase
467 )
468 {
469 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
470 }