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