xref: /linux/drivers/net/ethernet/intel/ice/ice_tspll.c (revision c5fbdf0ba7c1a6ed52dc3650bee73ce00c86cf7f)
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_clk_src_str - Convert time_ref_src to string
76  * @clk_src: Clock source
77  *
78  * Return: specified clock source converted to its string name
79  */
80 static const char *ice_tspll_clk_src_str(enum ice_clk_src clk_src)
81 {
82 	switch (clk_src) {
83 	case ICE_CLK_SRC_TCXO:
84 		return "TCXO";
85 	case ICE_CLK_SRC_TIME_REF:
86 		return "TIME_REF";
87 	default:
88 		return "Unknown";
89 	}
90 }
91 
92 /**
93  * ice_tspll_log_cfg - Log current/new TSPLL configuration
94  * @hw: Pointer to the HW struct
95  * @enable: CGU enabled/disabled
96  * @clk_src: Current clock source
97  * @tspll_freq: Current clock frequency
98  * @lock: CGU lock status
99  * @new_cfg: true if this is a new config
100  */
101 static void ice_tspll_log_cfg(struct ice_hw *hw, bool enable, u8 clk_src,
102 			      u8 tspll_freq, bool lock, bool new_cfg)
103 {
104 	dev_dbg(ice_hw_to_dev(hw),
105 		"%s TSPLL configuration -- %s, src %s, freq %s, PLL %s\n",
106 		new_cfg ? "New" : "Current", str_enabled_disabled(enable),
107 		ice_tspll_clk_src_str((enum ice_clk_src)clk_src),
108 		ice_tspll_clk_freq_str((enum ice_tspll_freq)tspll_freq),
109 		lock ? "locked" : "unlocked");
110 }
111 
112 /**
113  * ice_tspll_cfg_e82x - Configure the Clock Generation Unit TSPLL
114  * @hw: Pointer to the HW struct
115  * @clk_freq: Clock frequency to program
116  * @clk_src: Clock source to select (TIME_REF, or TCXO)
117  *
118  * Configure the Clock Generation Unit with the desired clock frequency and
119  * time reference, enabling the PLL which drives the PTP hardware clock.
120  *
121  * Return:
122  * * %0       - success
123  * * %-EINVAL - input parameters are incorrect
124  * * %-EBUSY  - failed to lock TSPLL
125  * * %other   - CGU read/write failure
126  */
127 static int ice_tspll_cfg_e82x(struct ice_hw *hw, enum ice_tspll_freq clk_freq,
128 			      enum ice_clk_src clk_src)
129 {
130 	union tspll_ro_bwm_lf bwm_lf;
131 	union ice_cgu_r19_e82x dw19;
132 	union ice_cgu_r22 dw22;
133 	union ice_cgu_r24 dw24;
134 	union ice_cgu_r9 dw9;
135 	int err;
136 
137 	if (clk_freq >= NUM_ICE_TSPLL_FREQ) {
138 		dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n",
139 			 clk_freq);
140 		return -EINVAL;
141 	}
142 
143 	if (clk_src >= NUM_ICE_CLK_SRC) {
144 		dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n",
145 			 clk_src);
146 		return -EINVAL;
147 	}
148 
149 	if (clk_src == ICE_CLK_SRC_TCXO && clk_freq != ICE_TSPLL_FREQ_25_000) {
150 		dev_warn(ice_hw_to_dev(hw),
151 			 "TCXO only supports 25 MHz frequency\n");
152 		return -EINVAL;
153 	}
154 
155 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &dw9.val);
156 	if (err)
157 		return err;
158 
159 	err = ice_read_cgu_reg(hw, ICE_CGU_R24, &dw24.val);
160 	if (err)
161 		return err;
162 
163 	err = ice_read_cgu_reg(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
164 	if (err)
165 		return err;
166 
167 	ice_tspll_log_cfg(hw, dw24.ts_pll_enable, dw24.time_ref_sel,
168 			  dw9.time_ref_freq_sel, bwm_lf.plllock_true_lock_cri,
169 			  false);
170 
171 	/* Disable the PLL before changing the clock source or frequency */
172 	if (dw24.ts_pll_enable) {
173 		dw24.ts_pll_enable = 0;
174 
175 		err = ice_write_cgu_reg(hw, ICE_CGU_R24, dw24.val);
176 		if (err)
177 			return err;
178 	}
179 
180 	/* Set the frequency */
181 	dw9.time_ref_freq_sel = clk_freq;
182 	err = ice_write_cgu_reg(hw, ICE_CGU_R9, dw9.val);
183 	if (err)
184 		return err;
185 
186 	/* Configure the TSPLL feedback divisor */
187 	err = ice_read_cgu_reg(hw, ICE_CGU_R19, &dw19.val);
188 	if (err)
189 		return err;
190 
191 	dw19.fbdiv_intgr = e82x_tspll_params[clk_freq].feedback_div;
192 	dw19.ndivratio = 1;
193 
194 	err = ice_write_cgu_reg(hw, ICE_CGU_R19, dw19.val);
195 	if (err)
196 		return err;
197 
198 	/* Configure the TSPLL post divisor */
199 	err = ice_read_cgu_reg(hw, ICE_CGU_R22, &dw22.val);
200 	if (err)
201 		return err;
202 
203 	dw22.time1588clk_div = e82x_tspll_params[clk_freq].post_pll_div;
204 	dw22.time1588clk_sel_div2 = 0;
205 
206 	err = ice_write_cgu_reg(hw, ICE_CGU_R22, dw22.val);
207 	if (err)
208 		return err;
209 
210 	/* Configure the TSPLL pre divisor and clock source */
211 	err = ice_read_cgu_reg(hw, ICE_CGU_R24, &dw24.val);
212 	if (err)
213 		return err;
214 
215 	dw24.ref1588_ck_div = e82x_tspll_params[clk_freq].refclk_pre_div;
216 	dw24.fbdiv_frac = e82x_tspll_params[clk_freq].frac_n_div;
217 	dw24.time_ref_sel = clk_src;
218 
219 	err = ice_write_cgu_reg(hw, ICE_CGU_R24, dw24.val);
220 	if (err)
221 		return err;
222 
223 	/* Finally, enable the PLL */
224 	dw24.ts_pll_enable = 1;
225 
226 	err = ice_write_cgu_reg(hw, ICE_CGU_R24, dw24.val);
227 	if (err)
228 		return err;
229 
230 	/* Wait to verify if the PLL locks */
231 	usleep_range(1000, 5000);
232 
233 	err = ice_read_cgu_reg(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
234 	if (err)
235 		return err;
236 
237 	if (!bwm_lf.plllock_true_lock_cri) {
238 		dev_warn(ice_hw_to_dev(hw), "TSPLL failed to lock\n");
239 		return -EBUSY;
240 	}
241 
242 	ice_tspll_log_cfg(hw, dw24.ts_pll_enable, clk_src, clk_freq, true,
243 			  true);
244 
245 	return 0;
246 }
247 
248 /**
249  * ice_tspll_dis_sticky_bits_e82x - disable TSPLL sticky bits
250  * @hw: Pointer to the HW struct
251  *
252  * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on
253  * losing TSPLL lock, but always show current state.
254  *
255  * Return: 0 on success, other error codes when failed to read/write CGU.
256  */
257 static int ice_tspll_dis_sticky_bits_e82x(struct ice_hw *hw)
258 {
259 	union tspll_cntr_bist_settings cntr_bist;
260 	int err;
261 
262 	err = ice_read_cgu_reg(hw, TSPLL_CNTR_BIST_SETTINGS, &cntr_bist.val);
263 	if (err)
264 		return err;
265 
266 	/* Disable sticky lock detection so lock err reported is accurate */
267 	cntr_bist.i_plllock_sel_0 = 0;
268 	cntr_bist.i_plllock_sel_1 = 0;
269 
270 	return ice_write_cgu_reg(hw, TSPLL_CNTR_BIST_SETTINGS, cntr_bist.val);
271 }
272 
273 /**
274  * ice_tspll_cfg_e825c - Configure the TSPLL for E825-C
275  * @hw: Pointer to the HW struct
276  * @clk_freq: Clock frequency to program
277  * @clk_src: Clock source to select (TIME_REF, or TCXO)
278  *
279  * Configure the Clock Generation Unit with the desired clock frequency and
280  * time reference, enabling the PLL which drives the PTP hardware clock.
281  *
282  * Return:
283  * * %0       - success
284  * * %-EINVAL - input parameters are incorrect
285  * * %-EBUSY  - failed to lock TSPLL
286  * * %other   - CGU read/write failure
287  */
288 static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq,
289 			       enum ice_clk_src clk_src)
290 {
291 	union tspll_ro_lock_e825c ro_lock;
292 	union ice_cgu_r19_e825 dw19;
293 	union ice_cgu_r16 dw16;
294 	union ice_cgu_r23 dw23;
295 	union ice_cgu_r22 dw22;
296 	union ice_cgu_r9 dw9;
297 	int err;
298 
299 	if (clk_freq >= NUM_ICE_TSPLL_FREQ) {
300 		dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n",
301 			 clk_freq);
302 		return -EINVAL;
303 	}
304 
305 	if (clk_src >= NUM_ICE_CLK_SRC) {
306 		dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n",
307 			 clk_src);
308 		return -EINVAL;
309 	}
310 
311 	if (clk_freq != ICE_TSPLL_FREQ_156_250) {
312 		dev_warn(ice_hw_to_dev(hw), "Adapter only supports 156.25 MHz frequency\n");
313 		return -EINVAL;
314 	}
315 
316 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &dw9.val);
317 	if (err)
318 		return err;
319 
320 	err = ice_read_cgu_reg(hw, ICE_CGU_R16, &dw16.val);
321 	if (err)
322 		return err;
323 
324 	err = ice_read_cgu_reg(hw, ICE_CGU_R23, &dw23.val);
325 	if (err)
326 		return err;
327 
328 	err = ice_read_cgu_reg(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val);
329 	if (err)
330 		return err;
331 
332 	ice_tspll_log_cfg(hw, dw23.ts_pll_enable, dw23.time_ref_sel,
333 			  dw9.time_ref_freq_sel,
334 			  ro_lock.plllock_true_lock_cri, false);
335 
336 	/* Disable the PLL before changing the clock source or frequency */
337 	if (dw23.ts_pll_enable) {
338 		dw23.ts_pll_enable = 0;
339 
340 		err = ice_write_cgu_reg(hw, ICE_CGU_R23, dw23.val);
341 		if (err)
342 			return err;
343 	}
344 
345 	/* Set the frequency */
346 	dw9.time_ref_freq_sel = clk_freq;
347 
348 	/* Enable the correct receiver */
349 	if (clk_src == ICE_CLK_SRC_TCXO) {
350 		dw9.time_ref_en = 0;
351 		dw9.clk_eref0_en = 1;
352 	} else {
353 		dw9.time_ref_en = 1;
354 		dw9.clk_eref0_en = 0;
355 	}
356 	err = ice_write_cgu_reg(hw, ICE_CGU_R9, dw9.val);
357 	if (err)
358 		return err;
359 
360 	/* Choose the referenced frequency */
361 	dw16.ck_refclkfreq = ICE_TSPLL_CK_REFCLKFREQ_E825;
362 	err = ice_write_cgu_reg(hw, ICE_CGU_R16, dw16.val);
363 	if (err)
364 		return err;
365 
366 	/* Configure the TSPLL feedback divisor */
367 	err = ice_read_cgu_reg(hw, ICE_CGU_R19, &dw19.val);
368 	if (err)
369 		return err;
370 
371 	dw19.tspll_fbdiv_intgr = ICE_TSPLL_FBDIV_INTGR_E825;
372 	dw19.tspll_ndivratio = ICE_TSPLL_NDIVRATIO_E825;
373 
374 	err = ice_write_cgu_reg(hw, ICE_CGU_R19, dw19.val);
375 	if (err)
376 		return err;
377 
378 	/* Configure the TSPLL post divisor */
379 	err = ice_read_cgu_reg(hw, ICE_CGU_R22, &dw22.val);
380 	if (err)
381 		return err;
382 
383 	/* These two are constant for E825C */
384 	dw22.time1588clk_div = 5;
385 	dw22.time1588clk_sel_div2 = 0;
386 
387 	err = ice_write_cgu_reg(hw, ICE_CGU_R22, dw22.val);
388 	if (err)
389 		return err;
390 
391 	/* Configure the TSPLL pre divisor and clock source */
392 	err = ice_read_cgu_reg(hw, ICE_CGU_R23, &dw23.val);
393 	if (err)
394 		return err;
395 
396 	dw23.ref1588_ck_div = 0;
397 	dw23.time_ref_sel = clk_src;
398 
399 	err = ice_write_cgu_reg(hw, ICE_CGU_R23, dw23.val);
400 	if (err)
401 		return err;
402 
403 	/* Clear the R24 register. */
404 	err = ice_write_cgu_reg(hw, ICE_CGU_R24, 0);
405 	if (err)
406 		return err;
407 
408 	/* Finally, enable the PLL */
409 	dw23.ts_pll_enable = 1;
410 
411 	err = ice_write_cgu_reg(hw, ICE_CGU_R23, dw23.val);
412 	if (err)
413 		return err;
414 
415 	/* Wait to verify if the PLL locks */
416 	usleep_range(1000, 5000);
417 
418 	err = ice_read_cgu_reg(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val);
419 	if (err)
420 		return err;
421 
422 	if (!ro_lock.plllock_true_lock_cri) {
423 		dev_warn(ice_hw_to_dev(hw), "TSPLL failed to lock\n");
424 		return -EBUSY;
425 	}
426 
427 	ice_tspll_log_cfg(hw, dw23.ts_pll_enable, clk_src, clk_freq, true,
428 			  true);
429 
430 	return 0;
431 }
432 
433 /**
434  * ice_tspll_dis_sticky_bits_e825c - disable TSPLL sticky bits for E825-C
435  * @hw: Pointer to the HW struct
436  *
437  * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on
438  * losing TSPLL lock, but always show current state.
439  *
440  * Return: 0 on success, other error codes when failed to read/write CGU.
441  */
442 static int ice_tspll_dis_sticky_bits_e825c(struct ice_hw *hw)
443 {
444 	union tspll_bw_tdc_e825c bw_tdc;
445 	int err;
446 
447 	err = ice_read_cgu_reg(hw, TSPLL_BW_TDC_E825C, &bw_tdc.val);
448 	if (err)
449 		return err;
450 
451 	bw_tdc.i_plllock_sel_1_0 = 0;
452 
453 	return ice_write_cgu_reg(hw, TSPLL_BW_TDC_E825C, bw_tdc.val);
454 }
455 
456 #define ICE_ONE_PPS_OUT_AMP_MAX 3
457 
458 /**
459  * ice_tspll_cfg_pps_out_e825c - Enable/disable 1PPS output and set amplitude
460  * @hw: pointer to the HW struct
461  * @enable: true to enable 1PPS output, false to disable it
462  *
463  * Return: 0 on success, other negative error code when CGU read/write failed.
464  */
465 int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable)
466 {
467 	union ice_cgu_r9 r9;
468 	int err;
469 
470 	err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9.val);
471 	if (err)
472 		return err;
473 
474 	r9.one_pps_out_en = enable;
475 	r9.one_pps_out_amp = enable * ICE_ONE_PPS_OUT_AMP_MAX;
476 	return ice_write_cgu_reg(hw, ICE_CGU_R9, r9.val);
477 }
478 
479 /**
480  * ice_tspll_init - Initialize TSPLL with settings from firmware
481  * @hw: Pointer to the HW structure
482  *
483  * Initialize the Clock Generation Unit of the E82X/E825 device.
484  *
485  * Return: 0 on success, other error codes when failed to read/write/cfg CGU.
486  */
487 int ice_tspll_init(struct ice_hw *hw)
488 {
489 	struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info;
490 	int err;
491 
492 	/* Disable sticky lock detection so lock err reported is accurate. */
493 	if (hw->mac_type == ICE_MAC_GENERIC_3K_E825)
494 		err = ice_tspll_dis_sticky_bits_e825c(hw);
495 	else
496 		err = ice_tspll_dis_sticky_bits_e82x(hw);
497 	if (err)
498 		return err;
499 
500 	/* Configure the TSPLL using the parameters from the function
501 	 * capabilities.
502 	 */
503 	if (hw->mac_type == ICE_MAC_GENERIC_3K_E825)
504 		err = ice_tspll_cfg_e825c(hw, ts_info->time_ref,
505 					  (enum ice_clk_src)ts_info->clk_src);
506 	else
507 		err = ice_tspll_cfg_e82x(hw, ts_info->time_ref,
508 					 (enum ice_clk_src)ts_info->clk_src);
509 
510 	return err;
511 }
512