]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
EmbeddedPkg/SerialPortExtLib.h: Changed SerialPortSetAttributes() prototype to return...
[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 BaudRate is zero then use default baud rate
134 if (BaudRate == 0) {
135 if (PcdGet32 (PL011UartInteger) != 0) {
136 MmioWrite32 (UartBase + UARTIBRD, PcdGet32 (PL011UartInteger));
137 MmioWrite32 (UartBase + UARTFBRD, PcdGet32 (PL011UartFractional));
138 } else {
139 *BaudRate = PcdGet32 (PcdSerialBaudRate);
140 ASSERT (*BaudRate != 0);
141 }
142 }
143
144 // If BaudRate != 0 then we must calculate the divisor from the value
145 if (*BaudRate != 0) {
146 Divisor = (PcdGet32 (PL011UartClkInHz) * 4) / *BaudRate;
147 MmioWrite32 (UartBase + UARTIBRD, Divisor >> 6);
148 MmioWrite32 (UartBase + UARTFBRD, Divisor & 0x3F);
149 }
150
151 // No parity, 1 stop, no fifo, 8 data bits
152 MmioWrite32 (UartBase + UARTLCR_H, LineControl);
153
154 // Clear any pending errors
155 MmioWrite32 (UartBase + UARTECR, 0);
156
157 // Enable tx, rx, and uart overall
158 MmioWrite32 (UartBase + UARTCR, PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);
159
160 return RETURN_SUCCESS;
161 }
162
163 /**
164 Set the serial device control bits.
165
166 @param UartBase The base address of the PL011 UART.
167 @param Control Control bits which are to be set on the serial device.
168
169 @retval EFI_SUCCESS The new control bits were set on the serial device.
170 @retval EFI_UNSUPPORTED The serial device does not support this operation.
171 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
172
173 **/
174 RETURN_STATUS
175 EFIAPI
176 PL011UartSetControl (
177 IN UINTN UartBase,
178 IN UINT32 Control
179 )
180 {
181 UINT32 Bits;
182 UINT32 ValidControlBits;
183
184 ValidControlBits = ( EFI_SERIAL_REQUEST_TO_SEND
185 | EFI_SERIAL_DATA_TERMINAL_READY
186 // | EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE // Not implemented yet.
187 // | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE // Not implemented yet.
188 | EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
189 );
190
191 if (Control & (~ValidControlBits)) {
192 return EFI_UNSUPPORTED;
193 }
194
195 Bits = MmioRead32 (UartBase + UARTCR);
196
197 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
198 Bits |= PL011_UARTCR_RTS;
199 }
200
201 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
202 Bits |= PL011_UARTCR_DTR;
203 }
204
205 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
206 Bits |= PL011_UARTCR_LBE;
207 }
208
209 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
210 Bits |= (PL011_UARTCR_CTSEN & PL011_UARTCR_RTSEN);
211 }
212
213 MmioWrite32 (UartBase + UARTCR, Bits);
214
215 return RETURN_SUCCESS;
216 }
217
218 /**
219 Get the serial device control bits.
220
221 @param UartBase The base address of the PL011 UART.
222 @param Control Control signals read from the serial device.
223
224 @retval EFI_SUCCESS The control bits were read from the serial device.
225 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
226
227 **/
228 RETURN_STATUS
229 EFIAPI
230 PL011UartGetControl (
231 IN UINTN UartBase,
232 OUT UINT32 *Control
233 )
234 {
235 UINT32 FlagRegister;
236 UINT32 ControlRegister;
237
238
239 FlagRegister = MmioRead32 (UartBase + UARTFR);
240 ControlRegister = MmioRead32 (UartBase + UARTCR);
241
242 *Control = 0;
243
244 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
245 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
246 }
247
248 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
249 *Control |= EFI_SERIAL_DATA_SET_READY;
250 }
251
252 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
253 *Control |= EFI_SERIAL_RING_INDICATE;
254 }
255
256 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
257 *Control |= EFI_SERIAL_CARRIER_DETECT;
258 }
259
260 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
261 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
262 }
263
264 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
265 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
266 }
267
268 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
269 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
270 }
271
272 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
273 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
274 }
275
276 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {
277 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
278 }
279
280 #ifdef NEVER
281 // ToDo: Implement EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE
282 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
283 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
284 }
285
286 // ToDo: Implement EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE
287 if (SoftwareLoopbackEnable) {
288 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
289 }
290 #endif
291
292 return RETURN_SUCCESS;
293 }
294
295 /**
296 Write data to serial device.
297
298 @param Buffer Point of data buffer which need to be written.
299 @param NumberOfBytes Number of output bytes which are cached in Buffer.
300
301 @retval 0 Write data failed.
302 @retval !0 Actual number of bytes written to serial device.
303
304 **/
305 UINTN
306 EFIAPI
307 PL011UartWrite (
308 IN UINTN UartBase,
309 IN UINT8 *Buffer,
310 IN UINTN NumberOfBytes
311 )
312 {
313 UINT8* CONST Final = &Buffer[NumberOfBytes];
314
315 while (Buffer < Final) {
316 // Wait until UART able to accept another char
317 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));
318
319 MmioWrite8 (UartBase + UARTDR, *Buffer++);
320 }
321
322 return NumberOfBytes;
323 }
324
325 /**
326 Read data from serial device and save the data in buffer.
327
328 @param Buffer Point of data buffer which need to be written.
329 @param NumberOfBytes Number of output bytes which are cached in Buffer.
330
331 @retval 0 Read data failed.
332 @retval !0 Actual number of bytes read from serial device.
333
334 **/
335 UINTN
336 EFIAPI
337 PL011UartRead (
338 IN UINTN UartBase,
339 OUT UINT8 *Buffer,
340 IN UINTN NumberOfBytes
341 )
342 {
343 UINTN Count;
344
345 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
346 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);
347 *Buffer = MmioRead8 (UartBase + UARTDR);
348 }
349
350 return NumberOfBytes;
351 }
352
353 /**
354 Check to see if any data is available to be read from the debug device.
355
356 @retval EFI_SUCCESS At least one byte of data is available to be read
357 @retval EFI_NOT_READY No data is available to be read
358 @retval EFI_DEVICE_ERROR The serial device is not functioning properly
359
360 **/
361 BOOLEAN
362 EFIAPI
363 PL011UartPoll (
364 IN UINTN UartBase
365 )
366 {
367 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
368 }