Thanks,
Chao
--------
Serial Port library for LoongarchQemuPkgREF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054Cc: Bibo Mao <maobibo@loongson.cn>Cc: Chao Li <lichao@loongson.cn>Cc: Leif Lindholm <quic_llindhol@quicinc.com>Cc: Liming Gao <gaoliming@byosoft.com.cn>Cc: Michael D Kinney <michael.d.kinney@intel.com>Signed-off-by: xianglai li <lixianglai@loongson.cn>---.../LoongArchQemuPkg/Include/Library/Cpu.h | 237 +++++++.../Include/LoongArchQemuPlatform.h | 95 +++.../Library/SerialPortLib/SerialPortLib.c | 593 ++++++++++++++++++.../Library/SerialPortLib/SerialPortLib.inf | 39 ++4 files changed, 964 insertions(+)create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.hcreate mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.hcreate mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.ccreate mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.infdiff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.hnew file mode 100644index 0000000000..c6599c6ed7--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h@@ -0,0 +1,237 @@+/** @file++ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>++ SPDX-License-Identifier: BSD-2-Clause-Patent++ @par Glossary:+ - EXC - Exception+ - INT - Interrupt+ - FPU - Floating Point Unit+ - CSR - CPU Status Register+ - READQ - Read Quad Word+**/+#ifndef LOONGARCH_CPU_H_+#define LOONGARCH_CPU_H_++/* Exception types decoded by machdep exception decoder */+#define EXC_INT 0 /* HW interrupt */+#define EXC_TLBL 1 /* TLB miss on a load */+#define EXC_TLBS 2 /* TLB miss on a store */+#define EXC_TLBI 3 /* TLB miss on a ifetch */+#define EXC_TLBM 4 /* TLB modified fault */+#define EXC_TLBRI 5 /* TLB Read-Inhibit exception */+#define EXC_TLBXI 6 /* TLB Execution-Inhibit exception */+#define EXC_TLBPE 7 /* TLB Privilege Error */+#define EXC_ADE 8 /* Address Error */+#define EXC_ALE 9 /* Unalign Access */+#define EXC_OOB 10 /* Out of bounds */+#define EXC_SYS 11 /* System call */+#define EXC_BP 12 /* Breakpoint */+#define EXC_INE 13 /* Inst. Not Exist */+#define EXC_IPE 14 /* Inst. Privileged Error */+#define EXC_FPDIS 15 /* FPU Disabled */+#define EXC_LSXDIS 16 /* LSX Disabled */+#define EXC_LASXDIS 17 /* LASX Disabled */+#define EXC_FPE 18 /* Floating Point Exception */+#define EXC_WATCH 19 /* Watch address reference */+#define EXC_BAD 255 /* Undecodeable */++#define COPY_SIGCODE // copy sigcode above user stack in exec+#define ZERO $r0 /* wired zero */+#define RA $r1 /* return address */+#define GP $r2 /* global pointer - caller saved for PIC */+#define SP $r3 /* stack pointer */+#define V0 $r4 /* return value - caller saved */+#define V1 $r5+#define A0 $r4 /* argument registers */+#define A1 $r5+#define A2 $r6+#define A3 $r7+#define A4 $r8 /* arg reg 64 bit; caller saved in 32 bit */+#define A5 $r9+#define A6 $r10+#define A7 $r11+#define T0 $r12 /* caller saved */+#define T1 $r13+#define T2 $r14+#define T3 $r15+#define T4 $r16 /* callee saved */+#define T5 $r17+#define T6 $r18+#define T7 $r19+#define T8 $r20 /* caller saved */+#define TP $r21 /* TLS */+#define FP $r22 /* frame pointer */+#define S0 $r23 /* callee saved */+#define S1 $r24+#define S2 $r25+#define S3 $r26+#define S4 $r27+#define S5 $r28+#define S6 $r29+#define S7 $r30+#define S8 $r31 /* callee saved */++#define FCSR0 $r0++//+// Location of the saved registers relative to ZERO.+// Usage is p->p_regs[XX].+//+#define RA_NUM 1+#define GP_NUM 2+#define SP_NUM 3+#define A0_NUM 4+#define A1_NUM 5+#define A2_NUM 6+#define A3_NUM 7+#define A4_NUM 8+#define A5_NUM 9+#define A6_NUM 10+#define A7_NUM 11+#define T0_NUM 12+#define T1_NUM 13+#define T2_NUM 14+#define T3_NUM 15+#define T4_NUM 16+#define T5_NUM 17+#define T6_NUM 18+#define T7_NUM 19+#define T8_NUM 20+#define TP_NUM 21+#define FP_NUM 22+#define S0_NUM 23+#define S1_NUM 24+#define S2_NUM 25+#define S3_NUM 26+#define S4_NUM 27+#define S5_NUM 28+#define S6_NUM 29+#define S7_NUM 30+#define S8_NUM 31++#define FP0_NUM 0+#define FP1_NUM 1+#define FP2_NUM 2+#define FP3_NUM 3+#define FP4_NUM 4+#define FP5_NUM 5+#define FP6_NUM 6+#define FP7_NUM 7+#define FP8_NUM 8+#define FP9_NUM 9+#define FP10_NUM 10+#define FP11_NUM 11+#define FP12_NUM 12+#define FP13_NUM 13+#define FP14_NUM 14+#define FP15_NUM 15+#define FP16_NUM 16+#define FP17_NUM 17+#define FP18_NUM 18+#define FP19_NUM 19+#define FP20_NUM 20+#define FP21_NUM 21+#define FP22_NUM 22+#define FP23_NUM 23+#define FP24_NUM 24+#define FP25_NUM 25+#define FP26_NUM 26+#define FP27_NUM 27+#define FP28_NUM 28+#define FP29_NUM 29+#define FP30_NUM 30+#define FP31_NUM 31+#define FCSR_NUM 32+#define FCC_NUM 33++#ifdef __ASSEMBLY__+#define _ULCAST_+#define _U64CAST_+#else+#define _ULCAST_ (unsigned long)+#define _U64CAST_ (u64)+#endif++#define LOONGARCH_CSR_CRMD 0+#define LOONGARCH_CSR_PRMD 1+#define LOONGARCH_CSR_EUEN 2+#define CSR_EUEN_LBTEN_SHIFT 3+#define CSR_EUEN_LBTEN (_ULCAST_(0x1) << CSR_EUEN_LBTEN_SHIFT)+#define CSR_EUEN_LASXEN_SHIFT 2+#define CSR_EUEN_LASXEN (_ULCAST_(0x1) << CSR_EUEN_LASXEN_SHIFT)+#define CSR_EUEN_LSXEN_SHIFT 1+#define CSR_EUEN_LSXEN (_ULCAST_(0x1) << CSR_EUEN_LSXEN_SHIFT)+#define CSR_EUEN_FPEN_SHIFT 0+#define CSR_EUEN_FPEN (_ULCAST_(0x1) << CSR_EUEN_FPEN_SHIFT)+#define LOONGARCH_CSR_ECFG 4++/* Exception status */+#define LOONGARCH_CSR_ESTAT 5+#define CSR_ESTAT_ESUBCODE_SHIFT 22+#define CSR_ESTAT_ESUBCODE_WIDTH 9+#define CSR_ESTAT_ESUBCODE (_ULCAST_(0x1ff) << CSR_ESTAT_ESUBCODE_SHIFT)+#define CSR_ESTAT_EXC_SHIFT 16+#define CSR_ESTAT_EXC_WIDTH 6+#define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT)+#define CSR_ESTAT_IS_SHIFT 0+#define CSR_ESTAT_IS_WIDTH 15+#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT)++#define LOONGARCH_CSR_EPC 6+#define LOONGARCH_CSR_BADV 7+#define LOONGARCH_CSR_BADINST 8+#define LOONGARCH_CSR_BADI 8+#define LOONGARCH_CSR_EBASE 0xc /* Exception entry base address */+#define LOONGARCH_CSR_CPUNUM 0x20 /* CPU core number */++/* register number save in stack on exception */+#define FP_BASE_NUM 34+#define BASE_NUM 32+#define CSR_NUM 10+#define FP_BASE_INDEX (CSR_NUM + BASE_NUM)+#define BOOTCORE_ID 0++#define LOONGSON_IOCSR_IPI_STATUS 0x1000+#define LOONGSON_IOCSR_IPI_EN 0x1004+#define LOONGSON_IOCSR_IPI_SET 0x1008+#define LOONGSON_IOCSR_IPI_CLEAR 0x100c+#define LOONGSON_CSR_MAIL_BUF0 0x1020+#define LOONGSON_CSR_MAIL_BUF1 0x1028+#define LOONGSON_CSR_MAIL_BUF2 0x1030+#define LOONGSON_CSR_MAIL_BUF3 0x1038++/* Bit Domains for CFG registers */+#define LOONGARCH_CPUCFG4 0x4+#define LOONGARCH_CPUCFG5 0x5++/* Kscratch registers */+#define LOONGARCH_CSR_KS0 0x30+#define LOONGARCH_CSR_KS1 0x31++/* Stable timer registers */+#define LOONGARCH_CSR_TMCFG 0x41+#define LOONGARCH_CSR_TMCFG_EN (1ULL << 0)+#define LOONGARCH_CSR_TMCFG_PERIOD (1ULL << 1)+#define LOONGARCH_CSR_TMCFG_TIMEVAL (0x3fffffffffffULL << 2)+#define LOONGARCH_CSR_TVAL 0x42 /* Timer value */+#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */+#define LOONGARCH_CSR_TINTCLR 0x44 /* Timer interrupt clear */++/* TLB refill exception base address */+#define LOONGARCH_CSR_TLBREBASE 0x88+#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KScratch for TLB refill exception */+#define LOONGARCH_CSR_PGD 0x1b /* Page table base */++/* Invalid addr with global=1 or matched asid in current tlb */+#define INVTLB_ADDR_GTRUE_OR_ASID 0x6++/* Bits 8 and 9 of FPU Status Register specify the rounding mode */+#define FPU_CSR_RM 0x300+#define FPU_CSR_RN 0x000 /* nearest */+#define FPU_CSR_RZ 0x100 /* towards zero */+#define FPU_CSR_RU 0x200 /* towards +Infinity */+#define FPU_CSR_RD 0x300 /* towards -Infinity */++#endifdiff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.hnew file mode 100644index 0000000000..e942e6a994--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h@@ -0,0 +1,95 @@+/** @file+ LoongArch Qemu Platform macro definition.++ Copyright (c) 2022, Loongson Limited. All rights reserved.++ SPDX-License-Identifier: BSD-2-Clause-Patent++ **/++#ifndef LOONGARCH_QEMU_PLATFORM_H_+#define LOONGARCH_QEMU_PLATFORM_H_++/* Acpi pm device */+#define LS7A_PCH_REG_BASE 0x10000000UL+#define LS7A_ACPI_REG_BASE (LS7A_PCH_REG_BASE + 0x000D0000)+#define LS7A_PM_CNT_BLK (0x14) /* 2 bytes */+#define LS7A_GPE0_RESET_REG (0x30) /* 4 bytes */++#define ACPI_BITMASK_SLEEP_TYPE 0x1C00+#define ACPI_BITMASK_SLEEP_ENABLE 0x2000++//---------------------------------------------+// UART Register Offsets+//---------------------------------------------+#define BAUD_LOW_OFFSET 0x00+#define BAUD_HIGH_OFFSET 0x01+#define IER_OFFSET 0x01+#define LCR_SHADOW_OFFSET 0x01+#define FCR_SHADOW_OFFSET 0x02+#define IR_CONTROL_OFFSET 0x02+#define FCR_OFFSET 0x02+#define EIR_OFFSET 0x02+#define BSR_OFFSET 0x03+#define LCR_OFFSET 0x03+#define MCR_OFFSET 0x04+#define LSR_OFFSET 0x05+#define MSR_OFFSET 0x06++/* character format control register */+#define CFCR_DLAB 0x80 /* divisor latch */+#define CFCR_SBREAK 0x40 /* send break */+#define CFCR_PZERO 0x30 /* zero parity */+#define CFCR_PONE 0x20 /* one parity */+#define CFCR_PEVEN 0x10 /* even parity */+#define CFCR_PODD 0x00 /* odd parity */+#define CFCR_PENAB 0x08 /* parity enable */+#define CFCR_STOPB 0x04 /* 2 stop bits */+#define CFCR_8BITS 0x03 /* 8 data bits */+#define CFCR_7BITS 0x02 /* 7 data bits */+#define CFCR_6BITS 0x01 /* 6 data bits */+#define CFCR_5BITS 0x00 /* 5 data bits */+/* modem control register */+#define MCR_LOOPBACK 0x10 /* loopback */+#define MCR_IENABLE 0x08 /* output 2 = int enable */+#define MCR_DRS 0x04 /* output 1 = xxx */+#define MCR_RTS 0x02 /* enable RTS */+#define MCR_DTR 0x01 /* enable DTR */++/* line status register */+#define LSR_RCV_FIFO 0x80 /* error in receive fifo */+#define LSR_TSRE 0x40 /* transmitter empty */+#define LSR_TXRDY 0x20 /* transmitter ready */+#define LSR_BI 0x10 /* break detected */+#define LSR_FE 0x08 /* framing error */+#define LSR_PE 0x04 /* parity error */+#define LSR_OE 0x02 /* overrun error */+#define LSR_RXRDY 0x01 /* receiver ready */+#define LSR_RCV_MASK 0x1f++/* 16550 UART register offsets and bitfields */+#define R_UART_RXBUF 0+#define R_UART_TXBUF 0+#define R_UART_BAUD_LOW 0+#define R_UART_BAUD_HIGH 1+#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+#define UART_BASE_ADDRESS (0x1fe001e0)+#define UART_BPS (115200)+#define UART_WAIT_TIMOUT (1000000)+#endifdiff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.cnew file mode 100644index 0000000000..7044db81ee--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c@@ -0,0 +1,593 @@+/** @file+ UART Serial Port library functions++ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>++ SPDX-License-Identifier: BSD-2-Clause-Patent++ @par Glossary:+ - Bps - Bit Per Second+ - CTL - Control+ - Config - Configure+**/++#include <Base.h>+#include <Library/Cpu.h>+#include <Library/IoLib.h>+#include <Library/SerialPortLib.h>+#include <LoongArchQemuPlatform.h>++UINTN gUartBase = UART_BASE_ADDRESS;+UINTN gBps = UART_BPS;++/**+ Initialize the serial device hardware.++ If no initialization is required, then return RETURN_SUCCESS.+ If the serial device was successfuly initialized, then return RETURN_SUCCESS.+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.++ @retval RETURN_SUCCESS The serial device was initialized.+ @retval RETURN_DEVICE_ERROR The serail device could not be initialized.+**/+RETURN_STATUS+EFIAPI+SerialPortInitialize (+ VOID+ )+{+ UINTN TimeOut;+ //+ // wait for Tx fifo to completely drain */+ //+ TimeOut = UART_WAIT_TIMOUT;+ while (!(MmioRead8 ((UINTN) gUartBase + LSR_OFFSET) & LSR_TSRE)) {+ if (--TimeOut == 0) {+ break;+ }+ }+ //+ // Set communications format+ //+ MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_DLAB);++ //+ // Configure baud rate+ //++ MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_8BITS);+ MmioWrite8 ((UINTN) (gUartBase + MCR_OFFSET), MCR_IENABLE | MCR_DTR | MCR_RTS);++ return RETURN_SUCCESS;+}++/**+ 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 read operation failed.+**/+UINTN+EFIAPI+UartCtlWrite (+ IN UINT8 *Buffer,+ IN UINTN NumberOfBytes,+ IN UINTN CtlAddr+)+{+ UINTN Result;+ UINT8 Data;++ if (Buffer == NULL) {+ return 0;+ }++ Result = NumberOfBytes;++ while (NumberOfBytes--) {+ //+ // Wait for the serail port to be ready.+ //+ do {+ Data = MmioRead8 (CtlAddr + LSR_OFFSET);+ } while ((Data & LSR_TXRDY) == 0);+ MmioWrite8 (CtlAddr, *Buffer++);+ }+ return Result;+}+/**+ Writes data to serial port.++ @param Buffer Pointer to the data buffer to store the data writed to serial port.+ @param NumberOfBytes Number of bytes to write to the serial port.++ @retval 0 NumberOfBytes is 0.+ @retval >0 The number of bytes write the serial port.+ If this value is less than NumberOfBytes, then the write operation failed.+**/+UINTN+EFIAPI+SerialPortWrite (+ IN UINT8 *Buffer,+ IN UINTN NumberOfBytes+)+{+ return UartCtlWrite (Buffer, NumberOfBytes, gUartBase);+}+/**+ Reads data from a serial device into a buffer.++ @param Buffer Pointer to the data buffer to store the data read from the serial device.+ @param NumberOfBytes Number of bytes to read from the serial device.++ @retval 0 NumberOfBytes is 0.+ @retval >0 The number of bytes read from the serial device.+ If this value is less than NumberOfBytes, then the read operation failed.+**/+UINTN+EFIAPI+UartCtlRead (+ OUT UINT8 *Buffer,+ IN UINTN NumberOfBytes,+ IN UINTN CtlAddr+)+{+ UINTN Result;+ UINT8 Data;++ if (NULL == Buffer) {+ return 0;+ }++ Result = NumberOfBytes;++ while (NumberOfBytes--) {+ //+ // Wait for the serail port to be ready.+ //+ do {+ Data = MmioRead8 (CtlAddr + LSR_OFFSET);+ } while ((Data & LSR_RXRDY) == 0);++ *Buffer++ = MmioRead8 (CtlAddr);+ }+ return Result;+}+/**+ Read data from serial port.++ @param Buffer Pointer to the data buffer to store the data read from serial port.+ @param NumberOfBytes Number of bytes to read from the serial port.++ @retval 0 NumberOfBytes is 0.+ @retval >0 The number of bytes read from the serial port.+ If this value is less than NumberOfBytes, then the read operation failed.+**/+UINTN+EFIAPI+SerialPortRead (+ OUT UINT8 *Buffer,+ IN UINTN NumberOfBytes+)+{+ return UartCtlRead (Buffer, NumberOfBytes, gUartBase);+}+/**+ Polls a serial device to see if there is any data waiting to be read.++ Polls aserial device to see if there is any data waiting to be read.+ If there is data waiting to be read from the serial device, then TRUE is returned.+ If there is no data waiting to be read from the serial device, then FALSE is returned.++ @retval TRUE Data is waiting to be read from the serial device.+ @retval FALSE There is no data waiting to be read from the serial device.+**/+BOOLEAN+EFIAPI+SerialPortPoll (+ VOID+ )+{+ UINT8 Data;++ //+ // Read the serial port status.+ //+ Data = MmioRead8 ((UINTN) gUartBase + LSR_OFFSET);++ return (BOOLEAN) ((Data & LSR_RXRDY) != 0);+}+/**+ To get serial register base address.++ @param VOID++ @return serial register base address.+**/+UINTN+GetSerialRegisterBase (+ VOID+ )+{+ return gUartBase;+}+/**+ Read an 8-bit register.+ @param Base The base address register of UART device.+ @param Offset The offset of the register to read.++ @return The value read from the 16550 register.+**/+UINT8+SerialPortReadRegister (+ UINTN Base,+ UINTN Offset+ )+{+ return MmioRead8 (Base + Offset);+}++/**+ Write an 8-bit register.+ @param Base The base address register of UART device.+ @param Offset The offset of the register to write.+ @param Value The value to write to the register specified by Offset.++ @return The value written to the 16550 register.+**/+UINT8+SerialPortWriteRegister (+ UINTN Base,+ UINTN Offset,+ UINT8 Value+ )+{+ return MmioWrite8 (Base + Offset, Value);+}++/**+ Sets the control bits on a serial device.++ @param Control Sets the bits of Control that are settable.++ @retval RETURN_SUCCESS The new control bits were set on the serial device.+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.+**/+RETURN_STATUS+EFIAPI+SerialPortSetControl (+ IN UINT32 Control+ )+{+ UINTN SerialRegisterBase;+ UINT8 Mcr;++ //+ // First determine the parameter is invalid.+ //+ if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0)+ {+ return RETURN_UNSUPPORTED;+ }++ SerialRegisterBase = GetSerialRegisterBase ();+ if (SerialRegisterBase ==0) {+ return RETURN_UNSUPPORTED;+ }++ //+ // Read the Modem Control Register.+ //+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);+ Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));++ if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {+ Mcr |= B_UART_MCR_DTRC;+ }++ if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {+ Mcr |= B_UART_MCR_RTS;+ }++ //+ // Write the Modem Control Register.+ //+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);++ return RETURN_SUCCESS;+}++/**+ Retrieve the status of the control bits on a serial device.++ @param Control A pointer to return the current control signals from the serial device.++ @retval RETURN_SUCCESS The control bits were read from the serial device.+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.+**/+RETURN_STATUS+EFIAPI+SerialPortGetControl (+ OUT UINT32 *Control+ )+{+ UINTN SerialRegisterBase;+ UINT8 Msr;+ UINT8 Mcr;+ UINT8 Lsr;++ SerialRegisterBase = GetSerialRegisterBase ();+ if (SerialRegisterBase ==0) {+ return RETURN_UNSUPPORTED;+ }++ *Control = 0;++ //+ // Read the Modem Status Register.+ //+ Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);++ if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {+ *Control |= EFI_SERIAL_CLEAR_TO_SEND;+ }++ if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {+ *Control |= EFI_SERIAL_DATA_SET_READY;+ }++ if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {+ *Control |= EFI_SERIAL_RING_INDICATE;+ }++ if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {+ *Control |= EFI_SERIAL_CARRIER_DETECT;+ }++ //+ // Read the Modem Control Register.+ //+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);++ if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {+ *Control |= EFI_SERIAL_DATA_TERMINAL_READY;+ }++ if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {+ *Control |= EFI_SERIAL_REQUEST_TO_SEND;+ }++ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {+ *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;+ }++ //+ // Read the Line Status Register.+ //+ Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);++ if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;+ }++ if ((Lsr & B_UART_LSR_RXRDY) == 0) {+ *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;+ }++ return RETURN_SUCCESS;+}++/**+ Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,+ data bits, and stop bits on a serial device.++ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the+ device's default interface speed.+ On output, the value actually set.+ @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the+ serial interface. A ReceiveFifoDepth value of 0 will use+ the device's default FIFO depth.+ On output, the value actually set.+ @param Timeout The requested time out for a single character in microseconds.+ This timeout applies to both the transmit and receive side of the+ interface. A Timeout value of 0 will use the device's default time+ out value.+ On output, the value actually set.+ @param Parity The type of parity to use on this serial device. A Parity value of+ DefaultParity will use the device's default parity value.+ On output, the value actually set.+ @param DataBits The number of data bits to use on the serial device. A DataBits+ vaule of 0 will use the device's default data bit setting.+ On output, the value actually set.+ @param StopBits The number of stop bits to use on this serial device. A StopBits+ value of DefaultStopBits will use the device's default number of+ stop bits.+ On output, the value actually set.++ @retval RETURN_SUCCESS The new attributes were set on the serial device.+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.+ @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.+**/+RETURN_STATUS+EFIAPI+UartCtlConfig (+ IN OUT UINT64 *BaudRate,+ IN OUT UINT32 *ReceiveFifoDepth,+ IN OUT UINT32 *Timeout,+ IN OUT EFI_PARITY_TYPE *Parity,+ IN OUT UINT8 *DataBits,+ IN OUT EFI_STOP_BITS_TYPE *StopBits,+ IN UINTN CtlAddr+ )+{+ UINTN SerialRegisterBase;+ UINT8 Lcr;+ UINT8 LcrData;+ UINT8 LcrParity;+ UINT8 LcrStop;++ SerialRegisterBase = CtlAddr;+ if (SerialRegisterBase ==0) {+ return RETURN_UNSUPPORTED;+ }++ //+ // Check for default settings and fill in actual values.+ //+ if (*BaudRate == 0) {+ *BaudRate = PcdGet32 (PcdSerialBaudRate);+ }++ if (*DataBits == 0) {+ LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);+ *DataBits = LcrData + 5;+ } else {+ if ((*DataBits < 5)+ || (*DataBits > 8))+ {+ return RETURN_INVALID_PARAMETER;+ }+ //+ // Map 5..8 to 0..3+ //+ LcrData = (UINT8) (*DataBits - (UINT8) 5);+ }++ if (*Parity == DefaultParity) {+ LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);+ switch (LcrParity) {+ case 0:+ *Parity = NoParity;+ break;++ case 3:+ *Parity = EvenParity;+ break;++ case 1:+ *Parity = OddParity;+ break;++ case 7:+ *Parity = SpaceParity;+ break;++ case 5:+ *Parity = MarkParity;+ break;++ default:+ break;+ }+ } else {+ switch (*Parity) {+ case NoParity:+ LcrParity = 0;+ break;++ case EvenParity:+ LcrParity = 3;+ break;++ case OddParity:+ LcrParity = 1;+ break;++ case SpaceParity:+ LcrParity = 7;+ break;++ case MarkParity:+ LcrParity = 5;+ break;++ default:+ return RETURN_INVALID_PARAMETER;+ }+ }++ if (*StopBits == DefaultStopBits) {+ LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);+ switch (LcrStop) {+ case 0:+ *StopBits = OneStopBit;+ break;++ case 1:+ if (*DataBits == 5) {+ *StopBits = OneFiveStopBits;+ } else {+ *StopBits = TwoStopBits;+ }+ break;++ default:+ break;+ }+ } else {+ switch (*StopBits) {+ case OneStopBit:+ LcrStop = 0;+ break;++ case OneFiveStopBits:+ case TwoStopBits:+ LcrStop = 1;+ break;++ default:+ return RETURN_INVALID_PARAMETER;+ }+ }+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);++ //+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.+ // Strip reserved bits from line control value+ //+ Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));++ return RETURN_SUCCESS;+}+/**+ Set the serial port Attributes.++ @param VOID++ @return serial register base address.+**/+RETURN_STATUS+EFIAPI+SerialPortSetAttributes (+ IN OUT UINT64 *BaudRate,+ IN OUT UINT32 *ReceiveFifoDepth,+ IN OUT UINT32 *Timeout,+ IN OUT EFI_PARITY_TYPE *Parity,+ IN OUT UINT8 *DataBits,+ IN OUT EFI_STOP_BITS_TYPE *StopBits+ )+{+ UINTN SerialRegisterBase;++ SerialRegisterBase = GetSerialRegisterBase ();++ return UartCtlConfig (&gBps, ReceiveFifoDepth, Timeout, Parity, DataBits, StopBits,+ SerialRegisterBase);+}diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.infnew file mode 100644index 0000000000..22cf82cf79--- /dev/null+++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf@@ -0,0 +1,39 @@+## @file+# UART Serial Port library functions+#+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>+#+# SPDX-License-Identifier: BSD-2-Clause-Patent+#+##++[Defines]+ INF_VERSION = 0x00010005+ BASE_NAME = PcAtSerialPortLib+ FILE_GUID = f4fb883d-8138-4f29-bb0c-c574e9312c74+ MODULE_TYPE = BASE+ VERSION_STRING = 1.0+ LIBRARY_CLASS = SerialPortLib++#+# VALID_ARCHITECTURES = LOONGARCH64+#++[Sources]+ SerialPortLib.c++[Packages]+ MdePkg/MdePkg.dec+ MdeModulePkg/MdeModulePkg.dec+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec++[LibraryClasses]+ BaseLib+ IoLib+ PcdLib++[Pcd]+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl ## CONSUMES+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate ## CONSUMES+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl ## CONSUMES+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate ## CONSUMES--2.31.1