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