aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/8250
diff options
context:
space:
mode:
authorAlexey Brodkin <Alexey.Brodkin@synopsys.com>2012-10-03 16:27:43 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-24 11:29:30 -0700
commitb15d5380e471f9ce27180b14d5080abc2e2f30ec (patch)
tree5f946f9f9d0beea0e63fe304513215fd2da9ab31 /drivers/tty/serial/8250
parent9484b009b57b6523a5c7477a899f4438942febde (diff)
downloadkernel_goldelico_gta04-b15d5380e471f9ce27180b14d5080abc2e2f30ec.zip
kernel_goldelico_gta04-b15d5380e471f9ce27180b14d5080abc2e2f30ec.tar.gz
kernel_goldelico_gta04-b15d5380e471f9ce27180b14d5080abc2e2f30ec.tar.bz2
serial/8250/8250_early: Prevent rounding error in uartclk
Modify divisor to select the nearest baud rate divider rather than the lowest. It minimizes baud rate errors especially on low UART clock frequencies. For example, if uartclk is 33000000 and baud is 115200 the ratio is about 17.9 The current code selects 17 (5% error) but should select 18 (0.5% error). This 5% error in baud rate leads to garbage on receiving end, while 0.5% doesn't. The issue showed up when using the stock 8250 driver for Synopsys DW UART. This was on a FPGA with ~12MHz UART clock. When we enabled early serial, we saw garbage which was narrowed down to the rounding error. So the bug had been latent and it only showed up with such low clock rates. Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index eaafb98..843a150 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -140,7 +140,7 @@ static void __init init_port(struct early_serial8250_device *device)
serial_out(port, UART_FCR, 0); /* no fifo */
serial_out(port, UART_MCR, 0x3); /* DTR + RTS */
- divisor = port->uartclk / (16 * device->baud);
+ divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
c = serial_in(port, UART_LCR);
serial_out(port, UART_LCR, c | UART_LCR_DLAB);
serial_out(port, UART_DLL, divisor & 0xff);