Эх сурвалжийг харах

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>
Shawn Guo 9 жил өмнө
parent
commit
0e125a5fac

+ 35 - 10
drivers/tty/serial/amba-pl011.c

@@ -93,6 +93,10 @@ static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
 struct vendor_data {
 struct vendor_data {
 	const u16		*reg_offset;
 	const u16		*reg_offset;
 	unsigned int		ifls;
 	unsigned int		ifls;
+	unsigned int		fr_busy;
+	unsigned int		fr_dsr;
+	unsigned int		fr_cts;
+	unsigned int		fr_ri;
 	bool			access_32b;
 	bool			access_32b;
 	bool			oversampling;
 	bool			oversampling;
 	bool			dma_threshold;
 	bool			dma_threshold;
@@ -111,6 +115,10 @@ static unsigned int get_fifosize_arm(struct amba_device *dev)
 static struct vendor_data vendor_arm = {
 static struct vendor_data vendor_arm = {
 	.reg_offset		= pl011_std_offsets,
 	.reg_offset		= pl011_std_offsets,
 	.ifls			= UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
 	.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,
 	.oversampling		= false,
 	.dma_threshold		= false,
 	.dma_threshold		= false,
 	.cts_event_workaround	= false,
 	.cts_event_workaround	= false,
@@ -121,6 +129,10 @@ static struct vendor_data vendor_arm = {
 
 
 static struct vendor_data vendor_sbsa = {
 static struct vendor_data vendor_sbsa = {
 	.reg_offset		= pl011_std_offsets,
 	.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,
 	.access_32b		= true,
 	.oversampling		= false,
 	.oversampling		= false,
 	.dma_threshold		= false,
 	.dma_threshold		= false,
@@ -164,6 +176,10 @@ static unsigned int get_fifosize_st(struct amba_device *dev)
 static struct vendor_data vendor_st = {
 static struct vendor_data vendor_st = {
 	.reg_offset		= pl011_st_offsets,
 	.reg_offset		= pl011_st_offsets,
 	.ifls			= UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
 	.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,
 	.oversampling		= true,
 	.dma_threshold		= true,
 	.dma_threshold		= true,
 	.cts_event_workaround	= true,
 	.cts_event_workaround	= true,
@@ -192,6 +208,10 @@ static struct vendor_data vendor_zte __maybe_unused = {
 	.reg_offset		= pl011_zte_offsets,
 	.reg_offset		= pl011_zte_offsets,
 	.access_32b		= true,
 	.access_32b		= true,
 	.ifls			= UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
 	.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,
 	.get_fifosize		= get_fifosize_arm,
 };
 };
 
 
@@ -1167,7 +1187,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
 		return;
 		return;
 
 
 	/* Disable RX and TX DMA */
 	/* 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();
 		cpu_relax();
 
 
 	spin_lock_irq(&uap->port.lock);
 	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)
 	if (delta & UART01x_FR_DCD)
 		uart_handle_dcd_change(&uap->port, status & 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++;
 		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);
 	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 =
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
 	    container_of(port, struct uart_amba_port, port);
 	unsigned int status = pl011_read(uap, REG_FR);
 	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)
 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
 		result |= tiocmbit
 
 
 	TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
 	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
 #undef TIOCMBIT
 	return result;
 	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
 	 *	Finally, wait for transmitter to become empty
 	 *	and restore the TCR
 	 *	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();
 		cpu_relax();
 	if (!uap->vendor->always_enabled)
 	if (!uap->vendor->always_enabled)
 		pl011_write(old_cr, uap, REG_CR);
 		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)
 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)
 	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
 		cpu_relax();
 		cpu_relax();
 	if (port->iotype == UPIO_MEM32)
 	if (port->iotype == UPIO_MEM32)
 		writel(c, port->membase + UART01x_DR);
 		writel(c, port->membase + UART01x_DR);
 	else
 	else
 		writeb(c, port->membase + UART01x_DR);
 		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();
 		cpu_relax();
 }
 }
 
 

+ 9 - 0
include/linux/amba/serial.h

@@ -104,6 +104,15 @@
 #define UART01x_FR_CTS 		0x001
 #define UART01x_FR_CTS 		0x001
 #define UART01x_FR_TMSK		(UART01x_FR_TXFF + UART01x_FR_BUSY)
 #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_CTSEN	0x8000	/* CTS hardware flow control */
 #define UART011_CR_RTSEN	0x4000	/* RTS hardware flow control */
 #define UART011_CR_RTSEN	0x4000	/* RTS hardware flow control */
 #define UART011_CR_OUT2		0x2000	/* OUT2 */
 #define UART011_CR_OUT2		0x2000	/* OUT2 */