File Index
Files and directories
Sign in
FILE

ice_tspll.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/intel/ice/ice_tspll.c C
  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
  8static const struct
  9ice_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 */
 54static 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 */
 80static 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 */
100static 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 */
132static 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 */
153static 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 */
179static 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 */
310static 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 */
340static 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 */
497static 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 */
518int 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 */
546static 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 */
568static 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 */
588int 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}
~/ Read-only file preview.