2 16550 UART Serial Port library functions
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) 2018, AMD Incorporated. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <IndustryStandard/Pci.h>
20 #include <Library/SerialPortLib.h>
21 #include <Library/PcdLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/PciLib.h>
24 #include <Library/PlatformHookLib.h>
25 #include <Library/BaseLib.h>
30 #define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
33 // 16550 UART register offsets and bitfields
35 #define R_UART_RXBUF 0 // LCR_DLAB = 0
36 #define R_UART_TXBUF 0 // LCR_DLAB = 0
37 #define R_UART_BAUD_LOW 0 // LCR_DLAB = 1
38 #define R_UART_BAUD_HIGH 1 // LCR_DLAB = 1
39 #define R_UART_IER 1 // LCR_DLAB = 0
41 #define B_UART_FCR_FIFOE BIT0
42 #define B_UART_FCR_FIFO64 BIT5
44 #define B_UART_LCR_DLAB BIT7
46 #define B_UART_MCR_DTRC BIT0
47 #define B_UART_MCR_RTS BIT1
49 #define B_UART_LSR_RXRDY BIT0
50 #define B_UART_LSR_TXRDY BIT5
51 #define B_UART_LSR_TEMT BIT6
53 #define B_UART_MSR_CTS BIT4
54 #define B_UART_MSR_DSR BIT5
55 #define B_UART_MSR_RI BIT6
56 #define B_UART_MSR_DCD BIT7
59 // 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
64 UINT16 PowerManagementStatusAndControlRegister
;
65 } PCI_UART_DEVICE_INFO
;
68 Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
69 MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
70 parameter Offset is added to the base address of the 16550 registers that is specified
71 by PcdSerialRegisterBase.
73 @param Base The base address register of UART device.
74 @param Offset The offset of the 16550 register to read.
76 @return The value read from the 16550 register.
80 SerialPortReadRegister (
85 if (PcdGetBool (PcdSerialUseMmio
)) {
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.
98 @param Base The base address register of UART device.
99 @param Offset The offset of the 16550 register to write.
100 @param Value The value to write to the 16550 register specified by Offset.
102 @return The value written to the 16550 register.
106 SerialPortWriteRegister (
112 if (PcdGetBool (PcdSerialUseMmio
)) {
113 return MmioWrite8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
), Value
);
115 return IoWrite8 (Base
+ Offset
* PcdGet32 (PcdSerialRegisterStride
), Value
);
120 Update the value of an 16-bit PCI configuration register in a PCI device. If the
121 PCI Configuration register specified by PciAddress is already programmed with a
122 non-zero value, then return the current value. Otherwise update the PCI configuration
123 register specified by PciAddress with the value specified by Value and return the
124 value programmed into the PCI configuration register. All values must be masked
125 using the bitmask specified by Mask.
127 @param PciAddress PCI Library address of the PCI Configuration register to update.
128 @param Value The value to program into the PCI Configuration Register.
129 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
133 SerialPortLibUpdatePciRegister16 (
141 CurrentValue
= PciRead16 (PciAddress
) & Mask
;
142 if (CurrentValue
!= 0) {
145 return PciWrite16 (PciAddress
, Value
& Mask
);
149 Update the value of an 32-bit PCI configuration register in a PCI device. If the
150 PCI Configuration register specified by PciAddress is already programmed with a
151 non-zero value, then return the current value. Otherwise update the PCI configuration
152 register specified by PciAddress with the value specified by Value and return the
153 value programmed into the PCI configuration register. All values must be masked
154 using the bitmask specified by Mask.
156 @param PciAddress PCI Library address of the PCI Configuration register to update.
157 @param Value The value to program into the PCI Configuration Register.
158 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
160 @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
164 SerialPortLibUpdatePciRegister32 (
172 CurrentValue
= PciRead32 (PciAddress
) & Mask
;
173 if (CurrentValue
!= 0) {
176 return PciWrite32 (PciAddress
, Value
& Mask
);
180 Retrieve the I/O or MMIO base address register for the PCI UART device.
182 This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
183 Device if they are not already enabled.
185 @return The base address register of the UART device.
189 GetSerialRegisterBase (
195 UINTN SubordinateBusNumber
;
197 UINT32 ParentIoLimit
;
198 UINT16 ParentMemoryBase
;
199 UINT16 ParentMemoryLimit
;
204 UINTN SerialRegisterBase
;
206 UINT32 RegisterBaseMask
;
207 PCI_UART_DEVICE_INFO
*DeviceInfo
;
210 // Get PCI Device Info
212 DeviceInfo
= (PCI_UART_DEVICE_INFO
*) PcdGetPtr (PcdSerialPciDeviceInfo
);
215 // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
217 if (DeviceInfo
->Device
== 0xff) {
218 return (UINTN
)PcdGet64 (PcdSerialRegisterBase
);
222 // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
224 ParentMemoryBase
= 0 >> 16;
225 ParentMemoryLimit
= 0xfff00000 >> 16;
226 ParentIoBase
= 0 >> 12;
227 ParentIoLimit
= 0xf000 >> 12;
230 // Enable I/O and MMIO in PCI Bridge
231 // Assume Root Bus Numer is Zero.
233 for (BusNumber
= 0; (DeviceInfo
+ 1)->Device
!= 0xff; DeviceInfo
++) {
235 // Compute PCI Lib Address to PCI to PCI Bridge
237 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
240 // Retrieve and verify the bus numbers in the PCI to PCI Bridge
242 BusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
);
243 SubordinateBusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET
);
244 if (BusNumber
== 0 || BusNumber
> SubordinateBusNumber
) {
249 // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
251 if (PcdGetBool (PcdSerialUseMmio
)) {
252 MemoryLimit
= PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.MemoryLimit
)) & 0xfff0;
253 MemoryBase
= PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.MemoryBase
)) & 0xfff0;
256 // If PCI Bridge MMIO window is disabled, then return 0
258 if (MemoryLimit
< MemoryBase
) {
263 // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
265 if (MemoryBase
< ParentMemoryBase
|| MemoryBase
> ParentMemoryLimit
|| MemoryLimit
> ParentMemoryLimit
) {
268 ParentMemoryBase
= MemoryBase
;
269 ParentMemoryLimit
= MemoryLimit
;
271 IoLimit
= PciRead8 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoLimit
));
272 if ((IoLimit
& PCI_BRIDGE_32_BIT_IO_SPACE
) == 0) {
273 IoLimit
= IoLimit
>> 4;
275 IoLimit
= (PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoLimitUpper16
)) << 4) | (IoLimit
>> 4);
277 IoBase
= PciRead8 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoBase
));
278 if ((IoBase
& PCI_BRIDGE_32_BIT_IO_SPACE
) == 0) {
279 IoBase
= IoBase
>> 4;
281 IoBase
= (PciRead16 (PciLibAddress
+ OFFSET_OF (PCI_TYPE01
, Bridge
.IoBaseUpper16
)) << 4) | (IoBase
>> 4);
285 // If PCI Bridge I/O window is disabled, then return 0
287 if (IoLimit
< IoBase
) {
292 // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
294 if (IoBase
< ParentIoBase
|| IoBase
> ParentIoLimit
|| IoLimit
> ParentIoLimit
) {
297 ParentIoBase
= IoBase
;
298 ParentIoLimit
= IoLimit
;
303 // Compute PCI Lib Address to PCI UART
305 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
308 // Find the first IO or MMIO BAR
310 RegisterBaseMask
= 0xFFFFFFF0;
311 for (BarIndex
= 0; BarIndex
< PCI_MAX_BAR
; BarIndex
++) {
312 SerialRegisterBase
= PciRead32 (PciLibAddress
+ PCI_BASE_ADDRESSREG_OFFSET
+ BarIndex
* 4);
313 if (PcdGetBool (PcdSerialUseMmio
) && ((SerialRegisterBase
& BIT0
) == 0)) {
317 RegisterBaseMask
= 0xFFFFFFF0;
321 if ((!PcdGetBool (PcdSerialUseMmio
)) && ((SerialRegisterBase
& BIT0
) != 0)) {
325 RegisterBaseMask
= 0xFFFFFFF8;
331 // MMIO or IO BAR is not found.
333 if (BarIndex
== PCI_MAX_BAR
) {
340 SerialRegisterBase
= SerialPortLibUpdatePciRegister32 (
341 PciLibAddress
+ PCI_BASE_ADDRESSREG_OFFSET
+ BarIndex
* 4,
342 (UINT32
)PcdGet64 (PcdSerialRegisterBase
),
347 // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
349 if (PcdGetBool (PcdSerialUseMmio
)) {
350 if (((SerialRegisterBase
>> 16) & 0xfff0) < ParentMemoryBase
|| ((SerialRegisterBase
>> 16) & 0xfff0) > ParentMemoryLimit
) {
354 if ((SerialRegisterBase
>> 12) < ParentIoBase
|| (SerialRegisterBase
>> 12) > ParentIoLimit
) {
360 // Enable I/O and MMIO in PCI UART Device if they are not already enabled
363 PciLibAddress
+ PCI_COMMAND_OFFSET
,
364 PcdGetBool (PcdSerialUseMmio
) ? EFI_PCI_COMMAND_MEMORY_SPACE
: EFI_PCI_COMMAND_IO_SPACE
368 // Force D0 state if a Power Management and Status Register is specified
370 if (DeviceInfo
->PowerManagementStatusAndControlRegister
!= 0x00) {
371 if ((PciRead16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
) & (BIT0
| BIT1
)) != 0x00) {
372 PciAnd16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
, (UINT16
)~(BIT0
| BIT1
));
374 // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
376 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, (UINT8
)(PcdGet8 (PcdSerialFifoControl
) & (B_UART_FCR_FIFOE
| B_UART_FCR_FIFO64
)));
381 // Get PCI Device Info
383 DeviceInfo
= (PCI_UART_DEVICE_INFO
*) PcdGetPtr (PcdSerialPciDeviceInfo
);
386 // Enable I/O or MMIO in PCI Bridge
387 // Assume Root Bus Numer is Zero.
389 for (BusNumber
= 0; (DeviceInfo
+ 1)->Device
!= 0xff; DeviceInfo
++) {
391 // Compute PCI Lib Address to PCI to PCI Bridge
393 PciLibAddress
= PCI_LIB_ADDRESS (BusNumber
, DeviceInfo
->Device
, DeviceInfo
->Function
, 0);
396 // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
399 PciLibAddress
+ PCI_COMMAND_OFFSET
,
400 PcdGetBool (PcdSerialUseMmio
) ? EFI_PCI_COMMAND_MEMORY_SPACE
: EFI_PCI_COMMAND_IO_SPACE
404 // Force D0 state if a Power Management and Status Register is specified
406 if (DeviceInfo
->PowerManagementStatusAndControlRegister
!= 0x00) {
407 if ((PciRead16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
) & (BIT0
| BIT1
)) != 0x00) {
408 PciAnd16 (PciLibAddress
+ DeviceInfo
->PowerManagementStatusAndControlRegister
, (UINT16
)~(BIT0
| BIT1
));
412 BusNumber
= PciRead8 (PciLibAddress
+ PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
);
415 return SerialRegisterBase
;
419 Return whether the hardware flow control signal allows writing.
421 @param SerialRegisterBase The base address register of UART device.
423 @retval TRUE The serial port is writable.
424 @retval FALSE The serial port is not writable.
428 UINTN SerialRegisterBase
431 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
432 if (PcdGetBool (PcdSerialDetectCable
)) {
434 // Wait for both DSR and CTS to be set
435 // DSR is set if a cable is connected.
436 // CTS is set if it is ok to transmit data
438 // DSR CTS Description Action
439 // === === ======================================== ========
440 // 0 0 No cable connected. Wait
441 // 0 1 No cable connected. Wait
442 // 1 0 Cable connected, but not clear to send. Wait
443 // 1 1 Cable connected, and clear to send. Transmit
445 return (BOOLEAN
) ((SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
) & (B_UART_MSR_DSR
| B_UART_MSR_CTS
)) == (B_UART_MSR_DSR
| B_UART_MSR_CTS
));
448 // Wait for both DSR and CTS to be set OR for DSR to be clear.
449 // DSR is set if a cable is connected.
450 // CTS is set if it is ok to transmit data
452 // DSR CTS Description Action
453 // === === ======================================== ========
454 // 0 0 No cable connected. Transmit
455 // 0 1 No cable connected. Transmit
456 // 1 0 Cable connected, but not clear to send. Wait
457 // 1 1 Cable connected, and clar to send. Transmit
459 return (BOOLEAN
) ((SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
) & (B_UART_MSR_DSR
| B_UART_MSR_CTS
)) != (B_UART_MSR_DSR
));
467 Initialize the serial device hardware.
469 If no initialization is required, then return RETURN_SUCCESS.
470 If the serial device was successfully initialized, then return RETURN_SUCCESS.
471 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
473 @retval RETURN_SUCCESS The serial device was initialized.
474 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
479 SerialPortInitialize (
483 RETURN_STATUS Status
;
484 UINTN SerialRegisterBase
;
486 UINT32 CurrentDivisor
;
490 // Perform platform specific initialization required to enable use of the 16550 device
491 // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
493 Status
= PlatformHookSerialPortInitialize ();
494 if (RETURN_ERROR (Status
)) {
499 // Calculate divisor for baud generator
500 // Ref_Clk_Rate / Baud_Rate / 16
502 Divisor
= PcdGet32 (PcdSerialClockRate
) / (PcdGet32 (PcdSerialBaudRate
) * 16);
503 if ((PcdGet32 (PcdSerialClockRate
) % (PcdGet32 (PcdSerialBaudRate
) * 16)) >= PcdGet32 (PcdSerialBaudRate
) * 8) {
508 // Get the base address of the serial port in either I/O or MMIO space
510 SerialRegisterBase
= GetSerialRegisterBase ();
511 if (SerialRegisterBase
==0) {
512 return RETURN_DEVICE_ERROR
;
516 // See if the serial port is already initialized
519 if ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) & 0x3F) != (PcdGet8 (PcdSerialLineControl
) & 0x3F)) {
522 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) | B_UART_LCR_DLAB
));
523 CurrentDivisor
= SerialPortReadRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
) << 8;
524 CurrentDivisor
|= (UINT32
) SerialPortReadRegister (SerialRegisterBase
, R_UART_BAUD_LOW
);
525 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_LCR
) & ~B_UART_LCR_DLAB
));
526 if (CurrentDivisor
!= Divisor
) {
530 return RETURN_SUCCESS
;
534 // Wait for the serial port to be ready.
535 // Verify that both the transmit FIFO and the shift register are empty.
537 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) != (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
));
540 // Configure baud rate
542 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, B_UART_LCR_DLAB
);
543 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
, (UINT8
) (Divisor
>> 8));
544 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_LOW
, (UINT8
) (Divisor
& 0xff));
547 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
548 // Strip reserved bits from PcdSerialLineControl
550 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
)(PcdGet8 (PcdSerialLineControl
) & 0x3F));
553 // Enable and reset FIFOs
554 // Strip reserved bits from PcdSerialFifoControl
556 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, 0x00);
557 SerialPortWriteRegister (SerialRegisterBase
, R_UART_FCR
, (UINT8
)(PcdGet8 (PcdSerialFifoControl
) & (B_UART_FCR_FIFOE
| B_UART_FCR_FIFO64
)));
560 // Set FIFO Polled Mode by clearing IER after setting FCR
562 SerialPortWriteRegister (SerialRegisterBase
, R_UART_IER
, 0x00);
565 // Put Modem Control Register(MCR) into its reset state of 0x00.
567 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, 0x00);
569 return RETURN_SUCCESS
;
573 Write data from buffer to serial device.
575 Writes NumberOfBytes data bytes from Buffer to the serial device.
576 The number of bytes actually written to the serial device is returned.
577 If the return value is less than NumberOfBytes, then the write operation failed.
579 If Buffer is NULL, then ASSERT().
581 If NumberOfBytes is zero, then return 0.
583 @param Buffer Pointer to the data buffer to be written.
584 @param NumberOfBytes Number of bytes to written to the serial device.
586 @retval 0 NumberOfBytes is 0.
587 @retval >0 The number of bytes written to the serial device.
588 If this value is less than NumberOfBytes, then the write operation failed.
595 IN UINTN NumberOfBytes
598 UINTN SerialRegisterBase
;
603 if (Buffer
== NULL
) {
607 SerialRegisterBase
= GetSerialRegisterBase ();
608 if (SerialRegisterBase
==0) {
612 if (NumberOfBytes
== 0) {
614 // Flush the hardware
618 // Wait for both the transmit FIFO and shift register empty.
620 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) != (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
));
623 // Wait for the hardware flow control signal
625 while (!SerialPortWritable (SerialRegisterBase
));
630 // Compute the maximum size of the Tx FIFO
633 if ((PcdGet8 (PcdSerialFifoControl
) & B_UART_FCR_FIFOE
) != 0) {
634 if ((PcdGet8 (PcdSerialFifoControl
) & B_UART_FCR_FIFO64
) == 0) {
637 FifoSize
= PcdGet32 (PcdSerialExtendedTxFifoSize
);
641 Result
= NumberOfBytes
;
642 while (NumberOfBytes
!= 0) {
644 // Wait for the serial port to be ready, to make sure both the transmit FIFO
645 // and shift register empty.
647 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_TEMT
) == 0);
650 // Fill then entire Tx FIFO
652 for (Index
= 0; Index
< FifoSize
&& NumberOfBytes
!= 0; Index
++, NumberOfBytes
--, Buffer
++) {
654 // Wait for the hardware flow control signal
656 while (!SerialPortWritable (SerialRegisterBase
));
659 // Write byte to the transmit buffer.
661 SerialPortWriteRegister (SerialRegisterBase
, R_UART_TXBUF
, *Buffer
);
668 Reads data from a serial device into a buffer.
670 @param Buffer Pointer to the data buffer to store the data read from the serial device.
671 @param NumberOfBytes Number of bytes to read from the serial device.
673 @retval 0 NumberOfBytes is 0.
674 @retval >0 The number of bytes read from the serial device.
675 If this value is less than NumberOfBytes, then the read operation failed.
682 IN UINTN NumberOfBytes
685 UINTN SerialRegisterBase
;
689 if (NULL
== Buffer
) {
693 SerialRegisterBase
= GetSerialRegisterBase ();
694 if (SerialRegisterBase
==0) {
698 Mcr
= (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) & ~B_UART_MCR_RTS
);
700 for (Result
= 0; NumberOfBytes
-- != 0; Result
++, Buffer
++) {
702 // Wait for the serial port to have some data.
704 while ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_RXRDY
) == 0) {
705 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
707 // Set RTS to let the peer send some data
709 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(Mcr
| B_UART_MCR_RTS
));
712 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
714 // Clear RTS to prevent peer from sending data
716 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, Mcr
);
720 // Read byte from the receive buffer.
722 *Buffer
= SerialPortReadRegister (SerialRegisterBase
, R_UART_RXBUF
);
730 Polls a serial device to see if there is any data waiting to be read.
732 Polls aserial device to see if there is any data waiting to be read.
733 If there is data waiting to be read from the serial device, then TRUE is returned.
734 If there is no data waiting to be read from the serial device, then FALSE is returned.
736 @retval TRUE Data is waiting to be read from the serial device.
737 @retval FALSE There is no data waiting to be read from the serial device.
746 UINTN SerialRegisterBase
;
748 SerialRegisterBase
= GetSerialRegisterBase ();
749 if (SerialRegisterBase
==0) {
754 // Read the serial port status
756 if ((SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
) & B_UART_LSR_RXRDY
) != 0) {
757 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
759 // Clear RTS to prevent peer from sending data
761 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) & ~B_UART_MCR_RTS
));
766 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
768 // Set RTS to let the peer send some data
770 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, (UINT8
)(SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
) | B_UART_MCR_RTS
));
777 Sets the control bits on a serial device.
779 @param Control Sets the bits of Control that are settable.
781 @retval RETURN_SUCCESS The new control bits were set on the serial device.
782 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
783 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
788 SerialPortSetControl (
792 UINTN SerialRegisterBase
;
796 // First determine the parameter is invalid.
798 if ((Control
& (~(EFI_SERIAL_REQUEST_TO_SEND
| EFI_SERIAL_DATA_TERMINAL_READY
|
799 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
))) != 0) {
800 return RETURN_UNSUPPORTED
;
803 SerialRegisterBase
= GetSerialRegisterBase ();
804 if (SerialRegisterBase
==0) {
805 return RETURN_UNSUPPORTED
;
809 // Read the Modem Control Register.
811 Mcr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
);
812 Mcr
&= (~(B_UART_MCR_DTRC
| B_UART_MCR_RTS
));
814 if ((Control
& EFI_SERIAL_DATA_TERMINAL_READY
) == EFI_SERIAL_DATA_TERMINAL_READY
) {
815 Mcr
|= B_UART_MCR_DTRC
;
818 if ((Control
& EFI_SERIAL_REQUEST_TO_SEND
) == EFI_SERIAL_REQUEST_TO_SEND
) {
819 Mcr
|= B_UART_MCR_RTS
;
823 // Write the Modem Control Register.
825 SerialPortWriteRegister (SerialRegisterBase
, R_UART_MCR
, Mcr
);
827 return RETURN_SUCCESS
;
831 Retrieve the status of the control bits on a serial device.
833 @param Control A pointer to return the current control signals from the serial device.
835 @retval RETURN_SUCCESS The control bits were read from the serial device.
836 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
837 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
842 SerialPortGetControl (
846 UINTN SerialRegisterBase
;
851 SerialRegisterBase
= GetSerialRegisterBase ();
852 if (SerialRegisterBase
==0) {
853 return RETURN_UNSUPPORTED
;
859 // Read the Modem Status Register.
861 Msr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MSR
);
863 if ((Msr
& B_UART_MSR_CTS
) == B_UART_MSR_CTS
) {
864 *Control
|= EFI_SERIAL_CLEAR_TO_SEND
;
867 if ((Msr
& B_UART_MSR_DSR
) == B_UART_MSR_DSR
) {
868 *Control
|= EFI_SERIAL_DATA_SET_READY
;
871 if ((Msr
& B_UART_MSR_RI
) == B_UART_MSR_RI
) {
872 *Control
|= EFI_SERIAL_RING_INDICATE
;
875 if ((Msr
& B_UART_MSR_DCD
) == B_UART_MSR_DCD
) {
876 *Control
|= EFI_SERIAL_CARRIER_DETECT
;
880 // Read the Modem Control Register.
882 Mcr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_MCR
);
884 if ((Mcr
& B_UART_MCR_DTRC
) == B_UART_MCR_DTRC
) {
885 *Control
|= EFI_SERIAL_DATA_TERMINAL_READY
;
888 if ((Mcr
& B_UART_MCR_RTS
) == B_UART_MCR_RTS
) {
889 *Control
|= EFI_SERIAL_REQUEST_TO_SEND
;
892 if (PcdGetBool (PcdSerialUseHardwareFlowControl
)) {
893 *Control
|= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE
;
897 // Read the Line Status Register.
899 Lsr
= SerialPortReadRegister (SerialRegisterBase
, R_UART_LSR
);
901 if ((Lsr
& (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) == (B_UART_LSR_TEMT
| B_UART_LSR_TXRDY
)) {
902 *Control
|= EFI_SERIAL_OUTPUT_BUFFER_EMPTY
;
905 if ((Lsr
& B_UART_LSR_RXRDY
) == 0) {
906 *Control
|= EFI_SERIAL_INPUT_BUFFER_EMPTY
;
909 return RETURN_SUCCESS
;
913 Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
914 data bits, and stop bits on a serial device.
916 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
917 device's default interface speed.
918 On output, the value actually set.
919 @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the
920 serial interface. A ReceiveFifoDepth value of 0 will use
921 the device's default FIFO depth.
922 On output, the value actually set.
923 @param Timeout The requested time out for a single character in microseconds.
924 This timeout applies to both the transmit and receive side of the
925 interface. A Timeout value of 0 will use the device's default time
927 On output, the value actually set.
928 @param Parity The type of parity to use on this serial device. A Parity value of
929 DefaultParity will use the device's default parity value.
930 On output, the value actually set.
931 @param DataBits The number of data bits to use on the serial device. A DataBits
932 vaule of 0 will use the device's default data bit setting.
933 On output, the value actually set.
934 @param StopBits The number of stop bits to use on this serial device. A StopBits
935 value of DefaultStopBits will use the device's default number of
937 On output, the value actually set.
939 @retval RETURN_SUCCESS The new attributes were set on the serial device.
940 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
941 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
942 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
947 SerialPortSetAttributes (
948 IN OUT UINT64
*BaudRate
,
949 IN OUT UINT32
*ReceiveFifoDepth
,
950 IN OUT UINT32
*Timeout
,
951 IN OUT EFI_PARITY_TYPE
*Parity
,
952 IN OUT UINT8
*DataBits
,
953 IN OUT EFI_STOP_BITS_TYPE
*StopBits
956 UINTN SerialRegisterBase
;
957 UINT32 SerialBaudRate
;
964 SerialRegisterBase
= GetSerialRegisterBase ();
965 if (SerialRegisterBase
==0) {
966 return RETURN_UNSUPPORTED
;
970 // Check for default settings and fill in actual values.
972 if (*BaudRate
== 0) {
973 *BaudRate
= PcdGet32 (PcdSerialBaudRate
);
975 SerialBaudRate
= (UINT32
) *BaudRate
;
977 if (*DataBits
== 0) {
978 LcrData
= (UINT8
) (PcdGet8 (PcdSerialLineControl
) & 0x3);
979 *DataBits
= LcrData
+ 5;
981 if ((*DataBits
< 5) || (*DataBits
> 8)) {
982 return RETURN_INVALID_PARAMETER
;
987 LcrData
= (UINT8
) (*DataBits
- (UINT8
) 5);
990 if (*Parity
== DefaultParity
) {
991 LcrParity
= (UINT8
) ((PcdGet8 (PcdSerialLineControl
) >> 3) & 0x7);
998 *Parity
= EvenParity
;
1002 *Parity
= OddParity
;
1006 *Parity
= SpaceParity
;
1010 *Parity
= MarkParity
;
1039 return RETURN_INVALID_PARAMETER
;
1043 if (*StopBits
== DefaultStopBits
) {
1044 LcrStop
= (UINT8
) ((PcdGet8 (PcdSerialLineControl
) >> 2) & 0x1);
1047 *StopBits
= OneStopBit
;
1051 if (*DataBits
== 5) {
1052 *StopBits
= OneFiveStopBits
;
1054 *StopBits
= TwoStopBits
;
1062 switch (*StopBits
) {
1067 case OneFiveStopBits
:
1073 return RETURN_INVALID_PARAMETER
;
1078 // Calculate divisor for baud generator
1079 // Ref_Clk_Rate / Baud_Rate / 16
1081 Divisor
= PcdGet32 (PcdSerialClockRate
) / (SerialBaudRate
* 16);
1082 if ((PcdGet32 (PcdSerialClockRate
) % (SerialBaudRate
* 16)) >= SerialBaudRate
* 8) {
1087 // Configure baud rate
1089 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, B_UART_LCR_DLAB
);
1090 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_HIGH
, (UINT8
) (Divisor
>> 8));
1091 SerialPortWriteRegister (SerialRegisterBase
, R_UART_BAUD_LOW
, (UINT8
) (Divisor
& 0xff));
1094 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
1095 // Strip reserved bits from line control value
1097 Lcr
= (UINT8
) ((LcrParity
<< 3) | (LcrStop
<< 2) | LcrData
);
1098 SerialPortWriteRegister (SerialRegisterBase
, R_UART_LCR
, (UINT8
) (Lcr
& 0x3F));
1100 return RETURN_SUCCESS
;