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