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