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 */
ice_tspll_clk_freq_str(enum ice_tspll_freq clk_freq)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 */
ice_tspll_default_freq(enum ice_mac_type mac_type)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 */
ice_tspll_check_params(struct ice_hw * hw,enum ice_tspll_freq clk_freq,enum ice_clk_src clk_src)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 */
ice_tspll_clk_src_str(enum ice_clk_src clk_src)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 */
ice_tspll_log_cfg(struct ice_hw * hw,bool enable,u8 clk_src,u8 tspll_freq,bool lock,bool new_cfg)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 */
ice_tspll_cfg_e82x(struct ice_hw * hw,enum ice_tspll_freq clk_freq,enum ice_clk_src clk_src)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 */
ice_tspll_dis_sticky_bits_e82x(struct ice_hw * hw)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 */
ice_tspll_cfg_e825c(struct ice_hw * hw,enum ice_tspll_freq clk_freq,enum ice_clk_src clk_src)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 */
ice_tspll_dis_sticky_bits_e825c(struct ice_hw * hw)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 */
ice_tspll_cfg_pps_out_e825c(struct ice_hw * hw,bool enable)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 */
ice_tspll_cfg(struct ice_hw * hw,enum ice_tspll_freq clk_freq,enum ice_clk_src clk_src)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 */
ice_tspll_dis_sticky_bits(struct ice_hw * hw)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 */
ice_tspll_init(struct ice_hw * hw)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