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