[PATCH] RFC: serial: pl011: allow very high baudrates

Subsystems: arm primecell uart pl010 and pl011 drivers, the rest, tty layer and serial drivers

STALE5058d

2 messages, 2 authors, 2012-09-26 · open the first message on its own page

[PATCH] RFC: serial: pl011: allow very high baudrates

From: Linus Walleij <hidden>
Date: 2012-09-21 17:59:59

From: Linus Walleij <redacted>

The ST Microelectronics variant of the PL011 is capable of supporting
very high non-standard baud rates, even above 4 Mbps. Mostly this
works, but when we try to use 4050000 baud, the code in
tty_termios_encode_baud_rate(), which is called from
uart_get_baud_rate() will do some fuzzy matching and "snap" the
baudrate to 4000000 baud, which happens to be in the baud_table[].

However there is an encouraging comment from Alan Cox above the
tty_termios_input_baud_rate() function stating that device
drivers should use ->c_[io]speed directly as they are updated.

I tried this, but that requires the driver to handle a few
odd cases such as when the ->c_ispeed and ->c_ospeed differs,
or when they are both send it as 0 (which happens a lot in
the kernel) so that would require pushing a lot of duplicate
code into the driver to get the same behaviour.

Here I take a middle-ground approach: if the baud rate of
->c_ispeed and ->c_ospeed differs, or if either of them is
zero, I still call the uart_get_baud_rate() function, but
root the baudrate to what the block can handle at max.

Cc: Par-Gunnar Hjalmdahl <redacted>
Signed-off-by: Guillaume Jaunet <redacted>
Signed-off-by: Christophe Arnal <redacted>
Signed-off-by: Matthias Locher <redacted>
Signed-off-by: Rajanikanth HV <redacted>
Signed-off-by: Linus Walleij <redacted>
---
After discussing with Alan and Russell I still don't feel this
is the right solution, but it demonstrates Russell's point of
how intelligence (here just some checking of ->c_[io]speed,
but you get the point) is moved out of the serial/tty core and
out into the drivers if we do this.

Maybe a new function is needed in the serial core, one that
will just call out to serial and tty like this if the c_[io]speed
differs or either is zero?
---
 drivers/tty/serial/amba-pl011.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index cb9f694..778a6a5 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1492,18 +1492,36 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
-	unsigned int baud, quot, clkdiv;
+	unsigned int max_baud, baud, quot;
 
 	if (uap->vendor->oversampling)
-		clkdiv = 8;
+		max_baud = port->uartclk / 8;
 	else
-		clkdiv = 16;
+		max_baud = port->uartclk / 16;
 
 	/*
-	 * Ask the core to calculate the divisor for us.
+	 * For "zero" speeds or in the case where in and output
+	 * speed differs, fall back on using the serial core to
+	 * determine applicable baudrate.
 	 */
-	baud = uart_get_baud_rate(port, termios, old, 0,
-				  port->uartclk / clkdiv);
+	if ((termios->c_ispeed != termios->c_ospeed) ||
+	    (termios->c_ispeed == 0) ||
+	    (termios->c_ospeed == 0))
+		baud = uart_get_baud_rate(port, termios, old, 0,
+					  max_baud);
+	else {
+		/*
+		 * Else we just use the requested speed from
+		 * termios. But we sanity check it so as not to
+		 * exceed hardware limits.
+		 */
+		baud = termios->c_ospeed;
+		if (baud > max_baud)
+			baud = max_baud;
+	}
+	dev_dbg(uap->port.dev, "c_ispeed: %u, c_ospeed: %u, "
+		"max_baud: %u, resulting baud rate %u bps\n",
+		termios->c_ispeed, termios->c_ospeed, max_baud, baud);
 
 	if (baud > port->uartclk/16)
 		quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
-- 
1.7.11.3

[PATCH] RFC: serial: pl011: allow very high baudrates

From: Linus Walleij <hidden>
Date: 2012-09-26 08:03:31

On Fri, Sep 21, 2012 at 7:59 PM, Linus Walleij
[off-list ref] wrote:
From: Linus Walleij <redacted>

The ST Microelectronics variant of the PL011 is capable of supporting
very high non-standard baud rates, even above 4 Mbps. Mostly this
works, but when we try to use 4050000 baud, the code in
tty_termios_encode_baud_rate(), which is called from
uart_get_baud_rate() will do some fuzzy matching and "snap" the
baudrate to 4000000 baud, which happens to be in the baud_table[].
So I've found the right solution to this problem, Greg ignore
this patch.

Yours,
Linus Walleij
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help