]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / PcAtChipsetPkg / Library / SerialIoLib / SerialPortLib.c
... / ...
CommitLineData
1/** @file\r
2 UART Serial Port library functions\r
3\r
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include <Base.h>\r
10#include <Library/IoLib.h>\r
11#include <Library/SerialPortLib.h>\r
12\r
13// ---------------------------------------------\r
14// UART Register Offsets\r
15// ---------------------------------------------\r
16#define BAUD_LOW_OFFSET 0x00\r
17#define BAUD_HIGH_OFFSET 0x01\r
18#define IER_OFFSET 0x01\r
19#define LCR_SHADOW_OFFSET 0x01\r
20#define FCR_SHADOW_OFFSET 0x02\r
21#define IR_CONTROL_OFFSET 0x02\r
22#define FCR_OFFSET 0x02\r
23#define EIR_OFFSET 0x02\r
24#define BSR_OFFSET 0x03\r
25#define LCR_OFFSET 0x03\r
26#define MCR_OFFSET 0x04\r
27#define LSR_OFFSET 0x05\r
28#define MSR_OFFSET 0x06\r
29\r
30// ---------------------------------------------\r
31// UART Register Bit Defines\r
32// ---------------------------------------------\r
33#define LSR_TXRDY 0x20\r
34#define LSR_RXDA 0x01\r
35#define DLAB 0x01\r
36#define MCR_DTRC 0x01\r
37#define MCR_RTS 0x02\r
38#define MSR_CTS 0x10\r
39#define MSR_DSR 0x20\r
40#define MSR_RI 0x40\r
41#define MSR_DCD 0x80\r
42\r
43// ---------------------------------------------\r
44// UART Settings\r
45// ---------------------------------------------\r
46UINT16 gUartBase = 0x3F8;\r
47UINTN gBps = 115200;\r
48UINT8 gData = 8;\r
49UINT8 gStop = 1;\r
50UINT8 gParity = 0;\r
51UINT8 gBreakSet = 0;\r
52\r
53/**\r
54 Initialize the serial device hardware.\r
55\r
56 If no initialization is required, then return RETURN_SUCCESS.\r
57 If the serial device was successfully initialized, then return RETURN_SUCCESS.\r
58 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.\r
59\r
60 @retval RETURN_SUCCESS The serial device was initialized.\r
61 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.\r
62\r
63**/\r
64RETURN_STATUS\r
65EFIAPI\r
66SerialPortInitialize (\r
67 VOID\r
68 )\r
69{\r
70 UINTN Divisor;\r
71 UINT8 OutputData;\r
72 UINT8 Data;\r
73\r
74 //\r
75 // Map 5..8 to 0..3\r
76 //\r
77 Data = (UINT8)(gData - (UINT8)5);\r
78\r
79 //\r
80 // Calculate divisor for baud generator\r
81 //\r
82 Divisor = 115200 / gBps;\r
83\r
84 //\r
85 // Set communications format\r
86 //\r
87 OutputData = (UINT8)((DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
88 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
89\r
90 //\r
91 // Configure baud rate\r
92 //\r
93 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8));\r
94 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff));\r
95\r
96 //\r
97 // Switch back to bank 0\r
98 //\r
99 OutputData = (UINT8)((gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
100 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
101\r
102 return RETURN_SUCCESS;\r
103}\r
104\r
105/**\r
106 Write data from buffer to serial device.\r
107\r
108 Writes NumberOfBytes data bytes from Buffer to the serial device.\r
109 The number of bytes actually written to the serial device is returned.\r
110 If the return value is less than NumberOfBytes, then the write operation failed.\r
111\r
112 If Buffer is NULL, then ASSERT().\r
113\r
114 If NumberOfBytes is zero, then return 0.\r
115\r
116 @param Buffer Pointer to the data buffer to be written.\r
117 @param NumberOfBytes Number of bytes to written to the serial device.\r
118\r
119 @retval 0 NumberOfBytes is 0.\r
120 @retval >0 The number of bytes written to the serial device.\r
121 If this value is less than NumberOfBytes, then the write operation failed.\r
122\r
123**/\r
124UINTN\r
125EFIAPI\r
126SerialPortWrite (\r
127 IN UINT8 *Buffer,\r
128 IN UINTN NumberOfBytes\r
129 )\r
130{\r
131 UINTN Result;\r
132 UINT8 Data;\r
133\r
134 if (Buffer == NULL) {\r
135 return 0;\r
136 }\r
137\r
138 Result = NumberOfBytes;\r
139\r
140 while ((NumberOfBytes--) != 0) {\r
141 //\r
142 // Wait for the serial port to be ready.\r
143 //\r
144 do {\r
145 Data = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
146 } while ((Data & LSR_TXRDY) == 0);\r
147\r
148 IoWrite8 ((UINT16)gUartBase, *Buffer++);\r
149 }\r
150\r
151 return Result;\r
152}\r
153\r
154/**\r
155 Reads data from a serial device into a buffer.\r
156\r
157 @param Buffer Pointer to the data buffer to store the data read from the serial device.\r
158 @param NumberOfBytes Number of bytes to read from the serial device.\r
159\r
160 @retval 0 NumberOfBytes is 0.\r
161 @retval >0 The number of bytes read from the serial device.\r
162 If this value is less than NumberOfBytes, then the read operation failed.\r
163\r
164**/\r
165UINTN\r
166EFIAPI\r
167SerialPortRead (\r
168 OUT UINT8 *Buffer,\r
169 IN UINTN NumberOfBytes\r
170 )\r
171{\r
172 UINTN Result;\r
173 UINT8 Data;\r
174\r
175 if (NULL == Buffer) {\r
176 return 0;\r
177 }\r
178\r
179 Result = NumberOfBytes;\r
180\r
181 while ((NumberOfBytes--) != 0) {\r
182 //\r
183 // Wait for the serial port to be ready.\r
184 //\r
185 do {\r
186 Data = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
187 } while ((Data & LSR_RXDA) == 0);\r
188\r
189 *Buffer++ = IoRead8 ((UINT16)gUartBase);\r
190 }\r
191\r
192 return Result;\r
193}\r
194\r
195/**\r
196 Polls a serial device to see if there is any data waiting to be read.\r
197\r
198 Polls a serial device to see if there is any data waiting to be read.\r
199 If there is data waiting to be read from the serial device, then TRUE is returned.\r
200 If there is no data waiting to be read from the serial device, then FALSE is returned.\r
201\r
202 @retval TRUE Data is waiting to be read from the serial device.\r
203 @retval FALSE There is no data waiting to be read from the serial device.\r
204\r
205**/\r
206BOOLEAN\r
207EFIAPI\r
208SerialPortPoll (\r
209 VOID\r
210 )\r
211{\r
212 UINT8 Data;\r
213\r
214 //\r
215 // Read the serial port status.\r
216 //\r
217 Data = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
218\r
219 return (BOOLEAN)((Data & LSR_RXDA) != 0);\r
220}\r
221\r
222/**\r
223 Sets the control bits on a serial device.\r
224\r
225 @param Control Sets the bits of Control that are settable.\r
226\r
227 @retval RETURN_SUCCESS The new control bits were set on the serial device.\r
228 @retval RETURN_UNSUPPORTED The serial device does not support this operation.\r
229 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.\r
230\r
231**/\r
232RETURN_STATUS\r
233EFIAPI\r
234SerialPortSetControl (\r
235 IN UINT32 Control\r
236 )\r
237{\r
238 UINT8 Mcr;\r
239\r
240 //\r
241 // First determine the parameter is invalid.\r
242 //\r
243 if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY))) != 0) {\r
244 return RETURN_UNSUPPORTED;\r
245 }\r
246\r
247 //\r
248 // Read the Modem Control Register.\r
249 //\r
250 Mcr = IoRead8 ((UINT16)gUartBase + MCR_OFFSET);\r
251 Mcr &= (~(MCR_DTRC | MCR_RTS));\r
252\r
253 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {\r
254 Mcr |= MCR_DTRC;\r
255 }\r
256\r
257 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {\r
258 Mcr |= MCR_RTS;\r
259 }\r
260\r
261 //\r
262 // Write the Modem Control Register.\r
263 //\r
264 IoWrite8 ((UINT16)gUartBase + MCR_OFFSET, Mcr);\r
265\r
266 return RETURN_SUCCESS;\r
267}\r
268\r
269/**\r
270 Retrieve the status of the control bits on a serial device.\r
271\r
272 @param Control A pointer to return the current control signals from the serial device.\r
273\r
274 @retval RETURN_SUCCESS The control bits were read from the serial device.\r
275 @retval RETURN_UNSUPPORTED The serial device does not support this operation.\r
276 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.\r
277\r
278**/\r
279RETURN_STATUS\r
280EFIAPI\r
281SerialPortGetControl (\r
282 OUT UINT32 *Control\r
283 )\r
284{\r
285 UINT8 Msr;\r
286 UINT8 Mcr;\r
287 UINT8 Lsr;\r
288\r
289 *Control = 0;\r
290\r
291 //\r
292 // Read the Modem Status Register.\r
293 //\r
294 Msr = IoRead8 ((UINT16)gUartBase + MSR_OFFSET);\r
295\r
296 if ((Msr & MSR_CTS) == MSR_CTS) {\r
297 *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
298 }\r
299\r
300 if ((Msr & MSR_DSR) == MSR_DSR) {\r
301 *Control |= EFI_SERIAL_DATA_SET_READY;\r
302 }\r
303\r
304 if ((Msr & MSR_RI) == MSR_RI) {\r
305 *Control |= EFI_SERIAL_RING_INDICATE;\r
306 }\r
307\r
308 if ((Msr & MSR_DCD) == MSR_DCD) {\r
309 *Control |= EFI_SERIAL_CARRIER_DETECT;\r
310 }\r
311\r
312 //\r
313 // Read the Modem Control Register.\r
314 //\r
315 Mcr = IoRead8 ((UINT16)gUartBase + MCR_OFFSET);\r
316\r
317 if ((Mcr & MCR_DTRC) == MCR_DTRC) {\r
318 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
319 }\r
320\r
321 if ((Mcr & MCR_RTS) == MCR_RTS) {\r
322 *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
323 }\r
324\r
325 //\r
326 // Read the Line Status Register.\r
327 //\r
328 Lsr = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
329\r
330 if ((Lsr & LSR_TXRDY) == LSR_TXRDY) {\r
331 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
332 }\r
333\r
334 if ((Lsr & LSR_RXDA) == 0) {\r
335 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
336 }\r
337\r
338 return RETURN_SUCCESS;\r
339}\r
340\r
341/**\r
342 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
343 data bits, and stop bits on a serial device.\r
344\r
345 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the\r
346 device's default interface speed.\r
347 On output, the value actually set.\r
348 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
349 serial interface. A ReceiveFifoDepth value of 0 will use\r
350 the device's default FIFO depth.\r
351 On output, the value actually set.\r
352 @param Timeout The requested time out for a single character in microseconds.\r
353 This timeout applies to both the transmit and receive side of the\r
354 interface. A Timeout value of 0 will use the device's default time\r
355 out value.\r
356 On output, the value actually set.\r
357 @param Parity The type of parity to use on this serial device. A Parity value of\r
358 DefaultParity will use the device's default parity value.\r
359 On output, the value actually set.\r
360 @param DataBits The number of data bits to use on the serial device. A DataBits\r
361 value of 0 will use the device's default data bit setting.\r
362 On output, the value actually set.\r
363 @param StopBits The number of stop bits to use on this serial device. A StopBits\r
364 value of DefaultStopBits will use the device's default number of\r
365 stop bits.\r
366 On output, the value actually set.\r
367\r
368 @retval RETURN_SUCCESS The new attributes were set on the serial device.\r
369 @retval RETURN_UNSUPPORTED The serial device does not support this operation.\r
370 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.\r
371 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.\r
372\r
373**/\r
374RETURN_STATUS\r
375EFIAPI\r
376SerialPortSetAttributes (\r
377 IN OUT UINT64 *BaudRate,\r
378 IN OUT UINT32 *ReceiveFifoDepth,\r
379 IN OUT UINT32 *Timeout,\r
380 IN OUT EFI_PARITY_TYPE *Parity,\r
381 IN OUT UINT8 *DataBits,\r
382 IN OUT EFI_STOP_BITS_TYPE *StopBits\r
383 )\r
384{\r
385 UINTN Divisor;\r
386 UINT8 OutputData;\r
387 UINT8 LcrData;\r
388 UINT8 LcrParity;\r
389 UINT8 LcrStop;\r
390\r
391 //\r
392 // Check for default settings and fill in actual values.\r
393 //\r
394 if (*BaudRate == 0) {\r
395 *BaudRate = gBps;\r
396 }\r
397\r
398 if (*DataBits == 0) {\r
399 *DataBits = gData;\r
400 }\r
401\r
402 if (*Parity == DefaultParity) {\r
403 *Parity = NoParity;\r
404 }\r
405\r
406 if (*StopBits == DefaultStopBits) {\r
407 *StopBits = OneStopBit;\r
408 }\r
409\r
410 if ((*DataBits < 5) || (*DataBits > 8)) {\r
411 return RETURN_INVALID_PARAMETER;\r
412 }\r
413\r
414 //\r
415 // Map 5..8 to 0..3\r
416 //\r
417 LcrData = (UINT8)(*DataBits - (UINT8)5);\r
418\r
419 switch (*Parity) {\r
420 case NoParity:\r
421 LcrParity = 0;\r
422 break;\r
423\r
424 case EvenParity:\r
425 LcrParity = 3;\r
426 break;\r
427\r
428 case OddParity:\r
429 LcrParity = 1;\r
430 break;\r
431\r
432 case SpaceParity:\r
433 LcrParity = 7;\r
434 break;\r
435\r
436 case MarkParity:\r
437 LcrParity = 5;\r
438 break;\r
439\r
440 default:\r
441 return RETURN_INVALID_PARAMETER;\r
442 }\r
443\r
444 switch (*StopBits) {\r
445 case OneStopBit:\r
446 LcrStop = 0;\r
447 break;\r
448\r
449 case OneFiveStopBits:\r
450 case TwoStopBits:\r
451 LcrStop = 1;\r
452 break;\r
453\r
454 default:\r
455 return RETURN_INVALID_PARAMETER;\r
456 }\r
457\r
458 //\r
459 // Calculate divisor for baud generator\r
460 //\r
461 Divisor = 115200 / (UINTN)*BaudRate;\r
462\r
463 //\r
464 // Set communications format\r
465 //\r
466 OutputData = (UINT8)((DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);\r
467 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
468\r
469 //\r
470 // Configure baud rate\r
471 //\r
472 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8));\r
473 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff));\r
474\r
475 //\r
476 // Switch back to bank 0\r
477 //\r
478 OutputData = (UINT8)((gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);\r
479 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
480\r
481 return RETURN_SUCCESS;\r
482}\r