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>
This commit is contained in:
Phil Elwell
2017-03-01 16:07:39 +00:00
committed by Dom Cobley
parent c2fa32a8da
commit 947ba6e85e

View File

@@ -1725,6 +1725,23 @@ static void pl011_put_poll_char(struct uart_port *port,
#endif /* CONFIG_CONSOLE_POLL */ #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) static int pl011_hwinit(struct uart_port *port)
{ {
struct uart_amba_port *uap = struct uart_amba_port *uap =
@@ -1741,7 +1758,7 @@ static int pl011_hwinit(struct uart_port *port)
if (retval) if (retval)
return 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 */ /* Clear pending error and receive interrupts */
pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS | pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
@@ -2432,7 +2449,7 @@ static int pl011_console_setup(struct console *co, char *options)
plat->init(); 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) { if (uap->vendor->fixed_options) {
baud = uap->fixed_baud; baud = uap->fixed_baud;
@@ -2649,6 +2666,7 @@ static struct uart_driver amba_reg = {
.cons = AMBA_CONSOLE, .cons = AMBA_CONSOLE,
}; };
#if 0
static int pl011_probe_dt_alias(int index, struct device *dev) static int pl011_probe_dt_alias(int index, struct device *dev)
{ {
struct device_node *np; struct device_node *np;
@@ -2680,6 +2698,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
return ret; return ret;
} }
#endif
/* unregisters the driver also if no more ports are left */ /* unregisters the driver also if no more ports are left */
static void pl011_unregister_port(struct uart_amba_port *uap) static void pl011_unregister_port(struct uart_amba_port *uap)