From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from loongson.cn (loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web12.441.1648174605606968491 for ; Thu, 24 Mar 2022 19:16:46 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: lixianglai@loongson.cn) Received: from localhost.localdomain (unknown [10.2.10.197]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9Dx3xMIJj1irWAPAA--.15467S3; Fri, 25 Mar 2022 10:16:42 +0800 (CST) From: "xianglai" To: devel@edk2.groups.io Cc: maobibo@loongson.cn Subject: [edk2-platforms][PATCH V2 01/16] Platform/Loongson: Add Serial Port library Date: Fri, 25 Mar 2022 10:16:05 +0800 Message-Id: <8017cb3f85604a65f1170b5f2b7a7ffd01ef92b3.1648171285.git.lixianglai@loongson.cn> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: AQAAf9Dx3xMIJj1irWAPAA--.15467S3 X-Coremail-Antispam: 1UD129KBjvAXoWfZr45tF1xGw17Wr4rZr4UXFb_yoW5AFyfKo WUZa1fAw1UJr1xuws5Gw17W3y8Aw4xZwn5Ja1Fqa48W3Z3Z3Z8uwn8Z395WrnxXryYgr15 Gr1xtas5Ja9Iyryrn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYW7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l82xGYIkIc2x26280x7IE14v26r18M28IrcIa0x kI8VCY1x0267AKxVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l84ACjcxK 6xIIjxv20xvE14v26F1j6w1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4UJVWxJr1l84 ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AKxVWxJr0_GcWl e2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI 8IcVAFwI0_Jr0_Jr4lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJVW8JwAC jcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lc2xSY4AK6svPMxAIw28Icx kI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2Iq xVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUXVWUAwCIc40Y0x0EwIxGrwCI42 IY6xIIjxv20xvE14v26r1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVWUJVW8JwCI42IY 6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aV CY1x0267AKxVWUJVW8JbIYCTnIWIevJa73UjIFyTuYvjfU5VbkUUUUU X-CM-SenderInfo: 5ol0xt5qjotxo6or00hjvr0hdfq/ Content-Transfer-Encoding: quoted-printable Serial Port library for LoongarchQemuPkg Signed-off-by: xianglai li --- .../LoongArchQemuPkg/Include/Library/Cpu.h | 344 ++++++++++ .../Include/LoongArchQemuPlatform.h | 103 +++ .../Library/SerialPortLib/SerialPortLib.c | 612 ++++++++++++++++++ .../Library/SerialPortLib/SerialPortLib.inf | 36 ++ 4 files changed, 1095 insertions(+) create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQem= uPlatform.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLi= b/SerialPortLib.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLi= b/SerialPortLib.inf diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h b/Pla= tform/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=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - EXC - Exception=0D + - INT - Interrupt=0D + - FPU - Floating Point Unit=0D + - CSR - CPU Status Register=0D + - READQ - Read Quad Word=0D +**/=0D +#ifndef LOONGARCH_CPU_H_=0D +#define LOONGARCH_CPU_H_=0D +=0D +/* Exception types decoded by machdep exception decoder */=0D +#define EXC_INT 0 /* HW interrupt */=0D +#define EXC_TLBL 1 /* TLB miss on a load */=0D +#define EXC_TLBS 2 /* TLB miss on a store */=0D +#define EXC_TLBI 3 /* TLB miss on a ifetch */=0D +#define EXC_TLBM 4 /* TLB modified fault */=0D +#define EXC_TLBRI 5 /* TLB Read-Inhibit exception */=0D +#define EXC_TLBXI 6 /* TLB Execution-Inhibit exception */=0D +#define EXC_TLBPE 7 /* TLB Privilege Error */=0D +#define EXC_ADE 8 /* Address Error */=0D +#define EXC_ALE 9 /* Unalign Access */=0D +#define EXC_OOB 10 /* Out of bounds */=0D +#define EXC_SYS 11 /* System call */=0D +#define EXC_BP 12 /* Breakpoint */=0D +#define EXC_INE 13 /* Inst. Not Exist */=0D +#define EXC_IPE 14 /* Inst. Privileged Error */=0D +#define EXC_FPDIS 15 /* FPU Disabled */=0D +#define EXC_LSXDIS 16 /* LSX Disabled */=0D +#define EXC_LASXDIS 17 /* LASX Disabled */=0D +#define EXC_FPE 18 /* Floating Point Exception */=0D +#define EXC_WATCH 19 /* Watch address reference */=0D +#define EXC_BAD 255 /* Undecodeable */=0D +=0D +#define COPY_SIGCODE // copy sigcode above user stack in exec=0D +#define ZERO $r0 /* wired zero */=0D +#define RA $r1 /* return address */=0D +#define GP $r2 /* global pointer - caller saved for PIC */=0D +#define SP $r3 /* stack pointer */=0D +#define V0 $r4 /* return value - caller saved */=0D +#define V1 $r5=0D +#define A0 $r4 /* argument registers */=0D +#define A1 $r5=0D +#define A2 $r6=0D +#define A3 $r7=0D +#define A4 $r8 /* arg reg 64 bit; caller saved in 32 bit */=0D +#define A5 $r9=0D +#define A6 $r10=0D +#define A7 $r11=0D +#define T0 $r12 /* caller saved */=0D +#define T1 $r13=0D +#define T2 $r14=0D +#define T3 $r15=0D +#define T4 $r16 /* callee saved */=0D +#define T5 $r17=0D +#define T6 $r18=0D +#define T7 $r19=0D +#define T8 $r20 /* caller saved */=0D +#define TP $r21 /* TLS */=0D +#define FP $r22 /* frame pointer */=0D +#define S0 $r23 /* callee saved */=0D +#define S1 $r24=0D +#define S2 $r25=0D +#define S3 $r26=0D +#define S4 $r27=0D +#define S5 $r28=0D +#define S6 $r29=0D +#define S7 $r30=0D +#define S8 $r31 /* callee saved */=0D +=0D +#define FCSR0 $r0=0D +=0D +//=0D +// Location of the saved registers relative to ZERO.=0D +// Usage is p->p_regs[XX].=0D +//=0D +#define RA_NUM 1=0D +#define GP_NUM 2=0D +#define SP_NUM 3=0D +#define A0_NUM 4=0D +#define A1_NUM 5=0D +#define A2_NUM 6=0D +#define A3_NUM 7=0D +#define A4_NUM 8=0D +#define A5_NUM 9=0D +#define A6_NUM 10=0D +#define A7_NUM 11=0D +#define T0_NUM 12=0D +#define T1_NUM 13=0D +#define T2_NUM 14=0D +#define T3_NUM 15=0D +#define T4_NUM 16=0D +#define T5_NUM 17=0D +#define T6_NUM 18=0D +#define T7_NUM 19=0D +#define T8_NUM 20=0D +#define TP_NUM 21=0D +#define FP_NUM 22=0D +#define S0_NUM 23=0D +#define S1_NUM 24=0D +#define S2_NUM 25=0D +#define S3_NUM 26=0D +#define S4_NUM 27=0D +#define S5_NUM 28=0D +#define S6_NUM 29=0D +#define S7_NUM 30=0D +#define S8_NUM 31=0D +=0D +#define FP0_NUM 0=0D +#define FP1_NUM 1=0D +#define FP2_NUM 2=0D +#define FP3_NUM 3=0D +#define FP4_NUM 4=0D +#define FP5_NUM 5=0D +#define FP6_NUM 6=0D +#define FP7_NUM 7=0D +#define FP8_NUM 8=0D +#define FP9_NUM 9=0D +#define FP10_NUM 10=0D +#define FP11_NUM 11=0D +#define FP12_NUM 12=0D +#define FP13_NUM 13=0D +#define FP14_NUM 14=0D +#define FP15_NUM 15=0D +#define FP16_NUM 16=0D +#define FP17_NUM 17=0D +#define FP18_NUM 18=0D +#define FP19_NUM 19=0D +#define FP20_NUM 20=0D +#define FP21_NUM 21=0D +#define FP22_NUM 22=0D +#define FP23_NUM 23=0D +#define FP24_NUM 24=0D +#define FP25_NUM 25=0D +#define FP26_NUM 26=0D +#define FP27_NUM 27=0D +#define FP28_NUM 28=0D +#define FP29_NUM 29=0D +#define FP30_NUM 30=0D +#define FP31_NUM 31=0D +#define FCSR_NUM 32=0D +#define FCC_NUM 33=0D +=0D +#ifdef __ASSEMBLY__=0D +#define _ULCAST_=0D +#define _U64CAST_=0D +#else=0D +#define _ULCAST_ (unsigned long)=0D +#define _U64CAST_ (u64)=0D +#endif=0D +=0D +#define LOONGARCH_CSR_CRMD 0=0D +#define LOONGARCH_CSR_PRMD 1=0D +#define LOONGARCH_CSR_EUEN 2=0D +#define CSR_EUEN_LBTEN_SHIFT 3=0D +#define CSR_EUEN_LBTEN (_ULCAST_(0x1) << CSR_EUEN_LBTEN_SHIFT= )=0D +#define CSR_EUEN_LASXEN_SHIFT 2=0D +#define CSR_EUEN_LASXEN (_ULCAST_(0x1) << CSR_EUEN_LASXEN_SHIF= T)=0D +#define CSR_EUEN_LSXEN_SHIFT 1=0D +#define CSR_EUEN_LSXEN (_ULCAST_(0x1) << CSR_EUEN_LSXEN_SHIFT= )=0D +#define CSR_EUEN_FPEN_SHIFT 0=0D +#define CSR_EUEN_FPEN (_ULCAST_(0x1) << CSR_EUEN_FPEN_SHIFT)= =0D +#define LOONGARCH_CSR_ECFG 4=0D +=0D +/* Exception status */=0D +#define LOONGARCH_CSR_ESTAT 5=0D +#define CSR_ESTAT_ESUBCODE_SHIFT 22=0D +#define CSR_ESTAT_ESUBCODE_WIDTH 9=0D +#define CSR_ESTAT_ESUBCODE (_ULCAST_(0x1ff) << CSR_ESTAT_ESUBC= ODE_SHIFT)=0D +#define CSR_ESTAT_EXC_SHIFT 16=0D +#define CSR_ESTAT_EXC_WIDTH 6=0D +#define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SH= IFT)=0D +#define CSR_ESTAT_IS_SHIFT 0=0D +#define CSR_ESTAT_IS_WIDTH 15=0D +#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_S= HIFT)=0D +#define LOONGARCH_CSR_EPC 6=0D +#define LOONGARCH_CSR_BADV 7=0D +#define LOONGARCH_CSR_BADINST 8=0D +#define LOONGARCH_CSR_BADI 8=0D +#define LOONGARCH_CSR_EBASE 0xc /* Exception entry base address */= =0D +#define LOONGARCH_CSR_CPUNUM 0x20 /* CPU core number */=0D +=0D +/* register number save in stack on exception */=0D +#define FP_BASE_NUM 34=0D +#define BASE_NUM 32=0D +#define CSR_NUM 10=0D +#define FP_BASE_INDEX (CSR_NUM + BASE_NUM)=0D +#define BOOTCORE_ID 0=0D +=0D +#define LOONGSON_IOCSR_IPI_STATUS 0x1000=0D +#define LOONGSON_IOCSR_IPI_EN 0x1004=0D +#define LOONGSON_IOCSR_IPI_SET 0x1008=0D +#define LOONGSON_IOCSR_IPI_CLEAR 0x100c=0D +#define LOONGSON_CSR_MAIL_BUF0 0x1020=0D +#define LOONGSON_CSR_MAIL_BUF1 0x1028=0D +#define LOONGSON_CSR_MAIL_BUF2 0x1030=0D +#define LOONGSON_CSR_MAIL_BUF3 0x1038=0D +=0D +/* Bit Domains for CFG registers */=0D +#define LOONGARCH_CPUCFG4 0x4=0D +#define LOONGARCH_CPUCFG5 0x5=0D +=0D +/* Kscratch registers */=0D +#define LOONGARCH_CSR_KS0 0x30=0D +#define LOONGARCH_CSR_KS1 0x31=0D +=0D +/* Stable timer registers */=0D +#define LOONGARCH_CSR_TMCFG 0x41=0D +#define LOONGARCH_CSR_TMCFG_EN (1ULL << 0)=0D +#define LOONGARCH_CSR_TMCFG_PERIOD (1ULL << 1)=0D +#define LOONGARCH_CSR_TMCFG_TIMEVAL (0x3fffffffffffULL << 2)=0D +#define LOONGARCH_CSR_TVAL 0x42 /* Timer value */=0D +#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */=0D +#define LOONGARCH_CSR_TINTCLR 0x44 /* Timer interrupt clear */=0D +=0D +/* TLB refill exception base address */=0D +#define LOONGARCH_CSR_TLBREBASE 0x88=0D +#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KScratch for TLB refill exce= ption */=0D +#define LOONGARCH_CSR_PGD 0x1b /* Page table base */=0D +=0D +/* Bits 8 and 9 of FPU Status Register specify the rounding mode */=0D +#define FPU_CSR_RM 0x300=0D +#define FPU_CSR_RN 0x000 /* nearest */=0D +#define FPU_CSR_RZ 0x100 /* towards zero */=0D +#define FPU_CSR_RU 0x200 /* towards +Infinity */=0D +#define FPU_CSR_RD 0x300 /* towards -Infinity */=0D +=0D +/*=0D + Reads data from the specified CSR register.=0D +=0D + @param[OUT] val The value is read from the CSR specified register.=0D + @param[IN] reg Specifies the register number of the CSR to read the = data.=0D +=0D + @retval VOID=0D + */=0D +#define LOONGARCH_CSR_READQ(val, reg) \=0D +do { \=0D + UINT64 __res; \=0D + /* csrrd rd, csr_num */ \=0D + __asm__ __volatile__( \=0D + "csrrd %0, %1 \n\t" \=0D + :"=3Dr"(__res) \=0D + :"i"(reg) \=0D + : \=0D + ); \=0D + (val) =3D __res; \=0D +} while(0)=0D +=0D +/*=0D + Write data to the specified CSR register.=0D +=0D + @param[OUT] val The value is write to the CSR specified register.=0D + @param[IN] reg Specifies the register number of the CSR to write the= data.=0D +=0D + @retval VOID=0D + */=0D +#define LOONGARCH_CSR_WRITEQ(val, reg) \=0D +do { \=0D + UINT64 __val =3D val; \=0D + /* csrwr rd, csr_num */ \=0D + __asm__ __volatile__( \=0D + "csrwr %0, %1 \n\t" \=0D + : "+r"(__val) \=0D + : "i"(reg), "r"(__val) \=0D + : "memory" \=0D + ); \=0D +} while(0)=0D +=0D +/*=0D + Exchange specified bit data with the specified CSR registers=0D +=0D + @param[IN] val The value Exchanged with the CSR specified register.=0D + @param[IN] mask Specifies the mask for swapping bits=0D + @param[IN] reg Specifies the register number of the CSR to Exchange = the data.=0D +=0D + @retval VOID=0D + */=0D +#define LOONGARCH_CSR_XCHGQ(val, mask, reg) \=0D +do { \=0D + UINT64 __val =3D val; \=0D + UINT64 __mask =3D mask; \=0D + /* csrwr rd, csr_num */ \=0D + __asm__ __volatile__( \=0D + "csrxchg %0, %1, %2 \n\t" \=0D + : "+r"(__val) \=0D + : "r"(__mask), "i"(reg), "r"(__val) \=0D + : "memory" \=0D + ); \=0D +} while(0)=0D +/*=0D + Reads data from the specified CPUCFG register.=0D +=0D + @param[OUT] val The value is read from the CPUCFG specified register.= =0D + @param[IN] reg Specifies the register number of the CPUCFG to read t= he data.=0D +=0D + @retval VOID=0D + */=0D +#define LOONGARCH_GET_CPUCFG(val, reg) \=0D +do { \=0D + UINT64 __res; \=0D + /* cpucfg rd, rj */ \=0D + __asm__ __volatile__( \=0D + "cpucfg %0, %1 \n\t" \=0D + :"=3Dr"(__res) \=0D + :"r"(reg) \=0D + : \=0D + ); \=0D + val =3D (UINT32)__res; \=0D +} while(0)=0D +=0D +/*=0D + Enables floating-point unit=0D +=0D + @param VOID=0D +=0D + @retval VOID=0D + */=0D +#define LOONGARCH_ENABLR_FPU() \=0D +do { \=0D + LOONGARCH_CSR_XCHGQ(CSR_EUEN_FPEN, \=0D + CSR_EUEN_FPEN, \=0D + LOONGARCH_CSR_EUEN); \=0D +} while (0)=0D +=0D +/*=0D + Disable floating-point unit=0D +=0D + @param VOID=0D +=0D + @retval VOID=0D + */=0D +#define LOONGARCH_DISABLE_FPU() \=0D +do { \=0D + LOONGARCH_CSR_XCHGQ(0, \=0D + CSR_EUEN_FPEN, \=0D + LOONGARCH_CSR_EUEN); \=0D +} while (0)=0D +=0D +#endif=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatfo= rm.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=0D + LoongArch Qemu Platform macro definition.=0D +=0D + Copyright (c) 2021, Loongson Limited. All rights reserved.=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + **/=0D +=0D +#ifndef LOONGARCH_QEMU_PLATFORM_H_=0D +#define LOONGARCH_QEMU_PLATFORM_H_=0D +=0D +=0D +/* Acpi pm device */=0D +#define LS7A_PCH_REG_BASE 0x10000000UL=0D +#define LS7A_ACPI_REG_BASE (LS7A_PCH_REG_BASE + 0x000D0000)=0D +#define LS7A_PM_CNT_BLK (0x14) /* 2 bytes */=0D +#define LS7A_GPE0_RESET_REG (0x30) /* 4 bytes */=0D +=0D +#define ACPI_BITMASK_SLEEP_TYPE 0x1C00=0D +#define ACPI_BITMASK_SLEEP_ENABLE 0x2000=0D +=0D +=0D +//---------------------------------------------=0D +// UART Register Offsets=0D +//---------------------------------------------=0D +#define BAUD_LOW_OFFSET 0x00=0D +#define BAUD_HIGH_OFFSET 0x01=0D +#define IER_OFFSET 0x01=0D +#define LCR_SHADOW_OFFSET 0x01=0D +#define FCR_SHADOW_OFFSET 0x02=0D +#define IR_CONTROL_OFFSET 0x02=0D +#define FCR_OFFSET 0x02=0D +#define EIR_OFFSET 0x02=0D +#define BSR_OFFSET 0x03=0D +#define LCR_OFFSET 0x03=0D +#define MCR_OFFSET 0x04=0D +#define LSR_OFFSET 0x05=0D +#define MSR_OFFSET 0x06=0D +=0D +/* character format control register */=0D +#define CFCR_DLAB 0x80 /* divisor latch */=0D +#define CFCR_SBREAK 0x40 /* send break */=0D +#define CFCR_PZERO 0x30 /* zero parity */=0D +#define CFCR_PONE 0x20 /* one parity */=0D +#define CFCR_PEVEN 0x10 /* even parity */=0D +#define CFCR_PODD 0x00 /* odd parity */=0D +#define CFCR_PENAB 0x08 /* parity enable */=0D +#define CFCR_STOPB 0x04 /* 2 stop bits */=0D +#define CFCR_8BITS 0x03 /* 8 data bits */=0D +#define CFCR_7BITS 0x02 /* 7 data bits */=0D +#define CFCR_6BITS 0x01 /* 6 data bits */=0D +#define CFCR_5BITS 0x00 /* 5 data bits */=0D +/* modem control register */=0D +#define MCR_LOOPBACK 0x10 /* loopback */=0D +#define MCR_IENABLE 0x08 /* output 2 =3D int enable */=0D +#define MCR_DRS 0x04 /* output 1 =3D xxx */=0D +#define MCR_RTS 0x02 /* enable RTS */=0D +#define MCR_DTR 0x01 /* enable DTR */=0D +=0D +/* line status register */=0D +#define LSR_RCV_FIFO 0x80 /* error in receive fifo */=0D +#define LSR_TSRE 0x40 /* transmitter empty */=0D +#define LSR_TXRDY 0x20 /* transmitter ready */=0D +#define LSR_BI 0x10 /* break detected */=0D +#define LSR_FE 0x08 /* framing error */=0D +#define LSR_PE 0x04 /* parity error */=0D +#define LSR_OE 0x02 /* overrun error */=0D +#define LSR_RXRDY 0x01 /* receiver ready */=0D +#define LSR_RCV_MASK 0x1f=0D +=0D +/* 16550 UART register offsets and bitfields */=0D +#define R_UART_RXBUF 0=0D +#define R_UART_TXBUF 0=0D +#define R_UART_BAUD_LOW 0=0D +#define R_UART_BAUD_HIGH 1=0D +#define R_UART_FCR 2=0D +#define B_UART_FCR_FIFOE BIT0=0D +#define B_UART_FCR_FIFO64 BIT5=0D +#define R_UART_LCR 3=0D +#define B_UART_LCR_DLAB BIT7=0D +#define R_UART_MCR 4=0D +#define B_UART_MCR_DTRC BIT0=0D +#define B_UART_MCR_RTS BIT1=0D +#define R_UART_LSR 5=0D +#define B_UART_LSR_RXRDY BIT0=0D +#define B_UART_LSR_TXRDY BIT5=0D +#define B_UART_LSR_TEMT BIT6=0D +#define R_UART_MSR 6=0D +#define B_UART_MSR_CTS BIT4=0D +#define B_UART_MSR_DSR BIT5=0D +#define B_UART_MSR_RI BIT6=0D +#define B_UART_MSR_DCD BIT7=0D +#define UART_BASE_ADDRESS (0x1fe001e0)=0D +#define UART_BPS (115200)=0D +#define UART_WAIT_TIMOUT (1000000)=0D +//---------------------------------------------=0D +// UART Settings=0D +//---------------------------------------------=0D +#define PHYS_TO_CACHED(x) ((x))=0D +#define PHYS_TO_UNCACHED(x) ((x))=0D +=0D +#endif=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/Seria= lPortLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/Seria= lPortLib.c new file mode 100644 index 0000000000..5b2f3a8194 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLi= b.c @@ -0,0 +1,612 @@ +/** @file=0D + UART Serial Port library functions=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - Bps - Bit Per Second=0D + - CTL - Control=0D + - Config - Configure=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +UINTN gUartBase =3D PHYS_TO_UNCACHED(UART_BASE_ADDRESS);=0D +UINTN gBps =3D UART_BPS;=0D +=0D +/**=0D + Initialize the serial device hardware.=0D +=0D + If no initialization is required, then return RETURN_SUCCESS.=0D + If the serial device was successfuly initialized, then return RETURN_SUC= CESS.=0D + If the serial device could not be initialized, then return RETURN_DEVICE= _ERROR.=0D +=0D + @retval RETURN_SUCCESS The serial device was initialized.=0D + @retval RETURN_DEVICE_ERROR The serail device could not be initialized= .=0D +=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +SerialPortInitialize (=0D + VOID=0D + )=0D +{=0D + UINTN TimeOut;=0D + //=0D + // wait for Tx fifo to completely drain */=0D + //=0D + TimeOut =3D UART_WAIT_TIMOUT;=0D + while (!(MmioRead8 ((UINTN) gUartBase + LSR_OFFSET) & LSR_TSRE)) {=0D + if (--TimeOut =3D=3D 0) {=0D + break;=0D + }=0D + }=0D + //=0D + // Set communications format=0D + //=0D + MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_DLAB);=0D +=0D + //=0D + // Configure baud rate=0D + //=0D +=0D +=0D + MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_8BITS);=0D + MmioWrite8 ((UINTN) (gUartBase + MCR_OFFSET), MCR_IENABLE | MCR_DTR | MC= R_RTS);=0D + //=0D + // if enable interrupt the kernel of lemote will error in STR mode durin= g wake up phase.=0D + //=0D + //MmioWrite8 ((UINTN) (gUartBase + IER_OFFSET), CFCR_8BITS);=0D +=0D + return RETURN_SUCCESS;=0D +}=0D +=0D +/**=0D + Write data from buffer to serial device.=0D +=0D + Writes NumberOfBytes data bytes from Buffer to the serial device.=0D + The number of bytes actually written to the serial device is returned.=0D + If the return value is less than NumberOfBytes, then the write operation= failed.=0D +=0D + If Buffer is NULL, then ASSERT ().=0D +=0D + If NumberOfBytes is zero, then return 0.=0D +=0D + @param Buffer Pointer to the data buffer to be written.=0D + @param NumberOfBytes Number of bytes to written to the serial device= .=0D +=0D + @retval 0 NumberOfBytes is 0.=0D + @retval >0 The number of bytes written to the serial devic= e.=0D + If this value is less than NumberOfBytes, then = the read operation failed.=0D +=0D +**/=0D +UINTN=0D +EFIAPI=0D +UartCtlWrite (=0D + IN UINT8 *Buffer,=0D + IN UINTN NumberOfBytes,=0D + IN UINTN CtlAddr=0D +)=0D +{=0D + UINTN Result;=0D + UINT8 Data;=0D +=0D + if (Buffer =3D=3D NULL) {=0D + return 0;=0D + }=0D +=0D + Result =3D NumberOfBytes;=0D +=0D + while (NumberOfBytes--) {=0D + //=0D + // Wait for the serail port to be ready.=0D + //=0D + do {=0D + Data =3D MmioRead8 (CtlAddr + LSR_OFFSET);=0D + } while ((Data & LSR_TXRDY) =3D=3D 0);=0D + MmioWrite8 (CtlAddr, *Buffer++);=0D + }=0D +=0D + return Result;=0D +}=0D +/**=0D + Writes data to serial port.=0D +=0D + @param Buffer Pointer to the data buffer to store the data wr= ited to serial port.=0D + @param NumberOfBytes Number of bytes to write to the serial port.=0D +=0D + @retval 0 NumberOfBytes is 0.=0D + @retval >0 The number of bytes write the serial port.=0D + If this value is less than NumberOfBytes, then = the write operation failed.=0D +=0D +**/=0D +UINTN=0D +EFIAPI=0D +SerialPortWrite (=0D + IN UINT8 *Buffer,=0D + IN UINTN NumberOfBytes=0D +)=0D +{=0D + return UartCtlWrite (Buffer, NumberOfBytes, gUartBase);=0D +}=0D +/**=0D + Reads data from a serial device into a buffer.=0D +=0D + @param Buffer Pointer to the data buffer to store the data re= ad from the serial device.=0D + @param NumberOfBytes Number of bytes to read from the serial device.= =0D +=0D + @retval 0 NumberOfBytes is 0.=0D + @retval >0 The number of bytes read from the serial device= .=0D + If this value is less than NumberOfBytes, then = the read operation failed.=0D +=0D +**/=0D +UINTN=0D +EFIAPI=0D +UartCtlRead (=0D + OUT UINT8 *Buffer,=0D + IN UINTN NumberOfBytes,=0D + IN UINTN CtlAddr=0D +)=0D +{=0D + UINTN Result;=0D + UINT8 Data;=0D +=0D + if (NULL =3D=3D Buffer) {=0D + return 0;=0D + }=0D +=0D + Result =3D NumberOfBytes;=0D +=0D + while (NumberOfBytes--) {=0D + //=0D + // Wait for the serail port to be ready.=0D + //=0D + do {=0D + Data =3D MmioRead8 (CtlAddr + LSR_OFFSET);=0D + } while ((Data & LSR_RXRDY) =3D=3D 0);=0D +=0D + *Buffer++ =3D MmioRead8 (CtlAddr);=0D + }=0D +=0D + return Result;=0D +}=0D +/**=0D + Read data from serial port.=0D +=0D + @param Buffer Pointer to the data buffer to store the data re= ad from serial port.=0D + @param NumberOfBytes Number of bytes to read from the serial port.=0D +=0D + @retval 0 NumberOfBytes is 0.=0D + @retval >0 The number of bytes read from the serial port.= =0D + If this value is less than NumberOfBytes, then = the read operation failed.=0D +=0D +**/=0D +UINTN=0D +EFIAPI=0D +SerialPortRead (=0D + OUT UINT8 *Buffer,=0D + IN UINTN NumberOfBytes=0D +)=0D +{=0D + return UartCtlRead (Buffer, NumberOfBytes, gUartBase);=0D +}=0D +/**=0D + Polls a serial device to see if there is any data waiting to be read.=0D +=0D + Polls aserial device to see if there is any data waiting to be read.=0D + If there is data waiting to be read from the serial device, then TRUE is= returned.=0D + If there is no data waiting to be read from the serial device, then FALS= E is returned.=0D +=0D + @retval TRUE Data is waiting to be read from the serial devi= ce.=0D + @retval FALSE There is no data waiting to be read from the se= rial device.=0D +=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +SerialPortPoll (=0D + VOID=0D + )=0D +{=0D + UINT8 Data;=0D +=0D + //=0D + // Read the serial port status.=0D + //=0D + Data =3D MmioRead8 ((UINTN) gUartBase + LSR_OFFSET);=0D +=0D + return (BOOLEAN) ((Data & LSR_RXRDY) !=3D 0);=0D +}=0D +/**=0D + To get serial register base address.=0D +=0D + @param VOID=0D +=0D + @return serial register base address.=0D +**/=0D +UINTN=0D +GetSerialRegisterBase (=0D + VOID=0D + )=0D +{=0D + return gUartBase;=0D +}=0D +/**=0D + Read an 8-bit register.=0D + @param Base The base address register of UART device.=0D + @param Offset The offset of the register to read.=0D +=0D + @return The value read from the 16550 register.=0D +=0D +**/=0D +UINT8=0D +SerialPortReadRegister (=0D + UINTN Base,=0D + UINTN Offset=0D + )=0D +{=0D + return MmioRead8 (Base + Offset);=0D +}=0D +=0D +/**=0D + Write an 8-bit register.=0D + @param Base The base address register of UART device.=0D + @param Offset The offset of the register to write.=0D + @param Value The value to write to the register specified by Offset.= =0D +=0D + @return The value written to the 16550 register.=0D +=0D +**/=0D +UINT8=0D +SerialPortWriteRegister (=0D + UINTN Base,=0D + UINTN Offset,=0D + UINT8 Value=0D + )=0D +{=0D + return MmioWrite8 (Base + Offset, Value);=0D +}=0D +=0D +/**=0D + Sets the control bits on a serial device.=0D +=0D + @param Control Sets the bits of Control that are settable= .=0D +=0D + @retval RETURN_SUCCESS The new control bits were set on the seria= l device.=0D + @retval RETURN_UNSUPPORTED The serial device does not support this op= eration.=0D + @retval RETURN_DEVICE_ERROR The serial device is not functioning corre= ctly.=0D +=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +SerialPortSetControl (=0D + IN UINT32 Control=0D + )=0D +{=0D + UINTN SerialRegisterBase;=0D + UINT8 Mcr;=0D +=0D + //=0D + // First determine the parameter is invalid.=0D + //=0D + if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_= READY |=0D + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) !=3D 0)=0D + {=0D + return RETURN_UNSUPPORTED;=0D + }=0D +=0D + SerialRegisterBase =3D GetSerialRegisterBase ();=0D + if (SerialRegisterBase =3D=3D0) {=0D + return RETURN_UNSUPPORTED;=0D + }=0D +=0D + //=0D + // Read the Modem Control Register.=0D + //=0D + Mcr =3D SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);=0D + Mcr &=3D (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));=0D +=0D + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) =3D=3D EFI_SERIAL_DATA_TE= RMINAL_READY) {=0D + Mcr |=3D B_UART_MCR_DTRC;=0D + }=0D +=0D + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) =3D=3D EFI_SERIAL_REQUEST_TO_= SEND) {=0D + Mcr |=3D B_UART_MCR_RTS;=0D + }=0D +=0D + //=0D + // Write the Modem Control Register.=0D + //=0D + SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);=0D +=0D + return RETURN_SUCCESS;=0D +}=0D +=0D +/**=0D + Retrieve the status of the control bits on a serial device.=0D +=0D + @param Control A pointer to return the current control si= gnals from the serial device.=0D +=0D + @retval RETURN_SUCCESS The control bits were read from the serial= device.=0D + @retval RETURN_UNSUPPORTED The serial device does not support this op= eration.=0D + @retval RETURN_DEVICE_ERROR The serial device is not functioning corre= ctly.=0D +=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +SerialPortGetControl (=0D + OUT UINT32 *Control=0D + )=0D +{=0D + UINTN SerialRegisterBase;=0D + UINT8 Msr;=0D + UINT8 Mcr;=0D + UINT8 Lsr;=0D +=0D + SerialRegisterBase =3D GetSerialRegisterBase ();=0D + if (SerialRegisterBase =3D=3D0) {=0D + return RETURN_UNSUPPORTED;=0D + }=0D +=0D + *Control =3D 0;=0D +=0D + //=0D + // Read the Modem Status Register.=0D + //=0D + Msr =3D SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);=0D +=0D + if ((Msr & B_UART_MSR_CTS) =3D=3D B_UART_MSR_CTS) {=0D + *Control |=3D EFI_SERIAL_CLEAR_TO_SEND;=0D + }=0D +=0D + if ((Msr & B_UART_MSR_DSR) =3D=3D B_UART_MSR_DSR) {=0D + *Control |=3D EFI_SERIAL_DATA_SET_READY;=0D + }=0D +=0D + if ((Msr & B_UART_MSR_RI) =3D=3D B_UART_MSR_RI) {=0D + *Control |=3D EFI_SERIAL_RING_INDICATE;=0D + }=0D +=0D + if ((Msr & B_UART_MSR_DCD) =3D=3D B_UART_MSR_DCD) {=0D + *Control |=3D EFI_SERIAL_CARRIER_DETECT;=0D + }=0D +=0D + //=0D + // Read the Modem Control Register.=0D + //=0D + Mcr =3D SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);=0D +=0D + if ((Mcr & B_UART_MCR_DTRC) =3D=3D B_UART_MCR_DTRC) {=0D + *Control |=3D EFI_SERIAL_DATA_TERMINAL_READY;=0D + }=0D +=0D + if ((Mcr & B_UART_MCR_RTS) =3D=3D B_UART_MCR_RTS) {=0D + *Control |=3D EFI_SERIAL_REQUEST_TO_SEND;=0D + }=0D +=0D + if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {=0D + *Control |=3D EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;=0D + }=0D +=0D + //=0D + // Read the Line Status Register.=0D + //=0D + Lsr =3D SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);=0D +=0D + if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) =3D=3D (B_UART_LSR_TEMT= | B_UART_LSR_TXRDY)) {=0D + *Control |=3D EFI_SERIAL_OUTPUT_BUFFER_EMPTY;=0D + }=0D +=0D + if ((Lsr & B_UART_LSR_RXRDY) =3D=3D 0) {=0D + *Control |=3D EFI_SERIAL_INPUT_BUFFER_EMPTY;=0D + }=0D +=0D + return RETURN_SUCCESS;=0D +}=0D +=0D +/**=0D + Sets the baud rate, receive FIFO depth, transmit/receice time out, parit= y,=0D + data bits, and stop bits on a serial device.=0D +=0D + @param BaudRate The requested baud rate. A BaudRate value of 0= will use the=0D + device's default interface speed.=0D + On output, the value actually set.=0D + @param ReveiveFifoDepth The requested depth of the FIFO on the receive= side of the=0D + serial interface. A ReceiveFifoDepth value of = 0 will use=0D + the device's default FIFO depth.=0D + On output, the value actually set.=0D + @param Timeout The requested time out for a single character = in microseconds.=0D + This timeout applies to both the transmit and = receive side of the=0D + interface. A Timeout value of 0 will use the d= evice's default time=0D + out value.=0D + On output, the value actually set.=0D + @param Parity The type of parity to use on this serial devic= e. A Parity value of=0D + DefaultParity will use the device's default pa= rity value.=0D + On output, the value actually set.=0D + @param DataBits The number of data bits to use on the serial d= evice. A DataBits=0D + vaule of 0 will use the device's default data = bit setting.=0D + On output, the value actually set.=0D + @param StopBits The number of stop bits to use on this serial = device. A StopBits=0D + value of DefaultStopBits will use the device's= default number of=0D + stop bits.=0D + On output, the value actually set.=0D +=0D + @retval RETURN_SUCCESS The new attributes were set on the ser= ial device.=0D + @retval RETURN_UNSUPPORTED The serial device does not support thi= s operation.=0D + @retval RETURN_INVALID_PARAMETER One or more of the attributes has an u= nsupported value.=0D + @retval RETURN_DEVICE_ERROR The serial device is not functioning c= orrectly.=0D +=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +UartCtlConfig (=0D + IN OUT UINT64 *BaudRate,=0D + IN OUT UINT32 *ReceiveFifoDepth,=0D + IN OUT UINT32 *Timeout,=0D + IN OUT EFI_PARITY_TYPE *Parity,=0D + IN OUT UINT8 *DataBits,=0D + IN OUT EFI_STOP_BITS_TYPE *StopBits,=0D + IN UINTN CtlAddr=0D + )=0D +{=0D + UINTN SerialRegisterBase;=0D + UINT8 Lcr;=0D + UINT8 LcrData;=0D + UINT8 LcrParity;=0D + UINT8 LcrStop;=0D +=0D +=0D + SerialRegisterBase =3D CtlAddr;=0D + if (SerialRegisterBase =3D=3D0) {=0D + return RETURN_UNSUPPORTED;=0D + }=0D +=0D + //=0D + // Check for default settings and fill in actual values.=0D + //=0D + if (*BaudRate =3D=3D 0) {=0D + *BaudRate =3D PcdGet32 (PcdSerialBaudRate);=0D + }=0D +=0D + if (*DataBits =3D=3D 0) {=0D + LcrData =3D (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);=0D + *DataBits =3D LcrData + 5;=0D + } else {=0D + if ((*DataBits < 5)=0D + || (*DataBits > 8))=0D + {=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D + //=0D + // Map 5..8 to 0..3=0D + //=0D + LcrData =3D (UINT8) (*DataBits - (UINT8) 5);=0D + }=0D +=0D + if (*Parity =3D=3D DefaultParity) {=0D + LcrParity =3D (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);=0D + switch (LcrParity) {=0D + case 0:=0D + *Parity =3D NoParity;=0D + break;=0D +=0D + case 3:=0D + *Parity =3D EvenParity;=0D + break;=0D +=0D + case 1:=0D + *Parity =3D OddParity;=0D + break;=0D +=0D + case 7:=0D + *Parity =3D SpaceParity;=0D + break;=0D +=0D + case 5:=0D + *Parity =3D MarkParity;=0D + break;=0D +=0D + default:=0D + break;=0D + }=0D + } else {=0D + switch (*Parity) {=0D + case NoParity:=0D + LcrParity =3D 0;=0D + break;=0D +=0D + case EvenParity:=0D + LcrParity =3D 3;=0D + break;=0D +=0D + case OddParity:=0D + LcrParity =3D 1;=0D + break;=0D +=0D + case SpaceParity:=0D + LcrParity =3D 7;=0D + break;=0D +=0D + case MarkParity:=0D + LcrParity =3D 5;=0D + break;=0D +=0D + default:=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D + }=0D +=0D + if (*StopBits =3D=3D DefaultStopBits) {=0D + LcrStop =3D (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);=0D + switch (LcrStop) {=0D + case 0:=0D + *StopBits =3D OneStopBit;=0D + break;=0D +=0D + case 1:=0D + if (*DataBits =3D=3D 5) {=0D + *StopBits =3D OneFiveStopBits;=0D + } else {=0D + *StopBits =3D TwoStopBits;=0D + }=0D + break;=0D +=0D + default:=0D + break;=0D + }=0D + } else {=0D + switch (*StopBits) {=0D + case OneStopBit:=0D + LcrStop =3D 0;=0D + break;=0D +=0D + case OneFiveStopBits:=0D + case TwoStopBits:=0D + LcrStop =3D 1;=0D + break;=0D +=0D + default:=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D + }=0D + SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB= );=0D +=0D + //=0D + // Clear DLAB and configure Data Bits, Parity, and Stop Bits.=0D + // Strip reserved bits from line control value=0D + //=0D + Lcr =3D (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);=0D + SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & = 0x3F));=0D +=0D + return RETURN_SUCCESS;=0D +}=0D +/**=0D + Set the serial port Attributes.=0D +=0D + @param VOID=0D +=0D + @return serial register base address.=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +SerialPortSetAttributes (=0D + IN OUT UINT64 *BaudRate,=0D + IN OUT UINT32 *ReceiveFifoDepth,=0D + IN OUT UINT32 *Timeout,=0D + IN OUT EFI_PARITY_TYPE *Parity,=0D + IN OUT UINT8 *DataBits,=0D + IN OUT EFI_STOP_BITS_TYPE *StopBits=0D + )=0D +{=0D + UINTN SerialRegisterBase;=0D +=0D + SerialRegisterBase =3D GetSerialRegisterBase ();=0D +=0D + return UartCtlConfig (&gBps, ReceiveFifoDepth, Timeout, Parity, DataBit= s, StopBits,=0D + SerialRegisterBase);=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/Seria= lPortLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/Ser= ialPortLib.inf new file mode 100644 index 0000000000..6c4674151b --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLi= b.inf @@ -0,0 +1,36 @@ +## @file=0D +# UART Serial Port library functions=0D +#=0D +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights = reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D PcAtSerialPortLib=0D + FILE_GUID =3D f4fb883d-8138-4f29-bb0c-c574e9312c74= =0D + MODULE_TYPE =3D BASE=0D + VERSION_STRING =3D 1.0=0D + LIBRARY_CLASS =3D SerialPortLib=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + Platform/Loongson/LoongArchQemuPkg/Loongson.dec=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + IoLib=0D + PcdLib=0D +=0D +[Sources]=0D + SerialPortLib.c=0D +=0D +[Pcd]=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl ## CONSU= MES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate ## CONSU= MES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl ## CONSU= MES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate ## CONSU= MES=0D --=20 2.31.1