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