[PATCH v3] serial: pl011: handle corruption at high clock speeds

Linus Walleij linus.walleij at stericsson.com
Wed Sep 26 11:21:36 EDT 2012

From: Linus Walleij <linus.walleij at linaro.org>

This works around a few glitches in the ST version of the PL011
serial driver when using very high baud rates, as we do in the
Ux500: 3, 3.25, 4 and 4.05 Mbps.

Problem Observed/rootcause:

When using high baud-rates, and the baudrate*8 is getting close to
the provided clock frequency (so a division factor close to 1), when
using bursts of characters (so they are abutted), then it seems as if
there is not enough time to detect the beginning of the start-bit which
is a timing reference for the entire character, and thus the sampling
moment of character bits is moving towards the end of each bit, instead
of the middle.

Increase slightly the RX baud rate of the UART above the theoretical
baudrate by 5%. This will definitely give more margin time to the
UART_RX to correctly sample the data at the middle of the bit period.

Also fix the ages old copy-paste error in the very stressed comment,
it's referencing the registers used in the PL010 driver rather than
the PL011 ones.

Cc: stable at kernel.org
Cc: Bibek Basu <bibek.basu at stericsson.com>
Cc: Par-Gunnar Hjalmdahl <par-gunnar.hjalmdahl at stericsson.com>
Signed-off-by: Guillaume Jaunet <guillaume.jaunet at stericsson.com>
Signed-off-by: Christophe Arnal <christophe.arnal at stericsson.com>
Signed-off-by: Matthias Locher <matthias.locher at stericsson.com>
Signed-off-by: Rajanikanth HV <rajanikanth.hv at stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij at linaro.org>
ChangeLog v2->v3:
- Actually commit the v2 changes...
ChangeLog v1->v2:
- Use >= comparison for 3 Mbaud, add some parenthesis to make the
  logical expressions crystal clear.
 drivers/tty/serial/amba-pl011.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d626d84..25508c7 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1594,13 +1594,26 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 			old_cr &= ~ST_UART011_CR_OVSFACT;
+	/*
+	 * Workaround for the ST Micro oversampling variants to
+	 * increase the bitrate slightly, by lowering the divisor,
+	 * to avoid delayed sampling of start bit at high speeds,
+	 * else we see data corruption.
+	 */
+	if (uap->vendor->oversampling) {
+		if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
+			quot -= 1;
+		else if ((baud > 3250000) && (quot > 2))
+			quot -= 2;
+	}
 	/* Set baud rate */
 	writew(quot & 0x3f, port->membase + UART011_FBRD);
 	writew(quot >> 6, port->membase + UART011_IBRD);
 	 * ----------v----------v----------v----------v-----
+	 * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER
+	 * UART011_FBRD & UART011_IBRD.
 	 * ----------^----------^----------^----------^-----
 	writew(lcr_h, port->membase + uap->lcrh_rx);

More information about the linux-arm-kernel mailing list