[edk2-devel] [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library

xianglai posted 15 patches 1 year, 10 months ago
There is a newer version of this series
[edk2-devel] [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library
Posted by xianglai 1 year, 10 months ago
Serial Port library for LoongarchQemuPkg

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: 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.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..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 */
+
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
new file mode 100644
index 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)
+#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..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.inf
new file mode 100644
index 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




-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#96273): https://edk2.groups.io/g/devel/message/96273
Mute This Topic: https://groups.io/mt/94955170/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library
Posted by Chao Li 1 year, 10 months ago
Reviewed-by: Chao Li <lichao@loongson.cn>

Thanks,
Chao
--------

On 11月 11 2022, at 5:12 下午, xianglai li <lixianglai@loongson.cn> wrote:
> Serial Port library for LoongarchQemuPkg
>
>
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054
>
>
> Cc: 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.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..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 */
> +
> +#endif
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
> new file mode 100644
> index 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)
> +#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..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.inf
> new file mode 100644
> index 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


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#96286): https://edk2.groups.io/g/devel/message/96286
Mute This Topic: https://groups.io/mt/94955170/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-