]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
ArmPlatformPkg: Correct mendacious comments.
[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
9f08a052 5 Copyright (c) 2011 - 2016, 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
9f08a052
EL
23#define FRACTION_PART_SIZE_IN_BITS 6\r
24#define FRACTION_PART_MASK ((1 << FRACTION_PART_SIZE_IN_BITS) - 1)\r
25\r
ab716191
RC
26//\r
27// EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE is the only\r
28// control bit that is not supported.\r
29//\r
30STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;\r
31\r
9f08a052 32/**\r
051e63bb 33\r
34 Initialise the serial port to the specified settings.\r
16146b98
EL
35 The serial port is re-configured only if the specified settings\r
36 are different from the current settings.\r
051e63bb 37 All unspecified settings will be set to the default values.\r
38\r
9f08a052 39 @param UartBase The base address of the serial device.\r
f6300528
EL
40 @param UartClkInHz The clock in Hz for the serial device.\r
41 Ignored if the PCD PL011UartInteger is not 0\r
9f08a052
EL
42 @param BaudRate The baud rate of the serial device. If the\r
43 baud rate is not supported, the speed will be\r
44 reduced to the nearest supported one and the\r
45 variable's value will be updated accordingly.\r
46 @param ReceiveFifoDepth The number of characters the device will\r
47 buffer on input. Value of 0 will use the\r
48 device's default FIFO depth.\r
49 @param Parity If applicable, this is the EFI_PARITY_TYPE\r
50 that is computed or checked as each character\r
51 is transmitted or received. If the device\r
52 does not support parity, the value is the\r
53 default parity value.\r
54 @param DataBits The number of data bits in each character.\r
55 @param StopBits If applicable, the EFI_STOP_BITS_TYPE number\r
56 of stop bits per character.\r
57 If the device does not support stop bits, the\r
58 value is the default stop bit value.\r
59\r
60 @retval RETURN_SUCCESS All attributes were set correctly on the\r
61 serial device.\r
62 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an\r
63 unsupported value.\r
051e63bb 64\r
65**/\r
66RETURN_STATUS\r
67EFIAPI\r
68PL011UartInitializePort (\r
9f08a052 69 IN UINTN UartBase,\r
f6300528 70 IN UINT32 UartClkInHz,\r
15e277d5 71 IN OUT UINT64 *BaudRate,\r
72 IN OUT UINT32 *ReceiveFifoDepth,\r
73 IN OUT EFI_PARITY_TYPE *Parity,\r
74 IN OUT UINT8 *DataBits,\r
75 IN OUT EFI_STOP_BITS_TYPE *StopBits\r
051e63bb 76 )\r
77{\r
78 UINT32 LineControl;\r
79 UINT32 Divisor;\r
f6300528
EL
80 UINT32 Integer;\r
81 UINT32 Fractional;\r
719a347c 82 UINT32 HardwareFifoDepth;\r
051e63bb 83\r
719a347c
EL
84 HardwareFifoDepth = (PL011_UARTPID2_VER (MmioRead32 (UartBase + UARTPID2)) \\r
85 > PL011_VER_R1P4) \\r
86 ? 32 : 16 ;\r
48edf6be 87 // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept\r
9f08a052
EL
88 // 1 char buffer as the minimum FIFO size. Because everything can be rounded\r
89 // down, there is no maximum FIFO size.\r
719a347c 90 if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= HardwareFifoDepth)) {\r
9f08a052 91 // Enable FIFO\r
ca0aad69 92 LineControl = PL011_UARTLCR_H_FEN;\r
719a347c 93 *ReceiveFifoDepth = HardwareFifoDepth;\r
15e277d5 94 } else {\r
ca0aad69
EL
95 // Disable FIFO\r
96 LineControl = 0;\r
9f08a052 97 // Nothing else to do. 1 byte FIFO is default.\r
15e277d5 98 *ReceiveFifoDepth = 1;\r
051e63bb 99 }\r
100\r
101 //\r
102 // Parity\r
103 //\r
15e277d5 104 switch (*Parity) {\r
051e63bb 105 case DefaultParity:\r
15e277d5 106 *Parity = NoParity;\r
051e63bb 107 case NoParity:\r
108 // Nothing to do. Parity is disabled by default.\r
109 break;\r
110 case EvenParity:\r
111 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);\r
112 break;\r
113 case OddParity:\r
114 LineControl |= PL011_UARTLCR_H_PEN;\r
115 break;\r
116 case MarkParity:\r
9f08a052
EL
117 LineControl |= ( PL011_UARTLCR_H_PEN \\r
118 | PL011_UARTLCR_H_SPS \\r
119 | PL011_UARTLCR_H_EPS);\r
051e63bb 120 break;\r
121 case SpaceParity:\r
122 LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);\r
123 break;\r
124 default:\r
125 return RETURN_INVALID_PARAMETER;\r
126 }\r
127\r
128 //\r
129 // Data Bits\r
130 //\r
15e277d5 131 switch (*DataBits) {\r
051e63bb 132 case 0:\r
15e277d5 133 *DataBits = 8;\r
051e63bb 134 case 8:\r
135 LineControl |= PL011_UARTLCR_H_WLEN_8;\r
136 break;\r
137 case 7:\r
138 LineControl |= PL011_UARTLCR_H_WLEN_7;\r
139 break;\r
140 case 6:\r
141 LineControl |= PL011_UARTLCR_H_WLEN_6;\r
142 break;\r
143 case 5:\r
144 LineControl |= PL011_UARTLCR_H_WLEN_5;\r
145 break;\r
146 default:\r
147 return RETURN_INVALID_PARAMETER;\r
148 }\r
149\r
150 //\r
151 // Stop Bits\r
152 //\r
15e277d5 153 switch (*StopBits) {\r
051e63bb 154 case DefaultStopBits:\r
15e277d5 155 *StopBits = OneStopBit;\r
051e63bb 156 case OneStopBit:\r
157 // Nothing to do. One stop bit is enabled by default.\r
158 break;\r
159 case TwoStopBits:\r
160 LineControl |= PL011_UARTLCR_H_STP2;\r
161 break;\r
162 case OneFiveStopBits:\r
9f08a052 163 // Only 1 or 2 stop bits are supported\r
051e63bb 164 default:\r
165 return RETURN_INVALID_PARAMETER;\r
166 }\r
40ab42dd 167\r
051e63bb 168 // Don't send the LineControl value to the PL011 yet,\r
169 // wait until after the Baud Rate setting.\r
170 // This ensures we do not mess up the UART settings halfway through\r
171 // in the rare case when there is an error with the Baud Rate.\r
172\r
173 //\r
174 // Baud Rate\r
175 //\r
6bc77e7a 176\r
9f08a052 177 // If PL011 Integer value has been defined then always ignore the BAUD rate\r
aadc64e6 178 if (FixedPcdGet32 (PL011UartInteger) != 0) {\r
f6300528
EL
179 Integer = FixedPcdGet32 (PL011UartInteger);\r
180 Fractional = FixedPcdGet32 (PL011UartFractional);\r
ec6b73d7
OM
181 } else {\r
182 // If BAUD rate is zero then replace it with the system default value\r
183 if (*BaudRate == 0) {\r
aadc64e6 184 *BaudRate = FixedPcdGet32 (PcdSerialBaudRate);\r
f6300528
EL
185 if (*BaudRate == 0) {\r
186 return RETURN_INVALID_PARAMETER;\r
187 }\r
188 }\r
189 if (0 == UartClkInHz) {\r
190 return RETURN_INVALID_PARAMETER;\r
6bc77e7a 191 }\r
6bc77e7a 192\r
f6300528
EL
193 Divisor = (UartClkInHz * 4) / *BaudRate;\r
194 Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;\r
195 Fractional = Divisor & FRACTION_PART_MASK;\r
051e63bb 196 }\r
16146b98
EL
197\r
198 //\r
199 // If PL011 is already initialized, check the current settings\r
200 // and re-initialize only if the settings are different.\r
201 //\r
202 if (((MmioRead32 (UartBase + UARTCR) & PL011_UARTCR_UARTEN) != 0) &&\r
203 (MmioRead32 (UartBase + UARTLCR_H) == LineControl) &&\r
204 (MmioRead32 (UartBase + UARTIBRD) == Integer) &&\r
205 (MmioRead32 (UartBase + UARTFBRD) == Fractional)) {\r
206 // Nothing to do - already initialized with correct attributes\r
207 return RETURN_SUCCESS;\r
208 }\r
209\r
210 // Wait for the end of transmission\r
211 while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0);\r
212\r
213 // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed\r
214 // when the UART is enabled"\r
215 MmioWrite32 (UartBase + UARTCR, 0);\r
216\r
f6300528
EL
217 // Set Baud Rate Registers\r
218 MmioWrite32 (UartBase + UARTIBRD, Integer);\r
219 MmioWrite32 (UartBase + UARTFBRD, Fractional);\r
051e63bb 220\r
221 // No parity, 1 stop, no fifo, 8 data bits\r
222 MmioWrite32 (UartBase + UARTLCR_H, LineControl);\r
223\r
224 // Clear any pending errors\r
225 MmioWrite32 (UartBase + UARTECR, 0);\r
226\r
9f08a052
EL
227 // Enable Tx, Rx, and UART overall\r
228 MmioWrite32 (UartBase + UARTCR,\r
229 PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);\r
051e63bb 230\r
231 return RETURN_SUCCESS;\r
232}\r
233\r
234/**\r
051e63bb 235\r
ab716191
RC
236 Assert or deassert the control signals on a serial port.\r
237 The following control signals are set according their bit settings :\r
238 . Request to Send\r
239 . Data Terminal Ready\r
240\r
241 @param[in] UartBase UART registers base address\r
242 @param[in] Control The following bits are taken into account :\r
243 . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the\r
244 "Request To Send" control signal if this bit is\r
245 equal to one/zero.\r
246 . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert\r
247 the "Data Terminal Ready" control signal if this\r
248 bit is equal to one/zero.\r
249 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable\r
250 the hardware loopback if this bit is equal to\r
251 one/zero.\r
252 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported.\r
253 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/\r
254 disable the hardware flow control based on CTS (Clear\r
255 To Send) and RTS (Ready To Send) control signals.\r
256\r
9f08a052
EL
257 @retval RETURN_SUCCESS The new control bits were set on the device.\r
258 @retval RETURN_UNSUPPORTED The device does not support this operation.\r
051e63bb 259\r
260**/\r
261RETURN_STATUS\r
262EFIAPI\r
263PL011UartSetControl (\r
ab716191
RC
264 IN UINTN UartBase,\r
265 IN UINT32 Control\r
051e63bb 266 )\r
267{\r
ab716191
RC
268 UINT32 Bits;\r
269\r
270 if (Control & (mInvalidControlBits)) {\r
271 return RETURN_UNSUPPORTED;\r
051e63bb 272 }\r
273\r
274 Bits = MmioRead32 (UartBase + UARTCR);\r
275\r
276 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {\r
277 Bits |= PL011_UARTCR_RTS;\r
ab716191
RC
278 } else {\r
279 Bits &= ~PL011_UARTCR_RTS;\r
051e63bb 280 }\r
281\r
282 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {\r
283 Bits |= PL011_UARTCR_DTR;\r
ab716191
RC
284 } else {\r
285 Bits &= ~PL011_UARTCR_DTR;\r
051e63bb 286 }\r
287\r
288 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {\r
289 Bits |= PL011_UARTCR_LBE;\r
ab716191
RC
290 } else {\r
291 Bits &= ~PL011_UARTCR_LBE;\r
051e63bb 292 }\r
293\r
294 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {\r
ab716191
RC
295 Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);\r
296 } else {\r
297 Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);\r
051e63bb 298 }\r
299\r
300 MmioWrite32 (UartBase + UARTCR, Bits);\r
301\r
302 return RETURN_SUCCESS;\r
303}\r
304\r
305/**\r
051e63bb 306\r
d2e7e385
RC
307 Retrieve the status of the control bits on a serial device.\r
308\r
309 @param[in] UartBase UART registers base address\r
310 @param[out] Control Status of the control bits on a serial device :\r
311\r
9f08a052
EL
312 . EFI_SERIAL_DATA_CLEAR_TO_SEND,\r
313 EFI_SERIAL_DATA_SET_READY,\r
314 EFI_SERIAL_RING_INDICATE,\r
315 EFI_SERIAL_CARRIER_DETECT,\r
316 EFI_SERIAL_REQUEST_TO_SEND,\r
317 EFI_SERIAL_DATA_TERMINAL_READY\r
318 are all related to the DTE (Data Terminal Equipment)\r
319 and DCE (Data Communication Equipment) modes of\r
320 operation of the serial device.\r
321 . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the\r
322 receive buffer is empty, 0 otherwise.\r
323 . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the\r
324 transmit buffer is empty, 0 otherwise.\r
325 . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if\r
326 the hardware loopback is enabled (the ouput feeds the\r
327 receive buffer), 0 otherwise.\r
328 . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if\r
329 a loopback is accomplished by software, 0 otherwise.\r
330 . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to\r
331 one if the hardware flow control based on CTS (Clear\r
332 To Send) and RTS (Ready To Send) control signals is\r
333 enabled, 0 otherwise.\r
d2e7e385
RC
334\r
335 @retval RETURN_SUCCESS The control bits were read from the serial device.\r
051e63bb 336\r
337**/\r
338RETURN_STATUS\r
339EFIAPI\r
340PL011UartGetControl (\r
d2e7e385
RC
341 IN UINTN UartBase,\r
342 OUT UINT32 *Control\r
051e63bb 343 )\r
344{\r
345 UINT32 FlagRegister;\r
346 UINT32 ControlRegister;\r
347\r
348\r
349 FlagRegister = MmioRead32 (UartBase + UARTFR);\r
350 ControlRegister = MmioRead32 (UartBase + UARTCR);\r
351\r
352 *Control = 0;\r
353\r
354 if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {\r
355 *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
356 }\r
357\r
358 if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {\r
359 *Control |= EFI_SERIAL_DATA_SET_READY;\r
360 }\r
361\r
362 if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {\r
363 *Control |= EFI_SERIAL_RING_INDICATE;\r
364 }\r
365\r
366 if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {\r
367 *Control |= EFI_SERIAL_CARRIER_DETECT;\r
368 }\r
369\r
370 if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {\r
371 *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
372 }\r
373\r
374 if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {\r
375 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
376 }\r
377\r
378 if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {\r
379 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
380 }\r
381\r
382 if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {\r
383 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
384 }\r
385\r
d2e7e385
RC
386 if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))\r
387 == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {\r
051e63bb 388 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;\r
389 }\r
390\r
051e63bb 391 if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {\r
392 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;\r
393 }\r
394\r
051e63bb 395 return RETURN_SUCCESS;\r
396}\r
397\r
398/**\r
399 Write data to serial device.\r
400\r
401 @param Buffer Point of data buffer which need to be written.\r
402 @param NumberOfBytes Number of output bytes which are cached in Buffer.\r
403\r
404 @retval 0 Write data failed.\r
405 @retval !0 Actual number of bytes written to serial device.\r
406\r
407**/\r
408UINTN\r
409EFIAPI\r
410PL011UartWrite (\r
411 IN UINTN UartBase,\r
412 IN UINT8 *Buffer,\r
413 IN UINTN NumberOfBytes\r
414 )\r
415{\r
ebef1b74 416 UINT8* CONST Final = &Buffer[NumberOfBytes];\r
051e63bb 417\r
ebef1b74 418 while (Buffer < Final) {\r
419 // Wait until UART able to accept another char\r
420 while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));\r
3402aac7 421\r
cdd3f032 422 MmioWrite8 (UartBase + UARTDR, *Buffer++);\r
40ab42dd 423 }\r
051e63bb 424\r
40ab42dd 425 return NumberOfBytes;\r
051e63bb 426}\r
427\r
428/**\r
429 Read data from serial device and save the data in buffer.\r
430\r
431 @param Buffer Point of data buffer which need to be written.\r
432 @param NumberOfBytes Number of output bytes which are cached in Buffer.\r
433\r
434 @retval 0 Read data failed.\r
435 @retval !0 Actual number of bytes read from serial device.\r
436\r
437**/\r
438UINTN\r
439EFIAPI\r
440PL011UartRead (\r
441 IN UINTN UartBase,\r
442 OUT UINT8 *Buffer,\r
443 IN UINTN NumberOfBytes\r
444 )\r
445{\r
446 UINTN Count;\r
447\r
40ab42dd 448 for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {\r
449 while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);\r
cdd3f032 450 *Buffer = MmioRead8 (UartBase + UARTDR);\r
40ab42dd 451 }\r
051e63bb 452\r
40ab42dd 453 return NumberOfBytes;\r
051e63bb 454}\r
455\r
456/**\r
457 Check to see if any data is available to be read from the debug device.\r
458\r
2d52a3a2
A
459 @retval TRUE At least one byte of data is available to be read\r
460 @retval FALSE No data is available to be read\r
051e63bb 461\r
462**/\r
463BOOLEAN\r
464EFIAPI\r
465PL011UartPoll (\r
466 IN UINTN UartBase\r
467 )\r
468{\r
469 return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);\r
470}\r