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