bk://bk.arm.linux.org.uk/linux-2.6-serial
rmk@flint.arm.linux.org.uk|ChangeSet|20040829120731|41481 rmk

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/08/29 13:07:31+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] 8250: Rename UART_STARTECH to UART_CAP_EFR
#   
#   UART_STARTECH is really telling us that the UART has an EFR register,
#   so call this flag UART_CAP_EFR.
# 
# drivers/serial/8250.h
#   2004/08/29 13:05:20+01:00 rmk@flint.arm.linux.org.uk +1 -0
#   Rename UART_STARTECH to UART_CAP_EFR, since that's what it's really
#   telling us - that the UART has an EFR register.
# 
# drivers/serial/8250.c
#   2004/08/29 13:05:19+01:00 rmk@flint.arm.linux.org.uk +10 -8
#   Rename UART_STARTECH to UART_CAP_EFR, since that's what it's really
#   telling us - that the UART has an EFR register.
# 
# ChangeSet
#   2004/08/29 12:59:58+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] 8250: add UART_CAP_SLEEP capability.
# 
# drivers/serial/8250.h
#   2004/08/29 12:57:48+01:00 rmk@flint.arm.linux.org.uk +1 -0
#   Add UART_CAP_SLEEP definition.
# 
# drivers/serial/8250.c
#   2004/08/29 12:57:48+01:00 rmk@flint.arm.linux.org.uk +17 -17
#   Add UART_CAP_SLEEP - this indicates which UART types have IER sleep
#   capability.  We generalise the code in serial8250_set_sleep() since
#   Startech is a superset of the TI16750 sleep code.
# 
# ChangeSet
#   2004/08/29 12:52:25+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] 8250: serial8250_set_sleep
#   
#   Add container function for UART sleep code.  Currently only Startech
#   and TI16750 uses this.
# 
# drivers/serial/8250.c
#   2004/08/29 12:49:56+01:00 rmk@flint.arm.linux.org.uk +24 -46
#   Add serial8250_set_sleep - this contains the code to place UARTs into
#   sleep mode.
# 
# ChangeSet
#   2004/08/29 11:52:58+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] 8250: combine UART_CLEAR_FIFO/UART_USE_FIFO into one flag.
#   
#   Combine UART_CLEAR_FIFO and UART_USE_FIFO into one capability -
#   UART_CAP_FIFO.  There is only one UART with an unused FIFO - ST16650.
#   Since we check the fifo size before enabling, we maintain the
#   existing behaviour.
# 
# drivers/serial/8250.h
#   2004/08/29 11:50:41+01:00 rmk@flint.arm.linux.org.uk +2 -0
#   Add UART_CAP_FIFO flag.
# 
# drivers/serial/8250.c
#   2004/08/29 11:50:41+01:00 rmk@flint.arm.linux.org.uk +12 -12
#   Combine UART_CLEAR_FIFO and UART_USE_FIFO into one capability -
#   UART_CAP_FIFO.  There is only one UART with an unused FIFO, ST16650.
#   Since we check the fifo size before enabling, we maintain the
#   existing behaviour.
# 
# ChangeSet
#   2004/08/29 00:48:16+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] 8250: tell transmit path the data transfer size.
#   
#   Some UARTs give us a transmit interrupt when the TX FIFO is less
#   than half empty.  This means we should not transfer a FIFO-full
#   of data to the device.  Introduce "tx_loadsz" to indicate the
#   size of this transfer.
# 
# drivers/serial/8250.h
#   2004/08/29 00:46:09+01:00 rmk@flint.arm.linux.org.uk +1 -0
#   Add tx_loadsz element to serial8250_config
# 
# drivers/serial/8250.c
#   2004/08/29 00:46:08+01:00 rmk@flint.arm.linux.org.uk +19 -17
#   Add "tx_loadsz".  This gives the size of the data transfer when we
#   receive a transmit interrupt.  Add transmit load size data to the
#   uart_config table.
# 
# ChangeSet
#   2004/08/29 00:29:43+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] 8250: Add serial8250_config structure definition.
#   
#   This structure replaces serial_uart_config to allow the 8250 driver
#   to extend it without breaking all the other users.
# 
# drivers/serial/8250.h
#   2004/08/29 00:27:37+01:00 rmk@flint.arm.linux.org.uk +9 -0
#   Add serial8250_config structure definition.
# 
# drivers/serial/8250.c
#   2004/08/29 00:27:36+01:00 rmk@flint.arm.linux.org.uk +2 -2
#   Rename serial_uart_config structure to serial8250_config, and
#   dfl_xmit_fifo_size to fifo_size.
# 
# ChangeSet
#   2004/08/29 00:06:41+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] 8250: We can only use the FIFO if fifosize > 1.
# 
# drivers/serial/8250.c
#   2004/08/29 00:03:54+01:00 rmk@flint.arm.linux.org.uk +1 -1
#   We can only use the FIFO if fifosize > 1.
# 
# ChangeSet
#   2004/08/28 23:48:25+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] Move XR16C850 Tx/Rx trigger level setup to startup code
# 
# drivers/serial/8250.c
#   2004/08/28 23:46:09+01:00 rmk@flint.arm.linux.org.uk +17 -17
#   Move TX/RX trigger level settings for XR16C850 into startup code
#   rather than power management code.
# 
# ChangeSet
#   2004/08/28 23:34:57+01:00 rmk@flint.arm.linux.org.uk 
#   [SERIAL] Factor out "clear fifo" functionality.
#   
#   Move "clear fifo" into separate function dependent on
#   UART_CLEAR_FIFO capability.  We take note of the comment about
#   Lucent Venus and always use the two-stage enable-then-clear as
#   we do on startup.
# 
# drivers/serial/8250.c
#   2004/08/28 23:32:32+01:00 rmk@flint.arm.linux.org.uk +16 -14
#   Move "clear fifo" into separate function dependent on
#   UART_CLEAR_FIFO capability.  We take note of the comment about
#   Lucent Venus and always use the two-stage enable-then-clear as
#   we do on startup.
# 
# ChangeSet
#   2004/08/23 14:44:29-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-serial
# 
# drivers/serial/8250_pci.c
#   2004/08/23 14:44:24-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/06 15:59:49-07:00 akpm@bix.(none) 
#   Merge bk://bk.arm.linux.org.uk/linux-2.6-serial
#   into bix.(none):/usr/src/bk-serial
# 
# drivers/serial/8250_pci.c
#   2004/08/06 15:59:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/04 23:00:03-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-serial
# 
# drivers/serial/8250_pnp.c
#   2004/07/04 22:59:59-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/serial/8250_pci.c
#   2004/07/04 22:59:59-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/01 14:28:30-07:00 akpm@bix.(none) 
#   Merge bk://bk.arm.linux.org.uk/linux-2.6-serial
#   into bix.(none):/usr/src/bk-serial
# 
# drivers/serial/8250_pnp.c
#   2004/07/01 14:28:27-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/serial/8250_pci.c
#   2004/07/01 14:28:27-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c
--- a/drivers/serial/8250.c	2004-08-30 17:55:32 -07:00
+++ b/drivers/serial/8250.c	2004-08-30 17:55:32 -07:00
@@ -130,6 +130,7 @@
 	struct timer_list	timer;		/* "no irq" timer */
 	struct list_head	list;		/* ports on this IRQ */
 	unsigned int		capabilities;	/* port capabilities */
