xref: /linux/drivers/net/ethernet/intel/ice/ice_tspll.c (revision af2d6148d2a159e1a0862bce5a2c88c1618a2b27)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2025, Intel Corporation. */
3 
4 #include "ice.h"
5 #include "ice_lib.h"
6 #include "ice_ptp_hw.h"
7 
8 static const struct
9 ice_tspll_params_e82x e82x_tspll_params[NUM_ICE_TSPLL_FREQ] = {
10 	[ICE_TSPLL_FREQ_25_000] = {
11 		.refclk_pre_div = 1,
12 		.post_pll_div = 6,
13 		.feedback_div = 197,
14 		.frac_n_div = 2621440,
15 	},
16 	[ICE_TSPLL_FREQ_122_880] = {
17 		.refclk_pre_div = 5,
18 		.post_pll_div = 7,
19 		.feedback_div = 223,
20 		.frac_n_div = 524288
21 	},
22 	[ICE_TSPLL_FREQ_125_000] = {
23 		.refclk_pre_div = 5,
24 		.post_pll_div = 7,
25 		.feedback_div = 223,
26 		.frac_n_div = 524288
27 	},
28 	[ICE_TSPLL_FREQ_153_600] = {
29 		.refclk_pre_div = 5,
30 		.post_pll_div = 6,
31 		.feedback_div = 159,
32 		.frac_n_div = 1572864
33 	},
34 	[ICE_TSPLL_FREQ_156_250] = {
35 		.refclk_pre_div = 5,
36 		.post_pll_div = 6,
37 		.feedback_div = 159,
38 		.frac_n_div = 1572864
39 	},
40 	[ICE_TSPLL_FREQ_245_760] = {
41 		.refclk_pre_div = 10,
42 		.post_pll_div = 7,
43 		.feedback_div = 223,
44 		.frac_n_div = 524288
45 	},
46 };
47 
48 /**
49  * ice_tspll_clk_freq_str - Convert time_ref_freq to string
50  * @clk_freq: Clock frequency
51  *
52  * Return: specified TIME_REF clock frequency converted to a string.
53  */
54 static const char *ice_tspll_clk_freq_str(enum ice_tspll_freq clk_freq)
55 {
56 	switch (clk_freq) {
57 	case ICE_TSPLL_FREQ_25_000:
58 		return "25 MHz";
59 	case ICE_TSPLL_FREQ_122_880:
60 		return "122.88 MHz";
61 	case ICE_TSPLL_FREQ_125_000:
62 		return "125 MHz";
63 	case ICE_TSPLL_FREQ_153_600:
64 		return "153.6 MHz";
65 	case ICE_TSPLL_FREQ_156_250:
66 		return "156.25 MHz";
67 	case ICE_TSPLL_FREQ_245_760:
68 		return "245.76 MHz";
69 	default:
70 		return "Unknown";
71 	}
72 }
73 
74 /**
75  * ice_tspll_default_freq - Return default frequency for a MAC type
76  * @mac_type: MAC type
77  *
78  * Return: default TSPLL frequency for a correct MAC type, -ERANGE otherwise.
79  */
80 static enum ice_tspll_freq ice_tspll_default_freq(enum ice_mac_type mac_type)
81 {
82 	switch (mac_type) {
83 	case ICE_MAC_GENERIC:
84 		return ICE_TSPLL_FREQ_25_000;
85 	case ICE_MAC_GENERIC_3K_E825:
86 		return ICE_TSPLL_FREQ_156_250;
87 	default:
88 		return -ERANGE;
89 	}
90 }
91 
92 /**
93  * ice_tspll_check_params - Check if TSPLL params are correct
94  * @hw: Pointer to the HW struct
95  * @clk_freq: Clock frequency to program
96  * @clk_src: Clock source to select (TIME_REF or TCXO)
97  *
98  * Return: true if TSPLL params are correct, false otherwise.
99  */
100 static bool ice_tspll_check_params(struct ice_hw *hw,
101 				   enum ice_tspll_freq clk_freq,
102 				   enum ice_clk_src clk_src)
103 {
104 	if (clk_freq >= NUM_ICE_TSPLL_FREQ) {
105 		dev_warn(ice_hw_to_dev(hw), "Invalid TSPLL frequency %u\n",
106 			 clk_freq);
107 		return false;
108 	}
109 
110 	if (clk_src >= NUM_ICE_CLK_SRC) {
111 		dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n",
112 			 clk_src);
113 		return false;
114 	}
115 
116 	if ((hw->mac_type == ICE_MAC_GENERIC_3K_E825 ||
117 	     clk_src == ICE_CLK_SRC_TCXO) &&
118 	    clk_freq != ice_tspll_default_freq(hw->mac_type)) {
119 		dev_warn(ice_hw_to_dev(hw), "Unsupported frequency for this clock source\n");
120 		return false;
121 	}
122 
123 	return true;
124 }
125 
126 /**
127  * ice_tspll_clk_src_str - Convert time_ref_src to string
128  * @clk_src: Clock source
129  *
130  * Return: specified clock source converted to its string name
131  */
132 static const char *ice_tspll_clk_src_str(enum ice_clk_src clk_src)
133 {
134 	switch (clk_src) {
135 	case ICE_CLK_SRC_TCXO:
136 		return "TCXO";
137 	case ICE_CLK_SRC_TIME_REF:
138 		return "TIME_REF";
139 	default:
140 		return "Unknown";
141 	}
142 }
143 
144 /**
145  * ice_tspll_log_cfg - Log current/new TSPLL configuration
146  * @hw: Pointer to the HW struct
147  * @enable: CGU enabled/disabled
148  * @clk_src: Current clock source
149  * @tspll_freq: Current clock frequency
150  * @lock: CGU lock status
151  * @new_cfg: true if this is a new config
152  */
153 static void ice_tspll_log_cfg(struct ice_hw *hw, bool enable, u8 clk_src,
154 			      u8 tspll_freq, bool lock, bool new_cfg)
155 {
156 	dev_dbg(ice_hw_to_dev(hw),
157 		"%s TSPLL configuration -- %s, src %s, freq %s, PLL %s\n",
158 		new_cfg ? "New" : "Current", str_enabled_disabled(enable),
159 		ice_tspll_clk_src_str((enum ice_clk_src)clk_src),
160 		ice_tspll_clk_freq_str((enum ice_tspll_freq)tspll_freq),
161 		lock ? "locked" : "unlocked");
162 }
163 
164 /**
165  * ice_tspll_cfg_e82x - Configure the Clock Generation Unit TSPLL
166  * @hw: Pointer to the HW struct
167  * @clk_freq: Clock frequency to program
168  * @clk_src: Clock source to select (TIME_REF, or TCXO)
169  *
170  * Configure the Clock Generation Unit with the desired clock frequency and
171  * time reference, enabling the PLL which drives the PTP hardware clock.
172  *
173  * Return:
174  * * %0       - success
175  * * %-EINVAL - input parameters are incorrect
176  * * %-EBUSY  - failed to lock TSPLL
177  * * %other   - CGU read/write failure
178  */
179 static int ice_tspll_cfg_e82x(struct ice_hw *hw, enum ice_tspll_freq clk_freq,
180 			      enum ice_clk_src clk_src)
181 {
182 	u32 val, r9, r24;
183 	int err;
184 
185 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9);
186 	if (err)
187 		return err;
188 
189 	err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24);
190 	if (err)
191 		return err;
192 
193 	err = ice_read_cgu_reg(hw, ICE_CGU_RO_BWM_LF, &val);
194 	if (err)
195 		return err;
196 
197 	ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24),
198 			  FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r24),
199 			  FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9),
200 			  !!FIELD_GET(ICE_CGU_RO_BWM_LF_TRUE_LOCK, val),
201 			  false);
202 
203 	/* Disable the PLL before changing the clock source or frequency */
204 	if (FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24)) {
205 		r24 &= ~ICE_CGU_R23_R24_TSPLL_ENABLE;
206 
207 		err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24);
208 		if (err)
209 			return err;
210 	}
211 
212 	/* Set the frequency */
213 	r9 &= ~ICE_CGU_R9_TIME_REF_FREQ_SEL;
214 	r9 |= FIELD_PREP(ICE_CGU_R9_TIME_REF_FREQ_SEL, clk_freq);
215 	err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9);
216 	if (err)
217 		return err;
218 
219 	/* Configure the TSPLL feedback divisor */
220 	err = ice_read_cgu_reg(hw, ICE_CGU_R19, &val);
221 	if (err)
222 		return err;
223 
224 	val &= ~(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X | ICE_CGU_R19_TSPLL_NDIVRATIO);
225 	val |= FIELD_PREP(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X,
226 			  e82x_tspll_params[clk_freq].feedback_div);
227 	val |= FIELD_PREP(ICE_CGU_R19_TSPLL_NDIVRATIO, 1);
228 
229 	err = ice_write_cgu_reg(hw, ICE_CGU_R19, val);
230 	if (err)
231 		return err;
232 
233 	/* Configure the TSPLL post divisor */
234 	err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val);
235 	if (err)
236 		return err;
237 
238 	val &= ~(ICE_CGU_R22_TIME1588CLK_DIV |
239 		 ICE_CGU_R22_TIME1588CLK_DIV2);
240 	val |= FIELD_PREP(ICE_CGU_R22_TIME1588CLK_DIV,
241 			  e82x_tspll_params[clk_freq].post_pll_div);
242 
243 	err = ice_write_cgu_reg(hw, ICE_CGU_R22, val);
244 	if (err)
245 		return err;
246 
247 	/* Configure the TSPLL pre divisor and clock source */
248 	err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24);
249 	if (err)
250 		return err;
251 
252 	r24 &= ~(ICE_CGU_R23_R24_REF1588_CK_DIV | ICE_CGU_R24_FBDIV_FRAC |
253 		 ICE_CGU_R23_R24_TIME_REF_SEL);
254 	r24 |= FIELD_PREP(ICE_CGU_R23_R24_REF1588_CK_DIV,
255 			  e82x_tspll_params[clk_freq].refclk_pre_div);
256 	r24 |= FIELD_PREP(ICE_CGU_R24_FBDIV_FRAC,
257 			  e82x_tspll_params[clk_freq].frac_n_div);
258 	r24 |= FIELD_PREP(ICE_CGU_R23_R24_TIME_REF_SEL, clk_src);
259 
260 	err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24);
261 	if (err)
262 		return err;
263 
264 	/* Wait to ensure everything is stable */
265 	usleep_range(10, 20);
266 
267 	/* Finally, enable the PLL */
268 	r24 |= ICE_CGU_R23_R24_TSPLL_ENABLE;
269 
270 	err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24);
271 	if (err)
272 		return err;
273 
274 	/* Wait at least 1 ms to verify if the PLL locks */
275 	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
276 
277 	err = ice_read_cgu_reg(hw, ICE_CGU_RO_BWM_LF, &val);
278 	if (err)
279 		return err;
280 
281 	if (!(val & ICE_CGU_RO_BWM_LF_TRUE_LOCK)) {
282 		dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n");
283 		return -EBUSY;
284 	}
285 
286 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9);
287 	if (err)
288 		return err;
289 	err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24);
290 	if (err)
291 		return err;
292 
293 	ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24),
294 			  FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r24),
295 			  FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9),
296 			  true, true);
297 
298 	return 0;
299 }
300 
301 /**
302  * ice_tspll_dis_sticky_bits_e82x - disable TSPLL sticky bits
303  * @hw: Pointer to the HW struct
304  *
305  * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on
306  * losing TSPLL lock, but always show current state.
307  *
308  * Return: 0 on success, other error codes when failed to read/write CGU.
309  */
310 static int ice_tspll_dis_sticky_bits_e82x(struct ice_hw *hw)
311 {
312 	u32 val;
313 	int err;
314 
315 	err = ice_read_cgu_reg(hw, ICE_CGU_CNTR_BIST, &val);
316 	if (err)
317 		return err;
318 
319 	val &= ~(ICE_CGU_CNTR_BIST_PLLLOCK_SEL_0 |
320 		 ICE_CGU_CNTR_BIST_PLLLOCK_SEL_1);
321 
322 	return ice_write_cgu_reg(hw, ICE_CGU_CNTR_BIST, val);
323 }
324 
325 /**
326  * ice_tspll_cfg_e825c - Configure the TSPLL for E825-C
327  * @hw: Pointer to the HW struct
328  * @clk_freq: Clock frequency to program
329  * @clk_src: Clock source to select (TIME_REF, or TCXO)
330  *
331  * Configure the Clock Generation Unit with the desired clock frequency and
332  * time reference, enabling the PLL which drives the PTP hardware clock.
333  *
334  * Return:
335  * * %0       - success
336  * * %-EINVAL - input parameters are incorrect
337  * * %-EBUSY  - failed to lock TSPLL
338  * * %other   - CGU read/write failure
339  */
340 static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq,
341 			       enum ice_clk_src clk_src)
342 {
343 	u32 val, r9, r23;
344 	int err;
345 
346 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9);
347 	if (err)
348 		return err;
349 
350 	err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23);
351 	if (err)
352 		return err;
353 
354 	err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val);
355 	if (err)
356 		return err;
357 
358 	ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23),
359 			  FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r23),
360 			  FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9),
361 			  !!FIELD_GET(ICE_CGU_RO_LOCK_TRUE_LOCK, val),
362 			  false);
363 
364 	/* Disable the PLL before changing the clock source or frequency */
365 	if (FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23)) {
366 		r23 &= ~ICE_CGU_R23_R24_TSPLL_ENABLE;
367 
368 		err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23);
369 		if (err)
370 			return err;
371 	}
372 
373 	if (FIELD_GET(ICE_CGU_R9_TIME_SYNC_EN, r9)) {
374 		r9 &= ~ICE_CGU_R9_TIME_SYNC_EN;
375 
376 		err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9);
377 		if (err)
378 			return err;
379 	}
380 
381 	/* Set the frequency and enable the correct receiver */
382 	r9 &= ~(ICE_CGU_R9_TIME_REF_FREQ_SEL | ICE_CGU_R9_CLK_EREF0_EN |
383 		ICE_CGU_R9_TIME_REF_EN);
384 	r9 |= FIELD_PREP(ICE_CGU_R9_TIME_REF_FREQ_SEL, clk_freq);
385 	if (clk_src == ICE_CLK_SRC_TCXO)
386 		r9 |= ICE_CGU_R9_CLK_EREF0_EN;
387 	else
388 		r9 |= ICE_CGU_R9_TIME_REF_EN;
389 	r9 |= ICE_CGU_R9_TIME_SYNC_EN;
390 	err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9);
391 	if (err)
392 		return err;
393 
394 	/* Choose the referenced frequency */
395 	err = ice_read_cgu_reg(hw, ICE_CGU_R16, &val);
396 	if (err)
397 		return err;
398 	val &= ~ICE_CGU_R16_TSPLL_CK_REFCLKFREQ;
399 	val |= FIELD_PREP(ICE_CGU_R16_TSPLL_CK_REFCLKFREQ,
400 			  ICE_TSPLL_CK_REFCLKFREQ_E825);
401 	err = ice_write_cgu_reg(hw, ICE_CGU_R16, val);
402 	if (err)
403 		return err;
404 
405 	/* Configure the TSPLL feedback divisor */
406 	err = ice_read_cgu_reg(hw, ICE_CGU_R19, &val);
407 	if (err)
408 		return err;
409 
410 	val &= ~(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825 |
411 		 ICE_CGU_R19_TSPLL_NDIVRATIO);
412 	val |= FIELD_PREP(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825,
413 			  ICE_TSPLL_FBDIV_INTGR_E825);
414 	val |= FIELD_PREP(ICE_CGU_R19_TSPLL_NDIVRATIO,
415 			  ICE_TSPLL_NDIVRATIO_E825);
416 
417 	err = ice_write_cgu_reg(hw, ICE_CGU_R19, val);
418 	if (err)
419 		return err;
420 
421 	/* Configure the TSPLL post divisor, these two are constant */
422 	err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val);
423 	if (err)
424 		return err;
425 
426 	val &= ~(ICE_CGU_R22_TIME1588CLK_DIV |
427 		 ICE_CGU_R22_TIME1588CLK_DIV2);
428 	val |= FIELD_PREP(ICE_CGU_R22_TIME1588CLK_DIV, 5);
429 
430 	err = ice_write_cgu_reg(hw, ICE_CGU_R22, val);
431 	if (err)
432 		return err;
433 
434 	/* Configure the TSPLL pre divisor (constant) and clock source */
435 	err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23);
436 	if (err)
437 		return err;
438 
439 	r23 &= ~(ICE_CGU_R23_R24_REF1588_CK_DIV | ICE_CGU_R23_R24_TIME_REF_SEL);
440 	r23 |= FIELD_PREP(ICE_CGU_R23_R24_TIME_REF_SEL, clk_src);
441 
442 	err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23);
443 	if (err)
444 		return err;
445 
446 	/* Clear the R24 register. */
447 	err = ice_write_cgu_reg(hw, ICE_CGU_R24, 0);
448 	if (err)
449 		return err;
450 
451 	/* Wait to ensure everything is stable */
452 	usleep_range(10, 20);
453 
454 	/* Finally, enable the PLL */
455 	r23 |= ICE_CGU_R23_R24_TSPLL_ENABLE;
456 
457 	err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23);
458 	if (err)
459 		return err;
460 
461 	/* Wait at least 1 ms to verify if the PLL locks */
462 	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
463 
464 	err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val);
465 	if (err)
466 		return err;
467 
468 	if (!(val & ICE_CGU_RO_LOCK_TRUE_LOCK)) {
469 		dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n");
470 		return -EBUSY;
471 	}
472 
473 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9);
474 	if (err)
475 		return err;
476 	err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23);
477 	if (err)
478 		return err;
479 
480 	ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23),
481 			  FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r23),
482 			  FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9),
483 			  true, true);
484 
485 	return 0;
486 }
487 
488 /**
489  * ice_tspll_dis_sticky_bits_e825c - disable TSPLL sticky bits for E825-C
490  * @hw: Pointer to the HW struct
491  *
492  * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on
493  * losing TSPLL lock, but always show current state.
494  *
495  * Return: 0 on success, other error codes when failed to read/write CGU.
496  */
497 static int ice_tspll_dis_sticky_bits_e825c(struct ice_hw *hw)
498 {
499 	u32 val;
500 	int err;
501 
502 	err = ice_read_cgu_reg(hw, ICE_CGU_BW_TDC, &val);
503 	if (err)
504 		return err;
505 
506 	val &= ~ICE_CGU_BW_TDC_PLLLOCK_SEL;
507 
508 	return ice_write_cgu_reg(hw, ICE_CGU_BW_TDC, val);
509 }
510 
511 /**
512  * ice_tspll_cfg_pps_out_e825c - Enable/disable 1PPS output and set amplitude
513  * @hw: pointer to the HW struct
514  * @enable: true to enable 1PPS output, false to disable it
515  *
516  * Return: 0 on success, other negative error code when CGU read/write failed.
517  */
518 int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable)
519 {
520 	u32 val;
521 	int err;
522 
523 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &val);
524 	if (err)
525 		return err;
526 
527 	val &= ~(ICE_CGU_R9_ONE_PPS_OUT_EN | ICE_CGU_R9_ONE_PPS_OUT_AMP);
528 	val |= FIELD_PREP(ICE_CGU_R9_ONE_PPS_OUT_EN, enable) |
529 	       ICE_CGU_R9_ONE_PPS_OUT_AMP;
530 
531 	return ice_write_cgu_reg(hw, ICE_CGU_R9, val);
532 }
533 
534 /**
535  * ice_tspll_cfg - Configure the Clock Generation Unit TSPLL
536  * @hw: Pointer to the HW struct
537  * @clk_freq: Clock frequency to program
538  * @clk_src: Clock source to select (TIME_REF, or TCXO)
539  *
540  * Configure the Clock Generation Unit with the desired clock frequency and
541  * time reference, enabling the TSPLL which drives the PTP hardware clock.
542  *
543  * Return: 0 on success, -ERANGE on unsupported MAC type, other negative error
544  *         codes when failed to configure CGU.
545  */
546 static int ice_tspll_cfg(struct ice_hw *hw, enum ice_tspll_freq clk_freq,
547 			 enum ice_clk_src clk_src)
548 {
549 	switch (hw->mac_type) {
550 	case ICE_MAC_GENERIC:
551 		return ice_tspll_cfg_e82x(hw, clk_freq, clk_src);
552 	case ICE_MAC_GENERIC_3K_E825:
553 		return ice_tspll_cfg_e825c(hw, clk_freq, clk_src);
554 	default:
555 		return -ERANGE;
556 	}
557 }
558 
559 /**
560  * ice_tspll_dis_sticky_bits - disable TSPLL sticky bits
561  * @hw: Pointer to the HW struct
562  *
563  * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on
564  * losing TSPLL lock, but always show current state.
565  *
566  * Return: 0 on success, -ERANGE on unsupported MAC type.
567  */
568 static int ice_tspll_dis_sticky_bits(struct ice_hw *hw)
569 {
570 	switch (hw->mac_type) {
571 	case ICE_MAC_GENERIC:
572 		return ice_tspll_dis_sticky_bits_e82x(hw);
573 	case ICE_MAC_GENERIC_3K_E825:
574 		return ice_tspll_dis_sticky_bits_e825c(hw);
575 	default:
576 		return -ERANGE;
577 	}
578 }
579 
580 /**
581  * ice_tspll_init - Initialize TSPLL with settings from firmware
582  * @hw: Pointer to the HW structure
583  *
584  * Initialize the Clock Generation Unit of the E82X/E825 device.
585  *
586  * Return: 0 on success, other error codes when failed to read/write/cfg CGU.
587  */
588 int ice_tspll_init(struct ice_hw *hw)
589 {
590 	struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info;
591 	enum ice_tspll_freq tspll_freq;
592 	enum ice_clk_src clk_src;
593 	int err;
594 
595 	/* Only E822, E823 and E825 products support TSPLL */
596 	if (hw->mac_type != ICE_MAC_GENERIC &&
597 	    hw->mac_type != ICE_MAC_GENERIC_3K_E825)
598 		return 0;
599 
600 	tspll_freq = (enum ice_tspll_freq)ts_info->time_ref;
601 	clk_src = (enum ice_clk_src)ts_info->clk_src;
602 	if (!ice_tspll_check_params(hw, tspll_freq, clk_src))
603 		return -EINVAL;
604 
605 	/* Disable sticky lock detection so lock status reported is accurate */
606 	err = ice_tspll_dis_sticky_bits(hw);
607 	if (err)
608 		return err;
609 
610 	/* Configure the TSPLL using the parameters from the function
611 	 * capabilities.
612 	 */
613 	err = ice_tspll_cfg(hw, tspll_freq, clk_src);
614 	if (err) {
615 		dev_warn(ice_hw_to_dev(hw), "Failed to lock TSPLL to predefined frequency. Retrying with fallback frequency.\n");
616 
617 		/* Try to lock to internal TCXO as a fallback. */
618 		tspll_freq = ice_tspll_default_freq(hw->mac_type);
619 		clk_src = ICE_CLK_SRC_TCXO;
620 		err = ice_tspll_cfg(hw, tspll_freq, clk_src);
621 		if (err)
622 			dev_warn(ice_hw_to_dev(hw), "Failed to lock TSPLL to fallback frequency.\n");
623 	}
624 
625 	return err;
626 }
627