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