2 16550 UART Serial Port library functions
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) 2018, AMD Incorporated. All rights reserved.<BR>
7 Copyright (c) 2020, ARM Limited. All rights reserved.
9 SPDX-License-Identifier: BSD-2-Clause-Patent
14 #include <IndustryStandard/Pci.h>
15 #include <Library/SerialPortLib.h>
16 #include <Library/PcdLib.h>
17 #include <Library/IoLib.h>
18 #include <Library/PciLib.h>
19 #include <Library/PlatformHookLib.h>
20 #include <Library/BaseLib.h>
25 #define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
28 // 16550 UART register offsets and bitfields
30 #define R_UART_RXBUF 0 // LCR_DLAB = 0
31 #define R_UART_TXBUF 0 // LCR_DLAB = 0
32 #define R_UART_BAUD_LOW 0 // LCR_DLAB = 1
33 #define R_UART_BAUD_HIGH 1 // LCR_DLAB = 1
34 #define R_UART_IER 1 // LCR_DLAB = 0
36 #define B_UART_FCR_FIFOE BIT0
37 #define B_UART_FCR_FIFO64 BIT5
39 #define B_UART_LCR_DLAB BIT7
41 #define B_UART_MCR_DTRC BIT0
42 #define B_UART_MCR_RTS BIT1
44 #define B_UART_LSR_RXRDY BIT0
45 #define B_UART_LSR_TXRDY BIT5
46 #define B_UART_LSR_TEMT BIT6
48 #define B_UART_MSR_CTS BIT4
49 #define B_UART_MSR_DSR BIT5
50 #define B_UART_MSR_RI BIT6
51 #define B_UART_MSR_DCD BIT7
54 // 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
59 UINT16 PowerManagementStatusAndControlRegister
;
60 } PCI_UART_DEVICE_INFO
;
63 Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
64 MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
65 parameter Offset is added to the base address of the 16550 registers that is specified
66 by PcdSerialRegisterBase. PcdSerialRegisterAccessWidth specifies the MMIO space access
67 width and defaults to 8 bit access, and supports 8 or 32 bit access.
69 @param Base The base address register of UART device.
70 @param Offset The offset of the 16550 register to read.
72 @return The value read from the 16550 register.
76 SerialPortReadRegister (
81 if (PcdGetBool (PcdSerialUseMmio
)) {
82 if (PcdGet8 (PcdSerialRegisterAccessWidth
) == 32) {
83 return (UINT8
)MmioRead32 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
));
86 return MmioRead8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
));
88 return IoRead8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
));
93 Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
94 MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
95 parameter Offset is added to the base address of the 16550 registers that is specified
96 by PcdSerialRegisterBase. PcdSerialRegisterAccessWidth specifies the MMIO space access
97 width and defaults to 8 bit access, and supports 8 or 32 bit access.
99 @param Base The base address register of UART device.
100 @param Offset The offset of the 16550 register to write.
101 @param Value The value to write to the 16550 register specified by Offset.
103 @return The value written to the 16550 register.
107 SerialPortWriteRegister (
113 if (PcdGetBool (PcdSerialUseMmio
)) {
114 if (PcdGet8 (PcdSerialRegisterAccessWidth
) == 32) {
115 return (UINT8
)MmioWrite32 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
), (UINT8
)Value
);
118 return MmioWrite8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
), Value
);
120 return IoWrite8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
), Value
);
125 Update the value of an 16-bit PCI configuration register in a PCI device. If the
126 PCI Configuration register specified by PciAddress is already programmed with a
127 non-zero value, then return the current value. Otherwise update the PCI configuration
128 register specified by PciAddress with the value specified by Value and return the
129 value programmed into the PCI configuration register. All values must be masked
130 using the bitmask specified by Mask.
132 @param PciAddress PCI Library address of the PCI Configuration register to update.
133 @param Value The value to program into the PCI Configuration Register.
134 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
138 SerialPortLibUpdatePciRegister16 (
146 CurrentValue
= PciRead16 (PciAddress
) & Mask
;
147 if (CurrentValue
!= 0) {
151 return PciWrite16 (PciAddress
, Value
& Mask
);
155 Update the value of an 32-bit PCI configuration register in a PCI device. If the
156 PCI Configuration register specified by PciAddress is already programmed with a
157 non-zero value, then return the current value. Otherwise update the PCI configuration
158 register specified by PciAddress with the value specified by Value and return the
159 value programmed into the PCI configuration register. All values must be masked
160 using the bitmask specified by Mask.
162 @param PciAddress PCI Library address of the PCI Configuration register to update.
163 @param Value The value to program into the PCI Configuration Register.
164 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
166 @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
170 SerialPortLibUpdatePciRegister32 (
178 CurrentValue
= PciRead32 (PciAddress
) & Mask
;
179 if (CurrentValue
!= 0) {
183 return PciWrite32 (PciAddress
, Value
& Mask
);
187 Retrieve the I/O or MMIO base address register for the PCI UART device.
189 This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
190 Device if they are not already enabled.
192 @return The base address register of the UART device.
196 GetSerialRegisterBase (
202 UINTN SubordinateBusNumber
;
204 UINT32 ParentIoLimit
;
205 UINT16 ParentMemoryBase
;
206 UINT16 ParentMemoryLimit
;
211 UINTN SerialRegisterBase
;
213 UINT32 RegisterBaseMask
;
214 PCI_UART_DEVICE_INFO
*DeviceInfo
;
217 // Get PCI Device Info
219 DeviceInfo
= (PCI_UART_DEVICE_INFO
*)PcdGetPtr (PcdSerialPciDeviceInfo
);
222 // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
224 if (DeviceInfo
->Device
== 0xff) {
225 return (UINTN
)PcdGet64 (PcdSerialRegisterBase
);
229 // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
231 ParentMemoryBase
= 0 >> 16;
232 ParentMemoryLimit
= 0xfff00000 >> 16;
233 ParentIoBase
= 0 >> 12;
234 ParentIoLimit
= 0xf000 >> 12;
237 // Enable I/O and MMIO in PCI Bridge
238 // Assume Root Bus Numer is Zero.
240 for (BusNumber
= 0; (DeviceInfo
+ 1)->Device
!= 0xff; DeviceInfo
++) {
242 // Compute PCI Lib Address to PCI to PCI Bridge
244 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
247 // Retrieve and verify the bus numbers in the PCI to PCI Bridge
249 BusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
);
250 SubordinateBusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET
);
251 if ((BusNumber
== 0) || (BusNumber
> SubordinateBusNumber
)) {
256 // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
258 if (PcdGetBool (PcdSerialUseMmio
)) {
259 MemoryLimit
= PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.MemoryLimit
)) & 0xfff0;
260 MemoryBase
= PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.MemoryBase
)) & 0xfff0;
263 // If PCI Bridge MMIO window is disabled, then return 0
265 if (MemoryLimit
< MemoryBase
) {
270 // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
272 if ((MemoryBase
< ParentMemoryBase
) || (MemoryBase
> ParentMemoryLimit
) || (MemoryLimit
> ParentMemoryLimit
)) {
276 ParentMemoryBase
= MemoryBase
;
277 ParentMemoryLimit
= MemoryLimit
;
279 IoLimit
= PciRead8 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoLimit
));
280 if ((IoLimit
& PCI_BRIDGE_32_BIT_IO_SPACE
) == 0) {
281 IoLimit
= IoLimit
>> 4;
283 IoLimit
= (PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoLimitUpper16
)) << 4) | (IoLimit
>> 4);
286 IoBase
= PciRead8 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoBase
));
287 if ((IoBase
& PCI_BRIDGE_32_BIT_IO_SPACE
) == 0) {
288 IoBase
= IoBase
>> 4;
290 IoBase
= (PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoBaseUpper16
)) << 4) | (IoBase
>> 4);
294 // If PCI Bridge I/O window is disabled, then return 0
296 if (IoLimit
< IoBase
) {
301 // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
303 if ((IoBase
< ParentIoBase
) || (IoBase
> ParentIoLimit
) || (IoLimit
> ParentIoLimit
)) {
307 ParentIoBase
= IoBase
;
308 ParentIoLimit
= IoLimit
;
313 // Compute PCI Lib Address to PCI UART
315 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
318 // Find the first IO or MMIO BAR
320 RegisterBaseMask
= 0xFFFFFFF0;
321 for (BarIndex
= 0; BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
322 SerialRegisterBase
= PciRead32 (PciLibAddress
+ PCI_BASE_ADDRESSREG_OFFSET
+ BarIndex
* 4);
323 if (PcdGetBool (PcdSerialUseMmio
) && ((SerialRegisterBase
& BIT0
) == 0)) {
327 RegisterBaseMask
= 0xFFFFFFF0;
331 if ((!PcdGetBool (PcdSerialUseMmio
)) && ((SerialRegisterBase
& BIT0
) != 0)) {
335 RegisterBaseMask
= 0xFFFFFFF8;
341 // MMIO or IO BAR is not found.
343 if (BarIndex
== PCI_MAX_BAR
) {
350 SerialRegisterBase
= SerialPortLibUpdatePciRegister32 (
351 PciLibAddress
+ PCI_BASE_ADDRESSREG_OFFSET
+ BarIndex
* 4,
352 (UINT32
)PcdGet64 (PcdSerialRegisterBase
),
357 // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
359 if (PcdGetBool (PcdSerialUseMmio
)) {
360 if ((((SerialRegisterBase
>> 16) & 0xfff0) < ParentMemoryBase
) || (((SerialRegisterBase
>> 16) & 0xfff0) > ParentMemoryLimit
)) {
364 if (((SerialRegisterBase
>> 12) < ParentIoBase
) || ((SerialRegisterBase
>> 12) > ParentIoLimit
)) {
370 // Enable I/O and MMIO in PCI UART Device if they are not already enabled
373 PciLibAddress
+ PCI_COMMAND_OFFSET
,
374 PcdGetBool (PcdSerialUseMmio
) ? EFI_PCI_COMMAND_MEMORY_SPACE
: EFI_PCI_COMMAND_IO_SPACE
378 // Force D0 state if a Power Management and Status Register is specified
380 if (DeviceInfo
->PowerManagementStatusAndControlRegister
!= 0x00) {
381 if ((PciRead16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
) & (BIT0
| BIT1
)) != 0x00) {
382 PciAnd16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
, (UINT16
) ~(BIT0
| BIT1
));
384 // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
386 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, (UINT8
)(PcdGet8 (PcdSerialFifoControl
) & (B_UART_FCR_FIFOE
| B_UART_FCR_FIFO64
)));
391 // Get PCI Device Info
393 DeviceInfo
= (PCI_UART_DEVICE_INFO
*)PcdGetPtr (PcdSerialPciDeviceInfo
);
396 // Enable I/O or MMIO in PCI Bridge
397 // Assume Root Bus Numer is Zero.
399 for (BusNumber
= 0; (DeviceInfo
+ 1)->Device
!= 0xff; DeviceInfo
++) {
401 // Compute PCI Lib Address to PCI to PCI Bridge
403 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
406 // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
409 PciLibAddress
+ PCI_COMMAND_OFFSET
,
410 PcdGetBool (PcdSerialUseMmio
) ? EFI_PCI_COMMAND_MEMORY_SPACE
: EFI_PCI_COMMAND_IO_SPACE
414 // Force D0 state if a Power Management and Status Register is specified
416 if (DeviceInfo
->PowerManagementStatusAndControlRegister
!= 0x00) {
417 if ((PciRead16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
) & (BIT0
| BIT1
)) != 0x00) {
418 PciAnd16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
, (UINT16
) ~(BIT0
| BIT1
));
422 BusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
);
425 return SerialRegisterBase
;
429 Return whether the hardware flow control signal allows writing.
431 @param SerialRegisterBase The base address register of UART device.
433 @retval TRUE The serial port is writable.
434 @retval FALSE The serial port is not writable.
438 UINTN SerialRegisterBase
441 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
442 if (PcdGetBool (PcdSerialDetectCable
)) {
444 // Wait for both DSR and CTS to be set
445 // DSR is set if a cable is connected.
446 // CTS is set if it is ok to transmit data
448 // DSR CTS Description Action
449 // === === ======================================== ========
450 // 0 0 No cable connected. Wait
451 // 0 1 No cable connected. Wait
452 // 1 0 Cable connected, but not clear to send. Wait
453 // 1 1 Cable connected, and clear to send. Transmit
455 return (BOOLEAN
)((SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
) & (B_UART_MSR_DSR
| B_UART_MSR_CTS
)) == (B_UART_MSR_DSR
| B_UART_MSR_CTS
));
458 // Wait for both DSR and CTS to be set OR for DSR to be clear.
459 // DSR is set if a cable is connected.
460 // CTS is set if it is ok to transmit data
462 // DSR CTS Description Action
463 // === === ======================================== ========
464 // 0 0 No cable connected. Transmit
465 // 0 1 No cable connected. Transmit
466 // 1 0 Cable connected, but not clear to send. Wait
467 // 1 1 Cable connected, and clar to send. Transmit
469 return (BOOLEAN
)((SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
) & (B_UART_MSR_DSR
| B_UART_MSR_CTS
)) != (B_UART_MSR_DSR
));
477 Initialize the serial device hardware.
479 If no initialization is required, then return RETURN_SUCCESS.
480 If the serial device was successfully initialized, then return RETURN_SUCCESS.
481 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
483 @retval RETURN_SUCCESS The serial device was initialized.
484 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
489 SerialPortInitialize (
493 RETURN_STATUS Status
;
494 UINTN SerialRegisterBase
;
496 UINT32 CurrentDivisor
;
500 // Perform platform specific initialization required to enable use of the 16550 device
501 // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
503 Status
= PlatformHookSerialPortInitialize ();
504 if (RETURN_ERROR (Status
)) {
509 // Calculate divisor for baud generator
510 // Ref_Clk_Rate / Baud_Rate / 16
512 Divisor
= PcdGet32 (PcdSerialClockRate
) / (PcdGet32 (PcdSerialBaudRate
) * 16);
513 if ((PcdGet32 (PcdSerialClockRate
) % (PcdGet32 (PcdSerialBaudRate
) * 16)) >= PcdGet32 (PcdSerialBaudRate
) * 8) {
518 // Get the base address of the serial port in either I/O or MMIO space
520 SerialRegisterBase
= GetSerialRegisterBase ();
521 if (SerialRegisterBase
== 0) {
522 return RETURN_DEVICE_ERROR
;
526 // See if the serial port is already initialized
529 if ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) & 0x3F) != (PcdGet8 (PcdSerialLineControl
) & 0x3F)) {
533 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) | B_UART_LCR_DLAB
));
534 CurrentDivisor
= SerialPortReadRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
) << 8;
535 CurrentDivisor
|= (UINT32
)SerialPortReadRegister (SerialRegisterBase
, R_UART_BAUD_LOW
);
536 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) & ~B_UART_LCR_DLAB
));
537 if (CurrentDivisor
!= Divisor
) {
542 return RETURN_SUCCESS
;
546 // Wait for the serial port to be ready.
547 // Verify that both the transmit FIFO and the shift register are empty.
549 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) != (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) {
553 // Configure baud rate
555 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, B_UART_LCR_DLAB
);
556 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
, (UINT8
)(Divisor
>> 8));
557 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_LOW
, (UINT8
)(Divisor
& 0xff));
560 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
561 // Strip reserved bits from PcdSerialLineControl
563 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(PcdGet8 (PcdSerialLineControl
) & 0x3F));
566 // Enable and reset FIFOs
567 // Strip reserved bits from PcdSerialFifoControl
569 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, 0x00);
570 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, (UINT8
)(PcdGet8 (PcdSerialFifoControl
) & (B_UART_FCR_FIFOE
| B_UART_FCR_FIFO64
)));
573 // Set FIFO Polled Mode by clearing IER after setting FCR
575 SerialPortWriteRegister (SerialRegisterBase
, R_UART_IER
, 0x00);
578 // Put Modem Control Register(MCR) into its reset state of 0x00.
580 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, 0x00);
582 return RETURN_SUCCESS
;
586 Write data from buffer to serial device.
588 Writes NumberOfBytes data bytes from Buffer to the serial device.
589 The number of bytes actually written to the serial device is returned.
590 If the return value is less than NumberOfBytes, then the write operation failed.
592 If Buffer is NULL, then ASSERT().
594 If NumberOfBytes is zero, then return 0.
596 @param Buffer Pointer to the data buffer to be written.
597 @param NumberOfBytes Number of bytes to written to the serial device.
599 @retval 0 NumberOfBytes is 0.
600 @retval >0 The number of bytes written to the serial device.
601 If this value is less than NumberOfBytes, then the write operation failed.
608 IN UINTN NumberOfBytes
611 UINTN SerialRegisterBase
;
616 if (Buffer
== NULL
) {
620 SerialRegisterBase
= GetSerialRegisterBase ();
621 if (SerialRegisterBase
== 0) {
625 if (NumberOfBytes
== 0) {
627 // Flush the hardware
631 // Wait for both the transmit FIFO and shift register empty.
633 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) != (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) {
637 // Wait for the hardware flow control signal
639 while (!SerialPortWritable (SerialRegisterBase
)) {
646 // Compute the maximum size of the Tx FIFO
649 if ((PcdGet8 (PcdSerialFifoControl
) & B_UART_FCR_FIFOE
) != 0) {
650 if ((PcdGet8 (PcdSerialFifoControl
) & B_UART_FCR_FIFO64
) == 0) {
653 FifoSize
= PcdGet32 (PcdSerialExtendedTxFifoSize
);
657 Result
= NumberOfBytes
;
658 while (NumberOfBytes
!= 0) {
660 // Wait for the serial port to be ready, to make sure both the transmit FIFO
661 // and shift register empty.
663 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) != (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) {
667 // Fill then entire Tx FIFO
669 for (Index
= 0; Index
< FifoSize
&& NumberOfBytes
!= 0; Index
++, NumberOfBytes
--, Buffer
++) {
671 // Wait for the hardware flow control signal
673 while (!SerialPortWritable (SerialRegisterBase
)) {
677 // Write byte to the transmit buffer.
679 SerialPortWriteRegister (SerialRegisterBase
, R_UART_TXBUF
, *Buffer
);
687 Reads data from a serial device into a buffer.
689 @param Buffer Pointer to the data buffer to store the data read from the serial device.
690 @param NumberOfBytes Number of bytes to read from the serial device.
692 @retval 0 NumberOfBytes is 0.
693 @retval >0 The number of bytes read from the serial device.
694 If this value is less than NumberOfBytes, then the read operation failed.
701 IN UINTN NumberOfBytes
704 UINTN SerialRegisterBase
;
708 if (NULL
== Buffer
) {
712 SerialRegisterBase
= GetSerialRegisterBase ();
713 if (SerialRegisterBase
== 0) {
717 Mcr
= (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) & ~B_UART_MCR_RTS
);
719 for (Result
= 0; NumberOfBytes
-- != 0; Result
++, Buffer
++) {
721 // Wait for the serial port to have some data.
723 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_RXRDY
) == 0) {
724 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
726 // Set RTS to let the peer send some data
728 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(Mcr
| B_UART_MCR_RTS
));
732 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
734 // Clear RTS to prevent peer from sending data
736 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, Mcr
);
740 // Read byte from the receive buffer.
742 *Buffer
= SerialPortReadRegister (SerialRegisterBase
, R_UART_RXBUF
);
749 Polls a serial device to see if there is any data waiting to be read.
751 Polls aserial device to see if there is any data waiting to be read.
752 If there is data waiting to be read from the serial device, then TRUE is returned.
753 If there is no data waiting to be read from the serial device, then FALSE is returned.
755 @retval TRUE Data is waiting to be read from the serial device.
756 @retval FALSE There is no data waiting to be read from the serial device.
765 UINTN SerialRegisterBase
;
767 SerialRegisterBase
= GetSerialRegisterBase ();
768 if (SerialRegisterBase
== 0) {
773 // Read the serial port status
775 if ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_RXRDY
) != 0) {
776 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
778 // Clear RTS to prevent peer from sending data
780 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) & ~B_UART_MCR_RTS
));
786 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
788 // Set RTS to let the peer send some data
790 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) | B_UART_MCR_RTS
));
797 Sets the control bits on a serial device.
799 @param Control Sets the bits of Control that are settable.
801 @retval RETURN_SUCCESS The new control bits were set on the serial device.
802 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
803 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
808 SerialPortSetControl (
812 UINTN SerialRegisterBase
;
816 // First determine the parameter is invalid.
818 if ((Control
& (~(EFI_SERIAL_REQUEST_TO_SEND
| EFI_SERIAL_DATA_TERMINAL_READY
|
819 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
))) != 0)
821 return RETURN_UNSUPPORTED
;
824 SerialRegisterBase
= GetSerialRegisterBase ();
825 if (SerialRegisterBase
== 0) {
826 return RETURN_UNSUPPORTED
;
830 // Read the Modem Control Register.
832 Mcr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
);
833 Mcr
&= (~(B_UART_MCR_DTRC
| B_UART_MCR_RTS
));
835 if ((Control
& EFI_SERIAL_DATA_TERMINAL_READY
) == EFI_SERIAL_DATA_TERMINAL_READY
) {
836 Mcr
|= B_UART_MCR_DTRC
;
839 if ((Control
& EFI_SERIAL_REQUEST_TO_SEND
) == EFI_SERIAL_REQUEST_TO_SEND
) {
840 Mcr
|= B_UART_MCR_RTS
;
844 // Write the Modem Control Register.
846 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, Mcr
);
848 return RETURN_SUCCESS
;
852 Retrieve the status of the control bits on a serial device.
854 @param Control A pointer to return the current control signals from the serial device.
856 @retval RETURN_SUCCESS The control bits were read from the serial device.
857 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
858 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
863 SerialPortGetControl (
867 UINTN SerialRegisterBase
;
872 SerialRegisterBase
= GetSerialRegisterBase ();
873 if (SerialRegisterBase
== 0) {
874 return RETURN_UNSUPPORTED
;
880 // Read the Modem Status Register.
882 Msr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
);
884 if ((Msr
& B_UART_MSR_CTS
) == B_UART_MSR_CTS
) {
885 *Control
|= EFI_SERIAL_CLEAR_TO_SEND
;
888 if ((Msr
& B_UART_MSR_DSR
) == B_UART_MSR_DSR
) {
889 *Control
|= EFI_SERIAL_DATA_SET_READY
;
892 if ((Msr
& B_UART_MSR_RI
) == B_UART_MSR_RI
) {
893 *Control
|= EFI_SERIAL_RING_INDICATE
;
896 if ((Msr
& B_UART_MSR_DCD
) == B_UART_MSR_DCD
) {
897 *Control
|= EFI_SERIAL_CARRIER_DETECT
;
901 // Read the Modem Control Register.
903 Mcr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
);
905 if ((Mcr
& B_UART_MCR_DTRC
) == B_UART_MCR_DTRC
) {
906 *Control
|= EFI_SERIAL_DATA_TERMINAL_READY
;
909 if ((Mcr
& B_UART_MCR_RTS
) == B_UART_MCR_RTS
) {
910 *Control
|= EFI_SERIAL_REQUEST_TO_SEND
;
913 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
914 *Control
|= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
;
918 // Read the Line Status Register.
920 Lsr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
);
922 if ((Lsr
& (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) == (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) {
923 *Control
|= EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
926 if ((Lsr
& B_UART_LSR_RXRDY
) == 0) {
927 *Control
|= EFI_SERIAL_INPUT_BUFFER_EMPTY
;
930 return RETURN_SUCCESS
;
934 Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
935 data bits, and stop bits on a serial device.
937 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
938 device's default interface speed.
939 On output, the value actually set.
940 @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the
941 serial interface. A ReceiveFifoDepth value of 0 will use
942 the device's default FIFO depth.
943 On output, the value actually set.
944 @param Timeout The requested time out for a single character in microseconds.
945 This timeout applies to both the transmit and receive side of the
946 interface. A Timeout value of 0 will use the device's default time
948 On output, the value actually set.
949 @param Parity The type of parity to use on this serial device. A Parity value of
950 DefaultParity will use the device's default parity value.
951 On output, the value actually set.
952 @param DataBits The number of data bits to use on the serial device. A DataBits
953 vaule of 0 will use the device's default data bit setting.
954 On output, the value actually set.
955 @param StopBits The number of stop bits to use on this serial device. A StopBits
956 value of DefaultStopBits will use the device's default number of
958 On output, the value actually set.
960 @retval RETURN_SUCCESS The new attributes were set on the serial device.
961 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
962 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
963 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
968 SerialPortSetAttributes (
969 IN OUT UINT64
*BaudRate
,
970 IN OUT UINT32
*ReceiveFifoDepth
,
971 IN OUT UINT32
*Timeout
,
972 IN OUT EFI_PARITY_TYPE
*Parity
,
973 IN OUT UINT8
*DataBits
,
974 IN OUT EFI_STOP_BITS_TYPE
*StopBits
977 UINTN SerialRegisterBase
;
978 UINT32 SerialBaudRate
;
985 SerialRegisterBase
= GetSerialRegisterBase ();
986 if (SerialRegisterBase
== 0) {
987 return RETURN_UNSUPPORTED
;
991 // Check for default settings and fill in actual values.
993 if (*BaudRate
== 0) {
994 *BaudRate
= PcdGet32 (PcdSerialBaudRate
);
997 SerialBaudRate
= (UINT32
)*BaudRate
;
999 if (*DataBits
== 0) {
1000 LcrData
= (UINT8
)(PcdGet8 (PcdSerialLineControl
) & 0x3);
1001 *DataBits
= LcrData
+ 5;
1003 if ((*DataBits
< 5) || (*DataBits
> 8)) {
1004 return RETURN_INVALID_PARAMETER
;
1010 LcrData
= (UINT8
)(*DataBits
- (UINT8
)5);
1013 if (*Parity
== DefaultParity
) {
1014 LcrParity
= (UINT8
)((PcdGet8 (PcdSerialLineControl
) >> 3) & 0x7);
1015 switch (LcrParity
) {
1021 *Parity
= EvenParity
;
1025 *Parity
= OddParity
;
1029 *Parity
= SpaceParity
;
1033 *Parity
= MarkParity
;
1062 return RETURN_INVALID_PARAMETER
;
1066 if (*StopBits
== DefaultStopBits
) {
1067 LcrStop
= (UINT8
)((PcdGet8 (PcdSerialLineControl
) >> 2) & 0x1);
1070 *StopBits
= OneStopBit
;
1074 if (*DataBits
== 5) {
1075 *StopBits
= OneFiveStopBits
;
1077 *StopBits
= TwoStopBits
;
1086 switch (*StopBits
) {
1091 case OneFiveStopBits
:
1097 return RETURN_INVALID_PARAMETER
;
1102 // Calculate divisor for baud generator
1103 // Ref_Clk_Rate / Baud_Rate / 16
1105 Divisor
= PcdGet32 (PcdSerialClockRate
) / (SerialBaudRate
* 16);
1106 if ((PcdGet32 (PcdSerialClockRate
) % (SerialBaudRate
* 16)) >= SerialBaudRate
* 8) {
1111 // Configure baud rate
1113 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, B_UART_LCR_DLAB
);
1114 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
, (UINT8
)(Divisor
>> 8));
1115 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_LOW
, (UINT8
)(Divisor
& 0xff));
1118 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
1119 // Strip reserved bits from line control value
1121 Lcr
= (UINT8
)((LcrParity
<< 3) | (LcrStop
<< 2) | LcrData
);
1122 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(Lcr
& 0x3F));
1124 return RETURN_SUCCESS
;
1127 /** Base Serial Port 16550 Library Constructor
1129 @retval RETURN_SUCCESS Success.
1133 BaseSerialPortLib16550 (
1137 // Nothing to do here. This constructor is added to
1138 // enable the chain of constructor invocation for
1139 // dependent libraries.
1140 return RETURN_SUCCESS
;