Current code calculates the fractional component in 32 bits before
assigning it to a 64-bit holding variable, causing overflow for real-world
values of k, given that OSC_HZ is 24000000U. It also does bitwise manual
massaging of an unsigned representation of what is actually a two's
complement signed value, which is confusing and makes the code harder to
read.

Read k into a properly signed type and promote operands to avoid overflow,
which also enables the use of div_s64() to express the math more clearly.

Fixes: b851c006a150 ("clk: rockchip: pll: Add pll_rk3588 type for rk3588")
Signed-off-by: Alexey Charkov <[email protected]>
---
 drivers/clk/rockchip/clk_pll.c | 25 ++++---------------------
 1 file changed, 4 insertions(+), 21 deletions(-)

diff --git a/drivers/clk/rockchip/clk_pll.c b/drivers/clk/rockchip/clk_pll.c
index ebe90b55ea06..9d529242be31 100644
--- a/drivers/clk/rockchip/clk_pll.c
+++ b/drivers/clk/rockchip/clk_pll.c
@@ -559,9 +559,10 @@ static int rk3588_pll_set_rate(struct rockchip_pll_clock 
*pll,
 static ulong rk3588_pll_get_rate(struct rockchip_pll_clock *pll,
                                 void __iomem *base, ulong pll_id)
 {
-       u32 m, p, s, k;
+       u32 m, p, s;
        u32 con = 0, shift, mode;
-       u64 rate, postdiv;
+       u64 rate;
+       s16 k;
 
        con = readl(base + pll->mode_offset);
        shift = pll->mode_shift;
@@ -588,25 +589,7 @@ static ulong rk3588_pll_get_rate(struct rockchip_pll_clock 
*pll,
 
                rate = OSC_HZ / p;
                rate *= m;
-               if (k & BIT(15)) {
-                       /* fractional mode */
-                       u64 frac_rate64;
-
-                       k = (~(k - 1)) & RK3588_PLLCON2_K_MASK;
-                       frac_rate64 = OSC_HZ * k;
-                       postdiv = p;
-                       postdiv *= 65536;
-                       do_div(frac_rate64, postdiv);
-                       rate -= frac_rate64;
-               } else {
-                       /* fractional mode */
-                       u64 frac_rate64 = OSC_HZ * k;
-
-                       postdiv = p;
-                       postdiv *= 65536;
-                       do_div(frac_rate64, postdiv);
-                       rate += frac_rate64;
-               }
+               rate += div_s64((s64)OSC_HZ * k, p * 65536);
                rate = rate >> s;
                return rate;
        case RKCLK_PLL_MODE_DEEP:

-- 
2.53.0

Reply via email to