tty: amba-pl011: define flag register bits for ZTE device
For some reason we do not really understand, ZTE hardware designers
choose to define PL011 Flag Register bit positions differently from
standard ones as below.
Bit Standard ZTE
-----------------------------------
CTS 0 1
DSR 1 3
BUSY 3 8
RI 8 0
Let's define these bits into vendor data and get ZTE PL011 supported
properly.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8a9e213..3914ad0 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -93,6 +93,10 @@
struct vendor_data {
const u16 *reg_offset;
unsigned int ifls;
+ unsigned int fr_busy;
+ unsigned int fr_dsr;
+ unsigned int fr_cts;
+ unsigned int fr_ri;
bool access_32b;
bool oversampling;
bool dma_threshold;
@@ -111,6 +115,10 @@
static struct vendor_data vendor_arm = {
.reg_offset = pl011_std_offsets,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+ .fr_busy = UART01x_FR_BUSY,
+ .fr_dsr = UART01x_FR_DSR,
+ .fr_cts = UART01x_FR_CTS,
+ .fr_ri = UART011_FR_RI,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
@@ -121,6 +129,10 @@
static struct vendor_data vendor_sbsa = {
.reg_offset = pl011_std_offsets,
+ .fr_busy = UART01x_FR_BUSY,
+ .fr_dsr = UART01x_FR_DSR,
+ .fr_cts = UART01x_FR_CTS,
+ .fr_ri = UART011_FR_RI,
.access_32b = true,
.oversampling = false,
.dma_threshold = false,
@@ -164,6 +176,10 @@
static struct vendor_data vendor_st = {
.reg_offset = pl011_st_offsets,
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
+ .fr_busy = UART01x_FR_BUSY,
+ .fr_dsr = UART01x_FR_DSR,
+ .fr_cts = UART01x_FR_CTS,
+ .fr_ri = UART011_FR_RI,
.oversampling = true,
.dma_threshold = true,
.cts_event_workaround = true,
@@ -192,6 +208,10 @@
.reg_offset = pl011_zte_offsets,
.access_32b = true,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+ .fr_busy = ZX_UART01x_FR_BUSY,
+ .fr_dsr = ZX_UART01x_FR_DSR,
+ .fr_cts = ZX_UART01x_FR_CTS,
+ .fr_ri = ZX_UART011_FR_RI,
.get_fifosize = get_fifosize_arm,
};
@@ -1167,7 +1187,7 @@
return;
/* Disable RX and TX DMA */
- while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+ while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
cpu_relax();
spin_lock_irq(&uap->port.lock);
@@ -1416,11 +1436,12 @@
if (delta & UART01x_FR_DCD)
uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
- if (delta & UART01x_FR_DSR)
+ if (delta & uap->vendor->fr_dsr)
uap->port.icount.dsr++;
- if (delta & UART01x_FR_CTS)
- uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
+ if (delta & uap->vendor->fr_cts)
+ uart_handle_cts_change(&uap->port,
+ status & uap->vendor->fr_cts);
wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
}
@@ -1493,7 +1514,8 @@
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
unsigned int status = pl011_read(uap, REG_FR);
- return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
+ return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
+ 0 : TIOCSER_TEMT;
}
static unsigned int pl011_get_mctrl(struct uart_port *port)
@@ -1508,9 +1530,9 @@
result |= tiocmbit
TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
- TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
- TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
- TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
+ TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR);
+ TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS);
+ TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG);
#undef TIOCMBIT
return result;
}
@@ -2191,7 +2213,7 @@
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
- while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+ while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
cpu_relax();
if (!uap->vendor->always_enabled)
pl011_write(old_cr, uap, REG_CR);
@@ -2303,13 +2325,16 @@
static void pl011_putc(struct uart_port *port, int c)
{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
cpu_relax();
if (port->iotype == UPIO_MEM32)
writel(c, port->membase + UART01x_DR);
else
writeb(c, port->membase + UART01x_DR);
- while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
+ while (readl(port->membase + UART01x_FR) & uap->vendor->fr_busy)
cpu_relax();
}