tty: amba-pl011: define flag register bits for ZTE device
authorShawn Guo <shawn.guo@linaro.org>
Fri, 8 Jul 2016 09:00:39 +0000 (17:00 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 31 Aug 2016 13:24:23 +0000 (15:24 +0200)
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>
drivers/tty/serial/amba-pl011.c
include/linux/amba/serial.h

index 8a9e213387a79fcc335caad27520a68edf03f446..3914ad0c2c26fccab03857ff8ae1593da54e260b 100644 (file)
@@ -93,6 +93,10 @@ static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
 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 unsigned int get_fifosize_arm(struct amba_device *dev)
 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_arm = {
 
 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 unsigned int get_fifosize_st(struct amba_device *dev)
 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 @@ static struct vendor_data vendor_zte __maybe_unused = {
        .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 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
                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 @@ static void pl011_modem_status(struct uart_amba_port *uap)
        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 @@ static unsigned int pl011_tx_empty(struct uart_port *port)
        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 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
                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 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
         *      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 struct console amba_console = {
 
 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();
 }
 
index d76a19ba2cffa68f1a2a0b0c830b8e562ab6eb13..ad0965e21a5e7610e1778d36eb3ee9a66739c44e 100644 (file)
 #define UART01x_FR_CTS                 0x001
 #define UART01x_FR_TMSK                (UART01x_FR_TXFF + UART01x_FR_BUSY)
 
+/*
+ * Some bits of Flag Register on ZTE device have different position from
+ * standard ones.
+ */
+#define ZX_UART01x_FR_BUSY     0x100
+#define ZX_UART01x_FR_DSR      0x008
+#define ZX_UART01x_FR_CTS      0x002
+#define ZX_UART011_FR_RI       0x001
+
 #define UART011_CR_CTSEN       0x8000  /* CTS hardware flow control */
 #define UART011_CR_RTSEN       0x4000  /* RTS hardware flow control */
 #define UART011_CR_OUT2                0x2000  /* OUT2 */