From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.9387.1588690241954806367 for ; Tue, 05 May 2020 07:50:42 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: ard.biesheuvel@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 81D5831B; Tue, 5 May 2020 07:50:41 -0700 (PDT) Received: from e123331-lin.nice.arm.com (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 1BBE73F68F; Tue, 5 May 2020 07:50:39 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, pete@akeo.ie, andrey.warkentin@gmail.com, Ard Biesheuvel Subject: [PATCH edk2-platforms 1/5] Platform/RaspberryPi/DualSerialPortLib: split up to ease reuse Date: Tue, 5 May 2020 16:50:25 +0200 Message-Id: <20200505145029.29826-2-ard.biesheuvel@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200505145029.29826-1-ard.biesheuvel@arm.com> References: <20200505145029.29826-1-ard.biesheuvel@arm.com> In preparation of creating different versions of DualSerialPortLib, split off the parts that will be shared between all versions. Signed-off-by: Ard Biesheuvel --- Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.inf | 5 +- Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.h | 82 +++++++ Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.c | 229 +------------------- Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLibCommon.c | 218 +++++++++++++++++++ 4 files changed, 305 insertions(+), 229 deletions(-) diff --git a/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.inf b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.inf index af1e6b026fe6..fda9ff2bcbf9 100644 --- a/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.inf +++ b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.inf @@ -19,9 +19,8 @@ [Defines] [Packages] ArmPlatformPkg/ArmPlatformPkg.dec - EmbeddedPkg/EmbeddedPkg.dec - MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec Silicon/Broadcom/Bcm283x/Bcm283x.dec [LibraryClasses] @@ -32,6 +31,8 @@ [LibraryClasses] [Sources] DualSerialPortLib.c + DualSerialPortLib.h + DualSerialPortLibCommon.c [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterAccessWidth ## SOMETIMES_CONSUMES diff --git a/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.h b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.h new file mode 100644 index 000000000000..a8d150f516b9 --- /dev/null +++ b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.h @@ -0,0 +1,82 @@ +/** @file + 16550 and PL011 Serial Port library functions for Raspberry Pi + + Copyright (c) 2020, Pete Batard + Copyright (c) 2018, AMD Incorporated. All rights reserved.
+ Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2012 - 2016, ARM Ltd. All rights reserved.
+ Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +#define PL011_UART_REGISTER_BASE BCM2836_PL011_UART_BASE_ADDRESS +#define MINI_UART_REGISTER_BASE (BCM2836_MINI_UART_BASE_ADDRESS + 0x40) + +// +// 16550 UART register offsets and bitfields +// +#define R_UART_RXBUF 0 // LCR_DLAB = 0 +#define R_UART_TXBUF 0 // LCR_DLAB = 0 +#define R_UART_BAUD_LOW 0 // LCR_DLAB = 1 +#define R_UART_BAUD_HIGH 1 // LCR_DLAB = 1 +#define R_UART_IER 1 // LCR_DLAB = 0 +#define R_UART_FCR 2 +#define B_UART_FCR_FIFOE BIT0 +#define B_UART_FCR_FIFO64 BIT5 +#define R_UART_LCR 3 +#define B_UART_LCR_DLAB BIT7 +#define R_UART_MCR 4 +#define B_UART_MCR_DTRC BIT0 +#define B_UART_MCR_RTS BIT1 +#define R_UART_LSR 5 +#define B_UART_LSR_RXRDY BIT0 +#define B_UART_LSR_TXRDY BIT5 +#define B_UART_LSR_TEMT BIT6 +#define R_UART_MSR 6 +#define B_UART_MSR_CTS BIT4 +#define B_UART_MSR_DSR BIT5 +#define B_UART_MSR_RI BIT6 +#define B_UART_MSR_DCD BIT7 + +extern BOOLEAN UsePl011Uart; +extern BOOLEAN UsePl011UartSet; + +/** + Read an 8-bit 16550 register. + + @param Base The base address register of UART device. + @param Offset The offset of the 16550 register to read. + + @return The value read from the 16550 register. + +**/ +UINT8 +SerialPortReadRegister ( + UINTN Base, + UINTN Offset + ); + +/** + Write an 8-bit 16550 register. + + @param Base The base address register of UART device. + @param Offset The offset of the 16550 register to write. + @param Value The value to write to the 16550 register specified by Offset. + + @return The value written to the 16550 register. + +**/ +UINT8 +SerialPortWriteRegister ( + UINTN Base, + UINTN Offset, + UINT8 Value + ); + diff --git a/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.c b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.c index 05e12f383785..b1d17d3fa04a 100644 --- a/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.c +++ b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLib.c @@ -13,132 +13,13 @@ **/ #include -#include -#include -#include #include #include #include #include #include -BOOLEAN UsePl011Uart = FALSE; -BOOLEAN UsePl011UartSet = FALSE; - -#define PL011_UART_REGISTER_BASE BCM2836_PL011_UART_BASE_ADDRESS -#define MINI_UART_REGISTER_BASE (BCM2836_MINI_UART_BASE_ADDRESS + 0x40) - -// -// 16550 UART register offsets and bitfields -// -#define R_UART_RXBUF 0 // LCR_DLAB = 0 -#define R_UART_TXBUF 0 // LCR_DLAB = 0 -#define R_UART_BAUD_LOW 0 // LCR_DLAB = 1 -#define R_UART_BAUD_HIGH 1 // LCR_DLAB = 1 -#define R_UART_IER 1 // LCR_DLAB = 0 -#define R_UART_FCR 2 -#define B_UART_FCR_FIFOE BIT0 -#define B_UART_FCR_FIFO64 BIT5 -#define R_UART_LCR 3 -#define B_UART_LCR_DLAB BIT7 -#define R_UART_MCR 4 -#define B_UART_MCR_DTRC BIT0 -#define B_UART_MCR_RTS BIT1 -#define R_UART_LSR 5 -#define B_UART_LSR_RXRDY BIT0 -#define B_UART_LSR_TXRDY BIT5 -#define B_UART_LSR_TEMT BIT6 -#define R_UART_MSR 6 -#define B_UART_MSR_CTS BIT4 -#define B_UART_MSR_DSR BIT5 -#define B_UART_MSR_RI BIT6 -#define B_UART_MSR_DCD BIT7 - -/** - Read an 8-bit 16550 register. - - @param Base The base address register of UART device. - @param Offset The offset of the 16550 register to read. - - @return The value read from the 16550 register. - -**/ -UINT8 -SerialPortReadRegister ( - UINTN Base, - UINTN Offset - ) -{ - return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride)); -} - -/** - Write an 8-bit 16550 register. - - @param Base The base address register of UART device. - @param Offset The offset of the 16550 register to write. - @param Value The value to write to the 16550 register specified by Offset. - - @return The value written to the 16550 register. - -**/ -UINT8 -SerialPortWriteRegister ( - UINTN Base, - UINTN Offset, - UINT8 Value - ) -{ - return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value); -} - -/** - Return whether the hardware flow control signal allows writing. - - @param SerialRegisterBase The base address register of UART device. - - @retval TRUE The serial port is writable. - @retval FALSE The serial port is not writable. -**/ -BOOLEAN -SerialPortWritable ( - UINTN SerialRegisterBase - ) -{ - if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { - if (PcdGetBool (PcdSerialDetectCable)) { - // - // Wait for both DSR and CTS to be set - // DSR is set if a cable is connected. - // CTS is set if it is ok to transmit data - // - // DSR CTS Description Action - // === === ======================================== ======== - // 0 0 No cable connected. Wait - // 0 1 No cable connected. Wait - // 1 0 Cable connected, but not clear to send. Wait - // 1 1 Cable connected, and clear to send. Transmit - // - return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS)); - } else { - // - // Wait for both DSR and CTS to be set OR for DSR to be clear. - // DSR is set if a cable is connected. - // CTS is set if it is ok to transmit data - // - // DSR CTS Description Action - // === === ======================================== ======== - // 0 0 No cable connected. Transmit - // 0 1 No cable connected. Transmit - // 1 0 Cable connected, but not clear to send. Wait - // 1 1 Cable connected, and clar to send. Transmit - // - return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR)); - } - } - - return TRUE; -} +#include "DualSerialPortLib.h" /** Return the baud generator divisor to use for 16650 setup. @@ -147,6 +28,7 @@ SerialPortWritable ( @return The baud generator divisor. **/ +STATIC UINT32 SerialPortGetDivisor ( UINT32 SerialBaudRate @@ -288,113 +170,6 @@ SerialPortInitialize ( } } -/** - Write data from buffer to serial device. - - Writes NumberOfBytes data bytes from Buffer to the serial device. - The number of bytes actually written to the serial device is returned. - If the return value is less than NumberOfBytes, then the write operation failed. - - If Buffer is NULL, then ASSERT(). - - If NumberOfBytes is zero, then return 0. - - @param Buffer Pointer to the data buffer to be written. - @param NumberOfBytes Number of bytes to written to the serial device. - - @retval 0 NumberOfBytes is 0. - @retval >0 The number of bytes written to the serial device. - If this value is less than NumberOfBytes, then the write operation failed. - -**/ -UINTN -EFIAPI -SerialPortWrite ( - IN UINT8 *Buffer, - IN UINTN NumberOfBytes - ) -{ - UINTN SerialRegisterBase; - UINTN Result; - UINTN Index; - UINTN FifoSize; - - // - // Serial writes may happen *before* the UART has been initialized - // and if we use the wrong UART then, all kind of bad things happen. - // To alleviate this, we add UART detection in SerialPortWrite and - // guard the UART detection with a second boolean. - // - if (!UsePl011UartSet) { - UsePl011Uart = ((MmioRead32(GPIO_BASE_ADDRESS + 4) & 0x0003F000) == 0x00024000); - UsePl011UartSet = TRUE; - } - - if (UsePl011Uart) { - return PL011UartWrite (PL011_UART_REGISTER_BASE, Buffer, NumberOfBytes); - } else { - if (Buffer == NULL) { - return 0; - } - - SerialRegisterBase = MINI_UART_REGISTER_BASE; - - if (NumberOfBytes == 0) { - // - // Flush the hardware - // - - // - // Wait for both the transmit FIFO and shift register empty. - // - while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)); - - // - // Wait for the hardware flow control signal - // - while (!SerialPortWritable (SerialRegisterBase)); - return 0; - } - - // - // Compute the maximum size of the Tx FIFO - // - FifoSize = 1; - if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) { - if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) { - FifoSize = 16; - } else { - FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize); - } - } - - Result = NumberOfBytes; - while (NumberOfBytes != 0) { - // - // Wait for the serial port to be ready, to make sure both the transmit FIFO - // and shift register empty. - // - while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)); - - // - // Fill then entire Tx FIFO - // - for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) { - // - // Wait for the hardware flow control signal - // - while (!SerialPortWritable (SerialRegisterBase)); - - // - // Write byte to the transmit buffer. - // - SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer); - } - } - return Result; - } -} - /** Reads data from a serial device into a buffer. diff --git a/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLibCommon.c b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLibCommon.c new file mode 100644 index 000000000000..48d8df280640 --- /dev/null +++ b/Platform/RaspberryPi/Library/DualSerialPortLib/DualSerialPortLibCommon.c @@ -0,0 +1,218 @@ +/** @file + 16550 and PL011 Serial Port library functions for Raspberry Pi + + Copyright (c) 2020, Pete Batard + Copyright (c) 2018, AMD Incorporated. All rights reserved.
+ Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2012 - 2016, ARM Ltd. All rights reserved.
+ Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#include "DualSerialPortLib.h" + +BOOLEAN UsePl011Uart = FALSE; +BOOLEAN UsePl011UartSet = FALSE; + +/** + Read an 8-bit 16550 register. + + @param Base The base address register of UART device. + @param Offset The offset of the 16550 register to read. + + @return The value read from the 16550 register. + +**/ +UINT8 +SerialPortReadRegister ( + UINTN Base, + UINTN Offset + ) +{ + return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride)); +} + +/** + Write an 8-bit 16550 register. + + @param Base The base address register of UART device. + @param Offset The offset of the 16550 register to write. + @param Value The value to write to the 16550 register specified by Offset. + + @return The value written to the 16550 register. + +**/ +UINT8 +SerialPortWriteRegister ( + UINTN Base, + UINTN Offset, + UINT8 Value + ) +{ + return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value); +} + +/** + Return whether the hardware flow control signal allows writing. + + @param SerialRegisterBase The base address register of UART device. + + @retval TRUE The serial port is writable. + @retval FALSE The serial port is not writable. +**/ +STATIC +BOOLEAN +SerialPortWritable ( + UINTN SerialRegisterBase + ) +{ + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) { + if (PcdGetBool (PcdSerialDetectCable)) { + // + // Wait for both DSR and CTS to be set + // DSR is set if a cable is connected. + // CTS is set if it is ok to transmit data + // + // DSR CTS Description Action + // === === ======================================== ======== + // 0 0 No cable connected. Wait + // 0 1 No cable connected. Wait + // 1 0 Cable connected, but not clear to send. Wait + // 1 1 Cable connected, and clear to send. Transmit + // + return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS)); + } else { + // + // Wait for both DSR and CTS to be set OR for DSR to be clear. + // DSR is set if a cable is connected. + // CTS is set if it is ok to transmit data + // + // DSR CTS Description Action + // === === ======================================== ======== + // 0 0 No cable connected. Transmit + // 0 1 No cable connected. Transmit + // 1 0 Cable connected, but not clear to send. Wait + // 1 1 Cable connected, and clar to send. Transmit + // + return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR)); + } + } + + return TRUE; +} + +/** + Write data from buffer to serial device. + + Writes NumberOfBytes data bytes from Buffer to the serial device. + The number of bytes actually written to the serial device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + + If Buffer is NULL, then ASSERT(). + + If NumberOfBytes is zero, then return 0. + + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the serial device. + If this value is less than NumberOfBytes, then the write operation failed. + +**/ +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + UINTN SerialRegisterBase; + UINTN Result; + UINTN Index; + UINTN FifoSize; + + // + // Serial writes may happen *before* the UART has been initialized + // and if we use the wrong UART then, all kind of bad things happen. + // To alleviate this, we add UART detection in SerialPortWrite and + // guard the UART detection with a second boolean. + // + if (!UsePl011UartSet) { + UsePl011Uart = ((MmioRead32(GPIO_BASE_ADDRESS + 4) & 0x0003F000) == 0x00024000); + UsePl011UartSet = TRUE; + } + + if (UsePl011Uart) { + return PL011UartWrite (PL011_UART_REGISTER_BASE, Buffer, NumberOfBytes); + } else { + if (Buffer == NULL) { + return 0; + } + + SerialRegisterBase = MINI_UART_REGISTER_BASE; + + if (NumberOfBytes == 0) { + // + // Flush the hardware + // + + // + // Wait for both the transmit FIFO and shift register empty. + // + while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)); + + // + // Wait for the hardware flow control signal + // + while (!SerialPortWritable (SerialRegisterBase)); + return 0; + } + + // + // Compute the maximum size of the Tx FIFO + // + FifoSize = 1; + if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) { + if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) { + FifoSize = 16; + } else { + FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize); + } + } + + Result = NumberOfBytes; + while (NumberOfBytes != 0) { + // + // Wait for the serial port to be ready, to make sure both the transmit FIFO + // and shift register empty. + // + while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)); + + // + // Fill then entire Tx FIFO + // + for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) { + // + // Wait for the hardware flow control signal + // + while (!SerialPortWritable (SerialRegisterBase)); + + // + // Write byte to the transmit buffer. + // + SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer); + } + } + return Result; + } +} -- 2.17.1