clk: rockchip: Fractional PLL coefficient on RK3588/RK3576 is two's complement

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.

Treating the fractional PLL coefficient as unsigned in rate recalculation
results in a kernel-visible rate which deviates from what the hardware
actually generates by Fin / (p * 2^s), or 2 MHz for the two affected table
entries.

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.

Rockchip's downstream commit introducing the two's complement logic for k
also does unrelated tweaks to the PLL parameters which are not explained
by the switch to the two's complement, so they are not replicated here.
If any of the parameters prove to need further tweaks (e.g. for precision
or jitter) that would better be done in targeted follow-up commits.

Fractional PLL rates don't seem to be used by any current mainline
consumers, so this is purely a correctness fix. It will also be important
to properly support DisplayPort output going forward, as the video output
controller derives its pixel clock from system PLLs with no dedicated PHY
PLL option for DP unlike HDMI, and some display modes are only achievable
using fractional PLL rates.

Link: 7a72bc05dc [1]
Fixes: f1c506d152 ("clk: rockchip: add clock controller for the RK3588")
Fixes: cc40f5baa9 ("clk: rockchip: Add clock controller for the RK3576")
Signed-off-by: Alexey Charkov <alchark@flipper.net>
Link: https://patch.msgid.link/20260723-rk3588-fracpll-v2-2-3adfb9dda235@flipper.net
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
This commit is contained in:
Alexey Charkov 2026-07-23 14:21:59 +04:00 committed by Heiko Stuebner
parent 52aef653c3
commit 5814788834
4 changed files with 12 additions and 11 deletions

View File

@ -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"
@ -906,6 +907,7 @@ static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll,
* For Fvco < 3 GHz: period jitter +-2% frac PLL, +-1.50% int PLL
* Fvco = ((m + k / 65536) * Fin) / p
* Fout = ((m + k / 65536) * Fin) / (p * 2^s)
* -32768 <= k <= 32767 (only available in frac PLLs, not int PLLs)
*/
static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
{
@ -920,11 +922,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 * 65536;
do_div(frac_rate64, postdiv);
rate64 += frac_rate64;
rate64 += div_s64(frac_rate64, postdiv);
}
rate64 = rate64 >> cur.s;

View File

@ -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),

View File

@ -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),

View File

@ -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 */
};
};
};