| From 409f4b56de7611d703790c54a70fad9a6e2bb161 Mon Sep 17 00:00:00 2001 |
| From: Phil Elwell <phil@raspberrypi.org> |
| 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 <phil@raspberrypi.org> |
| --- |
| drivers/tty/serial/amba-pl011.c | 23 +++++++++++++++++++++-- |
| 1 file changed, 21 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/tty/serial/amba-pl011.c |
| +++ b/drivers/tty/serial/amba-pl011.c |
| @@ -1665,6 +1665,23 @@ static void pl011_put_poll_char(struct u |
| |
| #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 = |
| @@ -1681,7 +1698,7 @@ static int pl011_hwinit(struct uart_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 | |
| @@ -2334,7 +2351,7 @@ static int pl011_console_setup(struct co |
| 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; |
| @@ -2519,6 +2536,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; |
| @@ -2550,6 +2568,7 @@ static int pl011_probe_dt_alias(int inde |
| |
| return ret; |
| } |
| +#endif |
| |
| /* unregisters the driver also if no more ports are left */ |
| static void pl011_unregister_port(struct uart_amba_port *uap) |