};
&xo_board_clk {
- clock-frequency = <24000000>;
+ clock-div = <4>;
+ clock-mult = <1>;
};
&blsp1_uart1 {
};
&xo_board_clk {
- clock-frequency = <24000000>;
+ clock-div = <4>;
+ clock-mult = <1>;
};
&blsp1_uart1 {
};
&xo_board_clk {
- clock-frequency = <24000000>;
+ clock-div = <4>;
+ clock-mult = <1>;
};
&blsp1_uart1 {
};
&xo_board_clk {
- clock-frequency = <24000000>;
+ clock-div = <4>;
+ clock-mult = <1>;
};
&blsp1_uart1 {
};
&xo_board_clk {
- clock-frequency = <24000000>;
+ clock-div = <4>;
+ clock-mult = <1>;
};
&blsp1_uart1 {
};
&xo_board_clk {
- clock-frequency = <24000000>;
+ clock-div = <4>;
+ clock-mult = <1>;
};
&blsp1_uart1 {
--- /dev/null
+From f81715a4c87c3b75ca2640bb61b6c66506061a64 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj@quicinc.com>
+Date: Fri, 3 Jan 2025 15:31:35 +0800
+Subject: clk: qcom: Add CMN PLL clock controller driver for IPQ SoC
+
+The CMN PLL clock controller supplies clocks to the hardware
+blocks that together make up the Ethernet function on Qualcomm
+IPQ SoCs and to GCC. The driver is initially supported for
+IPQ9574 SoC.
+
+The CMN PLL clock controller expects a reference input clock
+from the on-board Wi-Fi block acting as clock source. The input
+reference clock needs to be configured to one of the supported
+clock rates.
+
+The controller supplies a number of fixed-rate output clocks.
+For the IPQ9574, there is one output clock of 353 MHZ to PPE
+(Packet Process Engine) hardware block, three 50 MHZ output
+clocks and an additional 25 MHZ output clock supplied to the
+connected Ethernet devices. The PLL also supplies a 24 MHZ
+clock as XO and a 32 KHZ sleep clock to GCC, and one 31.25
+MHZ clock to PCS.
+
+Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
+Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20250103-qcom_ipq_cmnpll-v8-2-c89fb4d4849d@quicinc.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+---
+ drivers/clk/qcom/ipq-cmn-pll.c | 435 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 435 insertions(+)
+ create mode 100644 drivers/clk/qcom/ipq-cmn-pll.c
+
+(limited to 'drivers/clk/qcom/ipq-cmn-pll.c')
+
+--- /dev/null
++++ b/drivers/clk/qcom/ipq-cmn-pll.c
+@@ -0,0 +1,435 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ */
++
++/*
++ * CMN PLL block expects the reference clock from on-board Wi-Fi block,
++ * and supplies fixed rate clocks as output to the networking hardware
++ * blocks and to GCC. The networking related blocks include PPE (packet
++ * process engine), the externally connected PHY or switch devices, and
++ * the PCS.
++ *
++ * On the IPQ9574 SoC, there are three clocks with 50 MHZ and one clock
++ * with 25 MHZ which are output from the CMN PLL to Ethernet PHY (or switch),
++ * and one clock with 353 MHZ to PPE. The other fixed rate output clocks
++ * are supplied to GCC (24 MHZ as XO and 32 KHZ as sleep clock), and to PCS
++ * with 31.25 MHZ.
++ *
++ * +---------+
++ * | GCC |
++ * +--+---+--+
++ * AHB CLK| |SYS CLK
++ * V V
++ * +-------+---+------+
++ * | +-------------> eth0-50mhz
++ * REF CLK | IPQ9574 |
++ * -------->+ +-------------> eth1-50mhz
++ * | CMN PLL block |
++ * | +-------------> eth2-50mhz
++ * | |
++ * +----+----+----+---+-------------> eth-25mhz
++ * | | |
++ * V V V
++ * GCC PCS NSS/PPE
++ */
++
++#include <linux/bitfield.h>
++#include <linux/clk-provider.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/pm_clock.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++
++#include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
++
++#define CMN_PLL_REFCLK_SRC_SELECTION 0x28
++#define CMN_PLL_REFCLK_SRC_DIV GENMASK(9, 8)
++
++#define CMN_PLL_LOCKED 0x64
++#define CMN_PLL_CLKS_LOCKED BIT(8)
++
++#define CMN_PLL_POWER_ON_AND_RESET 0x780
++#define CMN_ANA_EN_SW_RSTN BIT(6)
++
++#define CMN_PLL_REFCLK_CONFIG 0x784
++#define CMN_PLL_REFCLK_EXTERNAL BIT(9)
++#define CMN_PLL_REFCLK_DIV GENMASK(8, 4)
++#define CMN_PLL_REFCLK_INDEX GENMASK(3, 0)
++
++#define CMN_PLL_CTRL 0x78c
++#define CMN_PLL_CTRL_LOCK_DETECT_EN BIT(15)
++
++#define CMN_PLL_DIVIDER_CTRL 0x794
++#define CMN_PLL_DIVIDER_CTRL_FACTOR GENMASK(9, 0)
++
++/**
++ * 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
++ */
++struct cmn_pll_fixed_output_clk {
++ unsigned int id;
++ const char *name;
++ unsigned long rate;
++};
++
++/**
++ * struct clk_cmn_pll - CMN PLL hardware specific data
++ * @regmap: hardware regmap.
++ * @hw: handle between common and hardware-specific interfaces
++ */
++struct clk_cmn_pll {
++ struct regmap *regmap;
++ struct clk_hw hw;
++};
++
++#define CLK_PLL_OUTPUT(_id, _name, _rate) { \
++ .id = _id, \
++ .name = _name, \
++ .rate = _rate, \
++}
++
++#define to_clk_cmn_pll(_hw) container_of(_hw, struct clk_cmn_pll, hw)
++
++static const struct regmap_config ipq_cmn_pll_regmap_config = {
++ .reg_bits = 32,
++ .reg_stride = 4,
++ .val_bits = 32,
++ .max_register = 0x7fc,
++ .fast_io = true,
++};
++
++static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
++ CLK_PLL_OUTPUT(XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
++ CLK_PLL_OUTPUT(SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
++ CLK_PLL_OUTPUT(PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
++ CLK_PLL_OUTPUT(NSS_1200MHZ_CLK, "nss-1200mhz", 1200000000UL),
++ CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
++ CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
++};
++
++/*
++ * CMN PLL has the single parent clock, which supports the several
++ * possible parent clock rates, each parent clock rate is reflected
++ * by the specific reference index value in the hardware.
++ */
++static int ipq_cmn_pll_find_freq_index(unsigned long parent_rate)
++{
++ int index = -EINVAL;
++
++ switch (parent_rate) {
++ case 25000000:
++ index = 3;
++ break;
++ case 31250000:
++ index = 4;
++ break;
++ case 40000000:
++ index = 6;
++ break;
++ case 48000000:
++ case 96000000:
++ /*
++ * Parent clock rate 48 MHZ and 96 MHZ take the same value
++ * of reference clock index. 96 MHZ needs the source clock
++ * divider to be programmed as 2.
++ */
++ index = 7;
++ break;
++ case 50000000:
++ index = 8;
++ break;
++ default:
++ break;
++ }
++
++ return index;
++}
++
++static unsigned long clk_cmn_pll_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
++ u32 val, factor;
++
++ /*
++ * The value of CMN_PLL_DIVIDER_CTRL_FACTOR is automatically adjusted
++ * by HW according to the parent clock rate.
++ */
++ regmap_read(cmn_pll->regmap, CMN_PLL_DIVIDER_CTRL, &val);
++ factor = FIELD_GET(CMN_PLL_DIVIDER_CTRL_FACTOR, val);
++
++ return parent_rate * 2 * factor;
++}
++
++static int clk_cmn_pll_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ int ret;
++
++ /* Validate the rate of the single parent clock. */
++ ret = ipq_cmn_pll_find_freq_index(req->best_parent_rate);
++
++ return ret < 0 ? ret : 0;
++}
++
++/*
++ * This function is used to initialize the CMN PLL to enable the fixed
++ * rate output clocks. It is expected to be configured once.
++ */
++static int clk_cmn_pll_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_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
++ * parent clock. The output clock rates are always of fixed value.
++ */
++ index = ipq_cmn_pll_find_freq_index(parent_rate);
++ if (index < 0)
++ return index;
++
++ ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG,
++ CMN_PLL_REFCLK_INDEX,
++ FIELD_PREP(CMN_PLL_REFCLK_INDEX, index));
++ if (ret)
++ return ret;
++
++ /*
++ * Update the source clock rate selection and source clock
++ * divider as 2 when the parent clock rate is 96 MHZ.
++ */
++ if (parent_rate == 96000000) {
++ ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG,
++ CMN_PLL_REFCLK_DIV,
++ FIELD_PREP(CMN_PLL_REFCLK_DIV, 2));
++ if (ret)
++ return ret;
++
++ ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_SRC_SELECTION,
++ CMN_PLL_REFCLK_SRC_DIV,
++ FIELD_PREP(CMN_PLL_REFCLK_SRC_DIV, 0));
++ if (ret)
++ return ret;
++ }
++
++ /* Enable PLL locked detect. */
++ ret = regmap_set_bits(cmn_pll->regmap, CMN_PLL_CTRL,
++ CMN_PLL_CTRL_LOCK_DETECT_EN);
++ if (ret)
++ return ret;
++
++ /*
++ * 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);
++}
++
++static const struct clk_ops clk_cmn_pll_ops = {
++ .recalc_rate = clk_cmn_pll_recalc_rate,
++ .determine_rate = clk_cmn_pll_determine_rate,
++ .set_rate = clk_cmn_pll_set_rate,
++};
++
++static struct clk_hw *ipq_cmn_pll_clk_hw_register(struct platform_device *pdev)
++{
++ struct clk_parent_data pdata = { .index = 0 };
++ struct device *dev = &pdev->dev;
++ struct clk_init_data init = {};
++ struct clk_cmn_pll *cmn_pll;
++ struct regmap *regmap;
++ void __iomem *base;
++ int ret;
++
++ base = devm_platform_ioremap_resource(pdev, 0);
++ if (IS_ERR(base))
++ return ERR_CAST(base);
++
++ regmap = devm_regmap_init_mmio(dev, base, &ipq_cmn_pll_regmap_config);
++ if (IS_ERR(regmap))
++ return ERR_CAST(regmap);
++
++ cmn_pll = devm_kzalloc(dev, sizeof(*cmn_pll), GFP_KERNEL);
++ if (!cmn_pll)
++ return ERR_PTR(-ENOMEM);
++
++ init.name = "cmn_pll";
++ init.parent_data = &pdata;
++ init.num_parents = 1;
++ init.ops = &clk_cmn_pll_ops;
++
++ cmn_pll->hw.init = &init;
++ cmn_pll->regmap = regmap;
++
++ ret = devm_clk_hw_register(dev, &cmn_pll->hw);
++ if (ret)
++ return ERR_PTR(ret);
++
++ return &cmn_pll->hw;
++}
++
++static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
++{
++ const struct cmn_pll_fixed_output_clk *fixed_clk;
++ struct clk_hw_onecell_data *hw_data;
++ struct device *dev = &pdev->dev;
++ struct clk_hw *cmn_pll_hw;
++ unsigned int num_clks;
++ struct clk_hw *hw;
++ int ret, i;
++
++ fixed_clk = ipq9574_output_clks;
++ num_clks = ARRAY_SIZE(ipq9574_output_clks);
++
++ hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, num_clks + 1),
++ GFP_KERNEL);
++ if (!hw_data)
++ return -ENOMEM;
++
++ /*
++ * Register the CMN PLL clock, which is the parent clock of
++ * the fixed rate output clocks.
++ */
++ cmn_pll_hw = ipq_cmn_pll_clk_hw_register(pdev);
++ if (IS_ERR(cmn_pll_hw))
++ return PTR_ERR(cmn_pll_hw);
++
++ /* 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;
++ }
++
++ hw_data->hws[fixed_clk[i].id] = hw;
++ }
++
++ /*
++ * Provide the CMN PLL clock. The clock rate of CMN PLL
++ * is configured to 12 GHZ by DT property assigned-clock-rates-u64.
++ */
++ hw_data->hws[CMN_PLL_CLK] = cmn_pll_hw;
++ hw_data->num = num_clks + 1;
++
++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
++ if (ret)
++ goto unregister_fixed_clk;
++
++ 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)
++{
++ struct device *dev = &pdev->dev;
++ int ret;
++
++ ret = devm_pm_runtime_enable(dev);
++ if (ret)
++ return ret;
++
++ ret = devm_pm_clk_create(dev);
++ if (ret)
++ return ret;
++
++ /*
++ * To access the CMN PLL registers, the GCC AHB & SYS clocks
++ * of CMN PLL block need to be enabled.
++ */
++ ret = pm_clk_add(dev, "ahb");
++ if (ret)
++ return dev_err_probe(dev, ret, "Fail to add AHB clock\n");
++
++ ret = pm_clk_add(dev, "sys");
++ if (ret)
++ return dev_err_probe(dev, ret, "Fail to add SYS clock\n");
++
++ ret = pm_runtime_resume_and_get(dev);
++ if (ret)
++ return ret;
++
++ /* Register CMN PLL clock and fixed rate output clocks. */
++ ret = ipq_cmn_pll_register_clks(pdev);
++ pm_runtime_put(dev);
++ if (ret)
++ return dev_err_probe(dev, ret,
++ "Fail to register CMN PLL clocks\n");
++
++ 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)
++};
++
++static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
++ { .compatible = "qcom,ipq9574-cmn-pll", },
++ { }
++};
++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,
++ .pm = &ipq_cmn_pll_pm_ops,
++ },
++};
++module_platform_driver(ipq_cmn_pll_clk_driver);
++
++MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPQ CMN PLL Driver");
++MODULE_LICENSE("GPL");
--- /dev/null
+From a2afa4c33f0a7f7f70d54a1bc5110e326753f982 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj@quicinc.com>
+Date: Tue, 10 Jun 2025 18:35:19 +0800
+Subject: clk: qcom: cmnpll: Add IPQ5424 SoC support
+
+The CMN PLL in IPQ5424 SoC supplies the fixed clock to NSS at 300 MHZ
+and to PPE at 375 MHZ. Other output clocks from CMN PLL on this SoC,
+and their rates are same as IPQ9574.
+
+Acked-by: Stephen Boyd <sboyd@kernel.org>
+Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
+Link: https://lore.kernel.org/r/20250610-qcom_ipq5424_cmnpll-v3-2-ceada8165645@quicinc.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+---
+ drivers/clk/qcom/ipq-cmn-pll.c | 35 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 30 insertions(+), 5 deletions(-)
+
+(limited to 'drivers/clk/qcom/ipq-cmn-pll.c')
+
+--- a/drivers/clk/qcom/ipq-cmn-pll.c
++++ b/drivers/clk/qcom/ipq-cmn-pll.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ /*
+- * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ /*
+@@ -16,6 +16,10 @@
+ * are supplied to GCC (24 MHZ as XO and 32 KHZ as sleep clock), and to PCS
+ * with 31.25 MHZ.
+ *
++ * On the IPQ5424 SoC, there is an output clock from CMN PLL to PPE at 375 MHZ,
++ * and an output clock to NSS (network subsystem) at 300 MHZ. The other output
++ * clocks from CMN PLL on IPQ5424 are the same as IPQ9574.
++ *
+ * +---------+
+ * | GCC |
+ * +--+---+--+
+@@ -46,6 +50,7 @@
+ #include <linux/regmap.h>
+
+ #include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
++#include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
+
+ #define CMN_PLL_REFCLK_SRC_SELECTION 0x28
+ #define CMN_PLL_REFCLK_SRC_DIV GENMASK(9, 8)
+@@ -115,6 +120,20 @@ static const struct cmn_pll_fixed_output
+ CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
+ CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
+ CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
++ { /* Sentinel */ }
++};
++
++static const struct cmn_pll_fixed_output_clk ipq5424_output_clks[] = {
++ CLK_PLL_OUTPUT(IPQ5424_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
++ CLK_PLL_OUTPUT(IPQ5424_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
++ CLK_PLL_OUTPUT(IPQ5424_PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
++ CLK_PLL_OUTPUT(IPQ5424_NSS_300MHZ_CLK, "nss-300mhz", 300000000UL),
++ CLK_PLL_OUTPUT(IPQ5424_PPE_375MHZ_CLK, "ppe-375mhz", 375000000UL),
++ CLK_PLL_OUTPUT(IPQ5424_ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(IPQ5424_ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(IPQ5424_ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(IPQ5424_ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
++ { /* Sentinel */ }
+ };
+
+ /*
+@@ -297,7 +316,7 @@ static struct clk_hw *ipq_cmn_pll_clk_hw
+
+ static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
+ {
+- const struct cmn_pll_fixed_output_clk *fixed_clk;
++ const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
+ struct clk_hw_onecell_data *hw_data;
+ struct device *dev = &pdev->dev;
+ struct clk_hw *cmn_pll_hw;
+@@ -305,8 +324,13 @@ static int ipq_cmn_pll_register_clks(str
+ struct clk_hw *hw;
+ int ret, i;
+
+- fixed_clk = ipq9574_output_clks;
+- num_clks = ARRAY_SIZE(ipq9574_output_clks);
++ fixed_clk = device_get_match_data(dev);
++ if (!fixed_clk)
++ return -EINVAL;
++
++ num_clks = 0;
++ for (p = fixed_clk; p->name; p++)
++ num_clks++;
+
+ hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, num_clks + 1),
+ GFP_KERNEL);
+@@ -415,7 +439,8 @@ static const struct dev_pm_ops ipq_cmn_p
+ };
+
+ static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
+- { .compatible = "qcom,ipq9574-cmn-pll", },
++ { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
++ { .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, ipq_cmn_pll_clk_ids);
--- /dev/null
+From 314b903c30040632db7edd187cd33003b2aee512 Mon Sep 17 00:00:00 2001
+From: George Moussalem <george.moussalem@outlook.com>
+Date: Fri, 16 May 2025 16:36:09 +0400
+Subject: dt-bindings: clock: qcom: Add CMN PLL support for IPQ5018 SoC
+
+The CMN PLL block in the IPQ5018 SoC takes 96 MHZ as the reference
+input clock. Its output clocks are the XO (24Mhz), sleep (32Khz), and
+ethernet (50Mhz) clocks.
+
+Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: George Moussalem <george.moussalem@outlook.com>
+Link: https://lore.kernel.org/r/20250516-ipq5018-cmn-pll-v4-2-389a6b30e504@outlook.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+---
+ include/dt-bindings/clock/qcom,ipq5018-cmn-pll.h | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+ create mode 100644 include/dt-bindings/clock/qcom,ipq5018-cmn-pll.h
+
+(limited to 'include/dt-bindings/clock/qcom,ipq5018-cmn-pll.h')
+
+--- /dev/null
++++ b/include/dt-bindings/clock/qcom,ipq5018-cmn-pll.h
+@@ -0,0 +1,16 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
++/*
++ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ */
++
++#ifndef _DT_BINDINGS_CLK_QCOM_IPQ5018_CMN_PLL_H
++#define _DT_BINDINGS_CLK_QCOM_IPQ5018_CMN_PLL_H
++
++/* CMN PLL core clock. */
++#define IPQ5018_CMN_PLL_CLK 0
++
++/* The output clocks from CMN PLL of IPQ5018. */
++#define IPQ5018_XO_24MHZ_CLK 1
++#define IPQ5018_SLEEP_32KHZ_CLK 2
++#define IPQ5018_ETH_50MHZ_CLK 3
++#endif
--- /dev/null
+From 25d12630561d8d0906f1f5eceb055da3af67c8c9 Mon Sep 17 00:00:00 2001
+From: George Moussalem <george.moussalem@outlook.com>
+Date: Fri, 16 May 2025 16:36:10 +0400
+Subject: clk: qcom: ipq-cmn-pll: Add IPQ5018 SoC support
+
+The CMN PLL in IPQ5018 SoC supplies fixed clocks to XO, sleep, and the
+ethernet block.
+
+Signed-off-by: George Moussalem <george.moussalem@outlook.com>
+Link: https://lore.kernel.org/r/20250516-ipq5018-cmn-pll-v4-3-389a6b30e504@outlook.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+---
+ drivers/clk/qcom/ipq-cmn-pll.c | 37 +++++++++++++++++++++++--------------
+ 1 file changed, 23 insertions(+), 14 deletions(-)
+
+(limited to 'drivers/clk/qcom/ipq-cmn-pll.c')
+
+--- a/drivers/clk/qcom/ipq-cmn-pll.c
++++ b/drivers/clk/qcom/ipq-cmn-pll.c
+@@ -50,6 +50,7 @@
+ #include <linux/regmap.h>
+
+ #include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
++#include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
+ #include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
+
+ #define CMN_PLL_REFCLK_SRC_SELECTION 0x28
+@@ -110,16 +111,10 @@ static const struct regmap_config ipq_cm
+ .fast_io = true,
+ };
+
+-static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
+- CLK_PLL_OUTPUT(XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
+- CLK_PLL_OUTPUT(SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
+- CLK_PLL_OUTPUT(PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
+- CLK_PLL_OUTPUT(NSS_1200MHZ_CLK, "nss-1200mhz", 1200000000UL),
+- CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
+- CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
+- CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
+- CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
+- CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
++static const struct cmn_pll_fixed_output_clk ipq5018_output_clks[] = {
++ CLK_PLL_OUTPUT(IPQ5018_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
++ CLK_PLL_OUTPUT(IPQ5018_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
++ CLK_PLL_OUTPUT(IPQ5018_ETH_50MHZ_CLK, "eth-50mhz", 50000000UL),
+ { /* Sentinel */ }
+ };
+
+@@ -136,6 +131,19 @@ static const struct cmn_pll_fixed_output
+ { /* Sentinel */ }
+ };
+
++static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
++ CLK_PLL_OUTPUT(XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
++ CLK_PLL_OUTPUT(SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
++ CLK_PLL_OUTPUT(PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
++ CLK_PLL_OUTPUT(NSS_1200MHZ_CLK, "nss-1200mhz", 1200000000UL),
++ CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
++ CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
++ CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
++ { /* Sentinel */ }
++};
++
+ /*
+ * CMN PLL has the single parent clock, which supports the several
+ * possible parent clock rates, each parent clock rate is reflected
+@@ -399,11 +407,11 @@ static int ipq_cmn_pll_clk_probe(struct
+ */
+ ret = pm_clk_add(dev, "ahb");
+ if (ret)
+- return dev_err_probe(dev, ret, "Fail to add AHB clock\n");
++ return dev_err_probe(dev, ret, "Failed to add AHB clock\n");
+
+ ret = pm_clk_add(dev, "sys");
+ if (ret)
+- return dev_err_probe(dev, ret, "Fail to add SYS clock\n");
++ return dev_err_probe(dev, ret, "Failed to add SYS clock\n");
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+@@ -414,7 +422,7 @@ static int ipq_cmn_pll_clk_probe(struct
+ pm_runtime_put(dev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+- "Fail to register CMN PLL clocks\n");
++ "Failed to register CMN PLL clocks\n");
+
+ return 0;
+ }
+@@ -439,8 +447,9 @@ static const struct dev_pm_ops ipq_cmn_p
+ };
+
+ static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
+- { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
++ { .compatible = "qcom,ipq5018-cmn-pll", .data = &ipq5018_output_clks },
+ { .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
++ { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, ipq_cmn_pll_clk_ids);
--- /dev/null
+From c006b249c54441dd8a3a493c7c87158f441f8178 Mon Sep 17 00:00:00 2001
+From: George Moussalem <george.moussalem@outlook.com>
+Date: Mon, 21 Jul 2025 10:04:35 +0400
+Subject: arm64: dts: ipq5018: Add CMN PLL node
+
+Add CMN PLL node for enabling output clocks to the networking
+hardware blocks on IPQ5018 devices.
+
+The reference clock of CMN PLL is routed from XO to the CMN PLL
+through the internal WiFi block.
+.XO (48 MHZ) --> WiFi (multiplier/divider)--> 96 MHZ to CMN PLL.
+
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Signed-off-by: George Moussalem <george.moussalem@outlook.com>
+Link: https://lore.kernel.org/r/20250721-ipq5018-cmn-pll-v5-1-4cbf3479af65@outlook.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/ipq5018.dtsi | 33 +++++++++++++++++++++++++++++++--
+ 1 file changed, 31 insertions(+), 2 deletions(-)
+
+(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
+
+--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+@@ -2,12 +2,13 @@
+ /*
+ * IPQ5018 SoC device tree source
+ *
+- * Copyright (c) 2023 The Linux Foundation. All rights reserved.
++ * Copyright (c) 2023-2025 The Linux Foundation. All rights reserved.
+ */
+
+ #include <dt-bindings/clock/qcom,apss-ipq.h>
+-#include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
++#include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
++#include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
+ #include <dt-bindings/thermal/thermal.h>
+
+@@ -29,6 +30,14 @@
+ #clock-cells = <0>;
+ };
+
++ ref_96mhz_clk: ref-96mhz-clk {
++ compatible = "fixed-factor-clock";
++ clocks = <&xo_clk>;
++ #clock-cells = <0>;
++ clock-div = <1>;
++ clock-mult = <2>;
++ };
++
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+@@ -38,6 +47,12 @@
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
++
++ xo_clk: xo-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <48000000>;
++ };
+ };
+
+ cpus {
+@@ -229,6 +244,20 @@
+ status = "disabled";
+ };
+
++ cmn_pll: clock-controller@9b000 {
++ compatible = "qcom,ipq5018-cmn-pll";
++ reg = <0x0009b000 0x800>;
++ clocks = <&ref_96mhz_clk>,
++ <&gcc GCC_CMN_BLK_AHB_CLK>,
++ <&gcc GCC_CMN_BLK_SYS_CLK>;
++ clock-names = "ref",
++ "ahb",
++ "sys";
++ #clock-cells = <1>;
++ assigned-clocks = <&cmn_pll IPQ5018_CMN_PLL_CLK>;
++ assigned-clock-rates-u64 = /bits/ 64 <9600000000>;
++ };
++
+ qfprom: qfprom@a0000 {
+ compatible = "qcom,ipq5018-qfprom", "qcom,qfprom";
+ reg = <0x000a0000 0x1000>;
--- /dev/null
+From 5ca3d42384a66bcb66f91d75da16ec9e9f053aab Mon Sep 17 00:00:00 2001
+From: George Moussalem <george.moussalem@outlook.com>
+Date: Mon, 21 Jul 2025 10:04:36 +0400
+Subject: arm64: dts: qcom: Update IPQ5018 xo_board_clk to use fixed factor
+ clock
+
+The xo_board_clk is fixed to 24 MHZ, which is routed from WiFi output
+clock 96 MHZ (also being the reference clock of CMN PLL) divided by 4
+to the analog block routing channel. Update the xo_board_clk nodes in
+the board DTS files to use clock-div/clock-mult accordingly.
+
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Signed-off-by: George Moussalem <george.moussalem@outlook.com>
+Link: https://lore.kernel.org/r/20250721-ipq5018-cmn-pll-v5-2-4cbf3479af65@outlook.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/ipq5018.dtsi | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+(limited to 'arch/arm64/boot/dts/qcom/ipq5018.dtsi')
+
+--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+@@ -44,7 +44,8 @@
+ };
+
+ xo_board_clk: xo-board-clk {
+- compatible = "fixed-clock";
++ compatible = "fixed-factor-clock";
++ clocks = <&ref_96mhz_clk>;
+ #clock-cells = <0>;
+ };
+
---
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -423,6 +423,16 @@
+@@ -453,6 +453,16 @@
reg = <0x01937000 0x21000>;
};
---
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -470,6 +470,16 @@
+@@ -500,6 +500,16 @@
status = "disabled";
};
---
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -494,6 +494,21 @@
+@@ -524,6 +524,21 @@
status = "disabled";
};
+++ /dev/null
-From 7b89dbf5c7dcd8a9c131721e93c1292e5993968b Mon Sep 17 00:00:00 2001
-From: Luo Jie <quic_luoj@quicinc.com>
-Date: Tue, 20 Aug 2024 22:02:42 +0800
-Subject: [PATCH] dt-bindings: clock: qcom: Add CMN PLL clock controller
- for IPQ SoC
-
-The CMN PLL controller provides clocks to networking hardware blocks
-on Qualcomm IPQ9574 SoC. It receives input clock from the on-chip Wi-Fi,
-and produces output clocks at fixed rates. These output rates are
-predetermined, and are unrelated to the input clock rate. The output
-clocks are supplied to the Ethernet hardware such as PPE (packet
-process engine) and the externally connected switch or PHY device.
-
-Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
----
- .../bindings/clock/qcom,ipq9574-cmn-pll.yaml | 70 +++++++++++++++++++
- include/dt-bindings/clock/qcom,ipq-cmn-pll.h | 15 ++++
- 2 files changed, 85 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
- create mode 100644 include/dt-bindings/clock/qcom,ipq-cmn-pll.h
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
-@@ -0,0 +1,70 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/clock/qcom,ipq9574-cmn-pll.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Qualcomm CMN PLL Clock Controller on IPQ SoC
-+
-+maintainers:
-+ - Bjorn Andersson <andersson@kernel.org>
-+ - Luo Jie <quic_luoj@quicinc.com>
-+
-+description:
-+ The CMN PLL clock controller expects a reference input clock.
-+ This reference clock is from the on-board Wi-Fi. The CMN PLL
-+ supplies a number of fixed rate output clocks to the Ethernet
-+ devices including PPE (packet process engine) and the connected
-+ switch or PHY device.
-+
-+properties:
-+ compatible:
-+ enum:
-+ - qcom,ipq9574-cmn-pll
-+
-+ reg:
-+ maxItems: 1
-+
-+ clocks:
-+ items:
-+ - description: The reference clock. The supported clock rates include
-+ 25000000, 31250000, 40000000, 48000000, 50000000 and 96000000 HZ.
-+ - description: The AHB clock
-+ - description: The SYS clock
-+ description:
-+ The reference clock is the source clock of CMN PLL, which is from the
-+ Wi-Fi. The AHB and SYS clocks must be enabled to access CMN PLL
-+ clock registers.
-+
-+ clock-names:
-+ items:
-+ - const: ref
-+ - const: ahb
-+ - const: sys
-+
-+ "#clock-cells":
-+ const: 1
-+
-+required:
-+ - compatible
-+ - reg
-+ - clocks
-+ - clock-names
-+ - "#clock-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ #include <dt-bindings/clock/qcom,ipq9574-gcc.h>
-+
-+ clock-controller@9b000 {
-+ compatible = "qcom,ipq9574-cmn-pll";
-+ reg = <0x0009b000 0x800>;
-+ clocks = <&cmn_pll_ref_clk>,
-+ <&gcc GCC_CMN_12GPLL_AHB_CLK>,
-+ <&gcc GCC_CMN_12GPLL_SYS_CLK>;
-+ clock-names = "ref", "ahb", "sys";
-+ #clock-cells = <1>;
-+ };
-+...
---- /dev/null
-+++ b/include/dt-bindings/clock/qcom,ipq-cmn-pll.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ_CMN_PLL_H
-+#define _DT_BINDINGS_CLK_QCOM_IPQ_CMN_PLL_H
-+
-+/* The output clocks from CMN PLL of IPQ9574. */
-+#define PPE_353MHZ_CLK 0
-+#define ETH0_50MHZ_CLK 1
-+#define ETH1_50MHZ_CLK 2
-+#define ETH2_50MHZ_CLK 3
-+#define ETH_25MHZ_CLK 4
-+#endif
+++ /dev/null
-From a7e8397e2db6133e3435054a3f312dbd9cab05ed Mon Sep 17 00:00:00 2001
-From: Luo Jie <quic_luoj@quicinc.com>
-Date: Tue, 20 Aug 2024 22:02:43 +0800
-Subject: [PATCH] clk: qcom: Add CMN PLL clock controller driver for IPQ
- SoC
-
-The CMN PLL clock controller supplies clocks to the hardware
-blocks that together make up the Ethernet function on Qualcomm
-IPQ SoCs. The driver is initially supported for IPQ9574 SoC.
-
-The CMN PLL clock controller expects a reference input clock
-from the on-board Wi-Fi block acting as clock source. The input
-reference clock needs to be configured to one of the supported
-clock rates.
-
-The controller supplies a number of fixed-rate output clocks.
-For the IPQ9574, there is one output clock of 353 MHZ to PPE
-(Packet Process Engine) hardware block, three 50 MHZ output
-clocks and an additional 25 MHZ output clock supplied to the
-connected Ethernet devices.
-
-Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
----
- drivers/clk/qcom/Kconfig | 10 ++
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/clk-ipq-cmn-pll.c | 227 +++++++++++++++++++++++++++++
- 3 files changed, 238 insertions(+)
- create mode 100644 drivers/clk/qcom/clk-ipq-cmn-pll.c
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -190,6 +190,16 @@ config IPQ_APSS_6018
- Say Y if you want to support CPU frequency scaling on
- ipq based devices.
-
-+config IPQ_CMN_PLL
-+ tristate "IPQ CMN PLL Clock Controller"
-+ depends on IPQ_GCC_9574
-+ help
-+ Support for CMN PLL clock controller on IPQ platform. The
-+ CMN PLL feeds the reference clocks to the Ethernet devices
-+ based on IPQ SoC.
-+ Say Y or M if you want to support CMN PLL clock on the IPQ
-+ based devices.
-+
- config IPQ_GCC_4019
- tristate "IPQ4019 Global Clock Controller"
- help
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -29,6 +29,7 @@ obj-$(CONFIG_CLK_X1E80100_TCSRCC) += tcs
- obj-$(CONFIG_CLK_QCM2290_GPUCC) += gpucc-qcm2290.o
- obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o
- obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o
-+obj-$(CONFIG_IPQ_CMN_PLL) += clk-ipq-cmn-pll.o
- obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
- obj-$(CONFIG_IPQ_GCC_5018) += gcc-ipq5018.o
- obj-$(CONFIG_IPQ_GCC_5332) += gcc-ipq5332.o
---- /dev/null
-+++ b/drivers/clk/qcom/clk-ipq-cmn-pll.c
-@@ -0,0 +1,227 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
-+ */
-+
-+/*
-+ * CMN PLL block expects the reference clock from on-board Wi-Fi block, and
-+ * supplies fixed rate clocks as output to the Ethernet hardware blocks.
-+ * The Ethernet related blocks include PPE (packet process engine) and the
-+ * external connected PHY (or switch) chip receiving clocks from the CMN PLL.
-+ *
-+ * On the IPQ9574 SoC, There are three clocks with 50 MHZ, one clock with
-+ * 25 MHZ which are output from the CMN PLL to Ethernet PHY (or switch),
-+ * and one clock with 353 MHZ to PPE.
-+ *
-+ * +---------+
-+ * | GCC |
-+ * +--+---+--+
-+ * AHB CLK| |SYS CLK
-+ * V V
-+ * +-------+---+------+
-+ * | +-------------> eth0-50mhz
-+ * REF CLK | IPQ9574 |
-+ * -------->+ +-------------> eth1-50mhz
-+ * | CMN PLL block |
-+ * | +-------------> eth2-50mhz
-+ * | |
-+ * +---------+--------+-------------> eth-25mhz
-+ * |
-+ * V
-+ * ppe-353mhz
-+ */
-+
-+#include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
-+#include <linux/bitfield.h>
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+
-+#define CMN_PLL_REFCLK_SRC_SELECTION 0x28
-+#define CMN_PLL_REFCLK_SRC_DIV GENMASK(9, 8)
-+
-+#define CMN_PLL_REFCLK_CONFIG 0x784
-+#define CMN_PLL_REFCLK_EXTERNAL BIT(9)
-+#define CMN_PLL_REFCLK_DIV GENMASK(8, 4)
-+#define CMN_PLL_REFCLK_INDEX GENMASK(3, 0)
-+
-+#define CMN_PLL_POWER_ON_AND_RESET 0x780
-+#define CMN_ANA_EN_SW_RSTN BIT(6)
-+
-+/**
-+ * 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
-+ */
-+struct cmn_pll_fixed_output_clk {
-+ unsigned int id;
-+ const char *name;
-+ const unsigned long rate;
-+};
-+
-+#define CLK_PLL_OUTPUT(_id, _name, _rate) { \
-+ .id = _id, \
-+ .name = _name, \
-+ .rate = _rate, \
-+}
-+
-+static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
-+ CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
-+ CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
-+ CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
-+ CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
-+ CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
-+};
-+
-+static int ipq_cmn_pll_config(struct device *dev, unsigned long parent_rate)
-+{
-+ void __iomem *base;
-+ u32 val;
-+
-+ base = devm_of_iomap(dev, dev->of_node, 0, NULL);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ val = readl(base + CMN_PLL_REFCLK_CONFIG);
-+ val &= ~(CMN_PLL_REFCLK_EXTERNAL | CMN_PLL_REFCLK_INDEX);
-+
-+ /*
-+ * Configure the reference input clock selection as per the given rate.
-+ * The output clock rates are always of fixed value.
-+ */
-+ switch (parent_rate) {
-+ case 25000000:
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_INDEX, 3);
-+ break;
-+ case 31250000:
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_INDEX, 4);
-+ break;
-+ case 40000000:
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_INDEX, 6);
-+ break;
-+ case 48000000:
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_INDEX, 7);
-+ break;
-+ case 50000000:
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_INDEX, 8);
-+ break;
-+ case 96000000:
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_INDEX, 7);
-+ val &= ~CMN_PLL_REFCLK_DIV;
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_DIV, 2);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ writel(val, base + CMN_PLL_REFCLK_CONFIG);
-+
-+ /* Update the source clock rate selection. Only 96 MHZ uses 0. */
-+ val = readl(base + CMN_PLL_REFCLK_SRC_SELECTION);
-+ val &= ~CMN_PLL_REFCLK_SRC_DIV;
-+ if (parent_rate != 96000000)
-+ val |= FIELD_PREP(CMN_PLL_REFCLK_SRC_DIV, 1);
-+
-+ writel(val, base + CMN_PLL_REFCLK_SRC_SELECTION);
-+
-+ /*
-+ * Reset the CMN PLL block by asserting/de-asserting for 100 ms
-+ * each, to ensure the updated configurations take effect.
-+ */
-+ val = readl(base + CMN_PLL_POWER_ON_AND_RESET);
-+ val &= ~CMN_ANA_EN_SW_RSTN;
-+ writel(val, base);
-+ msleep(100);
-+
-+ val |= CMN_ANA_EN_SW_RSTN;
-+ writel(val, base + CMN_PLL_POWER_ON_AND_RESET);
-+ msleep(100);
-+
-+ return 0;
-+}
-+
-+static int ipq_cmn_pll_clk_register(struct device *dev, const char *parent)
-+{
-+ const struct cmn_pll_fixed_output_clk *fixed_clk;
-+ struct clk_hw_onecell_data *data;
-+ unsigned int num_clks;
-+ struct clk_hw *hw;
-+ int i;
-+
-+ num_clks = ARRAY_SIZE(ipq9574_output_clks);
-+ fixed_clk = ipq9574_output_clks;
-+
-+ data = devm_kzalloc(dev, struct_size(data, hws, num_clks), GFP_KERNEL);
-+ if (!data)
-+ return -ENOMEM;
-+
-+ for (i = 0; i < num_clks; i++) {
-+ hw = devm_clk_hw_register_fixed_rate(dev, fixed_clk[i].name,
-+ parent, 0,
-+ fixed_clk[i].rate);
-+ if (IS_ERR(hw))
-+ return PTR_ERR(hw);
-+
-+ data->hws[fixed_clk[i].id] = hw;
-+ }
-+ data->num = num_clks;
-+
-+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
-+}
-+
-+static int ipq_cmn_pll_clk_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct clk *clk;
-+ int ret;
-+
-+ /*
-+ * To access the CMN PLL registers, the GCC AHB & SYSY clocks
-+ * for CMN PLL block need to be enabled.
-+ */
-+ clk = devm_clk_get_enabled(dev, "ahb");
-+ if (IS_ERR(clk))
-+ return dev_err_probe(dev, PTR_ERR(clk),
-+ "Enable AHB clock failed\n");
-+
-+ clk = devm_clk_get_enabled(dev, "sys");
-+ if (IS_ERR(clk))
-+ return dev_err_probe(dev, PTR_ERR(clk),
-+ "Enable SYS clock failed\n");
-+
-+ clk = devm_clk_get(dev, "ref");
-+ if (IS_ERR(clk))
-+ return dev_err_probe(dev, PTR_ERR(clk),
-+ "Get reference clock failed\n");
-+
-+ /* Configure CMN PLL to apply the reference clock. */
-+ ret = ipq_cmn_pll_config(dev, clk_get_rate(clk));
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Configure CMN PLL failed\n");
-+
-+ return ipq_cmn_pll_clk_register(dev, __clk_get_name(clk));
-+}
-+
-+static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
-+ { .compatible = "qcom,ipq9574-cmn-pll", },
-+ { }
-+};
-+
-+static struct platform_driver ipq_cmn_pll_clk_driver = {
-+ .probe = ipq_cmn_pll_clk_probe,
-+ .driver = {
-+ .name = "ipq_cmn_pll",
-+ .of_match_table = ipq_cmn_pll_clk_ids,
-+ },
-+};
-+
-+module_platform_driver(ipq_cmn_pll_clk_driver);
-+
-+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPQ CMN PLL Driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From a28797563b8c97c9abced82e0cf89302fcd2bf37 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:11 +0800
-Subject: [PATCH 1/2] clk: qcom: cmn-pll: add IPQ5018 support
-
-Add support for IPQ5018 (and removing dependency on the IPQ9574 platform).
-The common network block in IPQ5018 must be enabled first through a
-specific register at a fixed offset in the TCSR area, set in the DTS.
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
-Signed-off-by: George Moussalem <george.moussalem@outlook.com>
----
- drivers/clk/qcom/Kconfig | 1 -
- drivers/clk/qcom/clk-ipq-cmn-pll.c | 29 +++++++++++++++++++++++++++++
- 2 files changed, 29 insertions(+), 1 deletion(-)
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -192,7 +192,6 @@ config IPQ_APSS_6018
-
- config IPQ_CMN_PLL
- tristate "IPQ CMN PLL Clock Controller"
-- depends on IPQ_GCC_9574
- help
- Support for CMN PLL clock controller on IPQ platform. The
- CMN PLL feeds the reference clocks to the Ethernet devices
---- a/drivers/clk/qcom/clk-ipq-cmn-pll.c
-+++ b/drivers/clk/qcom/clk-ipq-cmn-pll.c
-@@ -42,6 +42,9 @@
- #include <linux/platform_device.h>
- #include <linux/slab.h>
-
-+#define TCSR_ETH_CMN 0x0
-+#define TCSR_ETH_CMN_ENABLE BIT(0)
-+
- #define CMN_PLL_REFCLK_SRC_SELECTION 0x28
- #define CMN_PLL_REFCLK_SRC_DIV GENMASK(9, 8)
-
-@@ -79,6 +82,28 @@ static const struct cmn_pll_fixed_output
- CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
- };
-
-+static int ipq_cmn_pll_tcsr_enable(struct platform_device *pdev)
-+{
-+ struct resource *res;
-+ void __iomem *tcsr_base;
-+ u32 val;
-+
-+ /* For IPQ50xx, tcsr is necessary to enable cmn block */
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcsr");
-+ if (!res)
-+ return 0;
-+
-+ tcsr_base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR_OR_NULL(tcsr_base))
-+ return PTR_ERR(tcsr_base);
-+
-+ val = readl(tcsr_base + TCSR_ETH_CMN);
-+ val |= TCSR_ETH_CMN_ENABLE;
-+ writel(val, (tcsr_base + TCSR_ETH_CMN));
-+
-+ return 0;
-+}
-+
- static int ipq_cmn_pll_config(struct device *dev, unsigned long parent_rate)
- {
- void __iomem *base;
-@@ -181,6 +206,10 @@ static int ipq_cmn_pll_clk_probe(struct
- struct clk *clk;
- int ret;
-
-+ ret = ipq_cmn_pll_tcsr_enable(pdev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Enable CMN PLL failed\n");
-+
- /*
- * To access the CMN PLL registers, the GCC AHB & SYSY clocks
- * for CMN PLL block need to be enabled.
+++ /dev/null
-From 1b625a37b96b0448aac126d7720eec38de8e5956 Mon Sep 17 00:00:00 2001
-From: Ziyang Huang <hzyitc@outlook.com>
-Date: Sun, 8 Sep 2024 16:40:11 +0800
-Subject: [PATCH 2/2] arm64: dts: qcom: ipq5018: Add ethernet cmn node
-
-Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 19 +++++++++++++++++++
- 1 file changed, 19 insertions(+)
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -17,6 +17,12 @@
- #size-cells = <2>;
-
- clocks {
-+ cmn_pll_ref_clk: cmn-pll-ref-clk {
-+ compatible = "fixed-clock";
-+ clock-frequency = <96000000>;
-+ #clock-cells = <0>;
-+ };
-+
- gephy_rx_clk: gephy-rx-clk {
- compatible = "fixed-clock";
- clock-frequency = <125000000>;
-@@ -229,6 +235,17 @@
- status = "disabled";
- };
-
-+ cmn_pll: clock-controller@9b000 {
-+ compatible = "qcom,ipq9574-cmn-pll";
-+ reg = <0x0009b000 0x800>;
-+ reg-names = "cmn";
-+ clocks = <&cmn_pll_ref_clk>,
-+ <&gcc GCC_CMN_BLK_AHB_CLK>,
-+ <&gcc GCC_CMN_BLK_SYS_CLK>;
-+ clock-names = "ref", "ahb", "sys";
-+ #clock-cells = <1>;
-+ };
-+
- qfprom: qfprom@a0000 {
- compatible = "qcom,ipq5018-qfprom", "qcom,qfprom";
- reg = <0x000a0000 0x1000>;
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -204,7 +204,7 @@
+@@ -214,7 +214,7 @@
};
mdio0: mdio@88000 {
---
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -714,6 +714,225 @@
+@@ -727,6 +727,225 @@
};
};
---
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -126,6 +126,11 @@
+@@ -136,6 +136,11 @@
#size-cells = <2>;
ranges;