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