diff options
author | Jakub Kicinski <kuba@kernel.org> | 2025-06-27 16:27:08 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2025-06-27 16:27:09 -0700 |
commit | 8c72b2a2edd5cf0ba95b0ec42a1b031f64d98574 (patch) | |
tree | ffa588da657acb9c7fec10626520f2df42293f4a | |
parent | f7dbedba63124256feb9d9fcf36e8a2e43858d1e (diff) | |
parent | 8b4987543453c6172983f4b0b084c55a18e250ad (diff) |
Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
Tony Nguyen says:
====================
ice: remaining TSPLL cleanups
These are the remaining patches from the "ice: Separate TSPLL from PTP
and cleanup" series [1] with control flow macros removed. What remains
are cleanups and some minor improvements.
[1] https://lore.kernel.org/netdev/20250618174231.3100231-1-anthony.l.nguyen@intel.com/
* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
ice: default to TIME_REF instead of TXCO on E825-C
ice: move TSPLL init calls to ice_ptp.c
ice: fall back to TCXO on TSPLL lock fail
ice: wait before enabling TSPLL
ice: add multiple TSPLL helpers
ice: use bitfields instead of unions for CGU regs
ice: read TSPLL registers again before reporting status
ice: clear time_sync_en field for E825-C during reprogramming
====================
Link: https://patch.msgid.link/20250626162921.1173068-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_common.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_common.h | 212 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_ptp.c | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 22 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_tspll.c | 427 |
5 files changed, 316 insertions, 358 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index bc292d61892c..84cd8c6dcf39 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2302,7 +2302,7 @@ ice_parse_1588_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, info->clk_src = ((number & ICE_TS_CLK_SRC_M) != 0); } else { info->clk_freq = ICE_TSPLL_FREQ_156_250; - info->clk_src = ICE_CLK_SRC_TCXO; + info->clk_src = ICE_CLK_SRC_TIME_REF; } if (info->clk_freq < NUM_ICE_TSPLL_FREQ) { diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index ed375babcde3..e8979b80c2f0 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -39,194 +39,46 @@ #define FEC_RECEIVER_ID_PCS0 (0x33 << FEC_RECV_ID_SHIFT) #define FEC_RECEIVER_ID_PCS1 (0x34 << FEC_RECV_ID_SHIFT) -#define ICE_CGU_R9 0x24 -union ice_cgu_r9 { - struct { - u32 time_ref_freq_sel : 3; - u32 clk_eref1_en : 1; - u32 clk_eref0_en : 1; - u32 time_ref_en : 1; - u32 time_sync_en : 1; - u32 one_pps_out_en : 1; - u32 clk_ref_synce_en : 1; - u32 clk_synce1_en : 1; - u32 clk_synce0_en : 1; - u32 net_clk_ref1_en : 1; - u32 net_clk_ref0_en : 1; - u32 clk_synce1_amp : 2; - u32 misc6 : 1; - u32 clk_synce0_amp : 2; - u32 one_pps_out_amp : 2; - u32 misc24 : 12; - }; - u32 val; -}; +#define ICE_CGU_R9 0x24 +#define ICE_CGU_R9_TIME_REF_FREQ_SEL GENMASK(2, 0) +#define ICE_CGU_R9_CLK_EREF0_EN BIT(4) +#define ICE_CGU_R9_TIME_REF_EN BIT(5) +#define ICE_CGU_R9_TIME_SYNC_EN BIT(6) +#define ICE_CGU_R9_ONE_PPS_OUT_EN BIT(7) +#define ICE_CGU_R9_ONE_PPS_OUT_AMP GENMASK(19, 18) -#define ICE_CGU_R16 0x40 -union ice_cgu_r16 { - struct { - u32 synce_remndr : 6; - u32 synce_phlmt_en : 1; - u32 misc13 : 17; - u32 ck_refclkfreq : 8; - }; - u32 val; -}; +#define ICE_CGU_R16 0x40 +#define ICE_CGU_R16_TSPLL_CK_REFCLKFREQ GENMASK(31, 24) -#define ICE_CGU_R19 0x4c -union ice_cgu_r19_e82x { - struct { - u32 fbdiv_intgr : 8; - u32 fdpll_ulck_thr : 5; - u32 misc15 : 3; - u32 ndivratio : 4; - u32 tspll_iref_ndivratio : 3; - u32 misc19 : 1; - u32 japll_ndivratio : 4; - u32 japll_iref_ndivratio : 3; - u32 misc27 : 1; - }; - u32 val; -}; +#define ICE_CGU_R19 0x4C +#define ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X GENMASK(7, 0) +#define ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825 GENMASK(9, 0) +#define ICE_CGU_R19_TSPLL_NDIVRATIO GENMASK(19, 16) -union ice_cgu_r19_e825 { - struct { - u32 tspll_fbdiv_intgr : 10; - u32 fdpll_ulck_thr : 5; - u32 misc15 : 1; - u32 tspll_ndivratio : 4; - u32 tspll_iref_ndivratio : 3; - u32 misc19 : 1; - u32 japll_ndivratio : 4; - u32 japll_postdiv_pdivratio : 3; - u32 misc27 : 1; - }; - u32 val; -}; +#define ICE_CGU_R22 0x58 +#define ICE_CGU_R22_TIME1588CLK_DIV GENMASK(23, 20) +#define ICE_CGU_R22_TIME1588CLK_DIV2 BIT(30) -#define ICE_CGU_R22 0x58 -union ice_cgu_r22 { - struct { - u32 fdpll_frac_div_out_nc : 2; - u32 fdpll_lock_int_for : 1; - u32 synce_hdov_int_for : 1; - u32 synce_lock_int_for : 1; - u32 fdpll_phlead_slip_nc : 1; - u32 fdpll_acc1_ovfl_nc : 1; - u32 fdpll_acc2_ovfl_nc : 1; - u32 synce_status_nc : 6; - u32 fdpll_acc1f_ovfl : 1; - u32 misc18 : 1; - u32 fdpllclk_div : 4; - u32 time1588clk_div : 4; - u32 synceclk_div : 4; - u32 synceclk_sel_div2 : 1; - u32 fdpllclk_sel_div2 : 1; - u32 time1588clk_sel_div2 : 1; - u32 misc3 : 1; - }; - u32 val; -}; +#define ICE_CGU_R23 0x5C +#define ICE_CGU_R24 0x60 +#define ICE_CGU_R24_FBDIV_FRAC GENMASK(21, 0) +#define ICE_CGU_R23_R24_TSPLL_ENABLE BIT(24) +#define ICE_CGU_R23_R24_REF1588_CK_DIV GENMASK(30, 27) +#define ICE_CGU_R23_R24_TIME_REF_SEL BIT(31) -#define ICE_CGU_R23 0x5C -union ice_cgu_r23 { - struct { - u32 cgupll_fbdiv_intgr : 10; - u32 ux56pll_fbdiv_intgr : 10; - u32 misc20 : 4; - u32 ts_pll_enable : 1; - u32 time_sync_tspll_align_sel : 1; - u32 ext_synce_sel : 1; - u32 ref1588_ck_div : 4; - u32 time_ref_sel : 1; +#define ICE_CGU_BW_TDC 0x31C +#define ICE_CGU_BW_TDC_PLLLOCK_SEL GENMASK(30, 29) - }; - u32 val; -}; +#define ICE_CGU_RO_LOCK 0x3F0 +#define ICE_CGU_RO_LOCK_TRUE_LOCK BIT(12) +#define ICE_CGU_RO_LOCK_UNLOCK BIT(13) -#define ICE_CGU_R24 0x60 -union ice_cgu_r24 { - struct { - u32 fbdiv_frac : 22; - u32 misc20 : 2; - u32 ts_pll_enable : 1; - u32 time_sync_tspll_align_sel : 1; - u32 ext_synce_sel : 1; - u32 ref1588_ck_div : 4; - u32 time_ref_sel : 1; - }; - u32 val; -}; +#define ICE_CGU_CNTR_BIST 0x344 +#define ICE_CGU_CNTR_BIST_PLLLOCK_SEL_0 BIT(15) +#define ICE_CGU_CNTR_BIST_PLLLOCK_SEL_1 BIT(16) -#define TSPLL_CNTR_BIST_SETTINGS 0x344 -union tspll_cntr_bist_settings { - struct { - u32 i_irefgen_settling_time_cntr_7_0 : 8; - u32 i_irefgen_settling_time_ro_standby_1_0 : 2; - u32 reserved195 : 5; - u32 i_plllock_sel_0 : 1; - u32 i_plllock_sel_1 : 1; - u32 i_plllock_cnt_6_0 : 7; - u32 i_plllock_cnt_10_7 : 4; - u32 reserved200 : 4; - }; - u32 val; -}; - -#define TSPLL_RO_BWM_LF 0x370 -union tspll_ro_bwm_lf { - struct { - u32 bw_freqov_high_cri_7_0 : 8; - u32 bw_freqov_high_cri_9_8 : 2; - u32 biascaldone_cri : 1; - u32 plllock_gain_tran_cri : 1; - u32 plllock_true_lock_cri : 1; - u32 pllunlock_flag_cri : 1; - u32 afcerr_cri : 1; - u32 afcdone_cri : 1; - u32 feedfwrdgain_cal_cri_7_0 : 8; - u32 m2fbdivmod_cri_7_0 : 8; - }; - u32 val; -}; - -#define TSPLL_RO_LOCK_E825C 0x3f0 -union tspll_ro_lock_e825c { - struct { - u32 bw_freqov_high_cri_7_0 : 8; - u32 bw_freqov_high_cri_9_8 : 2; - u32 reserved455 : 1; - u32 plllock_gain_tran_cri : 1; - u32 plllock_true_lock_cri : 1; - u32 pllunlock_flag_cri : 1; - u32 afcerr_cri : 1; - u32 afcdone_cri : 1; - u32 feedfwrdgain_cal_cri_7_0 : 8; - u32 reserved462 : 8; - }; - u32 val; -}; - -#define TSPLL_BW_TDC_E825C 0x31c -union tspll_bw_tdc_e825c { - struct { - u32 i_tdc_offset_lock_1_0 : 2; - u32 i_bbthresh1_2_0 : 3; - u32 i_bbthresh2_2_0 : 3; - u32 i_tdcsel_1_0 : 2; - u32 i_tdcovccorr_en_h : 1; - u32 i_divretimeren : 1; - u32 i_bw_ampmeas_window : 1; - u32 i_bw_lowerbound_2_0 : 3; - u32 i_bw_upperbound_2_0 : 3; - u32 i_bw_mode_1_0 : 2; - u32 i_ft_mode_sel_2_0 : 3; - u32 i_bwphase_4_0 : 5; - u32 i_plllock_sel_1_0 : 2; - u32 i_afc_divratio : 1; - }; - u32 val; -}; +#define ICE_CGU_RO_BWM_LF 0x370 +#define ICE_CGU_RO_BWM_LF_TRUE_LOCK BIT(12) int ice_init_hw(struct ice_hw *hw); void ice_deinit_hw(struct ice_hw *hw); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index b8cf8d64aaaa..e7005d757477 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2892,6 +2892,10 @@ static int ice_ptp_rebuild_owner(struct ice_pf *pf) if (err) return err; + err = ice_tspll_init(hw); + if (err) + return err; + /* Acquire the global hardware lock */ if (!ice_ptp_lock(hw)) { err = -EBUSY; @@ -3059,6 +3063,13 @@ static int ice_ptp_init_owner(struct ice_pf *pf) return err; } + err = ice_tspll_init(hw); + if (err) { + dev_err(ice_pf_to_dev(pf), "Failed to initialize CGU, status %d\n", + err); + return err; + } + /* Acquire the global hardware lock */ if (!ice_ptp_lock(hw)) { err = -EBUSY; diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index 278231443546..e8e439fd64a4 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -2116,20 +2116,6 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port) } /** - * ice_ptp_init_phc_e825 - Perform E825 specific PHC initialization - * @hw: pointer to HW struct - * - * Perform E825-specific PTP hardware clock initialization steps. - * - * Return: 0 on success, negative error code otherwise. - */ -static int ice_ptp_init_phc_e825(struct ice_hw *hw) -{ - /* Initialize the Clock Generation Unit */ - return ice_tspll_init(hw); -} - -/** * ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status * @hw: pointer to the HW struct * @ts_status: the timestamp mask pointer @@ -2788,7 +2774,6 @@ static int ice_ptp_set_vernier_wl(struct ice_hw *hw) */ static int ice_ptp_init_phc_e82x(struct ice_hw *hw) { - int err; u32 val; /* Enable reading switch and PHY registers over the sideband queue */ @@ -2798,11 +2783,6 @@ static int ice_ptp_init_phc_e82x(struct ice_hw *hw) val |= (PF_SB_REM_DEV_CTL_SWITCH_READ | PF_SB_REM_DEV_CTL_PHY0); wr32(hw, PF_SB_REM_DEV_CTL, val); - /* Initialize the Clock Generation Unit */ - err = ice_tspll_init(hw); - if (err) - return err; - /* Set window length for all the ports */ return ice_ptp_set_vernier_wl(hw); } @@ -5584,7 +5564,7 @@ int ice_ptp_init_phc(struct ice_hw *hw) case ICE_MAC_GENERIC: return ice_ptp_init_phc_e82x(hw); case ICE_MAC_GENERIC_3K_E825: - return ice_ptp_init_phc_e825(hw); + return 0; default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/intel/ice/ice_tspll.c b/drivers/net/ethernet/intel/ice/ice_tspll.c index 08af4ced50eb..66320a4ab86f 100644 --- a/drivers/net/ethernet/intel/ice/ice_tspll.c +++ b/drivers/net/ethernet/intel/ice/ice_tspll.c @@ -72,6 +72,58 @@ static const char *ice_tspll_clk_freq_str(enum ice_tspll_freq clk_freq) } /** + * ice_tspll_default_freq - Return default frequency for a MAC type + * @mac_type: MAC type + * + * Return: default TSPLL frequency for a correct MAC type, -ERANGE otherwise. + */ +static enum ice_tspll_freq ice_tspll_default_freq(enum ice_mac_type mac_type) +{ + switch (mac_type) { + case ICE_MAC_GENERIC: + return ICE_TSPLL_FREQ_25_000; + case ICE_MAC_GENERIC_3K_E825: + return ICE_TSPLL_FREQ_156_250; + default: + return -ERANGE; + } +} + +/** + * ice_tspll_check_params - Check if TSPLL params are correct + * @hw: Pointer to the HW struct + * @clk_freq: Clock frequency to program + * @clk_src: Clock source to select (TIME_REF or TCXO) + * + * Return: true if TSPLL params are correct, false otherwise. + */ +static bool ice_tspll_check_params(struct ice_hw *hw, + enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src) +{ + if (clk_freq >= NUM_ICE_TSPLL_FREQ) { + dev_warn(ice_hw_to_dev(hw), "Invalid TSPLL frequency %u\n", + clk_freq); + return false; + } + + if (clk_src >= NUM_ICE_CLK_SRC) { + dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", + clk_src); + return false; + } + + if ((hw->mac_type == ICE_MAC_GENERIC_3K_E825 || + clk_src == ICE_CLK_SRC_TCXO) && + clk_freq != ice_tspll_default_freq(hw->mac_type)) { + dev_warn(ice_hw_to_dev(hw), "Unsupported frequency for this clock source\n"); + return false; + } + + return true; +} + +/** * ice_tspll_clk_src_str - Convert time_ref_src to string * @clk_src: Clock source * @@ -127,120 +179,121 @@ static void ice_tspll_log_cfg(struct ice_hw *hw, bool enable, u8 clk_src, static int ice_tspll_cfg_e82x(struct ice_hw *hw, enum ice_tspll_freq clk_freq, enum ice_clk_src clk_src) { - union tspll_ro_bwm_lf bwm_lf; - union ice_cgu_r19_e82x dw19; - union ice_cgu_r22 dw22; - union ice_cgu_r24 dw24; - union ice_cgu_r9 dw9; + u32 val, r9, r24; int err; - if (clk_freq >= NUM_ICE_TSPLL_FREQ) { - dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", - clk_freq); - return -EINVAL; - } - - if (clk_src >= NUM_ICE_CLK_SRC) { - dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", - clk_src); - return -EINVAL; - } - - if (clk_src == ICE_CLK_SRC_TCXO && clk_freq != ICE_TSPLL_FREQ_25_000) { - dev_warn(ice_hw_to_dev(hw), - "TCXO only supports 25 MHz frequency\n"); - return -EINVAL; - } - - err = ice_read_cgu_reg(hw, ICE_CGU_R9, &dw9.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); if (err) return err; - err = ice_read_cgu_reg(hw, ICE_CGU_R24, &dw24.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24); if (err) return err; - err = ice_read_cgu_reg(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); + err = ice_read_cgu_reg(hw, ICE_CGU_RO_BWM_LF, &val); if (err) return err; - ice_tspll_log_cfg(hw, dw24.ts_pll_enable, dw24.time_ref_sel, - dw9.time_ref_freq_sel, bwm_lf.plllock_true_lock_cri, + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r24), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + !!FIELD_GET(ICE_CGU_RO_BWM_LF_TRUE_LOCK, val), false); /* Disable the PLL before changing the clock source or frequency */ - if (dw24.ts_pll_enable) { - dw24.ts_pll_enable = 0; + if (FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24)) { + r24 &= ~ICE_CGU_R23_R24_TSPLL_ENABLE; - err = ice_write_cgu_reg(hw, ICE_CGU_R24, dw24.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24); if (err) return err; } /* Set the frequency */ - dw9.time_ref_freq_sel = clk_freq; - err = ice_write_cgu_reg(hw, ICE_CGU_R9, dw9.val); + r9 &= ~ICE_CGU_R9_TIME_REF_FREQ_SEL; + r9 |= FIELD_PREP(ICE_CGU_R9_TIME_REF_FREQ_SEL, clk_freq); + err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9); if (err) return err; /* Configure the TSPLL feedback divisor */ - err = ice_read_cgu_reg(hw, ICE_CGU_R19, &dw19.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R19, &val); if (err) return err; - dw19.fbdiv_intgr = e82x_tspll_params[clk_freq].feedback_div; - dw19.ndivratio = 1; + val &= ~(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X | ICE_CGU_R19_TSPLL_NDIVRATIO); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E82X, + e82x_tspll_params[clk_freq].feedback_div); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_NDIVRATIO, 1); - err = ice_write_cgu_reg(hw, ICE_CGU_R19, dw19.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R19, val); if (err) return err; /* Configure the TSPLL post divisor */ - err = ice_read_cgu_reg(hw, ICE_CGU_R22, &dw22.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val); if (err) return err; - dw22.time1588clk_div = e82x_tspll_params[clk_freq].post_pll_div; - dw22.time1588clk_sel_div2 = 0; + val &= ~(ICE_CGU_R22_TIME1588CLK_DIV | + ICE_CGU_R22_TIME1588CLK_DIV2); + val |= FIELD_PREP(ICE_CGU_R22_TIME1588CLK_DIV, + e82x_tspll_params[clk_freq].post_pll_div); - err = ice_write_cgu_reg(hw, ICE_CGU_R22, dw22.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R22, val); if (err) return err; /* Configure the TSPLL pre divisor and clock source */ - err = ice_read_cgu_reg(hw, ICE_CGU_R24, &dw24.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24); if (err) return err; - dw24.ref1588_ck_div = e82x_tspll_params[clk_freq].refclk_pre_div; - dw24.fbdiv_frac = e82x_tspll_params[clk_freq].frac_n_div; - dw24.time_ref_sel = clk_src; + r24 &= ~(ICE_CGU_R23_R24_REF1588_CK_DIV | ICE_CGU_R24_FBDIV_FRAC | + ICE_CGU_R23_R24_TIME_REF_SEL); + r24 |= FIELD_PREP(ICE_CGU_R23_R24_REF1588_CK_DIV, + e82x_tspll_params[clk_freq].refclk_pre_div); + r24 |= FIELD_PREP(ICE_CGU_R24_FBDIV_FRAC, + e82x_tspll_params[clk_freq].frac_n_div); + r24 |= FIELD_PREP(ICE_CGU_R23_R24_TIME_REF_SEL, clk_src); - err = ice_write_cgu_reg(hw, ICE_CGU_R24, dw24.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24); if (err) return err; + /* Wait to ensure everything is stable */ + usleep_range(10, 20); + /* Finally, enable the PLL */ - dw24.ts_pll_enable = 1; + r24 |= ICE_CGU_R23_R24_TSPLL_ENABLE; - err = ice_write_cgu_reg(hw, ICE_CGU_R24, dw24.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R24, r24); if (err) return err; - /* Wait to verify if the PLL locks */ - usleep_range(1000, 5000); + /* Wait at least 1 ms to verify if the PLL locks */ + usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); - err = ice_read_cgu_reg(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); + err = ice_read_cgu_reg(hw, ICE_CGU_RO_BWM_LF, &val); if (err) return err; - if (!bwm_lf.plllock_true_lock_cri) { - dev_warn(ice_hw_to_dev(hw), "TSPLL failed to lock\n"); + if (!(val & ICE_CGU_RO_BWM_LF_TRUE_LOCK)) { + dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); return -EBUSY; } - ice_tspll_log_cfg(hw, dw24.ts_pll_enable, clk_src, clk_freq, true, - true); + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); + if (err) + return err; + err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24); + if (err) + return err; + + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r24), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r24), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + true, true); return 0; } @@ -256,18 +309,17 @@ static int ice_tspll_cfg_e82x(struct ice_hw *hw, enum ice_tspll_freq clk_freq, */ static int ice_tspll_dis_sticky_bits_e82x(struct ice_hw *hw) { - union tspll_cntr_bist_settings cntr_bist; + u32 val; int err; - err = ice_read_cgu_reg(hw, TSPLL_CNTR_BIST_SETTINGS, &cntr_bist.val); + err = ice_read_cgu_reg(hw, ICE_CGU_CNTR_BIST, &val); if (err) return err; - /* Disable sticky lock detection so lock err reported is accurate */ - cntr_bist.i_plllock_sel_0 = 0; - cntr_bist.i_plllock_sel_1 = 0; + val &= ~(ICE_CGU_CNTR_BIST_PLLLOCK_SEL_0 | + ICE_CGU_CNTR_BIST_PLLLOCK_SEL_1); - return ice_write_cgu_reg(hw, TSPLL_CNTR_BIST_SETTINGS, cntr_bist.val); + return ice_write_cgu_reg(hw, ICE_CGU_CNTR_BIST, val); } /** @@ -288,115 +340,106 @@ static int ice_tspll_dis_sticky_bits_e82x(struct ice_hw *hw) static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq, enum ice_clk_src clk_src) { - union tspll_ro_lock_e825c ro_lock; - union ice_cgu_r19_e825 dw19; - union ice_cgu_r16 dw16; - union ice_cgu_r23 dw23; - union ice_cgu_r22 dw22; - union ice_cgu_r9 dw9; + u32 val, r9, r23; int err; - if (clk_freq >= NUM_ICE_TSPLL_FREQ) { - dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", - clk_freq); - return -EINVAL; - } - - if (clk_src >= NUM_ICE_CLK_SRC) { - dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", - clk_src); - return -EINVAL; - } - - if (clk_freq != ICE_TSPLL_FREQ_156_250) { - dev_warn(ice_hw_to_dev(hw), "Adapter only supports 156.25 MHz frequency\n"); - return -EINVAL; - } - - err = ice_read_cgu_reg(hw, ICE_CGU_R9, &dw9.val); - if (err) - return err; - - err = ice_read_cgu_reg(hw, ICE_CGU_R16, &dw16.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); if (err) return err; - err = ice_read_cgu_reg(hw, ICE_CGU_R23, &dw23.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23); if (err) return err; - err = ice_read_cgu_reg(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val); + err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val); if (err) return err; - ice_tspll_log_cfg(hw, dw23.ts_pll_enable, dw23.time_ref_sel, - dw9.time_ref_freq_sel, - ro_lock.plllock_true_lock_cri, false); + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r23), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + !!FIELD_GET(ICE_CGU_RO_LOCK_TRUE_LOCK, val), + false); /* Disable the PLL before changing the clock source or frequency */ - if (dw23.ts_pll_enable) { - dw23.ts_pll_enable = 0; + if (FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23)) { + r23 &= ~ICE_CGU_R23_R24_TSPLL_ENABLE; - err = ice_write_cgu_reg(hw, ICE_CGU_R23, dw23.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23); if (err) return err; } - /* Set the frequency */ - dw9.time_ref_freq_sel = clk_freq; - - /* Enable the correct receiver */ - if (clk_src == ICE_CLK_SRC_TCXO) { - dw9.time_ref_en = 0; - dw9.clk_eref0_en = 1; - } else { - dw9.time_ref_en = 1; - dw9.clk_eref0_en = 0; + if (FIELD_GET(ICE_CGU_R9_TIME_SYNC_EN, r9)) { + r9 &= ~ICE_CGU_R9_TIME_SYNC_EN; + + err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9); + if (err) + return err; } - err = ice_write_cgu_reg(hw, ICE_CGU_R9, dw9.val); + + /* Set the frequency and enable the correct receiver */ + r9 &= ~(ICE_CGU_R9_TIME_REF_FREQ_SEL | ICE_CGU_R9_CLK_EREF0_EN | + ICE_CGU_R9_TIME_REF_EN); + r9 |= FIELD_PREP(ICE_CGU_R9_TIME_REF_FREQ_SEL, clk_freq); + if (clk_src == ICE_CLK_SRC_TCXO) + r9 |= ICE_CGU_R9_CLK_EREF0_EN; + else + r9 |= ICE_CGU_R9_TIME_REF_EN; + r9 |= ICE_CGU_R9_TIME_SYNC_EN; + err = ice_write_cgu_reg(hw, ICE_CGU_R9, r9); if (err) return err; /* Choose the referenced frequency */ - dw16.ck_refclkfreq = ICE_TSPLL_CK_REFCLKFREQ_E825; - err = ice_write_cgu_reg(hw, ICE_CGU_R16, dw16.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R16, &val); + if (err) + return err; + val &= ~ICE_CGU_R16_TSPLL_CK_REFCLKFREQ; + val |= FIELD_PREP(ICE_CGU_R16_TSPLL_CK_REFCLKFREQ, + ICE_TSPLL_CK_REFCLKFREQ_E825); + err = ice_write_cgu_reg(hw, ICE_CGU_R16, val); if (err) return err; /* Configure the TSPLL feedback divisor */ - err = ice_read_cgu_reg(hw, ICE_CGU_R19, &dw19.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R19, &val); if (err) return err; - dw19.tspll_fbdiv_intgr = ICE_TSPLL_FBDIV_INTGR_E825; - dw19.tspll_ndivratio = ICE_TSPLL_NDIVRATIO_E825; + val &= ~(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825 | + ICE_CGU_R19_TSPLL_NDIVRATIO); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_FBDIV_INTGR_E825, + ICE_TSPLL_FBDIV_INTGR_E825); + val |= FIELD_PREP(ICE_CGU_R19_TSPLL_NDIVRATIO, + ICE_TSPLL_NDIVRATIO_E825); - err = ice_write_cgu_reg(hw, ICE_CGU_R19, dw19.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R19, val); if (err) return err; - /* Configure the TSPLL post divisor */ - err = ice_read_cgu_reg(hw, ICE_CGU_R22, &dw22.val); + /* Configure the TSPLL post divisor, these two are constant */ + err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val); if (err) return err; - /* These two are constant for E825C */ - dw22.time1588clk_div = 5; - dw22.time1588clk_sel_div2 = 0; + val &= ~(ICE_CGU_R22_TIME1588CLK_DIV | + ICE_CGU_R22_TIME1588CLK_DIV2); + val |= FIELD_PREP(ICE_CGU_R22_TIME1588CLK_DIV, 5); - err = ice_write_cgu_reg(hw, ICE_CGU_R22, dw22.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R22, val); if (err) return err; - /* Configure the TSPLL pre divisor and clock source */ - err = ice_read_cgu_reg(hw, ICE_CGU_R23, &dw23.val); + /* Configure the TSPLL pre divisor (constant) and clock source */ + err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23); if (err) return err; - dw23.ref1588_ck_div = 0; - dw23.time_ref_sel = clk_src; + r23 &= ~(ICE_CGU_R23_R24_REF1588_CK_DIV | ICE_CGU_R23_R24_TIME_REF_SEL); + r23 |= FIELD_PREP(ICE_CGU_R23_R24_TIME_REF_SEL, clk_src); - err = ice_write_cgu_reg(hw, ICE_CGU_R23, dw23.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23); if (err) return err; @@ -405,27 +448,39 @@ static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq, if (err) return err; + /* Wait to ensure everything is stable */ + usleep_range(10, 20); + /* Finally, enable the PLL */ - dw23.ts_pll_enable = 1; + r23 |= ICE_CGU_R23_R24_TSPLL_ENABLE; - err = ice_write_cgu_reg(hw, ICE_CGU_R23, dw23.val); + err = ice_write_cgu_reg(hw, ICE_CGU_R23, r23); if (err) return err; - /* Wait to verify if the PLL locks */ - usleep_range(1000, 5000); + /* Wait at least 1 ms to verify if the PLL locks */ + usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); - err = ice_read_cgu_reg(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val); + err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val); if (err) return err; - if (!ro_lock.plllock_true_lock_cri) { - dev_warn(ice_hw_to_dev(hw), "TSPLL failed to lock\n"); + if (!(val & ICE_CGU_RO_LOCK_TRUE_LOCK)) { + dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); return -EBUSY; } - ice_tspll_log_cfg(hw, dw23.ts_pll_enable, clk_src, clk_freq, true, - true); + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9); + if (err) + return err; + err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23); + if (err) + return err; + + ice_tspll_log_cfg(hw, !!FIELD_GET(ICE_CGU_R23_R24_TSPLL_ENABLE, r23), + FIELD_GET(ICE_CGU_R23_R24_TIME_REF_SEL, r23), + FIELD_GET(ICE_CGU_R9_TIME_REF_FREQ_SEL, r9), + true, true); return 0; } @@ -441,20 +496,18 @@ static int ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq, */ static int ice_tspll_dis_sticky_bits_e825c(struct ice_hw *hw) { - union tspll_bw_tdc_e825c bw_tdc; + u32 val; int err; - err = ice_read_cgu_reg(hw, TSPLL_BW_TDC_E825C, &bw_tdc.val); + err = ice_read_cgu_reg(hw, ICE_CGU_BW_TDC, &val); if (err) return err; - bw_tdc.i_plllock_sel_1_0 = 0; + val &= ~ICE_CGU_BW_TDC_PLLLOCK_SEL; - return ice_write_cgu_reg(hw, TSPLL_BW_TDC_E825C, bw_tdc.val); + return ice_write_cgu_reg(hw, ICE_CGU_BW_TDC, val); } -#define ICE_ONE_PPS_OUT_AMP_MAX 3 - /** * ice_tspll_cfg_pps_out_e825c - Enable/disable 1PPS output and set amplitude * @hw: pointer to the HW struct @@ -464,16 +517,64 @@ static int ice_tspll_dis_sticky_bits_e825c(struct ice_hw *hw) */ int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable) { - union ice_cgu_r9 r9; + u32 val; int err; - err = ice_read_cgu_reg(hw, ICE_CGU_R9, &r9.val); + err = ice_read_cgu_reg(hw, ICE_CGU_R9, &val); if (err) return err; - r9.one_pps_out_en = enable; - r9.one_pps_out_amp = enable * ICE_ONE_PPS_OUT_AMP_MAX; - return ice_write_cgu_reg(hw, ICE_CGU_R9, r9.val); + val &= ~(ICE_CGU_R9_ONE_PPS_OUT_EN | ICE_CGU_R9_ONE_PPS_OUT_AMP); + val |= FIELD_PREP(ICE_CGU_R9_ONE_PPS_OUT_EN, enable) | + ICE_CGU_R9_ONE_PPS_OUT_AMP; + + return ice_write_cgu_reg(hw, ICE_CGU_R9, val); +} + +/** + * ice_tspll_cfg - Configure the Clock Generation Unit TSPLL + * @hw: Pointer to the HW struct + * @clk_freq: Clock frequency to program + * @clk_src: Clock source to select (TIME_REF, or TCXO) + * + * Configure the Clock Generation Unit with the desired clock frequency and + * time reference, enabling the TSPLL which drives the PTP hardware clock. + * + * Return: 0 on success, -ERANGE on unsupported MAC type, other negative error + * codes when failed to configure CGU. + */ +static int ice_tspll_cfg(struct ice_hw *hw, enum ice_tspll_freq clk_freq, + enum ice_clk_src clk_src) +{ + switch (hw->mac_type) { + case ICE_MAC_GENERIC: + return ice_tspll_cfg_e82x(hw, clk_freq, clk_src); + case ICE_MAC_GENERIC_3K_E825: + return ice_tspll_cfg_e825c(hw, clk_freq, clk_src); + default: + return -ERANGE; + } +} + +/** + * ice_tspll_dis_sticky_bits - disable TSPLL sticky bits + * @hw: Pointer to the HW struct + * + * Configure the Clock Generation Unit TSPLL sticky bits so they don't latch on + * losing TSPLL lock, but always show current state. + * + * Return: 0 on success, -ERANGE on unsupported MAC type. + */ +static int ice_tspll_dis_sticky_bits(struct ice_hw *hw) +{ + switch (hw->mac_type) { + case ICE_MAC_GENERIC: + return ice_tspll_dis_sticky_bits_e82x(hw); + case ICE_MAC_GENERIC_3K_E825: + return ice_tspll_dis_sticky_bits_e825c(hw); + default: + return -ERANGE; + } } /** @@ -487,25 +588,39 @@ int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable) int ice_tspll_init(struct ice_hw *hw) { struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; + enum ice_tspll_freq tspll_freq; + enum ice_clk_src clk_src; int err; - /* Disable sticky lock detection so lock err reported is accurate. */ - if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) - err = ice_tspll_dis_sticky_bits_e825c(hw); - else - err = ice_tspll_dis_sticky_bits_e82x(hw); + /* Only E822, E823 and E825 products support TSPLL */ + if (hw->mac_type != ICE_MAC_GENERIC && + hw->mac_type != ICE_MAC_GENERIC_3K_E825) + return 0; + + tspll_freq = (enum ice_tspll_freq)ts_info->time_ref; + clk_src = (enum ice_clk_src)ts_info->clk_src; + if (!ice_tspll_check_params(hw, tspll_freq, clk_src)) + return -EINVAL; + + /* Disable sticky lock detection so lock status reported is accurate */ + err = ice_tspll_dis_sticky_bits(hw); if (err) return err; /* Configure the TSPLL using the parameters from the function * capabilities. */ - if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) - err = ice_tspll_cfg_e825c(hw, ts_info->time_ref, - (enum ice_clk_src)ts_info->clk_src); - else - err = ice_tspll_cfg_e82x(hw, ts_info->time_ref, - (enum ice_clk_src)ts_info->clk_src); + err = ice_tspll_cfg(hw, tspll_freq, clk_src); + if (err) { + dev_warn(ice_hw_to_dev(hw), "Failed to lock TSPLL to predefined frequency. Retrying with fallback frequency.\n"); + + /* Try to lock to internal TCXO as a fallback. */ + tspll_freq = ice_tspll_default_freq(hw->mac_type); + clk_src = ICE_CLK_SRC_TCXO; + err = ice_tspll_cfg(hw, tspll_freq, clk_src); + if (err) + dev_warn(ice_hw_to_dev(hw), "Failed to lock TSPLL to fallback frequency.\n"); + } return err; } |