]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
ArmPlatformPkg: detect correct pl011 fifo depth
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL011Uart / PL011Uart.c
CommitLineData
051e63bb 1/** @file\r
2 Serial I/O Port library functions with no library constructor/destructor\r
3\r
4 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
ab716191 5 Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>\r
40ab42dd 6\r
051e63bb 7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include <Library/DebugLib.h>\r
18#include <Library/IoLib.h>\r
19#include <Library/PcdLib.h>\r
20\r
21#include <Drivers/PL011Uart.h>\r
22\r
ab716191
RC
23//\r
24// EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE is the only\r
25// control bit that is not supported.\r
26//\r
27STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
28\r
051e63bb 29/*\r
30\r
31 Initialise the serial port to the specified settings.\r
32 All unspecified settings will be set to the default values.\r
33\r
34 @return Always return EFI_SUCCESS or EFI_INVALID_PARAMETER.\r
35\r
36**/\r
37RETURN_STATUS\r
38EFIAPI\r
39PL011UartInitializePort (\r
15e277d5 40 IN OUT UINTN UartBase,\r
41 IN OUT UINT64 *BaudRate,\r
42 IN OUT UINT32 *ReceiveFifoDepth,\r
43 IN OUT EFI_PARITY_TYPE *Parity,\r
44 IN OUT UINT8 *DataBits,\r
45 IN OUT EFI_STOP_BITS_TYPE *StopBits\r
051e63bb 46 )\r
47{\r
48 UINT32 LineControl;\r
49 UINT32 Divisor;\r
50\r
051e63bb 51 LineControl = 0;\r
52\r
48edf6be 53 // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept\r
051e63bb 54 // 1 char buffer as the minimum fifo size. Because everything can be rounded down,\r
55 // there is no maximum fifo size.\r
15e277d5 56 if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= 32)) {\r
051e63bb 57 LineControl |= PL011_UARTLCR_H_FEN;\r
48edf6be
LL
58 if (PL011_UARTPID2_VER (MmioRead32 (UartBase + UARTPID2)) > PL011_VER_R1P4)\r
59 *ReceiveFifoDepth = 32;\r
60 else\r
61 *ReceiveFifoDepth = 16;\r
15e277d5 62 } else {\r
63 ASSERT (*ReceiveFifoDepth < 32);\r
051e63bb 64 // Nothing else to do. 1 byte fifo is default.\r
15e277d5 65 *ReceiveFifoDepth = 1;\r
051e63bb 66 }\r
67\r
68 //\r
69 // Parity\r
70 //\r
15e277d5 71 switch (*Parity) {\r
051e63bb 72 case DefaultParity:\r
15e277d5 73 *Parity = NoParity;\r
051e63bb 74 case NoParity:\r
75 // Nothing to do. Parity is disabled by default.\r
76 break;\r
77 case EvenParity:\r
78 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);\r
79 break;\r
80 case OddParity:\r
81 LineControl |= PL011_UARTLCR_H_PEN;\r
82 break;\r
83 case MarkParity:\r
84 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS | PL011_UARTLCR_H_EPS);\r
85 break;\r
86 case SpaceParity:\r
87 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);\r
88 break;\r
89 default:\r
90 return RETURN_INVALID_PARAMETER;\r
91 }\r
92\r
93 //\r
94 // Data Bits\r
95 //\r
15e277d5 96 switch (*DataBits) {\r
051e63bb 97 case 0:\r
15e277d5 98 *DataBits = 8;\r
051e63bb 99 case 8:\r
100 LineControl |= PL011_UARTLCR_H_WLEN_8;\r
101 break;\r
102 case 7:\r
103 LineControl |= PL011_UARTLCR_H_WLEN_7;\r
104 break;\r
105 case 6:\r
106 LineControl |= PL011_UARTLCR_H_WLEN_6;\r
107 break;\r
108 case 5:\r
109 LineControl |= PL011_UARTLCR_H_WLEN_5;\r
110 break;\r
111 default:\r
112 return RETURN_INVALID_PARAMETER;\r
113 }\r
114\r
115 //\r
116 // Stop Bits\r
117 //\r
15e277d5 118 switch (*StopBits) {\r
051e63bb 119 case DefaultStopBits:\r
15e277d5 120 *StopBits = OneStopBit;\r
051e63bb 121 case OneStopBit:\r
122 // Nothing to do. One stop bit is enabled by default.\r
123 break;\r
124 case TwoStopBits:\r
125 LineControl |= PL011_UARTLCR_H_STP2;\r
126 break;\r
127 case OneFiveStopBits:\r
128 // Only 1 or 2 stops bits are supported\r
129 default:\r
130 return RETURN_INVALID_PARAMETER;\r
131 }\r
40ab42dd 132\r
051e63bb 133 // Don't send the LineControl value to the PL011 yet,\r
134 // wait until after the Baud Rate setting.\r
135 // This ensures we do not mess up the UART settings halfway through\r
136 // in the rare case when there is an error with the Baud Rate.\r
137\r
138 //\r
139 // Baud Rate\r
140 //\r
6bc77e7a 141\r
ec6b73d7
OM
142 // If PL011 Integral value has been defined then always ignore the BAUD rate\r
143 if (PcdGet32 (PL011UartInteger) != 0) {\r
6bc77e7a 144 MmioWrite32 (UartBase + UARTIBRD, PcdGet32 (PL011UartInteger));\r
145 MmioWrite32 (UartBase + UARTFBRD, PcdGet32 (PL011UartFractional));\r
ec6b73d7
OM
146 } else {\r
147 // If BAUD rate is zero then replace it with the system default value\r
148 if (*BaudRate == 0) {\r
15e277d5 149 *BaudRate = PcdGet32 (PcdSerialBaudRate);\r
150 ASSERT (*BaudRate != 0);\r
6bc77e7a 151 }\r
6bc77e7a 152\r
15e277d5 153 Divisor = (PcdGet32 (PL011UartClkInHz) * 4) / *BaudRate;\r
051e63bb 154 MmioWrite32 (UartBase + UARTIBRD, Divisor >> 6);\r
155 MmioWrite32 (UartBase + UARTFBRD, Divisor & 0x3F);\r
156 }\r
157\r
158 // No parity, 1 stop, no fifo, 8 data bits\r
159 MmioWrite32 (UartBase + UARTLCR_H, LineControl);\r
160\r
161 // Clear any pending errors\r
162 MmioWrite32 (UartBase + UARTECR, 0);\r
163\r
164 // Enable tx, rx, and uart overall\r
165 MmioWrite32 (UartBase + UARTCR, PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);\r
166\r
167 return RETURN_SUCCESS;\r
168}\r
169\r
170/**\r
051e63bb 171\r
ab716191
RC
172 Assert or deassert the control signals on a serial port.\r
173 The following control signals are set according their bit settings :\r
174 . Request to Send\r
175 . Data Terminal Ready\r
176\r
177 @param[in] UartBase UART registers base address\r
178 @param[in] Control The following bits are taken into account :\r
179 . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the\r
180 "Request To Send" control signal if this bit is\r
181 equal to one/zero.\r
182 . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert\r
183 the "Data Terminal Ready" control signal if this\r
184 bit is equal to one/zero.\r
185 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable\r
186 the hardware loopback if this bit is equal to\r
187 one/zero.\r
188 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported.\r
189 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/\r
190 disable the hardware flow control based on CTS (Clear\r
191 To Send) and RTS (Ready To Send) control signals.\r
192\r
193 @retval RETURN_SUCCESS The new control bits were set on the serial device.\r
194 @retval RETURN_UNSUPPORTED The serial device does not support this operation.\r
051e63bb 195\r
196**/\r
197RETURN_STATUS\r
198EFIAPI\r
199PL011UartSetControl (\r
ab716191
RC
200 IN UINTN UartBase,\r
201 IN UINT32 Control\r
051e63bb 202 )\r
203{\r
ab716191
RC
204 UINT32 Bits;\r
205\r
206 if (Control & (mInvalidControlBits)) {\r
207 return RETURN_UNSUPPORTED;\r
051e63bb 208 }\r
209\r
210 Bits = MmioRead32 (UartBase + UARTCR);\r
211\r
212 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {\r
213 Bits |= PL011_UARTCR_RTS;\r
ab716191
RC
214 } else {\r
215 Bits &= ~PL011_UARTCR_RTS;\r
051e63bb 216 }\r
217\r
218 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {\r
219 Bits |= PL011_UARTCR_DTR;\r
ab716191
RC
220 } else {\r
221 Bits &= ~PL011_UARTCR_DTR;\r
051e63bb 222 }\r
223\r
224 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {\r
225 Bits |= PL011_UARTCR_LBE;\r
ab716191
RC
226 } else {\r
227 Bits &= ~PL011_UARTCR_LBE;\r
051e63bb 228 }\r
229\r
230 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {\r
ab716191
RC
231 Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);\r
232 } else {\r
233 Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);\r
051e63bb 234 }\r
235\r
236 MmioWrite32 (UartBase + UARTCR, Bits);\r
237\r
238 return RETURN_SUCCESS;\r
239}\r
240\r
241/**\r
051e63bb 242\r
d2e7e385
RC
243 Retrieve the status of the control bits on a serial device.\r
244\r
245 @param[in] UartBase UART registers base address\r
246 @param[out] Control Status of the control bits on a serial device :\r
247\r
248 . EFI_SERIAL_DATA_CLEAR_TO_SEND, EFI_SERIAL_DATA_SET_READY,\r
249 EFI_SERIAL_RING_INDICATE, EFI_SERIAL_CARRIER_DETECT,\r
250 EFI_SERIAL_REQUEST_TO_SEND, EFI_SERIAL_DATA_TERMINAL_READY\r
251 are all related to the DTE (Data Terminal Equipment) and\r
252 DCE (Data Communication Equipment) modes of operation of\r
253 the serial device.\r
254 . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the receive\r
255 buffer is empty, 0 otherwise.\r
256 . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the transmit\r
257 buffer is empty, 0 otherwise.\r
258 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if the\r
259 hardware loopback is enabled (the ouput feeds the receive\r
260 buffer), 0 otherwise.\r
261 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if a\r
262 loopback is accomplished by software, 0 otherwise.\r
263 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to one if the\r
264 hardware flow control based on CTS (Clear To Send) and RTS\r
265 (Ready To Send) control signals is enabled, 0 otherwise.\r
266\r
267 @retval RETURN_SUCCESS The control bits were read from the serial device.\r
051e63bb 268\r
269**/\r
270RETURN_STATUS\r
271EFIAPI\r
272PL011UartGetControl (\r
d2e7e385
RC
273 IN UINTN UartBase,\r
274 OUT UINT32 *Control\r
051e63bb 275 )\r
276{\r
277 UINT32 FlagRegister;\r
278 UINT32 ControlRegister;\r
279\r
280\r
281 FlagRegister = MmioRead32 (UartBase + UARTFR);\r
282 ControlRegister = MmioRead32 (UartBase + UARTCR);\r
283\r
284 *Control = 0;\r
285\r
286 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {\r
287 *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
288 }\r
289\r
290 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {\r
291 *Control |= EFI_SERIAL_DATA_SET_READY;\r
292 }\r
293\r
294 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {\r
295 *Control |= EFI_SERIAL_RING_INDICATE;\r
296 }\r
297\r
298 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {\r
299 *Control |= EFI_SERIAL_CARRIER_DETECT;\r
300 }\r
301\r
302 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {\r
303 *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
304 }\r
305\r
306 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {\r
307 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
308 }\r
309\r
310 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {\r
311 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
312 }\r
313\r
314 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {\r
315 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
316 }\r
317\r
d2e7e385
RC
318 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))\r
319 == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {\r
051e63bb 320 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
321 }\r
322\r
051e63bb 323 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {\r
324 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;\r
325 }\r
326\r
051e63bb 327 return RETURN_SUCCESS;\r
328}\r
329\r
330/**\r
331 Write data to serial device.\r
332\r
333 @param Buffer Point of data buffer which need to be written.\r
334 @param NumberOfBytes Number of output bytes which are cached in Buffer.\r
335\r
336 @retval 0 Write data failed.\r
337 @retval !0 Actual number of bytes written to serial device.\r
338\r
339**/\r
340UINTN\r
341EFIAPI\r
342PL011UartWrite (\r
343 IN UINTN UartBase,\r
344 IN UINT8 *Buffer,\r
345 IN UINTN NumberOfBytes\r
346 )\r
347{\r
ebef1b74 348 UINT8* CONST Final = &Buffer[NumberOfBytes];\r
051e63bb 349\r
ebef1b74 350 while (Buffer < Final) {\r
351 // Wait until UART able to accept another char\r
352 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));\r
3402aac7 353\r
cdd3f032 354 MmioWrite8 (UartBase + UARTDR, *Buffer++);\r
40ab42dd 355 }\r
051e63bb 356\r
40ab42dd 357 return NumberOfBytes;\r
051e63bb 358}\r
359\r
360/**\r
361 Read data from serial device and save the data in buffer.\r
362\r
363 @param Buffer Point of data buffer which need to be written.\r
364 @param NumberOfBytes Number of output bytes which are cached in Buffer.\r
365\r
366 @retval 0 Read data failed.\r
367 @retval !0 Actual number of bytes read from serial device.\r
368\r
369**/\r
370UINTN\r
371EFIAPI\r
372PL011UartRead (\r
373 IN UINTN UartBase,\r
374 OUT UINT8 *Buffer,\r
375 IN UINTN NumberOfBytes\r
376 )\r
377{\r
378 UINTN Count;\r
379\r
40ab42dd 380 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {\r
381 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);\r
cdd3f032 382 *Buffer = MmioRead8 (UartBase + UARTDR);\r
40ab42dd 383 }\r
051e63bb 384\r
40ab42dd 385 return NumberOfBytes;\r
051e63bb 386}\r
387\r
388/**\r
389 Check to see if any data is available to be read from the debug device.\r
390\r
391 @retval EFI_SUCCESS At least one byte of data is available to be read\r
392 @retval EFI_NOT_READY No data is available to be read\r
393 @retval EFI_DEVICE_ERROR The serial device is not functioning properly\r
394\r
395**/\r
396BOOLEAN\r
397EFIAPI\r
398PL011UartPoll (\r
399 IN UINTN UartBase\r
400 )\r
401{\r
402 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);\r
403}\r