]> git.proxmox.com Git - mirror_edk2.git/blame - PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / PcAtChipsetPkg / Library / SerialIoLib / SerialPortLib.c
CommitLineData
f5752cb2 1/** @file\r
a9fd6721 2 UART Serial Port library functions\r
f5752cb2 3\r
5a702acd 4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
e1d302e5 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
f5752cb2 6\r
7**/\r
8\r
f5752cb2 9#include <Base.h>\r
78297266 10#include <Library/IoLib.h>\r
a9fd6721 11#include <Library/SerialPortLib.h>\r
f5752cb2 12\r
5220bd21 13// ---------------------------------------------\r
f5752cb2 14// UART Register Offsets\r
5220bd21
MK
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
f5752cb2 31// UART Register Bit Defines\r
5220bd21
MK
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
78297266 44// UART Settings\r
5220bd21 45// ---------------------------------------------\r
78297266 46UINT16 gUartBase = 0x3F8;\r
47UINTN gBps = 115200;\r
48UINT8 gData = 8;\r
49UINT8 gStop = 1;\r
50UINT8 gParity = 0;\r
f5752cb2 51UINT8 gBreakSet = 0;\r
f5752cb2 52\r
78297266 53/**\r
54 Initialize the serial device hardware.\r
5a702acd 55\r
78297266 56 If no initialization is required, then return RETURN_SUCCESS.\r
619ad10f 57 If the serial device was successfully initialized, then return RETURN_SUCCESS.\r
78297266 58 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.\r
5a702acd 59\r
78297266 60 @retval RETURN_SUCCESS The serial device was initialized.\r
aad15888 61 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.\r
f5752cb2 62\r
63**/\r
64RETURN_STATUS\r
65EFIAPI\r
66SerialPortInitialize (\r
67 VOID\r
68 )\r
69{\r
78297266 70 UINTN Divisor;\r
71 UINT8 OutputData;\r
72 UINT8 Data;\r
f5752cb2 73\r
78297266 74 //\r
f5752cb2 75 // Map 5..8 to 0..3\r
76 //\r
5220bd21 77 Data = (UINT8)(gData - (UINT8)5);\r
f5752cb2 78\r
79 //\r
80 // Calculate divisor for baud generator\r
81 //\r
78297266 82 Divisor = 115200 / gBps;\r
5a702acd 83\r
f5752cb2 84 //\r
85 // Set communications format\r
86 //\r
5220bd21 87 OutputData = (UINT8)((DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
bbbc509f 88 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
f5752cb2 89\r
90 //\r
91 // Configure baud rate\r
92 //\r
5220bd21
MK
93 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8));\r
94 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff));\r
f5752cb2 95\r
96 //\r
97 // Switch back to bank 0\r
98 //\r
5220bd21 99 OutputData = (UINT8)((gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
bbbc509f 100 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
f5752cb2 101\r
102 return RETURN_SUCCESS;\r
103}\r
104\r
105/**\r
5a702acd
LG
106 Write data from buffer to serial device.\r
107\r
108 Writes NumberOfBytes data bytes from Buffer to the serial device.\r
78297266 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
f5752cb2 111\r
5a702acd 112 If Buffer is NULL, then ASSERT().\r
f5752cb2 113\r
78297266 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
5a702acd 120 @retval >0 The number of bytes written to the serial device.\r
091a1262 121 If this value is less than NumberOfBytes, then the write operation failed.\r
f5752cb2 122\r
123**/\r
124UINTN\r
125EFIAPI\r
126SerialPortWrite (\r
5220bd21
MK
127 IN UINT8 *Buffer,\r
128 IN UINTN NumberOfBytes\r
129 )\r
f5752cb2 130{\r
78297266 131 UINTN Result;\r
132 UINT8 Data;\r
f5752cb2 133\r
78297266 134 if (Buffer == NULL) {\r
f5752cb2 135 return 0;\r
136 }\r
137\r
138 Result = NumberOfBytes;\r
139\r
24115e44 140 while ((NumberOfBytes--) != 0) {\r
78297266 141 //\r
aad15888 142 // Wait for the serial port to be ready.\r
78297266 143 //\r
144 do {\r
5220bd21 145 Data = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
78297266 146 } while ((Data & LSR_TXRDY) == 0);\r
5220bd21
MK
147\r
148 IoWrite8 ((UINT16)gUartBase, *Buffer++);\r
f5752cb2 149 }\r
150\r
151 return Result;\r
f5752cb2 152}\r
153\r
f5752cb2 154/**\r
78297266 155 Reads data from a serial device into a buffer.\r
f5752cb2 156\r
78297266 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
f5752cb2 159\r
78297266 160 @retval 0 NumberOfBytes is 0.\r
5a702acd 161 @retval >0 The number of bytes read from the serial device.\r
78297266 162 If this value is less than NumberOfBytes, then the read operation failed.\r
f5752cb2 163\r
164**/\r
165UINTN\r
166EFIAPI\r
167SerialPortRead (\r
5220bd21
MK
168 OUT UINT8 *Buffer,\r
169 IN UINTN NumberOfBytes\r
170 )\r
f5752cb2 171{\r
78297266 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
24115e44 181 while ((NumberOfBytes--) != 0) {\r
78297266 182 //\r
aad15888 183 // Wait for the serial port to be ready.\r
78297266 184 //\r
185 do {\r
5220bd21 186 Data = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
78297266 187 } while ((Data & LSR_RXDA) == 0);\r
188\r
5220bd21 189 *Buffer++ = IoRead8 ((UINT16)gUartBase);\r
78297266 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
53b1dd10 198 Polls a serial device to see if there is any data waiting to be read.\r
78297266 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
5220bd21 217 Data = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
78297266 218\r
5220bd21 219 return (BOOLEAN)((Data & LSR_RXDA) != 0);\r
f5752cb2 220}\r
221\r
d63a0df5
SZ
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
5220bd21 235 IN UINT32 Control\r
d63a0df5
SZ
236 )\r
237{\r
5220bd21 238 UINT8 Mcr;\r
d63a0df5
SZ
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
5220bd21 250 Mcr = IoRead8 ((UINT16)gUartBase + MCR_OFFSET);\r
d63a0df5
SZ
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
5220bd21 264 IoWrite8 ((UINT16)gUartBase + MCR_OFFSET, Mcr);\r
d63a0df5
SZ
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
5220bd21 282 OUT UINT32 *Control\r
d63a0df5
SZ
283 )\r
284{\r
5220bd21
MK
285 UINT8 Msr;\r
286 UINT8 Mcr;\r
287 UINT8 Lsr;\r
d63a0df5
SZ
288\r
289 *Control = 0;\r
290\r
291 //\r
292 // Read the Modem Status Register.\r
293 //\r
5220bd21 294 Msr = IoRead8 ((UINT16)gUartBase + MSR_OFFSET);\r
d63a0df5
SZ
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
5220bd21 315 Mcr = IoRead8 ((UINT16)gUartBase + MCR_OFFSET);\r
d63a0df5
SZ
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
5220bd21 328 Lsr = IoRead8 ((UINT16)gUartBase + LSR_OFFSET);\r
d63a0df5
SZ
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
53b1dd10 342 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
d63a0df5
SZ
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
53b1dd10 348 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
d63a0df5
SZ
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
53b1dd10 361 value of 0 will use the device's default data bit setting.\r
d63a0df5
SZ
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
5220bd21
MK
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
d63a0df5
SZ
383 )\r
384{\r
5220bd21
MK
385 UINTN Divisor;\r
386 UINT8 OutputData;\r
387 UINT8 LcrData;\r
388 UINT8 LcrParity;\r
389 UINT8 LcrStop;\r
d63a0df5
SZ
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
d63a0df5
SZ
414 //\r
415 // Map 5..8 to 0..3\r
416 //\r
5220bd21 417 LcrData = (UINT8)(*DataBits - (UINT8)5);\r
d63a0df5
SZ
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
de3ecb33 441 return RETURN_INVALID_PARAMETER;\r
d63a0df5
SZ
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
de3ecb33 455 return RETURN_INVALID_PARAMETER;\r
d63a0df5
SZ
456 }\r
457\r
458 //\r
459 // Calculate divisor for baud generator\r
460 //\r
5220bd21 461 Divisor = 115200 / (UINTN)*BaudRate;\r
d63a0df5
SZ
462\r
463 //\r
464 // Set communications format\r
465 //\r
5220bd21 466 OutputData = (UINT8)((DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);\r
bbbc509f 467 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
d63a0df5
SZ
468\r
469 //\r
470 // Configure baud rate\r
471 //\r
5220bd21
MK
472 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8));\r
473 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff));\r
d63a0df5
SZ
474\r
475 //\r
476 // Switch back to bank 0\r
477 //\r
5220bd21 478 OutputData = (UINT8)((gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);\r
bbbc509f 479 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
d63a0df5
SZ
480\r
481 return RETURN_SUCCESS;\r
482}\r