2 16550 UART Serial Port library functions
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <IndustryStandard/Pci.h>
12 #include <Library/SerialPortLib.h>
13 #include <Library/PcdLib.h>
14 #include <Library/IoLib.h>
15 #include <Library/PciLib.h>
16 #include <Library/PlatformHookLib.h>
17 #include <Library/BaseLib.h>
22 #define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
25 // 16550 UART register offsets and bitfields
27 #define R_UART_RXBUF 0
28 #define R_UART_TXBUF 0
29 #define R_UART_BAUD_LOW 0
30 #define R_UART_BAUD_HIGH 1
32 #define B_UART_FCR_FIFOE BIT0
33 #define B_UART_FCR_FIFO64 BIT5
35 #define B_UART_LCR_DLAB BIT7
37 #define B_UART_MCR_DTRC BIT0
38 #define B_UART_MCR_RTS BIT1
40 #define B_UART_LSR_RXRDY BIT0
41 #define B_UART_LSR_TXRDY BIT5
42 #define B_UART_LSR_TEMT BIT6
44 #define B_UART_MSR_CTS BIT4
45 #define B_UART_MSR_DSR BIT5
46 #define B_UART_MSR_RI BIT6
47 #define B_UART_MSR_DCD BIT7
50 // 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
55 UINT16 PowerManagementStatusAndControlRegister
;
56 } PCI_UART_DEVICE_INFO
;
59 Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
60 MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
61 parameter Offset is added to the base address of the 16550 registers that is specified
62 by PcdSerialRegisterBase.
64 @param Base The base address register of UART device.
65 @param Offset The offset of the 16550 register to read.
67 @return The value read from the 16550 register.
71 SerialPortReadRegister (
76 if (PcdGetBool (PcdSerialUseMmio
)) {
77 return MmioRead8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
));
79 return IoRead8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
));
84 Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
85 MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
86 parameter Offset is added to the base address of the 16550 registers that is specified
87 by PcdSerialRegisterBase.
89 @param Base The base address register of UART device.
90 @param Offset The offset of the 16550 register to write.
91 @param Value The value to write to the 16550 register specified by Offset.
93 @return The value written to the 16550 register.
97 SerialPortWriteRegister (
103 if (PcdGetBool (PcdSerialUseMmio
)) {
104 return MmioWrite8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
), Value
);
106 return IoWrite8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
), Value
);
111 Update the value of an 16-bit PCI configuration register in a PCI device. If the
112 PCI Configuration register specified by PciAddress is already programmed with a
113 non-zero value, then return the current value. Otherwise update the PCI configuration
114 register specified by PciAddress with the value specified by Value and return the
115 value programmed into the PCI configuration register. All values must be masked
116 using the bitmask specified by Mask.
118 @param PciAddress PCI Library address of the PCI Configuration register to update.
119 @param Value The value to program into the PCI Configuration Register.
120 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
124 SerialPortLibUpdatePciRegister16 (
132 CurrentValue
= PciRead16 (PciAddress
) & Mask
;
133 if (CurrentValue
!= 0) {
136 return PciWrite16 (PciAddress
, Value
& Mask
);
140 Update the value of an 32-bit PCI configuration register in a PCI device. If the
141 PCI Configuration register specified by PciAddress is already programmed with a
142 non-zero value, then return the current value. Otherwise update the PCI configuration
143 register specified by PciAddress with the value specified by Value and return the
144 value programmed into the PCI configuration register. All values must be masked
145 using the bitmask specified by Mask.
147 @param PciAddress PCI Library address of the PCI Configuration register to update.
148 @param Value The value to program into the PCI Configuration Register.
149 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
151 @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
155 SerialPortLibUpdatePciRegister32 (
163 CurrentValue
= PciRead32 (PciAddress
) & Mask
;
164 if (CurrentValue
!= 0) {
167 return PciWrite32 (PciAddress
, Value
& Mask
);
171 Retrieve the I/O or MMIO base address register for the PCI UART device.
173 This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
174 Device if they are not already enabled.
176 @return The base address register of the UART device.
180 GetSerialRegisterBase (
186 UINTN SubordinateBusNumber
;
188 UINT32 ParentIoLimit
;
189 UINT16 ParentMemoryBase
;
190 UINT16 ParentMemoryLimit
;
195 UINTN SerialRegisterBase
;
197 UINT32 RegisterBaseMask
;
198 PCI_UART_DEVICE_INFO
*DeviceInfo
;
201 // Get PCI Device Info
203 DeviceInfo
= (PCI_UART_DEVICE_INFO
*) PcdGetPtr (PcdSerialPciDeviceInfo
);
206 // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
208 if (DeviceInfo
->Device
== 0xff) {
209 return (UINTN
)PcdGet64 (PcdSerialRegisterBase
);
213 // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
215 ParentMemoryBase
= 0 >> 16;
216 ParentMemoryLimit
= 0xfff00000 >> 16;
217 ParentIoBase
= 0 >> 12;
218 ParentIoLimit
= 0xf000 >> 12;
221 // Enable I/O and MMIO in PCI Bridge
222 // Assume Root Bus Numer is Zero.
224 for (BusNumber
= 0; (DeviceInfo
+ 1)->Device
!= 0xff; DeviceInfo
++) {
226 // Compute PCI Lib Address to PCI to PCI Bridge
228 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
231 // Retrieve and verify the bus numbers in the PCI to PCI Bridge
233 BusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
);
234 SubordinateBusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET
);
235 if (BusNumber
== 0 || BusNumber
> SubordinateBusNumber
) {
240 // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
242 if (PcdGetBool (PcdSerialUseMmio
)) {
243 MemoryLimit
= PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.MemoryLimit
)) & 0xfff0;
244 MemoryBase
= PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.MemoryBase
)) & 0xfff0;
247 // If PCI Bridge MMIO window is disabled, then return 0
249 if (MemoryLimit
< MemoryBase
) {
254 // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
256 if (MemoryBase
< ParentMemoryBase
|| MemoryBase
> ParentMemoryLimit
|| MemoryLimit
> ParentMemoryLimit
) {
259 ParentMemoryBase
= MemoryBase
;
260 ParentMemoryLimit
= MemoryLimit
;
262 IoLimit
= PciRead8 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoLimit
));
263 if ((IoLimit
& PCI_BRIDGE_32_BIT_IO_SPACE
) == 0) {
264 IoLimit
= IoLimit
>> 4;
266 IoLimit
= (PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoLimitUpper16
)) << 4) | (IoLimit
>> 4);
268 IoBase
= PciRead8 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoBase
));
269 if ((IoBase
& PCI_BRIDGE_32_BIT_IO_SPACE
) == 0) {
270 IoBase
= IoBase
>> 4;
272 IoBase
= (PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoBaseUpper16
)) << 4) | (IoBase
>> 4);
276 // If PCI Bridge I/O window is disabled, then return 0
278 if (IoLimit
< IoBase
) {
283 // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
285 if (IoBase
< ParentIoBase
|| IoBase
> ParentIoLimit
|| IoLimit
> ParentIoLimit
) {
288 ParentIoBase
= IoBase
;
289 ParentIoLimit
= IoLimit
;
294 // Compute PCI Lib Address to PCI UART
296 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
299 // Find the first IO or MMIO BAR
301 RegisterBaseMask
= 0xFFFFFFF0;
302 for (BarIndex
= 0; BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
303 SerialRegisterBase
= PciRead32 (PciLibAddress
+ PCI_BASE_ADDRESSREG_OFFSET
+ BarIndex
* 4);
304 if (PcdGetBool (PcdSerialUseMmio
) && ((SerialRegisterBase
& BIT0
) == 0)) {
308 RegisterBaseMask
= 0xFFFFFFF0;
312 if ((!PcdGetBool (PcdSerialUseMmio
)) && ((SerialRegisterBase
& BIT0
) != 0)) {
316 RegisterBaseMask
= 0xFFFFFFF8;
322 // MMIO or IO BAR is not found.
324 if (BarIndex
== PCI_MAX_BAR
) {
331 SerialRegisterBase
= SerialPortLibUpdatePciRegister32 (
332 PciLibAddress
+ PCI_BASE_ADDRESSREG_OFFSET
+ BarIndex
* 4,
333 (UINT32
)PcdGet64 (PcdSerialRegisterBase
),
338 // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
340 if (PcdGetBool (PcdSerialUseMmio
)) {
341 if (((SerialRegisterBase
>> 16) & 0xfff0) < ParentMemoryBase
|| ((SerialRegisterBase
>> 16) & 0xfff0) > ParentMemoryLimit
) {
345 if ((SerialRegisterBase
>> 12) < ParentIoBase
|| (SerialRegisterBase
>> 12) > ParentIoLimit
) {
351 // Enable I/O and MMIO in PCI UART Device if they are not already enabled
354 PciLibAddress
+ PCI_COMMAND_OFFSET
,
355 PcdGetBool (PcdSerialUseMmio
) ? EFI_PCI_COMMAND_MEMORY_SPACE
: EFI_PCI_COMMAND_IO_SPACE
359 // Force D0 state if a Power Management and Status Register is specified
361 if (DeviceInfo
->PowerManagementStatusAndControlRegister
!= 0x00) {
362 if ((PciRead16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
) & (BIT0
| BIT1
)) != 0x00) {
363 PciAnd16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
, (UINT16
)~(BIT0
| BIT1
));
365 // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
367 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, (UINT8
)(PcdGet8 (PcdSerialFifoControl
) & (B_UART_FCR_FIFOE
| B_UART_FCR_FIFO64
)));
372 // Get PCI Device Info
374 DeviceInfo
= (PCI_UART_DEVICE_INFO
*) PcdGetPtr (PcdSerialPciDeviceInfo
);
377 // Enable I/O or MMIO in PCI Bridge
378 // Assume Root Bus Numer is Zero.
380 for (BusNumber
= 0; (DeviceInfo
+ 1)->Device
!= 0xff; DeviceInfo
++) {
382 // Compute PCI Lib Address to PCI to PCI Bridge
384 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
387 // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
390 PciLibAddress
+ PCI_COMMAND_OFFSET
,
391 PcdGetBool (PcdSerialUseMmio
) ? EFI_PCI_COMMAND_MEMORY_SPACE
: EFI_PCI_COMMAND_IO_SPACE
395 // Force D0 state if a Power Management and Status Register is specified
397 if (DeviceInfo
->PowerManagementStatusAndControlRegister
!= 0x00) {
398 if ((PciRead16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
) & (BIT0
| BIT1
)) != 0x00) {
399 PciAnd16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
, (UINT16
)~(BIT0
| BIT1
));
403 BusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
);
406 return SerialRegisterBase
;
410 Return whether the hardware flow control signal allows writing.
412 @param SerialRegisterBase The base address register of UART device.
414 @retval TRUE The serial port is writable.
415 @retval FALSE The serial port is not writable.
419 UINTN SerialRegisterBase
422 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
423 if (PcdGetBool (PcdSerialDetectCable
)) {
425 // Wait for both DSR and CTS to be set
426 // DSR is set if a cable is connected.
427 // CTS is set if it is ok to transmit data
429 // DSR CTS Description Action
430 // === === ======================================== ========
431 // 0 0 No cable connected. Wait
432 // 0 1 No cable connected. Wait
433 // 1 0 Cable connected, but not clear to send. Wait
434 // 1 1 Cable connected, and clear to send. Transmit
436 return (BOOLEAN
) ((SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
) & (B_UART_MSR_DSR
| B_UART_MSR_CTS
)) == (B_UART_MSR_DSR
| B_UART_MSR_CTS
));
439 // Wait for both DSR and CTS to be set OR for DSR to be clear.
440 // DSR is set if a cable is connected.
441 // CTS is set if it is ok to transmit data
443 // DSR CTS Description Action
444 // === === ======================================== ========
445 // 0 0 No cable connected. Transmit
446 // 0 1 No cable connected. Transmit
447 // 1 0 Cable connected, but not clear to send. Wait
448 // 1 1 Cable connected, and clear to send. Transmit
450 return (BOOLEAN
) ((SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
) & (B_UART_MSR_DSR
| B_UART_MSR_CTS
)) != (B_UART_MSR_DSR
));
458 Initialize the serial device hardware.
460 If no initialization is required, then return RETURN_SUCCESS.
461 If the serial device was successfully initialized, then return RETURN_SUCCESS.
462 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
464 @retval RETURN_SUCCESS The serial device was initialized.
465 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
470 SerialPortInitialize (
474 RETURN_STATUS Status
;
475 UINTN SerialRegisterBase
;
477 UINT32 CurrentDivisor
;
481 // Perform platform specific initialization required to enable use of the 16550 device
482 // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
484 Status
= PlatformHookSerialPortInitialize ();
485 if (RETURN_ERROR (Status
)) {
490 // Calculate divisor for baud generator
491 // Ref_Clk_Rate / Baud_Rate / 16
493 Divisor
= PcdGet32 (PcdSerialClockRate
) / (PcdGet32 (PcdSerialBaudRate
) * 16);
494 if ((PcdGet32 (PcdSerialClockRate
) % (PcdGet32 (PcdSerialBaudRate
) * 16)) >= PcdGet32 (PcdSerialBaudRate
) * 8) {
499 // Get the base address of the serial port in either I/O or MMIO space
501 SerialRegisterBase
= GetSerialRegisterBase ();
502 if (SerialRegisterBase
==0) {
503 return RETURN_DEVICE_ERROR
;
507 // See if the serial port is already initialized
510 if ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) & 0x3F) != (PcdGet8 (PcdSerialLineControl
) & 0x3F)) {
513 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) | B_UART_LCR_DLAB
));
514 CurrentDivisor
= SerialPortReadRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
) << 8;
515 CurrentDivisor
|= (UINT32
) SerialPortReadRegister (SerialRegisterBase
, R_UART_BAUD_LOW
);
516 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) & ~B_UART_LCR_DLAB
));
517 if (CurrentDivisor
!= Divisor
) {
521 return RETURN_SUCCESS
;
525 // Wait for the serial port to be ready.
526 // Verify that both the transmit FIFO and the shift register are empty.
528 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) != (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
));
531 // Configure baud rate
533 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, B_UART_LCR_DLAB
);
534 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
, (UINT8
) (Divisor
>> 8));
535 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_LOW
, (UINT8
) (Divisor
& 0xff));
538 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
539 // Strip reserved bits from PcdSerialLineControl
541 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(PcdGet8 (PcdSerialLineControl
) & 0x3F));
544 // Enable and reset FIFOs
545 // Strip reserved bits from PcdSerialFifoControl
547 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, 0x00);
548 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, (UINT8
)(PcdGet8 (PcdSerialFifoControl
) & (B_UART_FCR_FIFOE
| B_UART_FCR_FIFO64
)));
551 // Set RTS and DTR in Modem Control Register(MCR)
553 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
,
554 EFI_SERIAL_REQUEST_TO_SEND
| EFI_SERIAL_DATA_TERMINAL_READY
);
556 return RETURN_SUCCESS
;
560 Write data from buffer to serial device.
562 Writes NumberOfBytes data bytes from Buffer to the serial device.
563 The number of bytes actually written to the serial device is returned.
564 If the return value is less than NumberOfBytes, then the write operation failed.
566 If Buffer is NULL, then ASSERT().
568 If NumberOfBytes is zero, then return 0.
570 @param Buffer Pointer to the data buffer to be written.
571 @param NumberOfBytes Number of bytes to written to the serial device.
573 @retval 0 NumberOfBytes is 0.
574 @retval >0 The number of bytes written to the serial device.
575 If this value is less than NumberOfBytes, then the write operation failed.
582 IN UINTN NumberOfBytes
585 UINTN SerialRegisterBase
;
590 if (Buffer
== NULL
) {
594 SerialRegisterBase
= GetSerialRegisterBase ();
595 if (SerialRegisterBase
==0) {
599 if (NumberOfBytes
== 0) {
601 // Flush the hardware
605 // Wait for both the transmit FIFO and shift register empty.
607 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) != (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
));
610 // Wait for the hardware flow control signal
612 while (!SerialPortWritable (SerialRegisterBase
));
617 // Compute the maximum size of the Tx FIFO
620 if ((PcdGet8 (PcdSerialFifoControl
) & B_UART_FCR_FIFOE
) != 0) {
621 if ((PcdGet8 (PcdSerialFifoControl
) & B_UART_FCR_FIFO64
) == 0) {
624 FifoSize
= PcdGet32 (PcdSerialExtendedTxFifoSize
);
628 Result
= NumberOfBytes
;
629 while (NumberOfBytes
!= 0) {
631 // Wait for the serial port to be ready, to make sure both the transmit FIFO
632 // and shift register empty.
634 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_TEMT
) == 0);
637 // Fill then entire Tx FIFO
639 for (Index
= 0; Index
< FifoSize
&& NumberOfBytes
!= 0; Index
++, NumberOfBytes
--, Buffer
++) {
641 // Wait for the hardware flow control signal
643 while (!SerialPortWritable (SerialRegisterBase
));
646 // Write byte to the transmit buffer.
648 SerialPortWriteRegister (SerialRegisterBase
, R_UART_TXBUF
, *Buffer
);
655 Reads data from a serial device into a buffer.
657 @param Buffer Pointer to the data buffer to store the data read from the serial device.
658 @param NumberOfBytes Number of bytes to read from the serial device.
660 @retval 0 NumberOfBytes is 0.
661 @retval >0 The number of bytes read from the serial device.
662 If this value is less than NumberOfBytes, then the read operation failed.
669 IN UINTN NumberOfBytes
672 UINTN SerialRegisterBase
;
676 if (NULL
== Buffer
) {
680 SerialRegisterBase
= GetSerialRegisterBase ();
681 if (SerialRegisterBase
==0) {
685 Mcr
= (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) & ~B_UART_MCR_RTS
);
687 for (Result
= 0; NumberOfBytes
-- != 0; Result
++, Buffer
++) {
689 // Wait for the serial port to have some data.
691 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_RXRDY
) == 0) {
692 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
694 // Set RTS to let the peer send some data
696 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(Mcr
| B_UART_MCR_RTS
));
699 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
701 // Clear RTS to prevent peer from sending data
703 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, Mcr
);
707 // Read byte from the receive buffer.
709 *Buffer
= SerialPortReadRegister (SerialRegisterBase
, R_UART_RXBUF
);
717 Polls a serial device to see if there is any data waiting to be read.
719 Polls a serial device to see if there is any data waiting to be read.
720 If there is data waiting to be read from the serial device, then TRUE is returned.
721 If there is no data waiting to be read from the serial device, then FALSE is returned.
723 @retval TRUE Data is waiting to be read from the serial device.
724 @retval FALSE There is no data waiting to be read from the serial device.
733 UINTN SerialRegisterBase
;
735 SerialRegisterBase
= GetSerialRegisterBase ();
736 if (SerialRegisterBase
==0) {
741 // Read the serial port status
743 if ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_RXRDY
) != 0) {
744 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
746 // Clear RTS to prevent peer from sending data
748 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) & ~B_UART_MCR_RTS
));
753 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
755 // Set RTS to let the peer send some data
757 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) | B_UART_MCR_RTS
));
764 Sets the control bits on a serial device.
766 @param Control Sets the bits of Control that are settable.
768 @retval RETURN_SUCCESS The new control bits were set on the serial device.
769 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
770 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
775 SerialPortSetControl (
779 UINTN SerialRegisterBase
;
783 // First determine the parameter is invalid.
785 if ((Control
& (~(EFI_SERIAL_REQUEST_TO_SEND
| EFI_SERIAL_DATA_TERMINAL_READY
|
786 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
))) != 0) {
787 return RETURN_UNSUPPORTED
;
790 SerialRegisterBase
= GetSerialRegisterBase ();
791 if (SerialRegisterBase
==0) {
792 return RETURN_UNSUPPORTED
;
796 // Read the Modem Control Register.
798 Mcr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
);
799 Mcr
&= (~(B_UART_MCR_DTRC
| B_UART_MCR_RTS
));
801 if ((Control
& EFI_SERIAL_DATA_TERMINAL_READY
) == EFI_SERIAL_DATA_TERMINAL_READY
) {
802 Mcr
|= B_UART_MCR_DTRC
;
805 if ((Control
& EFI_SERIAL_REQUEST_TO_SEND
) == EFI_SERIAL_REQUEST_TO_SEND
) {
806 Mcr
|= B_UART_MCR_RTS
;
810 // Write the Modem Control Register.
812 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, Mcr
);
814 return RETURN_SUCCESS
;
818 Retrieve the status of the control bits on a serial device.
820 @param Control A pointer to return the current control signals from the serial device.
822 @retval RETURN_SUCCESS The control bits were read from the serial device.
823 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
824 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
829 SerialPortGetControl (
833 UINTN SerialRegisterBase
;
838 SerialRegisterBase
= GetSerialRegisterBase ();
839 if (SerialRegisterBase
==0) {
840 return RETURN_UNSUPPORTED
;
846 // Read the Modem Status Register.
848 Msr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
);
850 if ((Msr
& B_UART_MSR_CTS
) == B_UART_MSR_CTS
) {
851 *Control
|= EFI_SERIAL_CLEAR_TO_SEND
;
854 if ((Msr
& B_UART_MSR_DSR
) == B_UART_MSR_DSR
) {
855 *Control
|= EFI_SERIAL_DATA_SET_READY
;
858 if ((Msr
& B_UART_MSR_RI
) == B_UART_MSR_RI
) {
859 *Control
|= EFI_SERIAL_RING_INDICATE
;
862 if ((Msr
& B_UART_MSR_DCD
) == B_UART_MSR_DCD
) {
863 *Control
|= EFI_SERIAL_CARRIER_DETECT
;
867 // Read the Modem Control Register.
869 Mcr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
);
871 if ((Mcr
& B_UART_MCR_DTRC
) == B_UART_MCR_DTRC
) {
872 *Control
|= EFI_SERIAL_DATA_TERMINAL_READY
;
875 if ((Mcr
& B_UART_MCR_RTS
) == B_UART_MCR_RTS
) {
876 *Control
|= EFI_SERIAL_REQUEST_TO_SEND
;
879 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
880 *Control
|= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
;
884 // Read the Line Status Register.
886 Lsr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
);
888 if ((Lsr
& (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) == (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) {
889 *Control
|= EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
892 if ((Lsr
& B_UART_LSR_RXRDY
) == 0) {
893 *Control
|= EFI_SERIAL_INPUT_BUFFER_EMPTY
;
896 return RETURN_SUCCESS
;
900 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
901 data bits, and stop bits on a serial device.
903 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
904 device's default interface speed.
905 On output, the value actually set.
906 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
907 serial interface. A ReceiveFifoDepth value of 0 will use
908 the device's default FIFO depth.
909 On output, the value actually set.
910 @param Timeout The requested time out for a single character in microseconds.
911 This timeout applies to both the transmit and receive side of the
912 interface. A Timeout value of 0 will use the device's default time
914 On output, the value actually set.
915 @param Parity The type of parity to use on this serial device. A Parity value of
916 DefaultParity will use the device's default parity value.
917 On output, the value actually set.
918 @param DataBits The number of data bits to use on the serial device. A DataBits
919 value of 0 will use the device's default data bit setting.
920 On output, the value actually set.
921 @param StopBits The number of stop bits to use on this serial device. A StopBits
922 value of DefaultStopBits will use the device's default number of
924 On output, the value actually set.
926 @retval RETURN_SUCCESS The new attributes were set on the serial device.
927 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
928 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
929 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
934 SerialPortSetAttributes (
935 IN OUT UINT64
*BaudRate
,
936 IN OUT UINT32
*ReceiveFifoDepth
,
937 IN OUT UINT32
*Timeout
,
938 IN OUT EFI_PARITY_TYPE
*Parity
,
939 IN OUT UINT8
*DataBits
,
940 IN OUT EFI_STOP_BITS_TYPE
*StopBits
943 UINTN SerialRegisterBase
;
944 UINT32 SerialBaudRate
;
951 SerialRegisterBase
= GetSerialRegisterBase ();
952 if (SerialRegisterBase
==0) {
953 return RETURN_UNSUPPORTED
;
957 // Check for default settings and fill in actual values.
959 if (*BaudRate
== 0) {
960 *BaudRate
= PcdGet32 (PcdSerialBaudRate
);
962 SerialBaudRate
= (UINT32
) *BaudRate
;
964 if (*DataBits
== 0) {
965 LcrData
= (UINT8
) (PcdGet8 (PcdSerialLineControl
) & 0x3);
966 *DataBits
= LcrData
+ 5;
968 if ((*DataBits
< 5) || (*DataBits
> 8)) {
969 return RETURN_INVALID_PARAMETER
;
974 LcrData
= (UINT8
) (*DataBits
- (UINT8
) 5);
977 if (*Parity
== DefaultParity
) {
978 LcrParity
= (UINT8
) ((PcdGet8 (PcdSerialLineControl
) >> 3) & 0x7);
985 *Parity
= EvenParity
;
993 *Parity
= SpaceParity
;
997 *Parity
= MarkParity
;
1026 return RETURN_INVALID_PARAMETER
;
1030 if (*StopBits
== DefaultStopBits
) {
1031 LcrStop
= (UINT8
) ((PcdGet8 (PcdSerialLineControl
) >> 2) & 0x1);
1034 *StopBits
= OneStopBit
;
1038 if (*DataBits
== 5) {
1039 *StopBits
= OneFiveStopBits
;
1041 *StopBits
= TwoStopBits
;
1049 switch (*StopBits
) {
1054 case OneFiveStopBits
:
1060 return RETURN_INVALID_PARAMETER
;
1065 // Calculate divisor for baud generator
1066 // Ref_Clk_Rate / Baud_Rate / 16
1068 Divisor
= PcdGet32 (PcdSerialClockRate
) / (SerialBaudRate
* 16);
1069 if ((PcdGet32 (PcdSerialClockRate
) % (SerialBaudRate
* 16)) >= SerialBaudRate
* 8) {
1074 // Configure baud rate
1076 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, B_UART_LCR_DLAB
);
1077 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
, (UINT8
) (Divisor
>> 8));
1078 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_LOW
, (UINT8
) (Divisor
& 0xff));
1081 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
1082 // Strip reserved bits from line control value
1084 Lcr
= (UINT8
) ((LcrParity
<< 3) | (LcrStop
<< 2) | LcrData
);
1085 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
) (Lcr
& 0x3F));
1087 return RETURN_SUCCESS
;