From: Rosen Penev <rosenp@gmail.com>
To: linux-mips@vger.kernel.org,
Thomas Bogendoerfer <tsbogend@alpha.franken.de>,
Stephen Boyd <sboyd@kernel.org>
Cc: Brian Masney <bmasney+clk@redhat.com>,
Jerome Brunet <jbrunet+clk@baylibre.com>,
Alban Bedel <albeu@free.fr>,
Antony Pavlov <antonynpavlov@gmail.com>,
linux-kernel@vger.kernel.org (open list),
linux-clk@vger.kernel.org (open list:COMMON CLK FRAMEWORK)
Subject: [PATCH 8/8] clk: ath79: share the fractional PLL calculation
Date: Tue, 3 Nov 2026 21:58:52 -0800 [thread overview]
Message-ID: <20261104055852.152340-9-rosenp@gmail.com> (raw)
In-Reply-To: <20261104055852.152340-1-rosenp@gmail.com>
AR934x, QCA953x and QCA955x compute their CPU and DDR PLL rates with the
same formula, ref / ref_div * (nint + nfrac / frac) / 2^out_div, written
three different ways. Use one helper for all of them, with 64-bit
intermediates.
That fixes the QCA955x DDR PLL rate, whose nfrac * ref product could
overflow 32 bits: with a 40 MHz reference clock it did for any nfrac
above 107, and with 25 MHz for any above 171. The other rates are
unchanged, as checked against the old code with random register values.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/clk/clk-ath79.c | 47 +++++++++++++----------------------------
1 file changed, 15 insertions(+), 32 deletions(-)
diff --git a/drivers/clk/clk-ath79.c b/drivers/clk/clk-ath79.c
index 8086b4f6378c..f9a8c9b9aa24 100644
--- a/drivers/clk/clk-ath79.c
+++ b/drivers/clk/clk-ath79.c
@@ -10,6 +10,7 @@
#include <linux/bitfield.h>
#include <linux/kernel.h>
+#include <linux/math64.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/err.h>
@@ -21,7 +22,6 @@
#include <linux/slab.h>
#include <dt-bindings/clock/ath79-clk.h>
-#include <asm/div64.h>
#include "clk-ath79.h"
@@ -189,24 +189,17 @@ static int __init ar933x_clocks_init(void __iomem *pll_base)
ref_div * out_div * ahb_div);
}
-static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
- u32 frac, u32 out_div)
+/* a fractional PLL: ref / ref_div * (nint + nfrac / frac) / 2^out_div */
+static unsigned long __init ath79_pll_rate(unsigned long ref, u32 ref_div,
+ u32 nint, u32 nfrac, u32 frac,
+ u32 out_div)
{
- u64 t;
- u32 ret;
+ unsigned long rate;
- t = ref;
- t *= nint;
- do_div(t, ref_div);
- ret = t;
+ rate = div_u64((u64)ref * nint, ref_div);
+ rate += div_u64((u64)ref * nfrac, ref_div * frac);
- t = ref;
- t *= nfrac;
- do_div(t, ref_div * frac);
- ret += t;
-
- ret /= (1 << out_div);
- return ret;
+ return rate >> out_div;
}
static int __init ar934x_clocks_init(void __iomem *pll_base)
@@ -243,8 +236,7 @@ static int __init ar934x_clocks_init(void __iomem *pll_base)
frac = 1 << 6;
}
- cpu_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
- nfrac, frac, out_div);
+ cpu_pll = ath79_pll_rate(ref_rate, ref_div, nint, nfrac, frac, out_div);
pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL2_REG);
if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
@@ -263,8 +255,7 @@ static int __init ar934x_clocks_init(void __iomem *pll_base)
frac = 1 << 10;
}
- ddr_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
- nfrac, frac, out_div);
+ ddr_pll = ath79_pll_rate(ref_rate, ref_div, nint, nfrac, frac, out_div);
iounmap(dpll_base);
@@ -325,9 +316,7 @@ static int __init qca953x_clocks_init(void __iomem *pll_base)
nint = FIELD_GET(QCA953X_PLL_CPU_CONFIG_NINT, pll);
frac = FIELD_GET(QCA953X_PLL_CPU_CONFIG_NFRAC, pll);
- cpu_pll = nint * ref_rate / ref_div;
- cpu_pll += frac * (ref_rate >> 6) / ref_div;
- cpu_pll /= (1 << out_div);
+ cpu_pll = ath79_pll_rate(ref_rate, ref_div, nint, frac, 1 << 6, out_div);
pll = __raw_readl(pll_base + QCA953X_PLL_DDR_CONFIG_REG);
out_div = FIELD_GET(QCA953X_PLL_DDR_CONFIG_OUTDIV, pll);
@@ -335,9 +324,7 @@ static int __init qca953x_clocks_init(void __iomem *pll_base)
nint = FIELD_GET(QCA953X_PLL_DDR_CONFIG_NINT, pll);
frac = FIELD_GET(QCA953X_PLL_DDR_CONFIG_NFRAC, pll);
- ddr_pll = nint * ref_rate / ref_div;
- ddr_pll += frac * (ref_rate >> 6) / (ref_div << 4);
- ddr_pll /= (1 << out_div);
+ ddr_pll = ath79_pll_rate(ref_rate, ref_div, nint, frac, 1 << 10, out_div);
clk_ctrl = __raw_readl(pll_base + QCA953X_PLL_CLK_CTRL_REG);
@@ -388,9 +375,7 @@ static int __init qca955x_clocks_init(void __iomem *pll_base)
nint = FIELD_GET(QCA955X_PLL_CPU_CONFIG_NINT, pll);
frac = FIELD_GET(QCA955X_PLL_CPU_CONFIG_NFRAC, pll);
- cpu_pll = nint * ref_rate / ref_div;
- cpu_pll += frac * ref_rate / (ref_div * (1 << 6));
- cpu_pll /= (1 << out_div);
+ cpu_pll = ath79_pll_rate(ref_rate, ref_div, nint, frac, 1 << 6, out_div);
pll = __raw_readl(pll_base + QCA955X_PLL_DDR_CONFIG_REG);
out_div = FIELD_GET(QCA955X_PLL_DDR_CONFIG_OUTDIV, pll);
@@ -398,9 +383,7 @@ static int __init qca955x_clocks_init(void __iomem *pll_base)
nint = FIELD_GET(QCA955X_PLL_DDR_CONFIG_NINT, pll);
frac = FIELD_GET(QCA955X_PLL_DDR_CONFIG_NFRAC, pll);
- ddr_pll = nint * ref_rate / ref_div;
- ddr_pll += frac * ref_rate / (ref_div * (1 << 10));
- ddr_pll /= (1 << out_div);
+ ddr_pll = ath79_pll_rate(ref_rate, ref_div, nint, frac, 1 << 10, out_div);
clk_ctrl = __raw_readl(pll_base + QCA955X_PLL_CLK_CTRL_REG);
--
2.56.0
prev parent reply other threads:[~2026-11-04 5:59 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 5:58 [PATCH 0/8] clk: ath79: move the PLL clock driver to drivers/clk Rosen Penev
2026-11-04 5:58 ` [PATCH 1/8] MIPS: ath79: apply the QCA956x timer workaround in setup Rosen Penev
2026-11-04 5:58 ` [PATCH 2/8] MIPS: ath79: move the bootstrap reference clock to setup Rosen Penev
2026-11-04 5:58 ` [PATCH 3/8] clk: ath79: move the ath79 clock driver to drivers/clk Rosen Penev
2026-11-04 5:58 ` [PATCH 4/8] clk: ath79: use FIELD_GET() for the PLL register fields Rosen Penev
2026-11-04 5:58 ` [PATCH 5/8] clk: ath79: convert to clk_hw based registration Rosen Penev
2026-11-04 5:58 ` [PATCH 6/8] clk: ath79: fix the error handling Rosen Penev
2026-11-04 5:58 ` [PATCH 7/8] clk: ath79: give each compatible its own init function Rosen Penev
2026-11-04 5:58 ` Rosen Penev [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261104055852.152340-9-rosenp@gmail.com \
--to=rosenp@gmail.com \
--cc=albeu@free.fr \
--cc=antonynpavlov@gmail.com \
--cc=bmasney+clk@redhat.com \
--cc=jbrunet+clk@baylibre.com \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@vger.kernel.org \
--cc=sboyd@kernel.org \
--cc=tsbogend@alpha.franken.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®