From ab3f1b39537f6d3825b8873006fbe2fc5ff057b7 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 1 Mar 2017 16:07:39 +0000 Subject: [PATCH] amba_pl011: Round input clock up The UART clock is initialised to be as close to the requested frequency as possible without exceeding it. Now that there is a clock manager that returns the actual frequencies, an expected 48MHz clock is reported as 47999625. If the requested baudrate == requested clock/16, there is no headroom and the slight reduction in actual clock rate results in failure. Detect cases where it looks like a "round" clock was chosen and adjust the reported clock to match that "round" value. As the code comment says: /* * If increasing a clock by less than 0.1% changes it * from ..999.. to ..000.., round up. */ Signed-off-by: Phil Elwell --- drivers/tty/serial/amba-pl011.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6f22939240025..0b84ee7397e76 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1720,6 +1720,23 @@ static void pl011_put_poll_char(struct uart_port *port, #endif /* CONFIG_CONSOLE_POLL */ +unsigned long pl011_clk_round(unsigned long clk) +{ + unsigned long scaler; + + /* + * If increasing a clock by less than 0.1% changes it + * from ..999.. to ..000.., round up. + */ + scaler = 1; + while (scaler * 100000 < clk) + scaler *= 10; + if ((clk + scaler - 1)/scaler % 1000 == 0) + clk = (clk/scaler + 1) * scaler; + + return clk; +} + static int pl011_hwinit(struct uart_port *port) { struct uart_amba_port *uap = @@ -1736,7 +1753,7 @@ static int pl011_hwinit(struct uart_port *port) if (retval) return retval; - uap->port.uartclk = clk_get_rate(uap->clk); + uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk)); /* Clear pending error and receive interrupts */ pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS | @@ -2429,7 +2446,7 @@ static int pl011_console_setup(struct console *co, char *options) plat->init(); } - uap->port.uartclk = clk_get_rate(uap->clk); + uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk)); if (uap->vendor->fixed_options) { baud = uap->fixed_baud; @@ -2646,6 +2663,7 @@ static struct uart_driver amba_reg = { .cons = AMBA_CONSOLE, }; +#if 0 static int pl011_probe_dt_alias(int index, struct device *dev) { struct device_node *np; @@ -2677,6 +2695,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev) return ret; } +#endif /* unregisters the driver also if no more ports are left */ static void pl011_unregister_port(struct uart_amba_port *uap)