+	unsigned int		tx_loadsz;	/* transmit fifo load size */
 	unsigned short		rev;
 	unsigned char		acr;
 	unsigned char		ier;
@@ -156,23 +157,23 @@
 /*
  * Here we define the default xmit fifo size used for each type of UART.
  */
-static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
-	{ "unknown",	1,	0 },
-	{ "8250",	1,	0 },
-	{ "16450",	1,	0 },
-	{ "16550",	1,	0 },
-	{ "16550A",	16,	UART_CLEAR_FIFO | UART_USE_FIFO },
-	{ "Cirrus",	1, 	0 },
-	{ "ST16650",	1,	UART_CLEAR_FIFO | UART_STARTECH },
-	{ "ST16650V2",	32,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-	{ "TI16750",	64,	UART_CLEAR_FIFO | UART_USE_FIFO },
-	{ "Startech",	1,	0 },
-	{ "16C950/954",	128,	UART_CLEAR_FIFO | UART_USE_FIFO },
-	{ "ST16654",	64,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-	{ "XR16850",	128,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-	{ "RSA",	2048,	UART_CLEAR_FIFO | UART_USE_FIFO },
-	{ "NS16550A",	16,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI },
-	{ "XScale",	32,	UART_CLEAR_FIFO | UART_USE_FIFO  },
+static const struct serial8250_config uart_config[PORT_MAX_8250+1] = {
+	{ "unknown",	1,	1,	0 },
+	{ "8250",	1,	1,	0 },
+	{ "16450",	1,	1,	0 },
+	{ "16550",	1,	1,	0 },
+	{ "16550A",	16,	16,	UART_CAP_FIFO },
+	{ "Cirrus",	1, 	1,	0 },
+	{ "ST16650",	1,	1,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+	{ "ST16650V2",	32,	16,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+	{ "TI16750",	64,	64,	UART_CAP_FIFO | UART_CAP_SLEEP },
+	{ "Startech",	1,	1,	0 },
+	{ "16C950/954",	128,	128,	UART_CAP_FIFO },
+	{ "ST16654",	64,	32,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+	{ "XR16850",	128,	128,	UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+	{ "RSA",	2048,	2048,	UART_CAP_FIFO },
+	{ "NS16550A",	16,	16,	UART_CAP_FIFO | UART_NATSEMI },
+	{ "XScale",	32,	32,	UART_CAP_FIFO },
 };
 
 static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
@@ -243,6 +244,41 @@
 	return value;
 }
 
+/*
+ * FIFO support.
+ */
+static inline void serial8250_clear_fifos(struct uart_8250_port *p)
+{
+	if (p->capabilities & UART_CAP_FIFO) {
+		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO |
+			       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+		serial_outp(p, UART_FCR, 0);
+	}
+}
+
+/*
+ * IER sleep support.  UARTs which have EFRs need the "extended
+ * capability" bit enabled.  Note that on XR16C850s, we need to
+ * reset LCR to write to IER.
+ */
+static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+{
+	if (p->capabilities & UART_CAP_SLEEP) {
+		if (p->capabilities & UART_CAP_EFR) {
+			serial_outp(p, UART_LCR, 0xBF);
+			serial_outp(p, UART_EFR, UART_EFR_ECB);
+			serial_outp(p, UART_LCR, 0);
+		}
+		serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
+		if (p->capabilities & UART_CAP_EFR) {
+			serial_outp(p, UART_LCR, 0xBF);
+			serial_outp(p, UART_EFR, 0);
+			serial_outp(p, UART_LCR, 0);
+		}
+	}
+}
+
 #ifdef CONFIG_SERIAL_8250_RSA
 /*
  * Attempts to turn on the RSA FIFO.  Returns zero on failure.
@@ -697,8 +733,9 @@
 #endif
 	serial_outp(up, UART_LCR, save_lcr);
 
-	up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+	up->port.fifosize = uart_config[up->port.type].fifo_size;
 	up->capabilities = uart_config[up->port.type].flags;
+	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
 
 	if (up->port.type == PORT_UNKNOWN)
 		goto out;
@@ -711,10 +748,7 @@
 		serial_outp(up, UART_RSA_FRR, 0);
 #endif
 	serial_outp(up, UART_MCR, save_mcr);
-	serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
-				     UART_FCR_CLEAR_RCVR |
-				     UART_FCR_CLEAR_XMIT));
-	serial_outp(up, UART_FCR, 0);
+	serial8250_clear_fifos(up);
 	(void)serial_in(up, UART_RX);
 	serial_outp(up, UART_IER, 0);
 
@@ -923,7 +957,7 @@
 		return;
 	}
 
-	count = up->port.fifosize;
+	count = up->tx_loadsz;
 	do {
 		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -1227,12 +1261,7 @@
 	 * Clear the FIFO buffers and disable them.
 	 * (they will be reeanbled in set_termios())
 	 */
-	if (up->capabilities & UART_CLEAR_FIFO) {
-		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
-		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-				UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-		serial_outp(up, UART_FCR, 0);
-	}
+	serial8250_clear_fifos(up);
 
 	/*
 	 * Clear the interrupt registers.
@@ -1254,6 +1283,23 @@
 	}
 
 	/*
+	 * For a XR16C850, we need to set the trigger levels
+	 */
+	if (up->port.type == PORT_16850) {
+		unsigned char fctr;
+
+		serial_outp(up, UART_LCR, 0xbf);
+
+		fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
+		serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX);
+		serial_outp(up, UART_TRG, UART_TRG_96);
+		serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX);
+		serial_outp(up, UART_TRG, UART_TRG_96);
+
+		serial_outp(up, UART_LCR, 0);
+	}
+
+	/*
 	 * If the "interrupt" for this port doesn't correspond with any
 	 * hardware interrupt, we use a timer-based system.  The original
 	 * driver used to do this with IRQ0.
@@ -1345,10 +1391,7 @@
 	 * Disable break condition and FIFOs
 	 */
 	serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
-	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
-				  UART_FCR_CLEAR_RCVR |
-				  UART_FCR_CLEAR_XMIT);
-	serial_outp(up, UART_FCR, 0);
+	serial8250_clear_fifos(up);
 
 #ifdef CONFIG_SERIAL_8250_RSA
 	/*
@@ -1440,7 +1483,7 @@
 	    up->rev == 0x5201)
 		quot ++;
 
-	if (up->capabilities & UART_USE_FIFO) {
+	if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
 		if (baud < 2400)
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
 #ifdef CONFIG_SERIAL_8250_RSA
@@ -1514,7 +1557,7 @@
 
 	serial_out(up, UART_IER, up->ier);
 
-	if (up->capabilities & UART_STARTECH) {
+	if (up->capabilities & UART_CAP_EFR) {
 		serial_outp(up, UART_LCR, 0xBF);
 		serial_outp(up, UART_EFR,
 			    termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
@@ -1554,71 +1597,12 @@
 serial8250_pm(struct uart_port *port, unsigned int state,
 	      unsigned int oldstate)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
-	if (state) {
-		/* sleep */
-		if (up->capabilities & UART_STARTECH) {
-			/* Arrange to enter sleep mode */
-			serial_outp(up, UART_LCR, 0xBF);
-			serial_outp(up, UART_EFR, UART_EFR_ECB);
-			serial_outp(up, UART_LCR, 0);
-			serial_outp(up, UART_IER, UART_IERX_SLEEP);
-			serial_outp(up, UART_LCR, 0xBF);
-			serial_outp(up, UART_EFR, 0);
-			serial_outp(up, UART_LCR, 0);
-		}
-		if (up->port.type == PORT_16750) {
-			/* Arrange to enter sleep mode */
-			serial_outp(up, UART_IER, UART_IERX_SLEEP);
-		}
-
-		if (up->pm)
-			up->pm(port, state, oldstate);
-	} else {
-		/* wake */
-		if (up->capabilities & UART_STARTECH) {
-			/* Wake up UART */
-			serial_outp(up, UART_LCR, 0xBF);
-			serial_outp(up, UART_EFR, UART_EFR_ECB);
-			/*
-			 * Turn off LCR == 0xBF so we actually set the IER
-			 * register on the XR16C850
-			 */
-			serial_outp(up, UART_LCR, 0);
-			serial_outp(up, UART_IER, 0);
-			/*
-			 * Now reset LCR so we can turn off the ECB bit
-			 */
-			serial_outp(up, UART_LCR, 0xBF);
-			serial_outp(up, UART_EFR, 0);
-			/*
-			 * For a XR16C850, we need to set the trigger levels
-			 */
-			if (up->port.type == PORT_16850) {
-				unsigned char fctr;
+	struct uart_8250_port *p = (struct uart_8250_port *)port;
 
-				fctr = serial_inp(up, UART_FCTR) &
-					 ~(UART_FCTR_RX | UART_FCTR_TX);
-				serial_outp(up, UART_FCTR, fctr |
-						UART_FCTR_TRGD |
-						UART_FCTR_RX);
-				serial_outp(up, UART_TRG, UART_TRG_96);
-				serial_outp(up, UART_FCTR, fctr |
-						UART_FCTR_TRGD |
-						UART_FCTR_TX);
-				serial_outp(up, UART_TRG, UART_TRG_96);
-			}
-			serial_outp(up, UART_LCR, 0);
-		}
+	serial8250_set_sleep(p, state != 0);
 
-		if (up->port.type == PORT_16750) {
-			/* Wake up UART */
-			serial_outp(up, UART_IER, 0);
-		}
-
-		if (up->pm)
-			up->pm(port, state, oldstate);
-	}
+	if (p->pm)
+		p->pm(port, state, oldstate);
 }
 
 /*
diff -Nru a/drivers/serial/8250.h b/drivers/serial/8250.h
--- a/drivers/serial/8250.h	2004-08-30 17:55:32 -07:00
+++ b/drivers/serial/8250.h	2004-08-30 17:55:32 -07:00
@@ -33,6 +33,20 @@
 	unsigned short iomem_reg_shift;
 };
 
+/*
+ * This replaces serial_uart_config in include/linux/serial.h
+ */
+struct serial8250_config {
+	const char	*name;
+	unsigned int	fifo_size;
+	unsigned int	tx_loadsz;
+	unsigned int	flags;
+};
+
+#define UART_CAP_FIFO	(1 << 8)	/* UART has FIFO */
+#define UART_CAP_EFR	(1 << 9)	/* UART has EFR */
+#define UART_CAP_SLEEP	(1 << 10)	/* UART has IER sleep */
+
 #undef SERIAL_DEBUG_PCI
 
 #if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
