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