diff mbox series

[05/27] clk: sunxi-ng: Use u64 for calculation of NM rate

Message ID 20180902072643.4917-6-jernej.skrabec@siol.net (mailing list archive)
State New, archived
Headers show
Series Allwinner H6 DE3 and HDMI support | expand

Commit Message

Jernej Škrabec Sept. 2, 2018, 7:26 a.m. UTC
Allwinner H6 SoC has multiplier N range between 1 and 254. Since parent
rate is 24MHz, intermediate result when calculating final rate easily
overflows 32 bit variable.

Because of that, introduce function for calculating clock rate which
uses 64 bit variable for intermediate result.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/clk/sunxi-ng/ccu_nm.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

Comments

Chen-Yu Tsai Sept. 4, 2018, 9:18 a.m. UTC | #1
On Sun, Sep 2, 2018 at 3:27 PM Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> Allwinner H6 SoC has multiplier N range between 1 and 254. Since parent
> rate is 24MHz, intermediate result when calculating final rate easily
> overflows 32 bit variable.
>
> Because of that, introduce function for calculating clock rate which
> uses 64 bit variable for intermediate result.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

The code looks good. The A80's Video PLLs are also affected by this.
The range for N on the A80 is 12 ~ 255.

Can you add fixes and stable tags?

ChenYu
Jernej Škrabec Sept. 4, 2018, 6:06 p.m. UTC | #2
Dne torek, 04. september 2018 ob 11:18:47 CEST je Chen-Yu Tsai napisal(a):
> On Sun, Sep 2, 2018 at 3:27 PM Jernej Skrabec <jernej.skrabec@siol.net> 
wrote:
> > Allwinner H6 SoC has multiplier N range between 1 and 254. Since parent
> > rate is 24MHz, intermediate result when calculating final rate easily
> > overflows 32 bit variable.
> > 
> > Because of that, introduce function for calculating clock rate which
> > uses 64 bit variable for intermediate result.
> > 
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> 
> The code looks good. The A80's Video PLLs are also affected by this.
> The range for N on the A80 is 12 ~ 255.
> 
> Can you add fixes and stable tags?

Sure.

> 
> ChenYu
diff mbox series

Patch

diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index 6fe3c14f7b2d..424d8635b053 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -19,6 +19,17 @@  struct _ccu_nm {
 	unsigned long	m, min_m, max_m;
 };
 
+static unsigned long ccu_nm_calc_rate(unsigned long parent,
+				      unsigned long n, unsigned long m)
+{
+	u64 rate = parent;
+
+	rate *= n;
+	do_div(rate, m);
+
+	return rate;
+}
+
 static void ccu_nm_find_best(unsigned long parent, unsigned long rate,
 			     struct _ccu_nm *nm)
 {
@@ -28,7 +39,8 @@  static void ccu_nm_find_best(unsigned long parent, unsigned long rate,
 
 	for (_n = nm->min_n; _n <= nm->max_n; _n++) {
 		for (_m = nm->min_m; _m <= nm->max_m; _m++) {
-			unsigned long tmp_rate = parent * _n  / _m;
+			unsigned long tmp_rate = ccu_nm_calc_rate(parent,
+								  _n, _m);
 
 			if (tmp_rate > rate)
 				continue;
@@ -100,7 +112,7 @@  static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
 	if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm))
 		rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n);
 	else
-		rate = parent_rate * n / m;
+		rate = ccu_nm_calc_rate(parent_rate, n, m);
 
 	if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
 		rate /= nm->fixed_post_div;
@@ -149,7 +161,7 @@  static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
 	_nm.max_m = nm->m.max ?: 1 << nm->m.width;
 
 	ccu_nm_find_best(*parent_rate, rate, &_nm);
-	rate = *parent_rate * _nm.n / _nm.m;
+	rate = ccu_nm_calc_rate(*parent_rate, _nm.n, _nm.m);
 
 	if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
 		rate /= nm->fixed_post_div;