public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "xianglai" <lixianglai@loongson.cn>
To: devel@edk2.groups.io
Subject: [edk2-platforms][PATCH V1 01/15] Platform/Loongson: Add Serial Port library
Date: Wed,  2 Mar 2022 03:44:33 -0500	[thread overview]
Message-ID: <20220302084447.2991355-2-lixianglai@loongson.cn> (raw)
In-Reply-To: <20220302084447.2991355-1-lixianglai@loongson.cn>

Serial Port library for LoongarchQemuPkg

Signed-off-by: xianglai li <lixianglai@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


  reply	other threads:[~2022-03-02  8:45 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-02  8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
2022-03-02  8:44 ` xianglai [this message]
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 02/15] Platform/Loongson: Support SEC And Add Readme.md xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 05/15] Platform/Loongson: Add BpiLib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 06/15] Platform/Loongson: Add MmuLib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 07/15] Platform/Loongson: Add StableTimerLib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 08/15] Platform/Loongson: Support PEI phase xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 09/15] Platform/Loongson: Add CPU DXE driver xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 10/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 11/15] Platform/Loongson: Add timer Dxe driver xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 12/15] Platform/Loongson: Add RealTime Clock lib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 13/15] Platform/Loongson: Add Platform Boot Manager Lib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 14/15] Platform/Loongson: Add Reset System Lib xianglai
2022-03-02  8:44 ` [edk2-platforms][PATCH V1 15/15] Platform/Loongson: Support Dxe xianglai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220302084447.2991355-2-lixianglai@loongson.cn \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox