[PATCH] clk: rockchip: Fractional PLL coefficient on RK3588/RK3576 is two's complement
From: Alexey Charkov <hidden>
Date: 2026-07-21 19:17:51
Also in:
linux-clk, linux-rockchip, lkml
Subsystem:
arm/rockchip soc support, common clk framework, the rest · Maintainers:
Heiko Stuebner, Michael Turquette, Stephen Boyd, Linus Torvalds
When the PLL rates table was first committed for RK3588 (and later reused for RK3576), the fractional PLL coefficient was defined as an unsigned value, while the TRM clearly states that it is a two's complement 16-bit value. Rockchip's downstream kernel later revised the fractional PLL code [1] to account for the two's complement nature of the coefficient, but that change wasn't upstreamed. Change the PLL table definition to use two's complement for the fractional coefficient and update its users accordingly. Note that a negative fractional coefficient is meant to be subtracted from the next larger integer multiplier, so the _m values in the table are also adjusted accordingly for the two negative-k entries. While at it, fix the denominator of the fractional PLL calculation to use 65536 instead of 65535, as per the TRM (RK3576 TRM Part 1 V1.2, Section 2.13.1.4 Setting Guide on P, M, S, and K): Fout = ((m + k/65536) * Fin) / (p * 2^s) Link: https://github.com/flipperdevices/rockchip-linux/commit/7a72bc05dcc3a51e85ae531749e6270bf9b9212d [1] Fixes: f1c506d152ff ("clk: rockchip: add clock controller for the RK3588") Fixes: cc40f5baa91b ("clk: rockchip: Add clock controller for the RK3576") Signed-off-by: Alexey Charkov <redacted> --- Not adding Cc stable, because while this fixes a real bug it's not a regression, as the issue was introduced in the same commit that added the RK3576/RK3588 support. Note that there is a separate unrelated issue with the rate table, namely the 2256000000 Hz entry currently leads to a VCO frequency of 4512 MHz, which is just above the TRM-stated maximum of 4500 MHz. Also multiple entries in the table end up with Fvco < 3 GHz, which according to the TRM leads to a PLL period jitter of +-2% vs. the +-1% for Fvco > 3 GHz. To be revisited separately. --- drivers/clk/rockchip/clk-pll.c | 8 ++++---- drivers/clk/rockchip/clk-rk3576.c | 4 ++-- drivers/clk/rockchip/clk-rk3588.c | 4 ++-- drivers/clk/rockchip/clk.h | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 6b853800cb6b..f445b01aabd0 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c@@ -13,6 +13,7 @@ #include <linux/delay.h> #include <linux/clk-provider.h> #include <linux/iopoll.h> +#include <linux/math64.h> #include <linux/regmap.h> #include <linux/clk.h> #include "clk.h"
@@ -913,11 +914,10 @@ static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned if (cur.k) { /* fractional mode */ - u64 frac_rate64 = prate * cur.k; + s64 frac_rate64 = (s64)prate * cur.k; - postdiv = cur.p * 65535; - do_div(frac_rate64, postdiv); - rate64 += frac_rate64; + postdiv = cur.p * 65536; + rate64 += div_s64(frac_rate64, postdiv); } rate64 = rate64 >> cur.s;
diff --git a/drivers/clk/rockchip/clk-rk3576.c b/drivers/clk/rockchip/clk-rk3576.c
index 2557358e0b9d..63f229e73a45 100644
--- a/drivers/clk/rockchip/clk-rk3576.c
+++ b/drivers/clk/rockchip/clk-rk3576.c@@ -79,13 +79,13 @@ static struct rockchip_pll_rate_table rk3576_pll_rates[] = { RK3588_PLL_RATE(1008000000, 2, 336, 2, 0), RK3588_PLL_RATE(1000000000, 3, 500, 2, 0), RK3588_PLL_RATE(983040000, 4, 655, 2, 23592), - RK3588_PLL_RATE(955520000, 3, 477, 2, 49806), + RK3588_PLL_RATE(955520000, 3, 478, 2, -15730), RK3588_PLL_RATE(903168000, 6, 903, 2, 11009), RK3588_PLL_RATE(900000000, 2, 300, 2, 0), RK3588_PLL_RATE(816000000, 2, 272, 2, 0), RK3588_PLL_RATE(786432000, 2, 262, 2, 9437), RK3588_PLL_RATE(786000000, 1, 131, 2, 0), - RK3588_PLL_RATE(785560000, 3, 392, 2, 51117), + RK3588_PLL_RATE(785560000, 3, 393, 2, -14419), RK3588_PLL_RATE(722534400, 8, 963, 2, 24850), RK3588_PLL_RATE(600000000, 2, 200, 2, 0), RK3588_PLL_RATE(594000000, 2, 198, 2, 0),
diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c
index 75d42fea2a11..24baa0ef9bf3 100644
--- a/drivers/clk/rockchip/clk-rk3588.c
+++ b/drivers/clk/rockchip/clk-rk3588.c@@ -79,14 +79,14 @@ static struct rockchip_pll_rate_table rk3588_pll_rates[] = { RK3588_PLL_RATE(1008000000, 2, 336, 2, 0), RK3588_PLL_RATE(1000000000, 3, 500, 2, 0), RK3588_PLL_RATE(983040000, 4, 655, 2, 23592), - RK3588_PLL_RATE(955520000, 3, 477, 2, 49806), + RK3588_PLL_RATE(955520000, 3, 478, 2, -15730), RK3588_PLL_RATE(903168000, 6, 903, 2, 11009), RK3588_PLL_RATE(900000000, 2, 300, 2, 0), RK3588_PLL_RATE(850000000, 3, 425, 2, 0), RK3588_PLL_RATE(816000000, 2, 272, 2, 0), RK3588_PLL_RATE(786432000, 2, 262, 2, 9437), RK3588_PLL_RATE(786000000, 1, 131, 2, 0), - RK3588_PLL_RATE(785560000, 3, 392, 2, 51117), + RK3588_PLL_RATE(785560000, 3, 393, 2, -14419), RK3588_PLL_RATE(722534400, 8, 963, 2, 24850), RK3588_PLL_RATE(600000000, 2, 200, 2, 0), RK3588_PLL_RATE(594000000, 2, 198, 2, 0),
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 9e3503e2ffc2..72b36bba3152 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h@@ -635,10 +635,10 @@ struct rockchip_pll_rate_table { }; struct { /* for RK3588 */ - unsigned int m; - unsigned int p; - unsigned int s; - unsigned int k; + unsigned int m; /* main divider, 10 bit unsigned */ + unsigned int p; /* pre-divider, 6 bit unsigned */ + unsigned int s; /* scaler, 3 bit unsigned */ + s16 k; /* fractional part, 16 bit two's complement */ }; }; };
--- base-commit: 290aaf24a551d5a0dce037e3fab30820f9113a10 change-id: 20260721-rk3588-fracpll-f4377cd80983 Best regards, -- Alexey Charkov [off-list ref]