* [PATCH 01/12] clk: qcom: ipq-cmn-pll: Use devm_clk_hw_register_fixed_rate_parent_data
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:50 ` Konrad Dybcio
2026-07-24 15:00 ` [PATCH 02/12] dt-bindings: clock: qcom: Add CMN PLL support for IPQ5210 SoC Luo Jie
` (10 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
Replace clk_hw_register_fixed_rate_parent_hw() with the managed
devm_clk_hw_register_fixed_rate_parent_data() so the fixed-rate output
clocks are automatically unregistered when the device is unbound.
Since all clocks in the driver are now registered via devm_ variants,
the remove callback 'ipq_cmn_pll_clk_remove()' and the manual
'unregister_fixed_clk' error-path loop are no longer needed and are
removed.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 39 +++++++++------------------------------
1 file changed, 9 insertions(+), 30 deletions(-)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index dafe8c1738df..4fdf78f6829e 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -390,13 +390,14 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
/* Register the fixed rate output clocks. */
for (i = 0; i < num_clks; i++) {
- hw = clk_hw_register_fixed_rate_parent_hw(dev, fixed_clk[i].name,
- cmn_pll_hw, 0,
- fixed_clk[i].rate);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto unregister_fixed_clk;
- }
+ struct clk_parent_data pdata = { .hw = cmn_pll_hw };
+
+ hw = devm_clk_hw_register_fixed_rate_parent_data(dev,
+ fixed_clk[i].name,
+ &pdata, 0,
+ fixed_clk[i].rate);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
hw_data->hws[fixed_clk[i].id] = hw;
}
@@ -410,17 +411,11 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
if (ret)
- goto unregister_fixed_clk;
+ return ret;
platform_set_drvdata(pdev, hw_data);
return 0;
-
-unregister_fixed_clk:
- while (i > 0)
- clk_hw_unregister(hw_data->hws[fixed_clk[--i].id]);
-
- return ret;
}
static int ipq_cmn_pll_clk_probe(struct platform_device *pdev)
@@ -462,21 +457,6 @@ static int ipq_cmn_pll_clk_probe(struct platform_device *pdev)
return 0;
}
-static void ipq_cmn_pll_clk_remove(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *hw_data = platform_get_drvdata(pdev);
- int i;
-
- /*
- * The clock with index CMN_PLL_CLK is unregistered by
- * device management.
- */
- for (i = 0; i < hw_data->num; i++) {
- if (i != CMN_PLL_CLK)
- clk_hw_unregister(hw_data->hws[i]);
- }
-}
-
static const struct dev_pm_ops ipq_cmn_pll_pm_ops = {
SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
};
@@ -494,7 +474,6 @@ MODULE_DEVICE_TABLE(of, ipq_cmn_pll_clk_ids);
static struct platform_driver ipq_cmn_pll_clk_driver = {
.probe = ipq_cmn_pll_clk_probe,
- .remove = ipq_cmn_pll_clk_remove,
.driver = {
.name = "ipq_cmn_pll",
.of_match_table = ipq_cmn_pll_clk_ids,
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 01/12] clk: qcom: ipq-cmn-pll: Use devm_clk_hw_register_fixed_rate_parent_data
2026-07-24 15:00 ` [PATCH 01/12] clk: qcom: ipq-cmn-pll: Use devm_clk_hw_register_fixed_rate_parent_data Luo Jie
@ 2026-07-24 15:50 ` Konrad Dybcio
0 siblings, 0 replies; 18+ messages in thread
From: Konrad Dybcio @ 2026-07-24 15:50 UTC (permalink / raw)
To: Luo Jie, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia
On 7/24/26 5:00 PM, Luo Jie wrote:
> Replace clk_hw_register_fixed_rate_parent_hw() with the managed
> devm_clk_hw_register_fixed_rate_parent_data() so the fixed-rate output
> clocks are automatically unregistered when the device is unbound.
>
> Since all clocks in the driver are now registered via devm_ variants,
> the remove callback 'ipq_cmn_pll_clk_remove()' and the manual
> 'unregister_fixed_clk' error-path loop are no longer needed and are
> removed.
>
> Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 02/12] dt-bindings: clock: qcom: Add CMN PLL support for IPQ5210 SoC
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
2026-07-24 15:00 ` [PATCH 01/12] clk: qcom: ipq-cmn-pll: Use devm_clk_hw_register_fixed_rate_parent_data Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:00 ` [PATCH 03/12] clk: qcom: ipq-cmn-pll: Add analog soft-reset helper Luo Jie
` (9 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
Add the compatible string for the IPQ5210 CMN PLL clock controller and
the dt-bindings clock ID header for IPQ5210.
The IPQ5210 CMN PLL supplies configurable clocks to the NSS (network
subsystem), PPE (packet process engine), and PON (passive optical
network) hardware blocks. It also supplies a raw EPHY output clock for
the integrated Ethernet PHY and several gated fixed-rate outputs to
Ethernet PHY and switch devices.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
.../bindings/clock/qcom,ipq9574-cmn-pll.yaml | 1 +
include/dt-bindings/clock/qcom,ipq5210-cmn-pll.h | 30 ++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
index a4f9af8fa187..91e17f126a9b 100644
--- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
@@ -25,6 +25,7 @@ properties:
compatible:
enum:
- qcom,ipq5018-cmn-pll
+ - qcom,ipq5210-cmn-pll
- qcom,ipq5332-cmn-pll
- qcom,ipq5424-cmn-pll
- qcom,ipq6018-cmn-pll
diff --git a/include/dt-bindings/clock/qcom,ipq5210-cmn-pll.h b/include/dt-bindings/clock/qcom,ipq5210-cmn-pll.h
new file mode 100644
index 000000000000..191589fd5311
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,ipq5210-cmn-pll.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ5210_CMN_PLL_H
+#define _DT_BINDINGS_CLK_QCOM_IPQ5210_CMN_PLL_H
+
+/* Parent clock */
+#define IPQ5210_CMN_PLL_CLK 0
+
+/* Fixed-rate clocks */
+#define IPQ5210_XO_24MHZ_CLK 1
+#define IPQ5210_SLEEP_32KHZ_CLK 2
+
+/* Configurable divider clocks */
+#define IPQ5210_NSS_CLK 3
+#define IPQ5210_PPE_CLK 4
+#define IPQ5210_PON_REFCLK 5
+#define IPQ5210_EPHY_RAW_CLK 6
+
+/* Gate clocks */
+#define IPQ5210_PCS_31P25MHZ_CLK 7
+#define IPQ5210_ETH0_50MHZ_CLK 8
+#define IPQ5210_ETH1_50MHZ_CLK 9
+#define IPQ5210_ETH2_50MHZ_CLK 10
+#define IPQ5210_EPHY_50MHZ_CLK 11
+#define IPQ5210_ETH_25MHZ_CLK 12
+
+#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 03/12] clk: qcom: ipq-cmn-pll: Add analog soft-reset helper
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
2026-07-24 15:00 ` [PATCH 01/12] clk: qcom: ipq-cmn-pll: Use devm_clk_hw_register_fixed_rate_parent_data Luo Jie
2026-07-24 15:00 ` [PATCH 02/12] dt-bindings: clock: qcom: Add CMN PLL support for IPQ5210 SoC Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:00 ` [PATCH 04/12] clk: qcom: ipq-cmn-pll: Add NSS clock support Luo Jie
` (8 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
Add clk_cmn_pll_ana_soft_reset(), which toggles the CMN_ANA_EN_SW_RSTN
bit in CMN_PLL_POWER_ON_AND_RESET to perform an analog soft reset of the
PLL, then polls CMN_PLL_LOCKED until the output clocks are stable.
This helper will also be used by the NSS, PPE, and PON reference clock
set_rate handlers added in subsequent patches.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 39 +++++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 16 deletions(-)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index 4fdf78f6829e..aa319d577871 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -210,6 +210,28 @@ static int ipq_cmn_pll_find_freq_index(unsigned long parent_rate)
return index;
}
+static int clk_cmn_pll_ana_soft_reset(struct regmap *regmap)
+{
+ int ret;
+ u32 val;
+
+ ret = regmap_clear_bits(regmap, CMN_PLL_POWER_ON_AND_RESET,
+ CMN_ANA_EN_SW_RSTN);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 1200);
+ ret = regmap_set_bits(regmap, CMN_PLL_POWER_ON_AND_RESET,
+ CMN_ANA_EN_SW_RSTN);
+ if (ret)
+ return ret;
+
+ /* Stability check of CMN PLL output clocks. */
+ return regmap_read_poll_timeout(regmap, CMN_PLL_LOCKED, val,
+ (val & CMN_PLL_CLKS_LOCKED),
+ 100, 100 * USEC_PER_MSEC);
+}
+
static unsigned long clk_cmn_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -253,7 +275,6 @@ static int clk_cmn_pll_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
int ret, index;
- u32 val;
/*
* Configure the reference input clock selection as per the given
@@ -297,21 +318,7 @@ static int clk_cmn_pll_set_rate(struct clk_hw *hw, unsigned long rate,
* Reset the CMN PLL block to ensure the updated configurations
* take effect.
*/
- ret = regmap_clear_bits(cmn_pll->regmap, CMN_PLL_POWER_ON_AND_RESET,
- CMN_ANA_EN_SW_RSTN);
- if (ret)
- return ret;
-
- usleep_range(1000, 1200);
- ret = regmap_set_bits(cmn_pll->regmap, CMN_PLL_POWER_ON_AND_RESET,
- CMN_ANA_EN_SW_RSTN);
- if (ret)
- return ret;
-
- /* Stability check of CMN PLL output clocks. */
- return regmap_read_poll_timeout(cmn_pll->regmap, CMN_PLL_LOCKED, val,
- (val & CMN_PLL_CLKS_LOCKED),
- 100, 100 * USEC_PER_MSEC);
+ return clk_cmn_pll_ana_soft_reset(cmn_pll->regmap);
}
static const struct clk_ops clk_cmn_pll_ops = {
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 04/12] clk: qcom: ipq-cmn-pll: Add NSS clock support
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (2 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 03/12] clk: qcom: ipq-cmn-pll: Add analog soft-reset helper Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:15 ` sashiko-bot
2026-07-24 15:00 ` [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE " Luo Jie
` (7 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
The NSS (network subsystem) clock is derived from the CMN PLL output
divided by 2 and then further divided by a configurable 6-bit divider
with a valid range of 8-63.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 119 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 114 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index aa319d577871..3df326c22fba 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -66,6 +66,11 @@
#define CMN_PLL_LOCKED 0x64
#define CMN_PLL_CLKS_LOCKED BIT(8)
+#define CMN_PLL_NSS_PPE_FREQ_CTRL 0x98
+#define CMN_PLL_NSS_CLK_SEL GENMASK(13, 8)
+#define CMN_PLL_NSS_PPE_DIV_MIN 8
+#define CMN_PLL_NSS_PPE_DIV_MAX 63
+
#define CMN_PLL_POWER_ON_AND_RESET 0x780
#define CMN_ANA_EN_SW_RSTN BIT(6)
@@ -364,11 +369,105 @@ static struct clk_hw *ipq_cmn_pll_clk_hw_register(struct platform_device *pdev)
return &cmn_pll->hw;
}
+/*
+ * NSS (Network Subsystem) clock operations.
+ * The NSS clock is derived from CMN PLL rate / 2, then divided by
+ * a configurable 6-bit divider (8-63).
+ */
+static unsigned long clk_nss_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *nss_clk = to_clk_cmn_pll(hw);
+ u32 val, div;
+
+ regmap_read(nss_clk->regmap, CMN_PLL_NSS_PPE_FREQ_CTRL, &val);
+ div = FIELD_GET(CMN_PLL_NSS_CLK_SEL, val);
+ if (WARN_ON_ONCE(!div))
+ return 0;
+
+ return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * div);
+}
+
+static int clk_nss_ppe_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned long div;
+
+ if (WARN_ON_ONCE(!req->rate))
+ return 0;
+
+ div = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * req->rate);
+ div = clamp_t(unsigned long, div, CMN_PLL_NSS_PPE_DIV_MIN,
+ CMN_PLL_NSS_PPE_DIV_MAX);
+
+ req->rate = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * div);
+ return 0;
+}
+
+static int clk_nss_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *nss_clk = to_clk_cmn_pll(hw);
+ unsigned long div;
+ int ret;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ div = DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * rate);
+ if (div < CMN_PLL_NSS_PPE_DIV_MIN || div > CMN_PLL_NSS_PPE_DIV_MAX)
+ return -EINVAL;
+
+ ret = regmap_update_bits(nss_clk->regmap, CMN_PLL_NSS_PPE_FREQ_CTRL,
+ CMN_PLL_NSS_CLK_SEL,
+ FIELD_PREP(CMN_PLL_NSS_CLK_SEL, div));
+ if (ret)
+ return ret;
+
+ return clk_cmn_pll_ana_soft_reset(nss_clk->regmap);
+}
+
+static const struct clk_ops clk_nss_ops = {
+ .recalc_rate = clk_nss_recalc_rate,
+ .determine_rate = clk_nss_ppe_determine_rate,
+ .set_rate = clk_nss_set_rate,
+};
+
+static struct clk_hw *ipq_cmn_pll_nss_register(struct platform_device *pdev,
+ struct regmap *regmap,
+ struct clk_hw *cmn_pll_hw)
+{
+ struct clk_parent_data pdata = { .hw = cmn_pll_hw };
+ struct device *dev = &pdev->dev;
+ struct clk_init_data init = {};
+ struct clk_cmn_pll *nss_clk;
+ int ret;
+
+ nss_clk = devm_kzalloc(dev, sizeof(*nss_clk), GFP_KERNEL);
+ if (!nss_clk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = "nss-clk";
+ init.parent_data = &pdata;
+ init.num_parents = 1;
+ init.ops = &clk_nss_ops;
+
+ nss_clk->hw.init = &init;
+ nss_clk->regmap = regmap;
+
+ ret = devm_clk_hw_register(dev, &nss_clk->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &nss_clk->hw;
+}
+
static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
{
const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
struct clk_hw_onecell_data *hw_data;
struct device *dev = &pdev->dev;
+ struct clk_cmn_pll *cmn_pll;
struct clk_hw *cmn_pll_hw;
unsigned int num_clks;
struct clk_hw *hw;
@@ -395,14 +494,24 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
if (IS_ERR(cmn_pll_hw))
return PTR_ERR(cmn_pll_hw);
+ cmn_pll = to_clk_cmn_pll(cmn_pll_hw);
+
/* Register the fixed rate output clocks. */
for (i = 0; i < num_clks; i++) {
- struct clk_parent_data pdata = { .hw = cmn_pll_hw };
+ if (fixed_clk[i].rate) {
+ struct clk_parent_data pdata = { .hw = cmn_pll_hw };
+
+ hw = devm_clk_hw_register_fixed_rate_parent_data(dev,
+ fixed_clk[i].name,
+ &pdata, 0,
+ fixed_clk[i].rate);
+ } else if (!strcmp(fixed_clk[i].name, "nss")) {
+ hw = ipq_cmn_pll_nss_register(pdev, cmn_pll->regmap,
+ cmn_pll_hw);
+ } else {
+ continue;
+ }
- hw = devm_clk_hw_register_fixed_rate_parent_data(dev,
- fixed_clk[i].name,
- &pdata, 0,
- fixed_clk[i].rate);
if (IS_ERR(hw))
return PTR_ERR(hw);
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 04/12] clk: qcom: ipq-cmn-pll: Add NSS clock support
2026-07-24 15:00 ` [PATCH 04/12] clk: qcom: ipq-cmn-pll: Add NSS clock support Luo Jie
@ 2026-07-24 15:15 ` sashiko-bot
0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-07-24 15:15 UTC (permalink / raw)
To: Luo Jie; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] clk_nss_ppe_determine_rate violates the clock framework API contract when req->rate is 0.
- [Medium] Modifying the NSS clock divider resets the entire CMN PLL block, potentially disrupting other shared fixed-rate clocks.
--
--- Patch [4]: [PATCH 04/12] clk: qcom: ipq-cmn-pll: Add NSS clock support ---
commit b809b8bd5941993b064f7e68f395a77c3ea61452
Author: Luo Jie <jie.luo@oss.qualcomm.com>
clk: qcom: ipq-cmn-pll: Add NSS clock support
The NSS (network subsystem) clock is derived from the CMN PLL output
divided by 2 and then further divided by a configurable 6-bit divider
with a valid range of 8-63.
> diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
> index aa319d577871a..3df326c22fbac 100644
> --- a/drivers/clk/qcom/ipq-cmn-pll.c
> +++ b/drivers/clk/qcom/ipq-cmn-pll.c
[ ... ]
> @@ -364,11 +369,105 @@ static struct clk_hw *ipq_cmn_pll_clk_hw_register(struct platform_device *pdev)
> return &cmn_pll->hw;
> }
>
> +/*
> + * NSS (Network Subsystem) clock operations.
> + * The NSS clock is derived from CMN PLL rate / 2, then divided by
> + * a configurable 6-bit divider (8-63).
> + */
[ ... ]
> +static int clk_nss_ppe_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + unsigned long div;
> +
> + if (WARN_ON_ONCE(!req->rate))
> + return 0;
[Severity: Medium]
When req->rate is 0, this returns 0 (success) without updating req->rate to a
valid boundary or returning an error code like -EINVAL.
Can this regression violate the clock framework API contract by falsely
indicating to consumers that 0 Hz is a supported configuration?
> +
> + div = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * req->rate);
> + div = clamp_t(unsigned long, div, CMN_PLL_NSS_PPE_DIV_MIN,
> + CMN_PLL_NSS_PPE_DIV_MAX);
> +
> + req->rate = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * div);
> + return 0;
> +}
> +
> +static int clk_nss_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
[ ... ]
> + ret = regmap_update_bits(nss_clk->regmap, CMN_PLL_NSS_PPE_FREQ_CTRL,
> + CMN_PLL_NSS_CLK_SEL,
> + FIELD_PREP(CMN_PLL_NSS_CLK_SEL, div));
> + if (ret)
> + return ret;
> +
> + return clk_cmn_pll_ana_soft_reset(nss_clk->regmap);
[Severity: Medium]
Does updating the leaf NSS clock divider strictly require a hardware-level
analog reset of the parent PLL block?
Calling clk_cmn_pll_ana_soft_reset() drops the global PLL lock by toggling
CMN_ANA_EN_SW_RSTN:
clk_cmn_pll_ana_soft_reset() {
...
ret = regmap_clear_bits(regmap, CMN_PLL_POWER_ON_AND_RESET,
CMN_ANA_EN_SW_RSTN);
...
}
Will this regression interrupt other derived clocks (e.g., PCIe, WLAN,
SYS_CLK) and cause link drops or system instability whenever the NSS divider
is dynamically updated?
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-qcom_ipq5210_cmnpll-v1-0-a8b8679d215f@oss.qualcomm.com?part=4
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE clock support
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (3 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 04/12] clk: qcom: ipq-cmn-pll: Add NSS clock support Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:19 ` sashiko-bot
2026-07-24 15:00 ` [PATCH 06/12] clk: qcom: ipq-cmn-pll: Add PON reference " Luo Jie
` (6 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
The PPE (packet process engine) clock is derived from the CMN PLL output
divided by 2 and then further divided by a configurable 6-bit divider
with a valid range of 8-63. It shares the CMN_PLL_NSS_PPE_FREQ_CTRL
register with the NSS clock but uses a different field (bits [5:0]).
The determine_rate operation is shared with the NSS clock since the
divider constraints and calculation are identical.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 81 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index 3df326c22fba..020ad12ca1f2 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -68,6 +68,7 @@
#define CMN_PLL_NSS_PPE_FREQ_CTRL 0x98
#define CMN_PLL_NSS_CLK_SEL GENMASK(13, 8)
+#define CMN_PLL_PPE_CLK_SEL GENMASK(5, 0)
#define CMN_PLL_NSS_PPE_DIV_MIN 8
#define CMN_PLL_NSS_PPE_DIV_MAX 63
@@ -462,6 +463,83 @@ static struct clk_hw *ipq_cmn_pll_nss_register(struct platform_device *pdev,
return &nss_clk->hw;
}
+/*
+ * PPE (Packet Process Engine) clock operations.
+ * The PPE clock is derived from CMN PLL rate / 2, then divided by
+ * a configurable 6-bit divider (8-63).
+ */
+static unsigned long clk_ppe_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *ppe_clk = to_clk_cmn_pll(hw);
+ u32 val, div;
+
+ regmap_read(ppe_clk->regmap, CMN_PLL_NSS_PPE_FREQ_CTRL, &val);
+ div = FIELD_GET(CMN_PLL_PPE_CLK_SEL, val);
+ if (WARN_ON_ONCE(!div))
+ return 0;
+
+ return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * div);
+}
+
+static int clk_ppe_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *ppe_clk = to_clk_cmn_pll(hw);
+ unsigned long div;
+ int ret;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ div = DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * rate);
+ if (div < CMN_PLL_NSS_PPE_DIV_MIN || div > CMN_PLL_NSS_PPE_DIV_MAX)
+ return -EINVAL;
+
+ ret = regmap_update_bits(ppe_clk->regmap, CMN_PLL_NSS_PPE_FREQ_CTRL,
+ CMN_PLL_PPE_CLK_SEL,
+ FIELD_PREP(CMN_PLL_PPE_CLK_SEL, div));
+ if (ret)
+ return ret;
+
+ return clk_cmn_pll_ana_soft_reset(ppe_clk->regmap);
+}
+
+static const struct clk_ops clk_ppe_ops = {
+ .recalc_rate = clk_ppe_recalc_rate,
+ .determine_rate = clk_nss_ppe_determine_rate,
+ .set_rate = clk_ppe_set_rate,
+};
+
+static struct clk_hw *ipq_cmn_pll_ppe_register(struct platform_device *pdev,
+ struct regmap *regmap,
+ struct clk_hw *cmn_pll_hw)
+{
+ struct clk_parent_data pdata = { .hw = cmn_pll_hw };
+ struct device *dev = &pdev->dev;
+ struct clk_init_data init = {};
+ struct clk_cmn_pll *ppe_clk;
+ int ret;
+
+ ppe_clk = devm_kzalloc(dev, sizeof(*ppe_clk), GFP_KERNEL);
+ if (!ppe_clk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = "ppe-clk";
+ init.parent_data = &pdata;
+ init.num_parents = 1;
+ init.ops = &clk_ppe_ops;
+
+ ppe_clk->hw.init = &init;
+ ppe_clk->regmap = regmap;
+
+ ret = devm_clk_hw_register(dev, &ppe_clk->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &ppe_clk->hw;
+}
+
static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
{
const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
@@ -508,6 +586,9 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
} else if (!strcmp(fixed_clk[i].name, "nss")) {
hw = ipq_cmn_pll_nss_register(pdev, cmn_pll->regmap,
cmn_pll_hw);
+ } else if (!strcmp(fixed_clk[i].name, "ppe")) {
+ hw = ipq_cmn_pll_ppe_register(pdev, cmn_pll->regmap,
+ cmn_pll_hw);
} else {
continue;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE clock support
2026-07-24 15:00 ` [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE " Luo Jie
@ 2026-07-24 15:19 ` sashiko-bot
0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-07-24 15:19 UTC (permalink / raw)
To: Luo Jie; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Using DIV_ROUND_CLOSEST_ULL() with a 64-bit divisor causes a divide-by-zero kernel panic due to 32-bit truncation.
--
--- Patch [5]: [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE clock support ---
commit aed5f1938300824fb26726205b9e4ce2ebf415fa
Author: Luo Jie <jie.luo@oss.qualcomm.com>
clk: qcom: ipq-cmn-pll: Add PPE clock support
This commit adds support for the PPE (packet process engine) clock,
which is derived from the CMN PLL output. It uses a configurable 6-bit
divider and shares a frequency control register with the NSS clock.
> diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
> index 3df326c22fbac..020ad12ca1f2b 100644
> --- a/drivers/clk/qcom/ipq-cmn-pll.c
> +++ b/drivers/clk/qcom/ipq-cmn-pll.c
[ ... ]
> @@ -462,6 +463,83 @@ static struct clk_hw *ipq_cmn_pll_nss_register(struct platform_device *pdev,
> return &nss_clk->hw;
> }
>
> +/*
> + * PPE (Packet Process Engine) clock operations.
> + * The PPE clock is derived from CMN PLL rate / 2, then divided by
> + * a configurable 6-bit divider (8-63).
> + */
[ ... ]
> +static int clk_ppe_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_cmn_pll *ppe_clk = to_clk_cmn_pll(hw);
> + unsigned long div;
> + int ret;
> +
> + if (rate == 0)
> + return -EINVAL;
> +
> + div = DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * rate);
[Severity: High]
Does this code overflow the 32-bit divisor limit of DIV_ROUND_CLOSEST_ULL?
DIV_ROUND_CLOSEST_ULL relies on the kernel do_div() macro, which strictly
truncates the divisor to 32 bits on all architectures. If a caller requests
a large rate (e.g. 2,147,483,648 Hz), 2ULL * rate will have its lower 32
bits as 0. Could this regression cause the divisor to truncate to 0 and
trigger a direct divide-by-zero kernel panic?
> + if (div < CMN_PLL_NSS_PPE_DIV_MIN || div > CMN_PLL_NSS_PPE_DIV_MAX)
> + return -EINVAL;
> +
[ ... ]
> +static const struct clk_ops clk_ppe_ops = {
> + .recalc_rate = clk_ppe_recalc_rate,
> + .determine_rate = clk_nss_ppe_determine_rate,
> + .set_rate = clk_ppe_set_rate,
> +};
While clk_ppe_set_rate might be protected if the clock framework previously
clamps the rate via determine_rate, this patch also points to the shared
clk_nss_ppe_determine_rate.
Can unconstrained rates passed into clk_nss_ppe_determine_rate from the
clock framework (such as via debugfs or a malformed device tree) cause a
similar truncation and kernel panic during rate calculation?
> +static struct clk_hw *ipq_cmn_pll_ppe_register(struct platform_device *pdev,
> + struct regmap *regmap,
> + struct clk_hw *cmn_pll_hw)
> +{
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-qcom_ipq5210_cmnpll-v1-0-a8b8679d215f@oss.qualcomm.com?part=5
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 06/12] clk: qcom: ipq-cmn-pll: Add PON reference clock support
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (4 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE " Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:11 ` sashiko-bot
2026-07-24 15:00 ` [PATCH 07/12] clk: qcom: ipq-cmn-pll: Add EPHY-RAW " Luo Jie
` (5 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
The PON (Passive Optical Network) reference clock is derived from the
CMN PLL output divided by 2 and then further divided by a configurable
8-bit divider (1-255). The clock supports two modes:
- UNIPHY mode (CMN_PLL_PON_MODE_SEL = 0): fixed 31.25 MHz output
- PON mode (CMN_PLL_PON_MODE_SEL = 1): pll_rate / (2 * divider)
The clock output can be independently enabled and disabled via the
CMN_PLL_PON_EN bit.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 158 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index 020ad12ca1f2..1ae32052b563 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -72,6 +72,11 @@
#define CMN_PLL_NSS_PPE_DIV_MIN 8
#define CMN_PLL_NSS_PPE_DIV_MAX 63
+#define CMN_PLL_PON_CONFIG 0x42c
+#define CMN_PLL_PON_MODE_SEL BIT(9)
+#define CMN_PLL_PON_EN BIT(8)
+#define CMN_PLL_PON_DIV_CTRL GENMASK(7, 0)
+
#define CMN_PLL_POWER_ON_AND_RESET 0x780
#define CMN_ANA_EN_SW_RSTN BIT(6)
@@ -540,6 +545,155 @@ static struct clk_hw *ipq_cmn_pll_ppe_register(struct platform_device *pdev,
return &ppe_clk->hw;
}
+/*
+ * PON (Passive Optical Network) reference clock operations.
+ * The PON refclk is derived from CMN PLL rate / 2, then divided by
+ * a configurable 8-bit divider (1-255).
+ */
+static int clk_pon_refclk_enable(struct clk_hw *hw)
+{
+ struct clk_cmn_pll *pon_clk = to_clk_cmn_pll(hw);
+
+ return regmap_set_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
+ CMN_PLL_PON_EN);
+}
+
+static void clk_pon_refclk_disable(struct clk_hw *hw)
+{
+ struct clk_cmn_pll *pon_clk = to_clk_cmn_pll(hw);
+
+ regmap_clear_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
+ CMN_PLL_PON_EN);
+}
+
+static int clk_pon_refclk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_cmn_pll *pon_clk = to_clk_cmn_pll(hw);
+
+ return regmap_test_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
+ CMN_PLL_PON_EN);
+}
+
+static unsigned long clk_pon_refclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *pon_clk = to_clk_cmn_pll(hw);
+ u32 val, div;
+
+ regmap_read(pon_clk->regmap, CMN_PLL_PON_CONFIG, &val);
+
+ /* Check if in UNIPHY mode (bit 9 = 0) - fixed 31.25 MHz */
+ if (!(val & CMN_PLL_PON_MODE_SEL))
+ return 31250000UL;
+
+ /* PON mode: calculate from divider */
+ div = FIELD_GET(CMN_PLL_PON_DIV_CTRL, val);
+ if (WARN_ON_ONCE(!div))
+ return 0;
+
+ return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * div);
+}
+
+static int clk_pon_refclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned long div;
+
+ if (WARN_ON_ONCE(!req->rate))
+ return 0;
+
+ /* UNIPHY fixed mode */
+ if (req->rate == 31250000UL)
+ return 0;
+
+ div = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * req->rate);
+
+ /* Clamp to valid range (1-255) */
+ div = clamp_t(unsigned long, div, 1, 255);
+
+ req->rate = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * div);
+ return 0;
+}
+
+static int clk_pon_refclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *pon_clk = to_clk_cmn_pll(hw);
+ unsigned long div;
+ int ret;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ /* UNIPHY fixed mode (31.25 MHz) */
+ if (rate == 31250000UL)
+ return regmap_clear_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
+ CMN_PLL_PON_MODE_SEL);
+
+ div = DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * rate);
+ if (div == 0 || div > 255)
+ return -EINVAL;
+
+ /* Switch to PON mode */
+ ret = regmap_set_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
+ CMN_PLL_PON_MODE_SEL);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
+ CMN_PLL_PON_DIV_CTRL,
+ FIELD_PREP(CMN_PLL_PON_DIV_CTRL, div));
+ if (ret)
+ return ret;
+
+ return clk_cmn_pll_ana_soft_reset(pon_clk->regmap);
+}
+
+static const struct clk_ops clk_pon_refclk_ops = {
+ .enable = clk_pon_refclk_enable,
+ .disable = clk_pon_refclk_disable,
+ .is_enabled = clk_pon_refclk_is_enabled,
+ .recalc_rate = clk_pon_refclk_recalc_rate,
+ .determine_rate = clk_pon_refclk_determine_rate,
+ .set_rate = clk_pon_refclk_set_rate,
+};
+
+static struct clk_hw *ipq_cmn_pll_pon_refclk_register(struct platform_device *pdev,
+ struct regmap *regmap,
+ struct clk_hw *cmn_pll_hw)
+{
+ struct clk_parent_data pdata = { .hw = cmn_pll_hw };
+ struct device *dev = &pdev->dev;
+ struct clk_init_data init = {};
+ struct clk_cmn_pll *pon_clk;
+ int ret;
+
+ pon_clk = devm_kzalloc(dev, sizeof(*pon_clk), GFP_KERNEL);
+ if (!pon_clk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = "pon-clk";
+ init.parent_data = &pdata;
+ init.num_parents = 1;
+ init.ops = &clk_pon_refclk_ops;
+ /*
+ * The PON reference clock may already be enabled by bootloader
+ * or consumed by hardware without an in-kernel client driver.
+ * Add CLK_IGNORE_UNUSED so the clock framework does not disable
+ * it when no consumer has claimed it.
+ */
+ init.flags = CLK_IGNORE_UNUSED;
+
+ pon_clk->hw.init = &init;
+ pon_clk->regmap = regmap;
+
+ ret = devm_clk_hw_register(dev, &pon_clk->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &pon_clk->hw;
+}
+
static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
{
const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
@@ -589,6 +743,10 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
} else if (!strcmp(fixed_clk[i].name, "ppe")) {
hw = ipq_cmn_pll_ppe_register(pdev, cmn_pll->regmap,
cmn_pll_hw);
+ } else if (!strcmp(fixed_clk[i].name, "pon")) {
+ hw = ipq_cmn_pll_pon_refclk_register(pdev,
+ cmn_pll->regmap,
+ cmn_pll_hw);
} else {
continue;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 06/12] clk: qcom: ipq-cmn-pll: Add PON reference clock support
2026-07-24 15:00 ` [PATCH 06/12] clk: qcom: ipq-cmn-pll: Add PON reference " Luo Jie
@ 2026-07-24 15:11 ` sashiko-bot
0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-07-24 15:11 UTC (permalink / raw)
To: Luo Jie; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] 64-bit divisor passed to DIV_ROUND_CLOSEST_ULL causes 32-bit truncation and potential divide-by-zero panics.
- [Medium] Non-atomic register updates when switching to PON mode can cause transient invalid clock states.
- [Medium] `clk_pon_refclk_determine_rate()` returns 0 on invalid rate requests instead of an error code.
- [Medium] Missing PLL analog soft reset when entering UNIPHY fixed mode.
- [Medium] UNIPHY mode is incorrectly excluded from rate rounding for near-match requests.
- [Medium] Missing error check on regmap_read in clk_pon_refclk_recalc_rate leads to use of uninitialized variable.
--
--- Patch [6]: [PATCH 06/12] clk: qcom: ipq-cmn-pll: Add PON reference clock support ---
commit 66c5c5bce6266424eec1b5f6855bb022b40a0322
Author: Luo Jie <jie.luo@oss.qualcomm.com>
clk: qcom: ipq-cmn-pll: Add PON reference clock support
This commit adds support for the PON reference clock to the IPQ CMN PLL driver.
The clock supports UNIPHY and PON modes, with configurable dividers.
> diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
> index 020ad12ca1f2b..1ae32052b5634 100644
> --- a/drivers/clk/qcom/ipq-cmn-pll.c
> +++ b/drivers/clk/qcom/ipq-cmn-pll.c
[ ... ]
> @@ -540,6 +545,155 @@ static struct clk_hw *ipq_cmn_pll_ppe_register(struct platform_device *pdev,
> return &ppe_clk->hw;
> }
>
> +/*
> + * PON (Passive Optical Network) reference clock operations.
> + * The PON refclk is derived from CMN PLL rate / 2, then divided by
> + * a configurable 8-bit divider (1-255).
> + */
[ ... ]
> +static unsigned long clk_pon_refclk_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_cmn_pll *pon_clk = to_clk_cmn_pll(hw);
> + u32 val, div;
> +
> + regmap_read(pon_clk->regmap, CMN_PLL_PON_CONFIG, &val);
> +
> + /* Check if in UNIPHY mode (bit 9 = 0) - fixed 31.25 MHz */
> + if (!(val & CMN_PLL_PON_MODE_SEL))
[Severity: Medium]
Could this use uninitialized memory if the underlying MMIO read fails?
The return value of regmap_read() is a standard negative error code on failure.
Since it is not checked, val may be left uninitialized if the read fails,
causing garbage clock rates to be returned to the framework.
> + return 31250000UL;
> +
> + /* PON mode: calculate from divider */
> + div = FIELD_GET(CMN_PLL_PON_DIV_CTRL, val);
> + if (WARN_ON_ONCE(!div))
> + return 0;
> +
> + return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * div);
> +}
> +
> +static int clk_pon_refclk_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + unsigned long div;
> +
> + if (WARN_ON_ONCE(!req->rate))
> + return 0;
[Severity: Medium]
Should this return a negative error code (like -EINVAL) instead of 0?
Returning 0 tells the Common Clock Framework that the rate request was
successfully determined and adapted, which will cause it to proceed to call
set_rate() with rate = 0.
> +
> + /* UNIPHY fixed mode */
> + if (req->rate == 31250000UL)
> + return 0;
[Severity: Medium]
Does this exact match prevent near-match rounding to UNIPHY mode?
If a consumer requests 31249999 Hz, it seems it would bypass this exact match
and fall back to calculating a PON mode divider. This might yield a worse
rate, even though the hardware inherently supports exactly 31.25 MHz.
> +
> + div = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * req->rate);
[Severity: High]
Can this cause a divide-by-zero panic on 32-bit platforms?
DIV_ROUND_CLOSEST_ULL() internally uses do_div(), which fundamentally
requires a 32-bit divisor. When the requested rate is large enough,
2ULL * req->rate can exceed 32 bits. On 32-bit platforms, do_div() silently
truncates the 64-bit divisor to 32 bits, which could result in a divisor of 0.
> +
> + /* Clamp to valid range (1-255) */
> + div = clamp_t(unsigned long, div, 1, 255);
> +
> + req->rate = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, 2ULL * div);
> + return 0;
> +}
> +
> +static int clk_pon_refclk_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_cmn_pll *pon_clk = to_clk_cmn_pll(hw);
> + unsigned long div;
> + int ret;
> +
> + if (rate == 0)
> + return -EINVAL;
> +
> + /* UNIPHY fixed mode (31.25 MHz) */
> + if (rate == 31250000UL)
> + return regmap_clear_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
> + CMN_PLL_PON_MODE_SEL);
[Severity: Medium]
Is it intentional to bypass the analog soft reset here?
The soft reset is performed at the end of the function for PON mode. If
entering UNIPHY mode also requires a soft reset to reliably latch or
stabilize the new clock output, the hardware might be left in an
inconsistent state.
> +
> + div = DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * rate);
[Severity: High]
Can this cause a divide-by-zero panic on 32-bit platforms?
Similar to the determine_rate callback, the 64-bit expression 2ULL * rate
is passed to a macro that expects a 32-bit divisor.
> + if (div == 0 || div > 255)
> + return -EINVAL;
> +
> + /* Switch to PON mode */
> + ret = regmap_set_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
> + CMN_PLL_PON_MODE_SEL);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(pon_clk->regmap, CMN_PLL_PON_CONFIG,
> + CMN_PLL_PON_DIV_CTRL,
> + FIELD_PREP(CMN_PLL_PON_DIV_CTRL, div));
[Severity: Medium]
Can this sequential update cause transient invalid clock states?
There is a brief window where the mode bit is set to PON mode, but the
divider has not yet been updated. If the previous divider was 0 or
inappropriate, it might expose downstream hardware to an invalid
frequency or glitch.
> + if (ret)
> + return ret;
> +
> + return clk_cmn_pll_ana_soft_reset(pon_clk->regmap);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724-qcom_ipq5210_cmnpll-v1-0-a8b8679d215f@oss.qualcomm.com?part=6
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 07/12] clk: qcom: ipq-cmn-pll: Add EPHY-RAW clock support
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (5 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 06/12] clk: qcom: ipq-cmn-pll: Add PON reference " Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:00 ` [PATCH 08/12] clk: composite: Export devm_clk_hw_register_composite_pdata Luo Jie
` (4 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
The EPHY-RAW clock is an IPQ5210-specific output from the CMN PLL that
provides the raw reference clock to the SoC-integrated Ethernet PHY
(EPHY), which supports up to 2.5G link speed. The output frequency is
selected via bit 10 (CMN_PLL_GEPHY_312P5M_125M_SEL) of the
CMN_PLL_PON_CONFIG register:
- 0: 125 MHz - for 1G/100M/10M link speed
- 1: 312.5 MHz - for 2.5G link speed
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 86 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index 1ae32052b563..dfc28c12468b 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -76,6 +76,7 @@
#define CMN_PLL_PON_MODE_SEL BIT(9)
#define CMN_PLL_PON_EN BIT(8)
#define CMN_PLL_PON_DIV_CTRL GENMASK(7, 0)
+#define CMN_PLL_GEPHY_312P5M_125M_SEL BIT(10)
#define CMN_PLL_POWER_ON_AND_RESET 0x780
#define CMN_ANA_EN_SW_RSTN BIT(6)
@@ -694,6 +695,87 @@ static struct clk_hw *ipq_cmn_pll_pon_refclk_register(struct platform_device *pd
return &pon_clk->hw;
}
+/*
+ * EPHY-RAW clock operations for IPQ5210.
+ * The output clock rate is selected via bit 10 of CMN_PLL_PON_CONFIG:
+ * 0: 125 MHz (for 1G link speed)
+ * 1: 312.5 MHz (for 2.5G link speed)
+ */
+static unsigned long clk_ephy_raw_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *ephy_raw_clk = to_clk_cmn_pll(hw);
+ u32 val;
+
+ regmap_read(ephy_raw_clk->regmap, CMN_PLL_PON_CONFIG, &val);
+
+ if (val & CMN_PLL_GEPHY_312P5M_125M_SEL)
+ return 312500000UL;
+
+ return 125000000UL;
+}
+
+static int clk_ephy_raw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ if (req->rate <= 125000000UL)
+ req->rate = 125000000UL;
+ else
+ req->rate = 312500000UL;
+
+ return 0;
+}
+
+static int clk_ephy_raw_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_cmn_pll *ephy_raw_clk = to_clk_cmn_pll(hw);
+
+ if (rate == 125000000UL)
+ return regmap_clear_bits(ephy_raw_clk->regmap,
+ CMN_PLL_PON_CONFIG,
+ CMN_PLL_GEPHY_312P5M_125M_SEL);
+
+ return regmap_set_bits(ephy_raw_clk->regmap,
+ CMN_PLL_PON_CONFIG,
+ CMN_PLL_GEPHY_312P5M_125M_SEL);
+}
+
+static const struct clk_ops clk_ephy_raw_ops = {
+ .recalc_rate = clk_ephy_raw_recalc_rate,
+ .determine_rate = clk_ephy_raw_determine_rate,
+ .set_rate = clk_ephy_raw_set_rate,
+};
+
+static struct clk_hw *ipq_cmn_pll_ephy_raw_register(struct platform_device *pdev,
+ struct regmap *regmap,
+ struct clk_hw *cmn_pll_hw)
+{
+ struct clk_parent_data pdata = { .hw = cmn_pll_hw };
+ struct clk_cmn_pll *ephy_raw_clk;
+ struct device *dev = &pdev->dev;
+ struct clk_init_data init = {};
+ int ret;
+
+ ephy_raw_clk = devm_kzalloc(dev, sizeof(*ephy_raw_clk), GFP_KERNEL);
+ if (!ephy_raw_clk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = "ephy-raw";
+ init.parent_data = &pdata;
+ init.num_parents = 1;
+ init.ops = &clk_ephy_raw_ops;
+
+ ephy_raw_clk->hw.init = &init;
+ ephy_raw_clk->regmap = regmap;
+
+ ret = devm_clk_hw_register(dev, &ephy_raw_clk->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &ephy_raw_clk->hw;
+}
+
static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
{
const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
@@ -747,6 +829,10 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
hw = ipq_cmn_pll_pon_refclk_register(pdev,
cmn_pll->regmap,
cmn_pll_hw);
+ } else if (!strcmp(fixed_clk[i].name, "ephy-raw")) {
+ hw = ipq_cmn_pll_ephy_raw_register(pdev,
+ cmn_pll->regmap,
+ cmn_pll_hw);
} else {
continue;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 08/12] clk: composite: Export devm_clk_hw_register_composite_pdata
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (6 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 07/12] clk: qcom: ipq-cmn-pll: Add EPHY-RAW " Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 16:01 ` Brian Masney
2026-07-24 15:00 ` [PATCH 09/12] clk: qcom: ipq-cmn-pll: Add clock gate support for fixed clocks Luo Jie
` (3 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
devm_clk_hw_register_composite_pdata() is defined but not exported,
preventing its use from loadable modules. Add EXPORT_SYMBOL_GPL() so
that out-of-tree and built-as-module clock drivers can call it.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/clk-composite.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 835b1e4e5869..11842bce5918 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -462,3 +462,4 @@ struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev,
rate_hw, rate_ops, gate_hw,
gate_ops, flags);
}
+EXPORT_SYMBOL_GPL(devm_clk_hw_register_composite_pdata);
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 08/12] clk: composite: Export devm_clk_hw_register_composite_pdata
2026-07-24 15:00 ` [PATCH 08/12] clk: composite: Export devm_clk_hw_register_composite_pdata Luo Jie
@ 2026-07-24 16:01 ` Brian Masney
0 siblings, 0 replies; 18+ messages in thread
From: Brian Masney @ 2026-07-24 16:01 UTC (permalink / raw)
To: Luo Jie
Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, linux-arm-msm,
linux-clk, linux-kernel, devicetree, quic_kkumarcs, quic_linchen,
quic_leiwei, quic_suruchia
On Fri, Jul 24, 2026 at 08:00:30AM -0700, Luo Jie wrote:
> devm_clk_hw_register_composite_pdata() is defined but not exported,
> preventing its use from loadable modules. Add EXPORT_SYMBOL_GPL() so
> that out-of-tree and built-as-module clock drivers can call it.
>
> Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
FYI there's a separate series for the UltraRISC DP1000 SoC to export
this same symbol. It depends on which series Stephen merges first gets
in.
https://lore.kernel.org/linux-clk/20260720-ultrarisc-clock-v4-1-fe639d63bbac@ultrarisc.com/
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 09/12] clk: qcom: ipq-cmn-pll: Add clock gate support for fixed clocks
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (7 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 08/12] clk: composite: Export devm_clk_hw_register_composite_pdata Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:00 ` [PATCH 10/12] clk: qcom: ipq-cmn-pll: Add all output clocks for IPQ5210 Luo Jie
` (2 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
Some CMN PLL output clocks require a hardware gate in addition to a
fixed rate. The gate control bits reside in the register
CMN_PLL_OUTPUT_RELATED_1 (0x79c). Each such clock is registered as a
composite clock combining a clk_fixed_rate provider with a clk_gate.
The enable_bit field is added to struct cmn_pll_fixed_output_clk (set to
-1 for non-gated clocks). The CLK_PLL_OUTPUT_RAW() and CLK_PLL_GATE()
helper macros are introduced alongside the existing CLK_PLL_OUTPUT(). The
base MMIO address is added to struct clk_cmn_pll to allow gate clock
registration to locate the output control register.
Since CMN_PLL_OUTPUT_RELATED_1 is shared by all of these gate clocks,
protect it with a single spinlock stored in struct clk_cmn_pll, so that
concurrent enable and disable calls on different gate clocks correctly
serialize their read-modify-write access to the shared register.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 86 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index dfc28c12468b..00e243282b31 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -92,34 +92,62 @@
#define CMN_PLL_DIVIDER_CTRL 0x794
#define CMN_PLL_DIVIDER_CTRL_FACTOR GENMASK(9, 0)
+/* Clock gate enable bits. */
+#define CMN_PLL_OUTPUT_RELATED_1 0x79c
+#define CLK25M_EN_BIT 15
+#define CLK50M_EN_BIT3_BIT 14
+#define CLK250M_EN_BIT 13
+#define CLK31P25M_EN_BIT 12
+#define CLK50M_EN_BIT 11
+#define CLK50M_EN_BIT2_BIT 10
+
/**
* struct cmn_pll_fixed_output_clk - CMN PLL output clocks information
* @id: Clock specifier to be supplied
* @name: Clock name to be registered
* @rate: Clock rate
+ * @enable_bit: Enable bit in CMN_PLL_OUTPUT_RELATED_1 for gate clock,
+ * -1 for non-gated clocks.
*/
struct cmn_pll_fixed_output_clk {
unsigned int id;
const char *name;
unsigned long rate;
+ int enable_bit;
};
/**
* struct clk_cmn_pll - CMN PLL hardware specific data
* @regmap: hardware regmap.
+ * @base: register base address for gate clock registration
+ * @gate_lock: protects read-modify-write access to CMN_PLL_OUTPUT_RELATED_1,
+ * which is shared by multiple gate clocks
* @hw: handle between common and hardware-specific interfaces
+ *
+ * This structure is used for all CMN PLL-derived clocks including
+ * the main PLL, NSS clock, PPE clock, PON reference clock, and
+ * EPHY-RAW clock.
*/
struct clk_cmn_pll {
struct regmap *regmap;
+ void __iomem *base;
+ spinlock_t gate_lock;
struct clk_hw hw;
};
-#define CLK_PLL_OUTPUT(_id, _name, _rate) { \
+#define CLK_PLL_OUTPUT_RAW(_id, _name, _rate, _bit) { \
.id = _id, \
.name = _name, \
.rate = _rate, \
+ .enable_bit = _bit, \
}
+#define CLK_PLL_OUTPUT(_id, _name, _rate) \
+ CLK_PLL_OUTPUT_RAW(_id, _name, _rate, -1)
+
+#define CLK_PLL_GATE(_id, _name, _rate, _bit) \
+ CLK_PLL_OUTPUT_RAW(_id, _name, _rate, _bit)
+
#define to_clk_cmn_pll(_hw) container_of(_hw, struct clk_cmn_pll, hw)
static const struct regmap_config ipq_cmn_pll_regmap_config = {
@@ -368,6 +396,8 @@ static struct clk_hw *ipq_cmn_pll_clk_hw_register(struct platform_device *pdev)
cmn_pll->hw.init = &init;
cmn_pll->regmap = regmap;
+ cmn_pll->base = base;
+ spin_lock_init(&cmn_pll->gate_lock);
ret = devm_clk_hw_register(dev, &cmn_pll->hw);
if (ret)
@@ -776,6 +806,50 @@ static struct clk_hw *ipq_cmn_pll_ephy_raw_register(struct platform_device *pdev
return &ephy_raw_clk->hw;
}
+/*
+ * Register a composite clock that combines a fixed-rate clock with a gate.
+ * The gate control bit lives in CMN_PLL_OUTPUT_RELATED_1, which is shared
+ * across multiple gate clocks, so all of them must use the same lock.
+ */
+static struct clk_hw *ipq_cmn_pll_register_fixed_gate(struct device *dev,
+ const char *name,
+ struct clk_hw *parent_hw,
+ unsigned long rate,
+ void __iomem *base,
+ spinlock_t *lock,
+ u8 enable_bit)
+{
+ struct clk_parent_data pdata = { .hw = parent_hw };
+ struct clk_fixed_rate *fixed;
+ struct clk_gate *gate;
+
+ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL);
+ if (!fixed)
+ return ERR_PTR(-ENOMEM);
+
+ gate->reg = base + CMN_PLL_OUTPUT_RELATED_1;
+ gate->bit_idx = enable_bit;
+ gate->lock = lock;
+
+ fixed->fixed_rate = rate;
+
+ /*
+ * These gated clocks may be relied on by external hardware or
+ * bootloader-enabled paths without an in-kernel client driver.
+ * Add CLK_IGNORE_UNUSED so the clock framework does not disable
+ * them when no consumer has claimed them.
+ */
+ return devm_clk_hw_register_composite_pdata(dev, name, &pdata, 1,
+ NULL, NULL,
+ &fixed->hw, &clk_fixed_rate_ops,
+ &gate->hw, &clk_gate_ops,
+ CLK_IGNORE_UNUSED);
+}
+
static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
{
const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
@@ -812,7 +886,15 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
/* Register the fixed rate output clocks. */
for (i = 0; i < num_clks; i++) {
- if (fixed_clk[i].rate) {
+ if (fixed_clk[i].enable_bit != -1) {
+ hw = ipq_cmn_pll_register_fixed_gate(dev,
+ fixed_clk[i].name,
+ cmn_pll_hw,
+ fixed_clk[i].rate,
+ cmn_pll->base,
+ &cmn_pll->gate_lock,
+ fixed_clk[i].enable_bit);
+ } else if (fixed_clk[i].rate) {
struct clk_parent_data pdata = { .hw = cmn_pll_hw };
hw = devm_clk_hw_register_fixed_rate_parent_data(dev,
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 10/12] clk: qcom: ipq-cmn-pll: Add all output clocks for IPQ5210
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (8 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 09/12] clk: qcom: ipq-cmn-pll: Add clock gate support for fixed clocks Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:00 ` [PATCH 11/12] arm64: dts: qcom: ipq5210: Add CMN PLL device node Luo Jie
2026-07-24 15:00 ` [PATCH 12/12] arm64: dts: qcom: Update IPQ5210 xo_board to use fixed factor clock Luo Jie
11 siblings, 0 replies; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
Add the IPQ5210 output clock array and the device match table entry,
wiring together all the infrastructure added in the previous patches.
The IPQ5210 CMN PLL supplies 12 output clocks:
Fixed-rate: XO 24 MHz, sleep 32 kHz
Gated fixed-rate: PCS 31.25 MHz, ETH0/1/2 50 MHz, EPHY 50 MHz,
ETH 25 MHz
Configurable divider: NSS, PPE
PON reference: PON (enable/disable + 8-bit divider)
EPHY-RAW: 125/312.5 MHz select
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
drivers/clk/qcom/ipq-cmn-pll.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index 00e243282b31..902a222e4533 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -55,6 +55,7 @@
#include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
+#include <dt-bindings/clock/qcom,ipq5210-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq5332-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq6018-cmn-pll.h>
@@ -164,6 +165,22 @@ static const struct cmn_pll_fixed_output_clk ipq5018_output_clks[] = {
{ /* Sentinel */ }
};
+static const struct cmn_pll_fixed_output_clk ipq5210_output_clks[] = {
+ CLK_PLL_OUTPUT(IPQ5210_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
+ CLK_PLL_OUTPUT(IPQ5210_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
+ CLK_PLL_GATE(IPQ5210_PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL, CLK31P25M_EN_BIT),
+ CLK_PLL_GATE(IPQ5210_ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL, CLK50M_EN_BIT),
+ CLK_PLL_GATE(IPQ5210_ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL, CLK50M_EN_BIT2_BIT),
+ CLK_PLL_GATE(IPQ5210_ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL, CLK50M_EN_BIT3_BIT),
+ CLK_PLL_GATE(IPQ5210_EPHY_50MHZ_CLK, "ephy-50mhz", 50000000UL, CLK250M_EN_BIT),
+ CLK_PLL_GATE(IPQ5210_ETH_25MHZ_CLK, "eth-25mhz", 25000000UL, CLK25M_EN_BIT),
+ CLK_PLL_OUTPUT(IPQ5210_NSS_CLK, "nss", 0),
+ CLK_PLL_OUTPUT(IPQ5210_PPE_CLK, "ppe", 0),
+ CLK_PLL_OUTPUT(IPQ5210_PON_REFCLK, "pon", 0),
+ CLK_PLL_OUTPUT(IPQ5210_EPHY_RAW_CLK, "ephy-raw", 0),
+ { /* Sentinel */ }
+};
+
static const struct cmn_pll_fixed_output_clk ipq6018_output_clks[] = {
CLK_PLL_OUTPUT(IPQ6018_BIAS_PLL_CC_CLK, "bias_pll_cc_clk", 300000000UL),
CLK_PLL_OUTPUT(IPQ6018_BIAS_PLL_NSS_NOC_CLK, "bias_pll_nss_noc_clk", 416500000UL),
@@ -986,6 +1003,7 @@ static const struct dev_pm_ops ipq_cmn_pll_pm_ops = {
static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
{ .compatible = "qcom,ipq5018-cmn-pll", .data = &ipq5018_output_clks },
+ { .compatible = "qcom,ipq5210-cmn-pll", .data = &ipq5210_output_clks },
{ .compatible = "qcom,ipq5332-cmn-pll", .data = &ipq5332_output_clks },
{ .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
{ .compatible = "qcom,ipq6018-cmn-pll", .data = &ipq6018_output_clks },
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 11/12] arm64: dts: qcom: ipq5210: Add CMN PLL device node
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (9 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 10/12] clk: qcom: ipq-cmn-pll: Add all output clocks for IPQ5210 Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
2026-07-24 15:00 ` [PATCH 12/12] arm64: dts: qcom: Update IPQ5210 xo_board to use fixed factor clock Luo Jie
11 siblings, 0 replies; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
Add CMN PLL node for enabling output clocks to the networking
hardware blocks on IPQ5210 devices.
The reference clock of CMN PLL is routed from XO to the CMN PLL
through the WiFi block.
XO (48 MHZ or 96 MHZ or 192 MHZ)-->WiFi (multiplier/divider)-->
48 MHZ to CMN PLL.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts | 15 +++++++++++++++
arch/arm64/boot/dts/qcom/ipq5210.dtsi | 24 ++++++++++++++++++++++++
2 files changed, 39 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts b/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts
index 941f866ecfe9..7410d092814e 100644
--- a/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts
+++ b/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts
@@ -74,6 +74,21 @@ &uart1 {
status = "okay";
};
+/*
+ * The bootstrap pins for the board select the XO clock frequency that
+ * supports 48 MHZ, 96 MHZ or 192 MHZ. This setting automatically
+ * enables the right dividers, to ensure the reference clock output
+ * from WiFi to the CMN PLL is 48 MHZ.
+ */
+&ref_48mhz_clk {
+ clock-div = <1>;
+ clock-mult = <1>;
+};
+
&xo_board {
clock-frequency = <24000000>;
};
+
+&xo_clk {
+ clock-frequency = <48000000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/ipq5210.dtsi b/arch/arm64/boot/dts/qcom/ipq5210.dtsi
index 2cdc10529c48..9bbd55cc1e75 100644
--- a/arch/arm64/boot/dts/qcom/ipq5210.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5210.dtsi
@@ -5,6 +5,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,ipq5210-gcc.h>
+#include <dt-bindings/clock/qcom,ipq5210-cmn-pll.h>
#include <dt-bindings/reset/qcom,ipq5210-gcc.h>
/ {
@@ -13,6 +14,12 @@ / {
interrupt-parent = <&intc>;
clocks {
+ ref_48mhz_clk: ref-48mhz-clk {
+ compatible = "fixed-factor-clock";
+ clocks = <&xo_clk>;
+ #clock-cells = <0>;
+ };
+
sleep_clk: sleep-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -22,6 +29,11 @@ xo_board: xo-board-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
};
+
+ xo_clk: xo-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
};
cpus {
@@ -141,6 +153,18 @@ tlmm: pinctrl@1000000 {
#interrupt-cells = <2>;
};
+ cmn_pll: clock-controller@9b000 {
+ compatible = "qcom,ipq5210-cmn-pll";
+ reg = <0x0 0x0009b000 0x0 0x800>;
+ clocks = <&ref_48mhz_clk>,
+ <&gcc GCC_CMN_12GPLL_AHB_CLK>,
+ <&gcc GCC_CMN_12GPLL_SYS_CLK>;
+ clock-names = "ref", "ahb", "sys";
+ #clock-cells = <1>;
+ assigned-clocks = <&cmn_pll IPQ5210_CMN_PLL_CLK>;
+ assigned-clock-rates-u64 = /bits/ 64 <12000000000>;
+ };
+
gcc: clock-controller@1800000 {
compatible = "qcom,ipq5210-gcc";
reg = <0x0 0x01800000 0x0 0x40000>;
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 12/12] arm64: dts: qcom: Update IPQ5210 xo_board to use fixed factor clock
2026-07-24 15:00 [PATCH 00/12] clk: qcom: ipq-cmn-pll: Add IPQ5210 CMN PLL support Luo Jie
` (10 preceding siblings ...)
2026-07-24 15:00 ` [PATCH 11/12] arm64: dts: qcom: ipq5210: Add CMN PLL device node Luo Jie
@ 2026-07-24 15:00 ` Luo Jie
11 siblings, 0 replies; 18+ messages in thread
From: Luo Jie @ 2026-07-24 15:00 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, quic_kkumarcs,
quic_linchen, quic_leiwei, quic_suruchia, Luo Jie
xo_board is fixed to 24 MHZ, which is routed from WiFi output clock
48 MHZ (also being the reference clock of CMN PLL) divided 2 by
analog block routing channel.
Signed-off-by: Luo Jie <jie.luo@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts | 7 ++++++-
arch/arm64/boot/dts/qcom/ipq5210.dtsi | 3 ++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts b/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts
index 7410d092814e..fa537633d5f5 100644
--- a/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts
+++ b/arch/arm64/boot/dts/qcom/ipq5210-rdp504.dts
@@ -85,8 +85,13 @@ &ref_48mhz_clk {
clock-mult = <1>;
};
+/*
+ * The frequency of xo_board is fixed to 24 MHZ, which is routed
+ * from WiFi output clock 48 MHZ divided by 2.
+ */
&xo_board {
- clock-frequency = <24000000>;
+ clock-div = <2>;
+ clock-mult = <1>;
};
&xo_clk {
diff --git a/arch/arm64/boot/dts/qcom/ipq5210.dtsi b/arch/arm64/boot/dts/qcom/ipq5210.dtsi
index 9bbd55cc1e75..45026f7835bf 100644
--- a/arch/arm64/boot/dts/qcom/ipq5210.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5210.dtsi
@@ -26,7 +26,8 @@ sleep_clk: sleep-clk {
};
xo_board: xo-board-clk {
- compatible = "fixed-clock";
+ compatible = "fixed-factor-clock";
+ clocks = <&xo_clk>;
#clock-cells = <0>;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread