HV: vuart: support MSR and MCR

In Linux 8250 driver, it has different flags for UART ports. For COM1,
COM2 and COM3, UPF_SKIP_TEST is set, which is used to skip the loopback
test for the port. But for COM4, UPF_SKIP_TEST is not set, so when
probing COM4, the driver will access MCR and MSR registers to make sure
the port is exsit. So, add support for MSR and MCR.
Default ports info:
    COM1, ttyS0, 0x3F8
    COM2, ttyS1, 0x2F8
    COM3, ttyS2, 0x3E8
    COM4, ttyS3, 0x2E8

Tracked-On: #2987
Signed-off-by: Conghui Chen <conghui.chen@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Conghui Chen 2019-04-29 03:34:40 +08:00 committed by ACRN System Integration
parent 4efc9e3ef9
commit a090d03780
2 changed files with 88 additions and 5 deletions

View File

@ -120,6 +120,8 @@ static uint8_t vuart_intr_reason(const struct acrn_vuart *vu)
ret = IIR_RXTOUT;
} else if (vu->thre_int_pending && ((vu->ier & IER_ETBEI) != 0U)) {
ret = IIR_TXRDY;
} else if((vu->msr & MSR_DELTA_MASK) != 0 && (vu->ier & IER_EMSC) != 0) {
ret = IIR_MLSC;
}
return ret;
}
@ -182,6 +184,34 @@ static void vuart_write_to_target(struct acrn_vuart *vu, uint8_t value_u8)
vuart_unlock(vu);
}
static uint8_t modem_status(uint8_t mcr)
{
uint8_t msr;
if (mcr & MCR_LOOPBACK) {
/*
* In the loopback mode certain bits from the MCR are
* reflected back into MSR.
*/
msr = 0;
if (mcr & MCR_RTS)
msr |= MSR_CTS;
if (mcr & MCR_DTR)
msr |= MSR_DSR;
if (mcr & MCR_OUT1)
msr |= MSR_RI;
if (mcr & MCR_OUT2)
msr |= MSR_DCD;
} else {
/*
* Always assert DCD and DSR so tty open doesn't block
* even if CLOCAL is turned off.
*/
msr = MSR_DCD | MSR_DSR;
}
return msr;
}
static bool vuart_write(struct acrn_vm *vm, uint16_t offset_arg,
__unused size_t width, uint32_t value)
{
@ -189,11 +219,14 @@ static bool vuart_write(struct acrn_vm *vm, uint16_t offset_arg,
struct acrn_vuart *vu = find_vuart_by_port(vm, offset);
uint8_t value_u8 = (uint8_t)value;
struct acrn_vuart *target_vu = NULL;
uint8_t msr;
if (vu) {
offset -= vu->port_base;
target_vu = vu->target_vu;
if ((offset == UART16550_THR) && target_vu) {
if (!(vu->mcr & MCR_LOOPBACK) &&
(offset == UART16550_THR) && target_vu) {
vuart_write_to_target(target_vu, value_u8);
} else {
vuart_lock(vu);
@ -207,7 +240,12 @@ static bool vuart_write(struct acrn_vm *vm, uint16_t offset_arg,
} else {
switch (offset) {
case UART16550_THR:
if (vu->mcr & MCR_LOOPBACK) {
fifo_putchar(&vu->rxfifo, (char)value_u8);
vu->lsr |= LSR_OE;
} else {
fifo_putchar(&vu->txfifo, (char)value_u8);
}
vu->thre_int_pending = true;
break;
case UART16550_IER:
@ -236,7 +274,28 @@ static bool vuart_write(struct acrn_vm *vm, uint16_t offset_arg,
vu->lcr = value_u8;
break;
case UART16550_MCR:
/* ignore modem */
/* Apply mask so that bits 5-7 are 0 */
vu->mcr = value & 0x1F;
msr = modem_status(vu->mcr);
/*
* Detect if there has been any change between the
* previous and the new value of MSR. If there is
* then assert the appropriate MSR delta bit.
*/
if ((msr & MSR_CTS) ^ (vu->msr & MSR_CTS))
vu->msr |= MSR_DCTS;
if ((msr & MSR_DSR) ^ (vu->msr & MSR_DSR))
vu->msr |= MSR_DDSR;
if ((msr & MSR_DCD) ^ (vu->msr & MSR_DCD))
vu->msr |= MSR_DDCD;
if ((vu->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
vu->msr |= MSR_TERI;
/*
* Update the value of MSR while retaining the delta
* bits.
*/
vu->msr &= MSR_DELTA_MASK;
vu->msr |= msr;
break;
case UART16550_LSR:
/*
@ -332,8 +391,11 @@ static bool vuart_read(struct acrn_vm *vm, struct acrn_vcpu *vcpu, uint16_t offs
vu->lsr &= ~LSR_OE;
break;
case UART16550_MSR:
/* ignore modem I*/
reg = 0U;
/*
* MSR delta bits are cleared on read
*/
reg = vu->msr;
vu->msr &= ~MSR_DELTA_MASK;
break;
case UART16550_SCR:
reg = vu->scr;

View File

@ -36,6 +36,7 @@
/* value definitions for IIR */
#define IIR_FIFO_MASK 0xc0U /* set if FIFOs are enabled */
#define IIR_RXTOUT 0x0cU
#define IER_EMSC 0x08U
#define IIR_RLS 0x06U
#define IIR_RXRDY 0x04U
#define IIR_TXRDY 0x02U
@ -87,9 +88,29 @@
#define LSR_DR (1U << 0U)
/* definition for MCR */
#define MCR_PRESCALE (1U << 7U) /* only available on 16650 up */
#define MCR_LOOPBACK (1U << 4U)
#define MCR_IE (1U << 3U)
#define MCR_IENABLE MCR_IE
#define MCR_DRS (1U << 2U)
#define MCR_RTS (1U << 1U) /* Request to Send */
#define MCR_DTR (1U << 0U) /* Data Terminal Ready */
/* defifor MSR */
#define MSR_DCD (1U << 7U)
#define MSR_RI (1U << 6U)
#define MSR_DSR (1U << 5U)
#define MSR_CTS (1U << 4U)
#define MSR_DDCD (1U << 3U)
#define MSR_TERI (1U << 2U)
#define MSR_DDSR (1U << 1U)
#define MSR_DCTS (1U << 0U)
#define MCR_OUT2 (1U << 3U)
#define MCR_OUT1 (1U << 2U)
#define MSR_DELTA_MASK 0x0FU
/* definition for FCR */
#define FCR_RX_MASK 0xc0U
#define FCR_DMA (1U << 3U)