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