[PATCH RFT] clk: qcom: clk-alpha-pll: Fix the rate of Zonda PLLs with a negative alpha
From: Abel Vesa
Date: Tue Nov 03 2026 - 04:59:39 EST
The alpha value of the Zonda and Regera PLLs is a signed fraction.
clk_zonda_pll_set_rate() accounts for that by programming L one higher
whenever the alpha value has its MSB set, but both PLL types use
clk_trion_pll_recalc_rate(), which takes the alpha value as unsigned.
For such a configuration, the rate reported to the clock framework, and
so to all the children of the PLL, is higher than the actual one by the
parent rate.
Add a recalc_rate operation for these PLLs that takes the sign of the
alpha value into account.
Fixes: f21b6bfecc27 ("clk: qcom: clk-alpha-pll: add support for zonda pll")
Fixes: 0c31f6a3ab7f ("clk: qcom: clk-alpha-pll: Add support for Regera PLL ops")
Cc: stable@xxxxxxxxxxxxxxx
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://sashiko.dev/#/bug/linux-17339f1f-7afb-40a5-96cd-70361917e0f2
Signed-off-by: Abel Vesa <abel.vesa@xxxxxxxxxxxxxxxx>
---
Tested on the X1E80100 CRD, which boots without new warnings, but does
not exercise this change: the registers of gpu_cc_pll0 read as zero
while the GX domain is off, so its rate is reported as 0 either way.
Prepared with help from an LLM-based assistant.
---
drivers/clk/qcom/clk-alpha-pll.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 60173b076cc5..59fe8fde81c2 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -2274,6 +2274,32 @@ static void zonda_pll_adjust_l_val(unsigned long rate, unsigned long prate, u32
*l = rate + (u32)(remainder * 2 >= prate);
}
+static unsigned long
+clk_zonda_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ u32 l, frac, alpha_width = pll_alpha_width(pll);
+
+ if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l))
+ return 0;
+
+ if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac))
+ return 0;
+
+ /*
+ * The alpha value is signed, so with its MSB set, it is a negative
+ * fraction and L is one more than the integer part of the multiplier.
+ * See zonda_pll_adjust_l_val().
+ */
+ if (frac & PLL_ALPHA_MSB) {
+ if (!l)
+ return 0;
+ l--;
+ }
+
+ return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width);
+}
+
static int clk_zonda_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long prate)
{
@@ -2322,7 +2348,7 @@ const struct clk_ops clk_alpha_pll_zonda_ops = {
.enable = clk_zonda_pll_enable,
.disable = clk_zonda_pll_disable,
.is_enabled = clk_trion_pll_is_enabled,
- .recalc_rate = clk_trion_pll_recalc_rate,
+ .recalc_rate = clk_zonda_pll_recalc_rate,
.determine_rate = clk_alpha_pll_determine_rate,
.set_rate = clk_zonda_pll_set_rate,
};
@@ -2998,7 +3024,7 @@ const struct clk_ops clk_alpha_pll_regera_ops = {
.enable = clk_zonda_pll_enable,
.disable = clk_zonda_pll_disable,
.is_enabled = clk_alpha_pll_is_enabled,
- .recalc_rate = clk_trion_pll_recalc_rate,
+ .recalc_rate = clk_zonda_pll_recalc_rate,
.determine_rate = clk_alpha_pll_determine_rate,
.set_rate = clk_zonda_pll_set_rate,
};
---
base-commit: 2637bdec0535a2044cd830eba9a79363651d9043
change-id: 20261102-clk-qcom-zonda-signed-alpha-33846a18d82a
Best regards,
--
Abel