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