Re: [PATCH v4] clk: bcm2835: Round UART input clock up

From: Stefan Wahren
Date: Sun Sep 04 2022 - 09:50:06 EST


Hi Ivan,

Am 29.08.22 um 15:29 schrieb Ivan T. Ivanov:
It was reported that RPi3[1] and RPi Zero 2W boards have issues with
the Bluetooth. It turns out that when switching from initial to
operation speed host and device no longer can talk each other because
host uses incorrect UART baud rate.

The UART driver used in this case is amba-pl011. Original fix, see
below Github link[2], was inside pl011 module, but somehow it didn't
look as the right place to fix. Beside that this original rounding
function is not exactly perfect for all possible clock values. So I
deiced to move the hack to the platform which actually need it.

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 baud rate
== requested clock/16, there is no headroom and the slight
reduction in actual clock rate results in failure.

If increasing a clock by less than 0.1% changes it from ..999..
to ..000.., round it up.

[1] https://bugzilla.suse.com/show_bug.cgi?id=1188238
[2] https://github.com/raspberrypi/linux/commit/ab3f1b39537f6d3825b8873006fbe2fc5ff057b7

Cc: Phil Elwell <phil@xxxxxxxxxxxxxxx>
Signed-off-by: Ivan T. Ivanov <iivanov@xxxxxxx>
---

Changes since v3
* Rework 'scaler' calculation to avoid overflow
* Update Phil Elwell email address

Changes since v2
* Added more information in commit message
* Changed hand crafted round function with the one form math.h

Changes since v1
Make bcm2835_clock_round() static to fix following warning
when compiling for riscv:
drivers/clk/bcm/clk-bcm2835.c:997:15: warning: no previous prototype for 'bcm2835_clock_round' [-Wmissing-prototypes]
Reported-by: kernel test robot <lkp@xxxxxxxxx>

drivers/clk/bcm/clk-bcm2835.c | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 48a1eb9f2d55..26a5c9a0dd34 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -30,6 +30,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -502,6 +503,8 @@ struct bcm2835_clock_data {
bool low_jitter;
u32 tcnt_mux;
+
+ bool round_up;
};
struct bcm2835_gate_data {
@@ -993,12 +996,34 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
return temp;
}
+static unsigned long bcm2835_clock_round(unsigned long clk)
sorry, i missed this in my last mail. Please use "rate" instead of "clk" here.
+{
+ unsigned long scaler;
+ unsigned long limit;;
+
+ limit = clk / 100000;
+
+ scaler = 1;
+ while (scaler < limit)
+ scaler *= 10;
+
+ /*
+ * If increasing a clock by less than 0.1% changes it
+ * from ..999.. to ..000.., round up.
+ */
+ if ((clk + scaler - 1) / scaler % 1000 == 0)
+ clk = roundup(clk, scaler);
+
+ return clk;
+}
+