// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2024-2025 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. * * 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 | * +--+---+--+ * 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
*/
/* * 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.
*/ staticint ipq_cmn_pll_find_freq_index(unsignedlong 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;
}
/* * 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;
}
staticint 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.
*/ staticint clk_cmn_pll_set_rate(struct clk_hw *hw, unsignedlong rate, unsignedlong 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;
/* * 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]);
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, "Failed to add AHB clock\n");
ret = pm_clk_add(dev, "sys"); if (ret) return dev_err_probe(dev, ret, "Failed 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, "Failed to register CMN PLL clocks\n");
/* * 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]);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.