]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
ArmPlatformPkg: Add support to configure PL011 UART clock
[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 All unspecified settings will be set to the default values.
36
37 @param UartBase The base address of the serial device.
38 @param UartClkInHz The clock in Hz for the serial device.
39 Ignored if the PCD PL011UartInteger is not 0
40 @param BaudRate The baud rate of the serial device. If the
41 baud rate is not supported, the speed will be
42 reduced to the nearest supported one and the
43 variable's value will be updated accordingly.
44 @param ReceiveFifoDepth The number of characters the device will
45 buffer on input. Value of 0 will use the
46 device's default FIFO depth.
47 @param Parity If applicable, this is the EFI_PARITY_TYPE
48 that is computed or checked as each character
49 is transmitted or received. If the device
50 does not support parity, the value is the
51 default parity value.
52 @param DataBits The number of data bits in each character.
53 @param StopBits If applicable, the EFI_STOP_BITS_TYPE number
54 of stop bits per character.
55 If the device does not support stop bits, the
56 value is the default stop bit value.
57
58 @retval RETURN_SUCCESS All attributes were set correctly on the
59 serial device.
60 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an
61 unsupported value.
62
63 **/
64 RETURN_STATUS
65 EFIAPI
66 PL011UartInitializePort (
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
81 // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept
82 // 1 char buffer as the minimum FIFO size. Because everything can be rounded
83 // down, there is no maximum FIFO size.
84 if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= 32)) {
85 // Enable FIFO
86 LineControl = PL011_UARTLCR_H_FEN;
87 if (PL011_UARTPID2_VER (MmioRead32 (UartBase + UARTPID2)) > PL011_VER_R1P4)
88 *ReceiveFifoDepth = 32;
89 else
90 *ReceiveFifoDepth = 16;
91 } else {
92 // Disable FIFO
93 LineControl = 0;
94 // Nothing else to do. 1 byte FIFO is default.
95 *ReceiveFifoDepth = 1;
96 }
97
98 //
99 // Parity
100 //
101 switch (*Parity) {
102 case DefaultParity:
103 *Parity = NoParity;
104 case NoParity:
105 // Nothing to do. Parity is disabled by default.
106 break;
107 case EvenParity:
108 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);
109 break;
110 case OddParity:
111 LineControl |= PL011_UARTLCR_H_PEN;
112 break;
113 case MarkParity:
114 LineControl |= ( PL011_UARTLCR_H_PEN \
115 | PL011_UARTLCR_H_SPS \
116 | PL011_UARTLCR_H_EPS);
117 break;
118 case SpaceParity:
119 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);
120 break;
121 default:
122 return RETURN_INVALID_PARAMETER;
123 }
124
125 //
126 // Data Bits
127 //
128 switch (*DataBits) {
129 case 0:
130 *DataBits = 8;
131 case 8:
132 LineControl |= PL011_UARTLCR_H_WLEN_8;
133 break;
134 case 7:
135 LineControl |= PL011_UARTLCR_H_WLEN_7;
136 break;
137 case 6:
138 LineControl |= PL011_UARTLCR_H_WLEN_6;
139 break;
140 case 5:
141 LineControl |= PL011_UARTLCR_H_WLEN_5;
142 break;
143 default:
144 return RETURN_INVALID_PARAMETER;
145 }
146
147 //
148 // Stop Bits
149 //
150 switch (*StopBits) {
151 case DefaultStopBits:
152 *StopBits = OneStopBit;
153 case OneStopBit:
154 // Nothing to do. One stop bit is enabled by default.
155 break;
156 case TwoStopBits:
157 LineControl |= PL011_UARTLCR_H_STP2;
158 break;
159 case OneFiveStopBits:
160 // Only 1 or 2 stop bits are supported
161 default:
162 return RETURN_INVALID_PARAMETER;
163 }
164
165 // Don't send the LineControl value to the PL011 yet,
166 // wait until after the Baud Rate setting.
167 // This ensures we do not mess up the UART settings halfway through
168 // in the rare case when there is an error with the Baud Rate.
169
170 //
171 // Baud Rate
172 //
173
174 // If PL011 Integer value has been defined then always ignore the BAUD rate
175 if (FixedPcdGet32 (PL011UartInteger) != 0) {
176 Integer = FixedPcdGet32 (PL011UartInteger);
177 Fractional = FixedPcdGet32 (PL011UartFractional);
178 } else {
179 // If BAUD rate is zero then replace it with the system default value
180 if (*BaudRate == 0) {
181 *BaudRate = FixedPcdGet32 (PcdSerialBaudRate);
182 if (*BaudRate == 0) {
183 return RETURN_INVALID_PARAMETER;
184 }
185 }
186 if (0 == UartClkInHz) {
187 return RETURN_INVALID_PARAMETER;
188 }
189
190 Divisor = (UartClkInHz * 4) / *BaudRate;
191 Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;
192 Fractional = Divisor & FRACTION_PART_MASK;
193 }
194 // Set Baud Rate Registers
195 MmioWrite32 (UartBase + UARTIBRD, Integer);
196 MmioWrite32 (UartBase + UARTFBRD, Fractional);
197
198 // No parity, 1 stop, no fifo, 8 data bits
199 MmioWrite32 (UartBase + UARTLCR_H, LineControl);
200
201 // Clear any pending errors
202 MmioWrite32 (UartBase + UARTECR, 0);
203
204 // Enable Tx, Rx, and UART overall
205 MmioWrite32 (UartBase + UARTCR,
206 PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);
207
208 return RETURN_SUCCESS;
209 }
210
211 /**
212
213 Assert or deassert the control signals on a serial port.
214 The following control signals are set according their bit settings :
215 . Request to Send
216 . Data Terminal Ready
217
218 @param[in] UartBase UART registers base address
219 @param[in] Control The following bits are taken into account :
220 . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the
221 "Request To Send" control signal if this bit is
222 equal to one/zero.
223 . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert
224 the "Data Terminal Ready" control signal if this
225 bit is equal to one/zero.
226 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable
227 the hardware loopback if this bit is equal to
228 one/zero.
229 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported.
230 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/
231 disable the hardware flow control based on CTS (Clear
232 To Send) and RTS (Ready To Send) control signals.
233
234 @retval RETURN_SUCCESS The new control bits were set on the device.
235 @retval RETURN_UNSUPPORTED The device does not support this operation.
236
237 **/
238 RETURN_STATUS
239 EFIAPI
240 PL011UartSetControl (
241 IN UINTN UartBase,
242 IN UINT32 Control
243 )
244 {
245 UINT32 Bits;
246
247 if (Control & (mInvalidControlBits)) {
248 return RETURN_UNSUPPORTED;
249 }
250
251 Bits = MmioRead32 (UartBase + UARTCR);
252
253 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
254 Bits |= PL011_UARTCR_RTS;
255 } else {
256 Bits &= ~PL011_UARTCR_RTS;
257 }
258
259 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
260 Bits |= PL011_UARTCR_DTR;
261 } else {
262 Bits &= ~PL011_UARTCR_DTR;
263 }
264
265 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
266 Bits |= PL011_UARTCR_LBE;
267 } else {
268 Bits &= ~PL011_UARTCR_LBE;
269 }
270
271 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
272 Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
273 } else {
274 Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
275 }
276
277 MmioWrite32 (UartBase + UARTCR, Bits);
278
279 return RETURN_SUCCESS;
280 }
281
282 /**
283
284 Retrieve the status of the control bits on a serial device.
285
286 @param[in] UartBase UART registers base address
287 @param[out] Control Status of the control bits on a serial device :
288
289 . EFI_SERIAL_DATA_CLEAR_TO_SEND,
290 EFI_SERIAL_DATA_SET_READY,
291 EFI_SERIAL_RING_INDICATE,
292 EFI_SERIAL_CARRIER_DETECT,
293 EFI_SERIAL_REQUEST_TO_SEND,
294 EFI_SERIAL_DATA_TERMINAL_READY
295 are all related to the DTE (Data Terminal Equipment)
296 and DCE (Data Communication Equipment) modes of
297 operation of the serial device.
298 . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the
299 receive buffer is empty, 0 otherwise.
300 . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the
301 transmit buffer is empty, 0 otherwise.
302 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if
303 the hardware loopback is enabled (the ouput feeds the
304 receive buffer), 0 otherwise.
305 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if
306 a loopback is accomplished by software, 0 otherwise.
307 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to
308 one if the hardware flow control based on CTS (Clear
309 To Send) and RTS (Ready To Send) control signals is
310 enabled, 0 otherwise.
311
312 @retval RETURN_SUCCESS The control bits were read from the serial device.
313
314 **/
315 RETURN_STATUS
316 EFIAPI
317 PL011UartGetControl (
318 IN UINTN UartBase,
319 OUT UINT32 *Control
320 )
321 {
322 UINT32 FlagRegister;
323 UINT32 ControlRegister;
324
325
326 FlagRegister = MmioRead32 (UartBase + UARTFR);
327 ControlRegister = MmioRead32 (UartBase + UARTCR);
328
329 *Control = 0;
330
331 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
332 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
333 }
334
335 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
336 *Control |= EFI_SERIAL_DATA_SET_READY;
337 }
338
339 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
340 *Control |= EFI_SERIAL_RING_INDICATE;
341 }
342
343 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
344 *Control |= EFI_SERIAL_CARRIER_DETECT;
345 }
346
347 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
348 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
349 }
350
351 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
352 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
353 }
354
355 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
356 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
357 }
358
359 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
360 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
361 }
362
363 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
364 == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {
365 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
366 }
367
368 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
369 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
370 }
371
372 return RETURN_SUCCESS;
373 }
374
375 /**
376 Write data to serial device.
377
378 @param Buffer Point of data buffer which need to be written.
379 @param NumberOfBytes Number of output bytes which are cached in Buffer.
380
381 @retval 0 Write data failed.
382 @retval !0 Actual number of bytes written to serial device.
383
384 **/
385 UINTN
386 EFIAPI
387 PL011UartWrite (
388 IN UINTN UartBase,
389 IN UINT8 *Buffer,
390 IN UINTN NumberOfBytes
391 )
392 {
393 UINT8* CONST Final = &Buffer[NumberOfBytes];
394
395 while (Buffer < Final) {
396 // Wait until UART able to accept another char
397 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));
398
399 MmioWrite8 (UartBase + UARTDR, *Buffer++);
400 }
401
402 return NumberOfBytes;
403 }
404
405 /**
406 Read data from serial device and save the data in buffer.
407
408 @param Buffer Point of data buffer which need to be written.
409 @param NumberOfBytes Number of output bytes which are cached in Buffer.
410
411 @retval 0 Read data failed.
412 @retval !0 Actual number of bytes read from serial device.
413
414 **/
415 UINTN
416 EFIAPI
417 PL011UartRead (
418 IN UINTN UartBase,
419 OUT UINT8 *Buffer,
420 IN UINTN NumberOfBytes
421 )
422 {
423 UINTN Count;
424
425 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
426 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);
427 *Buffer = MmioRead8 (UartBase + UARTDR);
428 }
429
430 return NumberOfBytes;
431 }
432
433 /**
434 Check to see if any data is available to be read from the debug device.
435
436 @retval EFI_SUCCESS At least one byte of data is available to be read
437 @retval EFI_NOT_READY No data is available to be read
438 @retval EFI_DEVICE_ERROR The serial device is not functioning properly
439
440 **/
441 BOOLEAN
442 EFIAPI
443 PL011UartPoll (
444 IN UINTN UartBase
445 )
446 {
447 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
448 }