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