]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
EmbeddedPkg: Clarify the declaration of SerialPortSetControl()
[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 Get the serial device control bits.
240
241 @param UartBase The base address of the PL011 UART.
242 @param Control Control signals read from the serial device.
243
244 @retval EFI_SUCCESS The control bits were read from the serial device.
245 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
246
247 **/
248 RETURN_STATUS
249 EFIAPI
250 PL011UartGetControl (
251 IN UINTN UartBase,
252 OUT UINT32 *Control
253 )
254 {
255 UINT32 FlagRegister;
256 UINT32 ControlRegister;
257
258
259 FlagRegister = MmioRead32 (UartBase + UARTFR);
260 ControlRegister = MmioRead32 (UartBase + UARTCR);
261
262 *Control = 0;
263
264 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
265 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
266 }
267
268 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
269 *Control |= EFI_SERIAL_DATA_SET_READY;
270 }
271
272 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
273 *Control |= EFI_SERIAL_RING_INDICATE;
274 }
275
276 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
277 *Control |= EFI_SERIAL_CARRIER_DETECT;
278 }
279
280 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
281 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
282 }
283
284 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
285 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
286 }
287
288 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
289 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
290 }
291
292 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
293 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
294 }
295
296 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {
297 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
298 }
299
300 #ifdef NEVER
301 // ToDo: Implement EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
302 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
303 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
304 }
305
306 // ToDo: Implement EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
307 if (SoftwareLoopbackEnable) {
308 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
309 }
310 #endif
311
312 return RETURN_SUCCESS;
313 }
314
315 /**
316 Write data to serial device.
317
318 @param Buffer Point of data buffer which need to be written.
319 @param NumberOfBytes Number of output bytes which are cached in Buffer.
320
321 @retval 0 Write data failed.
322 @retval !0 Actual number of bytes written to serial device.
323
324 **/
325 UINTN
326 EFIAPI
327 PL011UartWrite (
328 IN UINTN UartBase,
329 IN UINT8 *Buffer,
330 IN UINTN NumberOfBytes
331 )
332 {
333 UINT8* CONST Final = &Buffer[NumberOfBytes];
334
335 while (Buffer < Final) {
336 // Wait until UART able to accept another char
337 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));
338
339 MmioWrite8 (UartBase + UARTDR, *Buffer++);
340 }
341
342 return NumberOfBytes;
343 }
344
345 /**
346 Read data from serial device and save the data in buffer.
347
348 @param Buffer Point of data buffer which need to be written.
349 @param NumberOfBytes Number of output bytes which are cached in Buffer.
350
351 @retval 0 Read data failed.
352 @retval !0 Actual number of bytes read from serial device.
353
354 **/
355 UINTN
356 EFIAPI
357 PL011UartRead (
358 IN UINTN UartBase,
359 OUT UINT8 *Buffer,
360 IN UINTN NumberOfBytes
361 )
362 {
363 UINTN Count;
364
365 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
366 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);
367 *Buffer = MmioRead8 (UartBase + UARTDR);
368 }
369
370 return NumberOfBytes;
371 }
372
373 /**
374 Check to see if any data is available to be read from the debug device.
375
376 @retval EFI_SUCCESS At least one byte of data is available to be read
377 @retval EFI_NOT_READY No data is available to be read
378 @retval EFI_DEVICE_ERROR The serial device is not functioning properly
379
380 **/
381 BOOLEAN
382 EFIAPI
383 PL011UartPoll (
384 IN UINTN UartBase
385 )
386 {
387 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
388 }