Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6/*
7 * CMN PLL block expects the reference clock from on-board Wi-Fi block,
8 * and supplies fixed rate clocks as output to the networking hardware
9 * blocks and to GCC. The networking related blocks include PPE (packet
10 * process engine), the externally connected PHY or switch devices, and
11 * the PCS.
12 *
13 * On the IPQ9574 SoC, there are three clocks with 50 MHZ and one clock
14 * with 25 MHZ which are output from the CMN PLL to Ethernet PHY (or switch),
15 * and one clock with 353 MHZ to PPE. The other fixed rate output clocks
16 * are supplied to GCC (24 MHZ as XO and 32 KHZ as sleep clock), and to PCS
17 * with 31.25 MHZ.
18 *
19 * On the IPQ5424 SoC, there is an output clock from CMN PLL to PPE at 375 MHZ,
20 * and an output clock to NSS (network subsystem) at 300 MHZ. The other output
21 * clocks from CMN PLL on IPQ5424 are the same as IPQ9574.
22 *
23 * +---------+
24 * | GCC |
25 * +--+---+--+
26 * AHB CLK| |SYS CLK
27 * V V
28 * +-------+---+------+
29 * | +-------------> eth0-50mhz
30 * REF CLK | IPQ9574 |
31 * -------->+ +-------------> eth1-50mhz
32 * | CMN PLL block |
33 * | +-------------> eth2-50mhz
34 * | |
35 * +----+----+----+---+-------------> eth-25mhz
36 * | | |
37 * V V V
38 * GCC PCS NSS/PPE
39 */
40
41#include <linux/bitfield.h>
42#include <linux/clk-provider.h>
43#include <linux/delay.h>
44#include <linux/err.h>
45#include <linux/mod_devicetable.h>
46#include <linux/module.h>
47#include <linux/platform_device.h>
48#include <linux/pm_clock.h>
49#include <linux/pm_runtime.h>
50#include <linux/regmap.h>
51
52#include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
53#include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
54#include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
55#include <dt-bindings/clock/qcom,ipq6018-cmn-pll.h>
56#include <dt-bindings/clock/qcom,ipq8074-cmn-pll.h>
57
58#define CMN_PLL_REFCLK_SRC_SELECTION 0x28
59#define CMN_PLL_REFCLK_SRC_DIV GENMASK(9, 8)
60
61#define CMN_PLL_LOCKED 0x64
62#define CMN_PLL_CLKS_LOCKED BIT(8)
63
64#define CMN_PLL_POWER_ON_AND_RESET 0x780
65#define CMN_ANA_EN_SW_RSTN BIT(6)
66
67#define CMN_PLL_REFCLK_CONFIG 0x784
68#define CMN_PLL_REFCLK_EXTERNAL BIT(9)
69#define CMN_PLL_REFCLK_DIV GENMASK(8, 4)
70#define CMN_PLL_REFCLK_INDEX GENMASK(3, 0)
71
72#define CMN_PLL_CTRL 0x78c
73#define CMN_PLL_CTRL_LOCK_DETECT_EN BIT(15)
74
75#define CMN_PLL_DIVIDER_CTRL 0x794
76#define CMN_PLL_DIVIDER_CTRL_FACTOR GENMASK(9, 0)
77
78/**
79 * struct cmn_pll_fixed_output_clk - CMN PLL output clocks information
80 * @id: Clock specifier to be supplied
81 * @name: Clock name to be registered
82 * @rate: Clock rate
83 */
84struct cmn_pll_fixed_output_clk {
85 unsigned int id;
86 const char *name;
87 unsigned long rate;
88};
89
90/**
91 * struct clk_cmn_pll - CMN PLL hardware specific data
92 * @regmap: hardware regmap.
93 * @hw: handle between common and hardware-specific interfaces
94 */
95struct clk_cmn_pll {
96 struct regmap *regmap;
97 struct clk_hw hw;
98};
99
100#define CLK_PLL_OUTPUT(_id, _name, _rate) { \
101 .id = _id, \
102 .name = _name, \
103 .rate = _rate, \
104}
105
106#define to_clk_cmn_pll(_hw) container_of(_hw, struct clk_cmn_pll, hw)
107
108static const struct regmap_config ipq_cmn_pll_regmap_config = {
109 .reg_bits = 32,
110 .reg_stride = 4,
111 .val_bits = 32,
112 .max_register = 0x7fc,
113};
114
115static const struct cmn_pll_fixed_output_clk ipq5018_output_clks[] = {
116 CLK_PLL_OUTPUT(IPQ5018_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
117 CLK_PLL_OUTPUT(IPQ5018_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
118 CLK_PLL_OUTPUT(IPQ5018_ETH_50MHZ_CLK, "eth-50mhz", 50000000UL),
119 { /* Sentinel */ }
120};
121
122static const struct cmn_pll_fixed_output_clk ipq6018_output_clks[] = {
123 CLK_PLL_OUTPUT(IPQ6018_BIAS_PLL_CC_CLK, "bias_pll_cc_clk", 300000000UL),
124 CLK_PLL_OUTPUT(IPQ6018_BIAS_PLL_NSS_NOC_CLK, "bias_pll_nss_noc_clk", 416500000UL),
125 { /* Sentinel */ }
126};
127
128static const struct cmn_pll_fixed_output_clk ipq8074_output_clks[] = {
129 CLK_PLL_OUTPUT(IPQ8074_BIAS_PLL_CC_CLK, "bias_pll_cc_clk", 300000000UL),
130 CLK_PLL_OUTPUT(IPQ8074_BIAS_PLL_NSS_NOC_CLK, "bias_pll_nss_noc_clk", 416500000UL),
131 { /* Sentinel */ }
132};
133
134static const struct cmn_pll_fixed_output_clk ipq5424_output_clks[] = {
135 CLK_PLL_OUTPUT(IPQ5424_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
136 CLK_PLL_OUTPUT(IPQ5424_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
137 CLK_PLL_OUTPUT(IPQ5424_PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
138 CLK_PLL_OUTPUT(IPQ5424_NSS_300MHZ_CLK, "nss-300mhz", 300000000UL),
139 CLK_PLL_OUTPUT(IPQ5424_PPE_375MHZ_CLK, "ppe-375mhz", 375000000UL),
140 CLK_PLL_OUTPUT(IPQ5424_ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
141 CLK_PLL_OUTPUT(IPQ5424_ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
142 CLK_PLL_OUTPUT(IPQ5424_ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
143 CLK_PLL_OUTPUT(IPQ5424_ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
144 { /* Sentinel */ }
145};
146
147static const struct cmn_pll_fixed_output_clk ipq9574_output_clks[] = {
148 CLK_PLL_OUTPUT(XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
149 CLK_PLL_OUTPUT(SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
150 CLK_PLL_OUTPUT(PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
151 CLK_PLL_OUTPUT(NSS_1200MHZ_CLK, "nss-1200mhz", 1200000000UL),
152 CLK_PLL_OUTPUT(PPE_353MHZ_CLK, "ppe-353mhz", 353000000UL),
153 CLK_PLL_OUTPUT(ETH0_50MHZ_CLK, "eth0-50mhz", 50000000UL),
154 CLK_PLL_OUTPUT(ETH1_50MHZ_CLK, "eth1-50mhz", 50000000UL),
155 CLK_PLL_OUTPUT(ETH2_50MHZ_CLK, "eth2-50mhz", 50000000UL),
156 CLK_PLL_OUTPUT(ETH_25MHZ_CLK, "eth-25mhz", 25000000UL),
157 { /* Sentinel */ }
158};
159
160/*
161 * CMN PLL has the single parent clock, which supports the several
162 * possible parent clock rates, each parent clock rate is reflected
163 * by the specific reference index value in the hardware.
164 */
165static int ipq_cmn_pll_find_freq_index(unsigned long parent_rate)
166{
167 int index = -EINVAL;
168
169 switch (parent_rate) {
170 case 25000000:
171 index = 3;
172 break;
173 case 31250000:
174 index = 4;
175 break;
176 case 40000000:
177 index = 6;
178 break;
179 case 48000000:
180 case 96000000:
181 /*
182 * Parent clock rate 48 MHZ and 96 MHZ take the same value
183 * of reference clock index. 96 MHZ needs the source clock
184 * divider to be programmed as 2.
185 */
186 index = 7;
187 break;
188 case 50000000:
189 index = 8;
190 break;
191 default:
192 break;
193 }
194
195 return index;
196}
197
198static unsigned long clk_cmn_pll_recalc_rate(struct clk_hw *hw,
199 unsigned long parent_rate)
200{
201 struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
202 u32 val, factor;
203
204 /*
205 * The value of CMN_PLL_DIVIDER_CTRL_FACTOR is automatically adjusted
206 * by HW according to the parent clock rate.
207 */
208 regmap_read(cmn_pll->regmap, CMN_PLL_DIVIDER_CTRL, &val);
209 factor = FIELD_GET(CMN_PLL_DIVIDER_CTRL_FACTOR, val);
210
211 return parent_rate * 2 * factor;
212}
213
214static int clk_cmn_pll_determine_rate(struct clk_hw *hw,
215 struct clk_rate_request *req)
216{
217 int ret;
218
219 /* Validate the rate of the single parent clock. */
220 ret = ipq_cmn_pll_find_freq_index(req->best_parent_rate);
221
222 return ret < 0 ? ret : 0;
223}
224
225/*
226 * This function is used to initialize the CMN PLL to enable the fixed
227 * rate output clocks. It is expected to be configured once.
228 */
229static int clk_cmn_pll_set_rate(struct clk_hw *hw, unsigned long rate,
230 unsigned long parent_rate)
231{
232 struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
233 int ret, index;
234 u32 val;
235
236 /*
237 * Configure the reference input clock selection as per the given
238 * parent clock. The output clock rates are always of fixed value.
239 */
240 index = ipq_cmn_pll_find_freq_index(parent_rate);
241 if (index < 0)
242 return index;
243
244 ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG,
245 CMN_PLL_REFCLK_INDEX,
246 FIELD_PREP(CMN_PLL_REFCLK_INDEX, index));
247 if (ret)
248 return ret;
249
250 /*
251 * Update the source clock rate selection and source clock
252 * divider as 2 when the parent clock rate is 96 MHZ.
253 */
254 if (parent_rate == 96000000) {
255 ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG,
256 CMN_PLL_REFCLK_DIV,
257 FIELD_PREP(CMN_PLL_REFCLK_DIV, 2));
258 if (ret)
259 return ret;
260
261 ret = regmap_update_bits(cmn_pll->regmap, CMN_PLL_REFCLK_SRC_SELECTION,
262 CMN_PLL_REFCLK_SRC_DIV,
263 FIELD_PREP(CMN_PLL_REFCLK_SRC_DIV, 0));
264 if (ret)
265 return ret;
266 }
267
268 /* Enable PLL locked detect. */
269 ret = regmap_set_bits(cmn_pll->regmap, CMN_PLL_CTRL,
270 CMN_PLL_CTRL_LOCK_DETECT_EN);
271 if (ret)
272 return ret;
273
274 /*
275 * Reset the CMN PLL block to ensure the updated configurations
276 * take effect.
277 */
278 ret = regmap_clear_bits(cmn_pll->regmap, CMN_PLL_POWER_ON_AND_RESET,
279 CMN_ANA_EN_SW_RSTN);
280 if (ret)
281 return ret;
282
283 usleep_range(1000, 1200);
284 ret = regmap_set_bits(cmn_pll->regmap, CMN_PLL_POWER_ON_AND_RESET,
285 CMN_ANA_EN_SW_RSTN);
286 if (ret)
287 return ret;
288
289 /* Stability check of CMN PLL output clocks. */
290 return regmap_read_poll_timeout(cmn_pll->regmap, CMN_PLL_LOCKED, val,
291 (val & CMN_PLL_CLKS_LOCKED),
292 100, 100 * USEC_PER_MSEC);
293}
294
295static const struct clk_ops clk_cmn_pll_ops = {
296 .recalc_rate = clk_cmn_pll_recalc_rate,
297 .determine_rate = clk_cmn_pll_determine_rate,
298 .set_rate = clk_cmn_pll_set_rate,
299};
300
301static struct clk_hw *ipq_cmn_pll_clk_hw_register(struct platform_device *pdev)
302{
303 struct clk_parent_data pdata = { .index = 0 };
304 struct device *dev = &pdev->dev;
305 struct clk_init_data init = {};
306 struct clk_cmn_pll *cmn_pll;
307 struct regmap *regmap;
308 void __iomem *base;
309 int ret;
310
311 base = devm_platform_ioremap_resource(pdev, 0);
312 if (IS_ERR(base))
313 return ERR_CAST(base);
314
315 regmap = devm_regmap_init_mmio(dev, base, &ipq_cmn_pll_regmap_config);
316 if (IS_ERR(regmap))
317 return ERR_CAST(regmap);
318
319 cmn_pll = devm_kzalloc(dev, sizeof(*cmn_pll), GFP_KERNEL);
320 if (!cmn_pll)
321 return ERR_PTR(-ENOMEM);
322
323 init.name = "cmn_pll";
324 init.parent_data = &pdata;
325 init.num_parents = 1;
326 init.ops = &clk_cmn_pll_ops;
327
328 cmn_pll->hw.init = &init;
329 cmn_pll->regmap = regmap;
330
331 ret = devm_clk_hw_register(dev, &cmn_pll->hw);
332 if (ret)
333 return ERR_PTR(ret);
334
335 return &cmn_pll->hw;
336}
337
338static int ipq_cmn_pll_register_clks(struct platform_device *pdev)
339{
340 const struct cmn_pll_fixed_output_clk *p, *fixed_clk;
341 struct clk_hw_onecell_data *hw_data;
342 struct device *dev = &pdev->dev;
343 struct clk_hw *cmn_pll_hw;
344 unsigned int num_clks;
345 struct clk_hw *hw;
346 int ret, i;
347
348 fixed_clk = device_get_match_data(dev);
349 if (!fixed_clk)
350 return -EINVAL;
351
352 num_clks = 0;
353 for (p = fixed_clk; p->name; p++)
354 num_clks++;
355
356 hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, num_clks + 1),
357 GFP_KERNEL);
358 if (!hw_data)
359 return -ENOMEM;
360
361 /*
362 * Register the CMN PLL clock, which is the parent clock of
363 * the fixed rate output clocks.
364 */
365 cmn_pll_hw = ipq_cmn_pll_clk_hw_register(pdev);
366 if (IS_ERR(cmn_pll_hw))
367 return PTR_ERR(cmn_pll_hw);
368
369 /* Register the fixed rate output clocks. */
370 for (i = 0; i < num_clks; i++) {
371 hw = clk_hw_register_fixed_rate_parent_hw(dev, fixed_clk[i].name,
372 cmn_pll_hw, 0,
373 fixed_clk[i].rate);
374 if (IS_ERR(hw)) {
375 ret = PTR_ERR(hw);
376 goto unregister_fixed_clk;
377 }
378
379 hw_data->hws[fixed_clk[i].id] = hw;
380 }
381
382 /*
383 * Provide the CMN PLL clock. The clock rate of CMN PLL
384 * is configured to 12 GHZ by DT property assigned-clock-rates-u64.
385 */
386 hw_data->hws[CMN_PLL_CLK] = cmn_pll_hw;
387 hw_data->num = num_clks + 1;
388
389 ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
390 if (ret)
391 goto unregister_fixed_clk;
392
393 platform_set_drvdata(pdev, hw_data);
394
395 return 0;
396
397unregister_fixed_clk:
398 while (i > 0)
399 clk_hw_unregister(hw_data->hws[fixed_clk[--i].id]);
400
401 return ret;
402}
403
404static int ipq_cmn_pll_clk_probe(struct platform_device *pdev)
405{
406 struct device *dev = &pdev->dev;
407 int ret;
408
409 ret = devm_pm_runtime_enable(dev);
410 if (ret)
411 return ret;
412
413 ret = devm_pm_clk_create(dev);
414 if (ret)
415 return ret;
416
417 /*
418 * To access the CMN PLL registers, the GCC AHB & SYS clocks
419 * of CMN PLL block need to be enabled.
420 */
421 ret = pm_clk_add(dev, "ahb");
422 if (ret)
423 return dev_err_probe(dev, ret, "Failed to add AHB clock\n");
424
425 ret = pm_clk_add(dev, "sys");
426 if (ret)
427 return dev_err_probe(dev, ret, "Failed to add SYS clock\n");
428
429 ret = pm_runtime_resume_and_get(dev);
430 if (ret)
431 return ret;
432
433 /* Register CMN PLL clock and fixed rate output clocks. */
434 ret = ipq_cmn_pll_register_clks(pdev);
435 pm_runtime_put(dev);
436 if (ret)
437 return dev_err_probe(dev, ret,
438 "Failed to register CMN PLL clocks\n");
439
440 return 0;
441}
442
443static void ipq_cmn_pll_clk_remove(struct platform_device *pdev)
444{
445 struct clk_hw_onecell_data *hw_data = platform_get_drvdata(pdev);
446 int i;
447
448 /*
449 * The clock with index CMN_PLL_CLK is unregistered by
450 * device management.
451 */
452 for (i = 0; i < hw_data->num; i++) {
453 if (i != CMN_PLL_CLK)
454 clk_hw_unregister(hw_data->hws[i]);
455 }
456}
457
458static const struct dev_pm_ops ipq_cmn_pll_pm_ops = {
459 SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
460};
461
462static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
463 { .compatible = "qcom,ipq5018-cmn-pll", .data = &ipq5018_output_clks },
464 { .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
465 { .compatible = "qcom,ipq6018-cmn-pll", .data = &ipq6018_output_clks },
466 { .compatible = "qcom,ipq8074-cmn-pll", .data = &ipq8074_output_clks },
467 { .compatible = "qcom,ipq9574-cmn-pll", .data = &ipq9574_output_clks },
468 { }
469};
470MODULE_DEVICE_TABLE(of, ipq_cmn_pll_clk_ids);
471
472static struct platform_driver ipq_cmn_pll_clk_driver = {
473 .probe = ipq_cmn_pll_clk_probe,
474 .remove = ipq_cmn_pll_clk_remove,
475 .driver = {
476 .name = "ipq_cmn_pll",
477 .of_match_table = ipq_cmn_pll_clk_ids,
478 .pm = &ipq_cmn_pll_pm_ops,
479 },
480};
481module_platform_driver(ipq_cmn_pll_clk_driver);
482
483MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPQ CMN PLL Driver");
484MODULE_LICENSE("GPL");