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