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