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