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
@@ -1653,6 +1653,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 =
@@ -1669,7 +1686,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 |
@@ -2324,7 +2341,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;
@@ -2509,6 +2526,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;
@@ -2540,6 +2558,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)
