* [PATCH] 8250.c: Fix to make 16C950 UARTs work
@ 2005-09-09 1:31 Mathias Adam
2005-09-09 1:58 ` Stefan Smietanowski
0 siblings, 1 reply; 6+ messages in thread
From: Mathias Adam @ 2005-09-09 1:31 UTC (permalink / raw)
To: linux-kernel; +Cc: rmk+serial
Currently serial8250_set_termios() refuses to program a baud rate larger
than uartclk/16. However the 16C950 supports baud rates up to uartclk/4.
This worked already with Linux 2.4 so the biggest part of this patch was
simply taken from there and adapted to 2.6.
I needed this to get a Socket Bluetooth CF Card to work with BlueZ under
2.6 (the card did work under 2.4 already).
I posted the patch a while ago on the BlueZ mailing list and got reports
that it works as it should for a number of people so one could consider
including it into the standard kernel - opinions?
Please CC me as I'm not subscribed to the list.
Mathias Adam
--- linux-2.6.13-org/drivers/serial/8250.c 2005-08-29 01:41:01.000000000 +0200
+++ linux-2.6.13/drivers/serial/8250.c 2005-09-09 02:16:49.000000000 +0200
@@ -1665,7 +1665,7 @@
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
unsigned long flags;
- unsigned int baud, quot;
+ unsigned int baud, quot, max_baud;
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -1697,9 +1697,28 @@
/*
* Ask the core to calculate the divisor for us.
*/
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ MAX_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16);
+ baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
quot = serial8250_get_divisor(port, baud);
+ /*
+ * 16C950 supports additional prescaler ratios between 1:16 and 1:4
+ * thus increasing max baud rate to uartclk/4. The following was taken
+ * from kernel 2.4 by Mathias Adam <a2@adamis.de> to make the Socket
+ * Bluetooth CF Card work under 2.6.13.
+ */
+ if (up->port.type == PORT_16C950) {
+ unsigned int baud_base = port->uartclk/16;
+ if (baud <= port->uartclk/16)
+ serial_icr_write(up, UART_TCR, 0);
+ else if (baud <= port->uartclk/8) {
+ serial_icr_write(up, UART_TCR, 0x8);
+ } else if (baud <= port->uartclk/4) {
+ serial_icr_write(up, UART_TCR, 0x4);
+ } else
+ serial_icr_write(up, UART_TCR, 0);
+ }
+
/*
* Oxford Semi 952 rev B workaround
*/
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH] 8250.c: Fix to make 16C950 UARTs work 2005-09-09 1:31 [PATCH] 8250.c: Fix to make 16C950 UARTs work Mathias Adam @ 2005-09-09 1:58 ` Stefan Smietanowski 2005-09-09 2:49 ` Mathias Adam 0 siblings, 1 reply; 6+ messages in thread From: Stefan Smietanowski @ 2005-09-09 1:58 UTC (permalink / raw) To: Mathias Adam; +Cc: linux-kernel, rmk+serial -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Mathias Adam wrote: > Currently serial8250_set_termios() refuses to program a baud rate larger > than uartclk/16. However the 16C950 supports baud rates up to uartclk/4. > This worked already with Linux 2.4 so the biggest part of this patch was > simply taken from there and adapted to 2.6. > - unsigned int baud, quot; > + unsigned int baud, quot, max_baud; ^^^^^^^^ > - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); > + MAX_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16); ^^^^^^^^ Did you even compile test this? // Stefan -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (MingW32) iD8DBQFDIOxFBrn2kJu9P78RAnG3AJ9EJKl6q4Q4+jXRdMifvmOEdO+HewCfUPd8 T2qQREDAgUq2C7j9yfaPemQ= =hGK0 -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] 8250.c: Fix to make 16C950 UARTs work 2005-09-09 1:58 ` Stefan Smietanowski @ 2005-09-09 2:49 ` Mathias Adam 2005-09-09 10:18 ` Russell King 0 siblings, 1 reply; 6+ messages in thread From: Mathias Adam @ 2005-09-09 2:49 UTC (permalink / raw) To: linux-kernel; +Cc: rmk+serial Stefan Smietanowski wrote: > Mathias Adam wrote: > > Currently serial8250_set_termios() refuses to program a baud rate larger > > than uartclk/16. However the 16C950 supports baud rates up to uartclk/4. > > This worked already with Linux 2.4 so the biggest part of this patch was > > simply taken from there and adapted to 2.6. > > - unsigned int baud, quot; > > + unsigned int baud, quot, max_baud; > ^^^^^^^^ > > - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); > > + MAX_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16); > ^^^^^^^^ > > Did you even compile test this? Oops, I really really wonder how THIS could have happened as I just attached my existing patch file (which was and still is correct) without touching it - at least that's what I thought... Sorry! Mathias Adam I hope everything's alright this time: --- linux-2.6.13-org/drivers/serial/8250.c 2005-08-29 01:41:01.000000000 +0200 +++ linux-2.6.13/drivers/serial/8250.c 2005-09-09 02:16:49.000000000 +0200 @@ -1665,7 +1665,7 @@ struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned char cval, fcr = 0; unsigned long flags; - unsigned int baud, quot; + unsigned int baud, quot, max_baud; switch (termios->c_cflag & CSIZE) { case CS5: @@ -1697,9 +1697,28 @@ /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + max_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, max_baud); quot = serial8250_get_divisor(port, baud); + /* + * 16C950 supports additional prescaler ratios between 1:16 and 1:4 + * thus increasing max baud rate to uartclk/4. The following was taken + * from kernel 2.4 by Mathias Adam <a2@adamis.de> to make the Socket + * Bluetooth CF Card work under 2.6.13. + */ + if (up->port.type == PORT_16C950) { + unsigned int baud_base = port->uartclk/16; + if (baud <= port->uartclk/16) + serial_icr_write(up, UART_TCR, 0); + else if (baud <= port->uartclk/8) { + serial_icr_write(up, UART_TCR, 0x8); + } else if (baud <= port->uartclk/4) { + serial_icr_write(up, UART_TCR, 0x4); + } else + serial_icr_write(up, UART_TCR, 0); + } + /* * Oxford Semi 952 rev B workaround */ ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] 8250.c: Fix to make 16C950 UARTs work 2005-09-09 2:49 ` Mathias Adam @ 2005-09-09 10:18 ` Russell King 2005-09-09 14:42 ` Mathias Adam 2005-09-16 12:11 ` Mathias Adam 0 siblings, 2 replies; 6+ messages in thread From: Russell King @ 2005-09-09 10:18 UTC (permalink / raw) To: Mathias Adam; +Cc: linux-kernel A couple of comments - see below. On Fri, Sep 09, 2005 at 04:49:27AM +0200, Mathias Adam wrote: > --- linux-2.6.13-org/drivers/serial/8250.c 2005-08-29 01:41:01.000000000 +0200 > +++ linux-2.6.13/drivers/serial/8250.c 2005-09-09 02:16:49.000000000 +0200 > @@ -1665,7 +1665,7 @@ > struct uart_8250_port *up = (struct uart_8250_port *)port; > unsigned char cval, fcr = 0; > unsigned long flags; > - unsigned int baud, quot; > + unsigned int baud, quot, max_baud; > > switch (termios->c_cflag & CSIZE) { > case CS5: > @@ -1697,9 +1697,28 @@ > /* > * Ask the core to calculate the divisor for us. > */ > - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); > + max_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16); > + baud = uart_get_baud_rate(port, termios, old, 0, max_baud); > quot = serial8250_get_divisor(port, baud); > > + /* > + * 16C950 supports additional prescaler ratios between 1:16 and 1:4 > + * thus increasing max baud rate to uartclk/4. The following was taken > + * from kernel 2.4 by Mathias Adam <a2@adamis.de> to make the Socket > + * Bluetooth CF Card work under 2.6.13. > + */ > + if (up->port.type == PORT_16C950) { > + unsigned int baud_base = port->uartclk/16; baud_base appears unused. > + if (baud <= port->uartclk/16) > + serial_icr_write(up, UART_TCR, 0); > + else if (baud <= port->uartclk/8) { > + serial_icr_write(up, UART_TCR, 0x8); > + } else if (baud <= port->uartclk/4) { > + serial_icr_write(up, UART_TCR, 0x4); > + } else > + serial_icr_write(up, UART_TCR, 0); baud can't be larger than port->uartclk/4 since you limited it above. > + } > + > /* > * Oxford Semi 952 rev B workaround > */ -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: 2.6 Serial core ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] 8250.c: Fix to make 16C950 UARTs work 2005-09-09 10:18 ` Russell King @ 2005-09-09 14:42 ` Mathias Adam 2005-09-16 12:11 ` Mathias Adam 1 sibling, 0 replies; 6+ messages in thread From: Mathias Adam @ 2005-09-09 14:42 UTC (permalink / raw) To: linux-kernel; +Cc: rmk+serial Russell King wrote: > On Fri, Sep 09, 2005 at 04:49:27AM +0200, Mathias Adam wrote: > > + if (up->port.type == PORT_16C950) { > > + unsigned int baud_base = port->uartclk/16; > > baud_base appears unused. you're right, it's not necessary anymore. (New patch below) > > + if (baud <= port->uartclk/16) > > + serial_icr_write(up, UART_TCR, 0); > > + else if (baud <= port->uartclk/8) { > > + serial_icr_write(up, UART_TCR, 0x8); > > + } else if (baud <= port->uartclk/4) { > > + serial_icr_write(up, UART_TCR, 0x4); > > + } else > > + serial_icr_write(up, UART_TCR, 0); > > baud can't be larger than port->uartclk/4 since you limited it above. Those lines come from 2.4.29's drivers/char/serial.c (>= line 1686). I left in the last "else" to have some fallback if uart_get_baud_rate() would change its behaviour to something else (i.e. does allow baud to be larger than max_baud). However this would lead to an incorrect baud rate to be set anyway (as the maximum baud rate of 16C950 is uartclk/4), so one could simply set the "/4" mode for everything larger than uartclk/8. Btw, if you look at lines 1700-1701 of original 2.6.13's 8250.c: baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = serial8250_get_divisor(port, baud); baud is limited to uartclk/16 here, but serial8250_get_divisor() tests it for being uartclk/4 or uartclk/8... I'm afraid that max_baud thing has to become somewhat more general, or do I miss something? Hmm and I don't get the point in the calculation of "quot" - is that formula correct in every case? I'll look into that a little bit now. Mathias Adam PS: I'm now subscribed to the list. --- linux-2.6.13-org/drivers/serial/8250.c 2005-08-29 01:41:01.000000000 +0200 +++ linux-2.6.13/drivers/serial/8250.c 2005-09-09 15:33:23.000000000 +0200 @@ -1665,7 +1665,7 @@ struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned char cval, fcr = 0; unsigned long flags; - unsigned int baud, quot; + unsigned int baud, quot, max_baud; switch (termios->c_cflag & CSIZE) { case CS5: @@ -1697,9 +1697,25 @@ /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + max_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, max_baud); quot = serial8250_get_divisor(port, baud); + /* + * 16C950 supports additional prescaler ratios between 1:16 and 1:4 + * thus increasing max baud rate to uartclk/4. The following was taken + * from kernel 2.4 by Mathias Adam <a2@adamis.de> to make the Socket + * Bluetooth CF Card work under 2.6.13. + */ + if (up->port.type == PORT_16C950) { + if (baud <= port->uartclk/16) + serial_icr_write(up, UART_TCR, 0); + else if (baud <= port->uartclk/8) { + serial_icr_write(up, UART_TCR, 0x8); + } else + serial_icr_write(up, UART_TCR, 0x4); + } + /* * Oxford Semi 952 rev B workaround */ ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] 8250.c: Fix to make 16C950 UARTs work 2005-09-09 10:18 ` Russell King 2005-09-09 14:42 ` Mathias Adam @ 2005-09-16 12:11 ` Mathias Adam 1 sibling, 0 replies; 6+ messages in thread From: Mathias Adam @ 2005-09-16 12:11 UTC (permalink / raw) To: Russell King; +Cc: linux-kernel I've reworked the patch a little. Now it should enable both the 230400 and the 460800 baud rates on any serial port which is using a 16C95x UART. However as my 16C950 device is part of a Bluetooth dongle I couldn't test the 460800 baud rate myself (I am able to set this rate with stty though). Please, could someone who owns such a UART try this out? Any other comments? Regards Mathias --- linux-2.6.13-org/drivers/serial/8250.c 2005-08-29 01:41:01.000000000 +0200 +++ linux-2.6.13/drivers/serial/8250.c 2005-09-16 12:18:14.000000000 +0200 @@ -7,6 +7,9 @@ * * Copyright (C) 2001 Russell King. * + * 2005/09/16: Enabled higher baud rates for 16C95x. + * (Mathias Adam <a2@adamis.de>) + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -1652,6 +1655,14 @@ else if ((port->flags & UPF_MAGIC_MULTIPLIER) && baud == (port->uartclk/8)) quot = 0x8002; + /* + * For 16C950s UART_TCR is used in combination with divisor==1 + * to achieve baud rates up to baud_base*4. + */ + else if ((port->type == PORT_16C950) && + baud > (port->uartclk/16)) + quot = 1; + else quot = uart_get_divisor(port, baud); @@ -1665,7 +1676,7 @@ struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned char cval, fcr = 0; unsigned long flags; - unsigned int baud, quot; + unsigned int baud, quot, max_baud; switch (termios->c_cflag & CSIZE) { case CS5: @@ -1697,7 +1708,8 @@ /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + max_baud = (up->port.type == PORT_16C950 ? port->uartclk/4 : port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, max_baud); quot = serial8250_get_divisor(port, baud); /* @@ -1733,6 +1745,19 @@ */ spin_lock_irqsave(&up->port.lock, flags); + /* + * 16C950 supports additional prescaler ratios between 1:16 and 1:4 + * thus increasing max baud rate to uartclk/4. + */ + if (up->port.type == PORT_16C950) { + if (baud == port->uartclk/4) + serial_icr_write(up, UART_TCR, 0x4); + else if (baud == port->uartclk/8) + serial_icr_write(up, UART_TCR, 0x8); + else + serial_icr_write(up, UART_TCR, 0); + } + /* * Update the per-port timeout. */ ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2005-09-16 12:10 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-09-09 1:31 [PATCH] 8250.c: Fix to make 16C950 UARTs work Mathias Adam 2005-09-09 1:58 ` Stefan Smietanowski 2005-09-09 2:49 ` Mathias Adam 2005-09-09 10:18 ` Russell King 2005-09-09 14:42 ` Mathias Adam 2005-09-16 12:11 ` Mathias Adam
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox