Serial Port library for LoongarchQemuPkg Signed-off-by: xianglai li <lixiang...@loongson.cn> --- .../LoongArchQemuPkg/Include/Library/Cpu.h | 344 ++++++++++ .../Include/LoongArchQemuPlatform.h | 103 +++ .../Library/SerialPortLib/SerialPortLib.c | 614 ++++++++++++++++++ .../Library/SerialPortLib/SerialPortLib.inf | 36 + 4 files changed, 1097 insertions(+) create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h new file mode 100644 index 0000000000..de466b7c6f --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h @@ -0,0 +1,344 @@ +/** @file + + Copyright (c) 2021 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 */ + +/* 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 */ + +/* + Reads data from the specified CSR register. + + @param[OUT] val The value is read from the CSR specified register. + @param[IN] reg Specifies the register number of the CSR to read the data. + + @retval VOID + */ +#define LOONGARCH_CSR_READQ(val, reg) \ +do { \ + UINT64 __res; \ + /* csrrd rd, csr_num */ \ + __asm__ __volatile__( \ + "csrrd %0, %1 \n\t" \ + :"=r"(__res) \ + :"i"(reg) \ + : \ + ); \ + (val) = __res; \ +} while(0) + +/* + Write data to the specified CSR register. + + @param[OUT] val The value is write to the CSR specified register. + @param[IN] reg Specifies the register number of the CSR to write the data. + + @retval VOID + */ +#define LOONGARCH_CSR_WRITEQ(val, reg) \ +do { \ + UINT64 __val = val; \ + /* csrwr rd, csr_num */ \ + __asm__ __volatile__( \ + "csrwr %0, %1 \n\t" \ + : "+r"(__val) \ + : "i"(reg), "r"(__val) \ + : "memory" \ + ); \ +} while(0) + +/* + Exchange specified bit data with the specified CSR registers + + @param[IN] val The value Exchanged with the CSR specified register. + @param[IN] mask Specifies the mask for swapping bits + @param[IN] reg Specifies the register number of the CSR to Exchange the data. + + @retval VOID + */ +#define LOONGARCH_CSR_XCHGQ(val, mask, reg) \ +do { \ + UINT64 __val = val; \ + UINT64 __mask = mask; \ + /* csrwr rd, csr_num */ \ + __asm__ __volatile__( \ + "csrxchg %0, %1, %2 \n\t" \ + : "+r"(__val) \ + : "r"(__mask), "i"(reg), "r"(__val) \ + : "memory" \ + ); \ +} while(0) +/* + Reads data from the specified CPUCFG register. + + @param[OUT] val The value is read from the CPUCFG specified register. + @param[IN] reg Specifies the register number of the CPUCFG to read the data. + + @retval VOID + */ +#define LOONGARCH_GET_CPUCFG(val, reg) \ +do { \ + UINT64 __res; \ + /* cpucfg rd, rj */ \ + __asm__ __volatile__( \ + "cpucfg %0, %1 \n\t" \ + :"=r"(__res) \ + :"r"(reg) \ + : \ + ); \ + val = (UINT32)__res; \ +} while(0) + +/* + Enables floating-point unit + + @param VOID + + @retval VOID + */ +#define LOONGARCH_ENABLR_FPU() \ +do { \ + LOONGARCH_CSR_XCHGQ(CSR_EUEN_FPEN, \ + CSR_EUEN_FPEN, \ + LOONGARCH_CSR_EUEN); \ +} while (0) + +/* + Disable floating-point unit + + @param VOID + + @retval VOID + */ +#define LOONGARCH_DISABLE_FPU() \ +do { \ + LOONGARCH_CSR_XCHGQ(0, \ + CSR_EUEN_FPEN, \ + LOONGARCH_CSR_EUEN); \ +} while (0) + +#endif diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h new file mode 100644 index 0000000000..62b81d88c3 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h @@ -0,0 +1,103 @@ +/** @file + LoongArch Qemu Platform macro definition. + + Copyright (c) 2021, 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) +//--------------------------------------------- +// UART Settings +//--------------------------------------------- +#define PHYS_TO_CACHED(x) ((x)) +#define PHYS_TO_UNCACHED(x) ((x)) + +#endif diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c new file mode 100644 index 0000000000..766e606be5 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c @@ -0,0 +1,614 @@ +/** @file + UART Serial Port library functions + + Copyright (c) 2021 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 = PHYS_TO_UNCACHED(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); + // + // if enable interrupt the kernel of lemote will error in STR mode during wake up phase. + // + //MmioWrite8 ((UINTN) (gUartBase + IER_OFFSET), CFCR_8BITS); + + 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.inf new file mode 100644 index 0000000000..6c4674151b --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf @@ -0,0 +1,36 @@ +## @file +# UART Serial Port library functions +# +# Copyright (c) 2021 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 + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Platform/Loongson/LoongArchQemuPkg/Loongson.dec + +[LibraryClasses] + BaseLib + IoLib + PcdLib + +[Sources] + SerialPortLib.c + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate ## CONSUMES -- 2.27.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#87198): https://edk2.groups.io/g/devel/message/87198 Mute This Topic: https://groups.io/mt/89497227/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-