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
628 /**
629 * ice_tspll_bypass_mux_active_e825c - check if the given port is set active
630 * @hw: Pointer to the HW struct
631 * @port: Number of the port
632 * @active: Output flag showing if port is active
633 * @output: Output pin, we have two in E825C
634 *
635 * Check if given port is selected as recovered clock source for given output.
636 *
637 * Return:
638 * * 0 - success
639 * * negative - error
640 */
ice_tspll_bypass_mux_active_e825c(struct ice_hw * hw,u8 port,bool * active,enum ice_synce_clk output)641 int ice_tspll_bypass_mux_active_e825c(struct ice_hw *hw, u8 port, bool *active,
642 enum ice_synce_clk output)
643 {
644 u8 active_clk;
645 u32 val;
646 int err;
647
648 switch (output) {
649 case ICE_SYNCE_CLK0:
650 err = ice_read_cgu_reg(hw, ICE_CGU_R10, &val);
651 if (err)
652 return err;
653 active_clk = FIELD_GET(ICE_CGU_R10_SYNCE_S_REF_CLK, val);
654 break;
655 case ICE_SYNCE_CLK1:
656 err = ice_read_cgu_reg(hw, ICE_CGU_R11, &val);
657 if (err)
658 return err;
659 active_clk = FIELD_GET(ICE_CGU_R11_SYNCE_S_BYP_CLK, val);
660 break;
661 default:
662 return -EINVAL;
663 }
664
665 if (active_clk == port % hw->ptp.ports_per_phy +
666 ICE_CGU_BYPASS_MUX_OFFSET_E825C)
667 *active = true;
668 else
669 *active = false;
670
671 return 0;
672 }
673
674 /**
675 * ice_tspll_cfg_bypass_mux_e825c - configure reference clock mux
676 * @hw: Pointer to the HW struct
677 * @ena: true to enable the reference, false if disable
678 * @port_num: Number of the port
679 * @output: Output pin, we have two in E825C
680 *
681 * Set reference clock source and output clock selection.
682 *
683 * Context: Called under pf->dplls.lock
684 * Return:
685 * * 0 - success
686 * * negative - error
687 */
ice_tspll_cfg_bypass_mux_e825c(struct ice_hw * hw,bool ena,u32 port_num,enum ice_synce_clk output)688 int ice_tspll_cfg_bypass_mux_e825c(struct ice_hw *hw, bool ena, u32 port_num,
689 enum ice_synce_clk output)
690 {
691 u8 first_mux;
692 int err;
693 u32 r10;
694
695 err = ice_read_cgu_reg(hw, ICE_CGU_R10, &r10);
696 if (err)
697 return err;
698
699 if (!ena)
700 first_mux = ICE_CGU_NET_REF_CLK0;
701 else
702 first_mux = port_num + ICE_CGU_BYPASS_MUX_OFFSET_E825C;
703
704 r10 &= ~(ICE_CGU_R10_SYNCE_DCK_RST | ICE_CGU_R10_SYNCE_DCK2_RST);
705
706 switch (output) {
707 case ICE_SYNCE_CLK0:
708 r10 &= ~(ICE_CGU_R10_SYNCE_ETHCLKO_SEL |
709 ICE_CGU_R10_SYNCE_ETHDIV_LOAD |
710 ICE_CGU_R10_SYNCE_S_REF_CLK);
711 r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_S_REF_CLK, first_mux);
712 r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_ETHCLKO_SEL,
713 ICE_CGU_REF_CLK_BYP0_DIV);
714 break;
715 case ICE_SYNCE_CLK1:
716 {
717 u32 val;
718
719 err = ice_read_cgu_reg(hw, ICE_CGU_R11, &val);
720 if (err)
721 return err;
722 val &= ~ICE_CGU_R11_SYNCE_S_BYP_CLK;
723 val |= FIELD_PREP(ICE_CGU_R11_SYNCE_S_BYP_CLK, first_mux);
724 err = ice_write_cgu_reg(hw, ICE_CGU_R11, val);
725 if (err)
726 return err;
727 r10 &= ~(ICE_CGU_R10_SYNCE_CLKODIV_LOAD |
728 ICE_CGU_R10_SYNCE_CLKO_SEL);
729 r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_CLKO_SEL,
730 ICE_CGU_REF_CLK_BYP1_DIV);
731 break;
732 }
733 default:
734 return -EINVAL;
735 }
736
737 err = ice_write_cgu_reg(hw, ICE_CGU_R10, r10);
738 if (err)
739 return err;
740
741 return 0;
742 }
743
744 /**
745 * ice_tspll_get_div_e825c - get the divider for the given speed
746 * @link_speed: link speed of the port
747 * @divider: output value, calculated divider
748 *
749 * Get CGU divider value based on the link speed.
750 *
751 * Return:
752 * * 0 - success
753 * * negative - error
754 */
ice_tspll_get_div_e825c(u16 link_speed,unsigned int * divider)755 static int ice_tspll_get_div_e825c(u16 link_speed, unsigned int *divider)
756 {
757 switch (link_speed) {
758 case ICE_AQ_LINK_SPEED_100GB:
759 case ICE_AQ_LINK_SPEED_50GB:
760 case ICE_AQ_LINK_SPEED_25GB:
761 *divider = 10;
762 break;
763 case ICE_AQ_LINK_SPEED_40GB:
764 case ICE_AQ_LINK_SPEED_10GB:
765 *divider = 4;
766 break;
767 case ICE_AQ_LINK_SPEED_5GB:
768 case ICE_AQ_LINK_SPEED_2500MB:
769 case ICE_AQ_LINK_SPEED_1000MB:
770 *divider = 2;
771 break;
772 case ICE_AQ_LINK_SPEED_100MB:
773 *divider = 1;
774 break;
775 default:
776 return -EOPNOTSUPP;
777 }
778
779 return 0;
780 }
781
782 /**
783 * ice_tspll_cfg_synce_ethdiv_e825c - set the divider on the mux
784 * @hw: Pointer to the HW struct
785 * @output: Output pin, we have two in E825C
786 *
787 * Set the correct CGU divider for RCLKA or RCLKB.
788 *
789 * Context: Called under pf->dplls.lock
790 * Return:
791 * * 0 - success
792 * * negative - error
793 */
ice_tspll_cfg_synce_ethdiv_e825c(struct ice_hw * hw,enum ice_synce_clk output)794 int ice_tspll_cfg_synce_ethdiv_e825c(struct ice_hw *hw,
795 enum ice_synce_clk output)
796 {
797 unsigned int divider;
798 u16 link_speed;
799 u32 val;
800 int err;
801
802 link_speed = hw->port_info->phy.link_info.link_speed;
803 if (!link_speed)
804 return 0;
805
806 err = ice_tspll_get_div_e825c(link_speed, ÷r);
807 if (err)
808 return err;
809
810 err = ice_read_cgu_reg(hw, ICE_CGU_R10, &val);
811 if (err)
812 return err;
813
814 /* programmable divider value (from 2 to 16) minus 1 for ETHCLKOUT */
815 switch (output) {
816 case ICE_SYNCE_CLK0:
817 val &= ~(ICE_CGU_R10_SYNCE_ETHDIV_M1 |
818 ICE_CGU_R10_SYNCE_ETHDIV_LOAD);
819 val |= FIELD_PREP(ICE_CGU_R10_SYNCE_ETHDIV_M1, divider - 1);
820 err = ice_write_cgu_reg(hw, ICE_CGU_R10, val);
821 if (err)
822 return err;
823 val |= ICE_CGU_R10_SYNCE_ETHDIV_LOAD;
824 break;
825 case ICE_SYNCE_CLK1:
826 val &= ~(ICE_CGU_R10_SYNCE_CLKODIV_M1 |
827 ICE_CGU_R10_SYNCE_CLKODIV_LOAD);
828 val |= FIELD_PREP(ICE_CGU_R10_SYNCE_CLKODIV_M1, divider - 1);
829 err = ice_write_cgu_reg(hw, ICE_CGU_R10, val);
830 if (err)
831 return err;
832 val |= ICE_CGU_R10_SYNCE_CLKODIV_LOAD;
833 break;
834 default:
835 return -EINVAL;
836 }
837
838 err = ice_write_cgu_reg(hw, ICE_CGU_R10, val);
839 if (err)
840 return err;
841
842 return 0;
843 }
844