From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 65A5145500; Wed, 26 Jun 2024 13:55:27 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8823442FF5; Wed, 26 Jun 2024 13:55:02 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) by mails.dpdk.org (Postfix) with ESMTP id F2E9642E95 for ; Wed, 26 Jun 2024 13:43:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1719402189; x=1750938189; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kXPiopgcdEed0yoE0ikyQ8yb4ZHDOGsWVI087EtLbGE=; b=DcVWXiFRuuPhH7TtdrqvAvz3GBBPhoa7d77/qH3CzySA32RqGBa1LX7h rujCLfW7zkKDEJFG4qumgm17QRsc2Amhbmtf7It2TEhkKszLLiKY7fAuk fAqDccDP8UEqKnqXtu3SzRzeo0rlHPFuypVtY9+JIFcK8IZUcQ7GZ2ILl nFXiBxV67xYYePBzp8Q5IUCw1Z2LCEC1e8nudpFKE4s92XkAIgufTMNIB xzLDIQbP7yuiX4++HIY3F9nuQlpCazHQnUJGvByelvRg5FTT/fvBCBz4X Hu2buTOkhAP/5W9RvO+ExPJprRO7h/khM1DiV1TrDreWllDrS+L3sr6fr w==; X-CSE-ConnectionGUID: hpDhbp2/TSGgjecsEZp6TA== X-CSE-MsgGUID: ntATl1MbQ4yM6iGd/U2kOQ== X-IronPort-AV: E=McAfee;i="6700,10204,11114"; a="38979279" X-IronPort-AV: E=Sophos;i="6.08,266,1712646000"; d="scan'208";a="38979279" Received: from orviesa010.jf.intel.com ([10.64.159.150]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Jun 2024 04:43:08 -0700 X-CSE-ConnectionGUID: WO8Yn2wdQC65ll+Bx1bcnQ== X-CSE-MsgGUID: AV3yXjlHRv29p+8SkxBoyw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.08,266,1712646000"; d="scan'208";a="43873429" Received: from unknown (HELO silpixa00401119.ir.intel.com) ([10.55.129.167]) by orviesa010.jf.intel.com with ESMTP; 26 Jun 2024 04:43:07 -0700 From: Anatoly Burakov To: dev@dpdk.org Cc: Michal Michalik , ian.stokes@intel.com, bruce.richardson@intel.com Subject: [PATCH v4 005/103] net/ice/base: add support for E825-C TX clock changing Date: Wed, 26 Jun 2024 12:40:53 +0100 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Michal Michalik E825-C hardware has a new feature which allows to change the clocks which drives the TX on the PHYs. The registers are accessed directly no interaction with FW via admin queue commands. Add this support. Signed-off-by: Michal Michalik Signed-off-by: Ian Stokes --- drivers/net/ice/base/ice_cgu_regs.h | 90 ++++++ drivers/net/ice/base/ice_common.c | 19 ++ drivers/net/ice/base/ice_common.h | 1 + drivers/net/ice/base/ice_phy_regs.h | 84 ++++++ drivers/net/ice/base/ice_ptp_hw.c | 453 ++++++++++++++++++++++++++-- drivers/net/ice/base/ice_ptp_hw.h | 12 + 6 files changed, 628 insertions(+), 31 deletions(-) create mode 100644 drivers/net/ice/base/ice_phy_regs.h diff --git a/drivers/net/ice/base/ice_cgu_regs.h b/drivers/net/ice/base/ice_cgu_regs.h index c44bfc1846..f24f4746dd 100644 --- a/drivers/net/ice/base/ice_cgu_regs.h +++ b/drivers/net/ice/base/ice_cgu_regs.h @@ -28,6 +28,42 @@ union nac_cgu_dword9 { u32 val; }; +#define NAC_CGU_DWORD10_E825C 0x28 +union nac_cgu_dword10_e825c { + struct { + u32 ja_pll_enable : 1; + u32 misc11 : 1; + u32 fdpll_enable : 1; + u32 fdpll_slow : 1; + u32 fdpll_lock_int_enb : 1; + u32 synce_clko_sel : 4; + u32 synce_clkodiv_m1 : 5; + u32 synce_clkodiv_load : 1; + u32 synce_dck_rst : 1; + u32 synce_ethclko_sel : 3; + u32 synce_ethdiv_m1 : 5; + u32 synce_ethdiv_load : 1; + u32 synce_dck2_rst : 1; + u32 synce_sel_gnd : 1; + u32 synce_s_ref_clk : 5; + } field; + u32 val; +}; + +#define NAC_CGU_DWORD11_E825C 0x2c +union nac_cgu_dword11_e825c { + struct { + u32 misc25 : 1; + u32 synce_s_byp_clk : 6; + u32 synce_hdov_mode : 1; + u32 synce_rat_sel : 2; + u32 synce_link_enable : 20; + u32 synce_misclk_en : 1; + u32 synce_misclk_rat_m1 : 1; + } field; + u32 val; +}; + #define NAC_CGU_DWORD19 0x4c union nac_cgu_dword19 { struct { @@ -68,6 +104,22 @@ union nac_cgu_dword22 { u32 val; }; +#define NAC_CGU_DWORD23_E825C 0x5C +union nac_cgu_dword23_e825c { + 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; + + } field; + u32 val; +}; + #define NAC_CGU_DWORD24 0x60 union nac_cgu_dword24 { struct { @@ -114,4 +166,42 @@ union tspll_ro_bwm_lf { 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; + } field; + 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; + } field; + u32 val; +}; + #endif /* _ICE_CGU_REGS_H_ */ diff --git a/drivers/net/ice/base/ice_common.c b/drivers/net/ice/base/ice_common.c index b68afdaa14..50c8a1b472 100644 --- a/drivers/net/ice/base/ice_common.c +++ b/drivers/net/ice/base/ice_common.c @@ -270,6 +270,25 @@ bool ice_is_e823(struct ice_hw *hw) } } +/** + * ice_is_e825c + * @hw: pointer to the hardware structure + * + * returns true if the device is E825-C based, false if not. + */ +bool ice_is_e825c(struct ice_hw *hw) +{ + switch (hw->device_id) { + case ICE_DEV_ID_E825C_BACKPLANE: + case ICE_DEV_ID_E825C_QSFP: + case ICE_DEV_ID_E825C_SFP: + case ICE_DEV_ID_E825C_SGMII: + return true; + default: + return false; + } +} + /** * ice_clear_pf_cfg - Clear PF configuration * @hw: pointer to the hardware structure diff --git a/drivers/net/ice/base/ice_common.h b/drivers/net/ice/base/ice_common.h index 2aeb1a520a..18cbe590c6 100644 --- a/drivers/net/ice/base/ice_common.h +++ b/drivers/net/ice/base/ice_common.h @@ -265,6 +265,7 @@ void ice_print_rollback_msg(struct ice_hw *hw); bool ice_is_generic_mac(struct ice_hw *hw); bool ice_is_e810(struct ice_hw *hw); bool ice_is_e810t(struct ice_hw *hw); +bool ice_is_e825c(struct ice_hw *hw); bool ice_is_e823(struct ice_hw *hw); int ice_sched_query_elem(struct ice_hw *hw, u32 node_teid, diff --git a/drivers/net/ice/base/ice_phy_regs.h b/drivers/net/ice/base/ice_phy_regs.h new file mode 100644 index 0000000000..4d0415b00a --- /dev/null +++ b/drivers/net/ice/base/ice_phy_regs.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2001-2024 Intel Corporation + */ + +#ifndef _ICE_PHY_REGS_H_ +#define _ICE_PHY_REGS_H_ + +#define CLKRX_CMN_CLK(i) (0x7E8000 + (i) * 0x5000) +#define CLKRX_CMN_CLK_NUM 5 + +#define CLKRX_CMN_REG_10(i) (CLKRX_CMN_CLK(i) + 0x28) +union clkrx_cmn_reg_10 { + struct { + u32 cmnntl_refck_pdmtchval : 19; + u32 cmnntl_refckm_charge_up_locovr : 1; + u32 cmnntl_refckm_pull_dn_locovr : 1; + u32 cmnntl_refckm_sense_locovr : 1; + u32 cmnntl_refckp_charge_up_locovr : 1; + u32 cmnntl_refckp_pull_dn_locovr : 1; + u32 cmnntl_refckp_sense_locovr : 1; + u32 cmnpmu_h8_off_delay : 4; + u32 cmnref_locovren : 1; + u32 cmnref_pad2cmos_ana_en_locovr : 1; + u32 cmnref_pad2cmos_dig_en_locovr : 1; + } field; + u32 val; +}; + +#define CLKRX_CMN_REG_12(i) (CLKRX_CMN_CLK(i) + 0x30) +union clkrx_cmn_reg_12 { + struct { + u32 cmnpmu_restore_off_delay : 4; + u32 cmnpmu_rst_off_delay : 4; + u32 cmnref_cdrdivsel_locovr : 5; + u32 cmnref_refsel0_locovr : 4; + u32 cmnref_refsel1_locovr : 4; + u32 cmnref_refsel1_powersave_en_locovr : 1; + u32 cmnref_refsel2_locovr : 4; + u32 cmnref_refsel2_powersave_en_locovr : 1; + u32 cmnref_refsel3_locovr : 4; + u32 cmnref_refsel3_powersave_en_locovr : 1; + } field; + u32 val; +}; + +#define CLKRX_CMN_REG_46(i) (CLKRX_CMN_CLK(i) + 0x220) +union clkrx_cmn_reg_46 { + struct { + u32 cmnntl_refck_lkgcnt : 19; + u32 cmnref_refsel0_loc : 4; + u32 cmnref_refsel1_loc : 4; + u32 cmnref_refsel1_powersave_en_loc : 1; + u32 cmnref_refsel2_loc : 4; + } field; + u32 val; +}; + +#define SERDES_IP_IF_LN_FLXM_GENERAL(n, m) \ + (0x32B800 + (m) * 0x100000 + (n) * 0x8000) +union serdes_ip_if_ln_flxm_general { + struct { + u32 reserved0_1 : 2; + u32 ictl_pcs_mode_nt : 1; + u32 ictl_pcs_rcomp_slave_en_nt : 1; + u32 ictl_pcs_cmn_force_pup_a : 1; + u32 ictl_pcs_rcomp_slave_valid_a : 1; + u32 ictl_pcs_ref_sel_rx_nt : 4; + u32 idat_dfx_obs_dig_ : 2; + u32 irst_apb_mem_b : 1; + u32 ictl_pcs_disconnect_nt : 1; + u32 ictl_pcs_isolate_nt : 1; + u32 reserved15_15 : 1; + u32 irst_pcs_tstbus_b_a : 1; + u32 ictl_pcs_ref_term_hiz_en_nt : 1; + u32 reserved18_19 : 2; + u32 ictl_pcs_synthlcslow_force_pup_a : 1; + u32 ictl_pcs_synthlcfast_force_pup_a : 1; + u32 reserved22_24 : 3; + u32 ictl_pcs_ref_sel_tx_nt : 4; + u32 reserved29_31 : 3; + } field; + u32 val; +}; +#endif /* _ICE_PHY_REGS_H_ */ diff --git a/drivers/net/ice/base/ice_ptp_hw.c b/drivers/net/ice/base/ice_ptp_hw.c index 427c16e1dd..e83f4d5357 100644 --- a/drivers/net/ice/base/ice_ptp_hw.c +++ b/drivers/net/ice/base/ice_ptp_hw.c @@ -7,6 +7,7 @@ #include "ice_ptp_hw.h" #include "ice_ptp_consts.h" #include "ice_cgu_regs.h" +#include "ice_phy_regs.h" /* Low level functions for interacting with and managing the device clock used * for the Precision Time Protocol. @@ -102,16 +103,16 @@ u64 ice_ptp_read_src_incval(struct ice_hw *hw) } /** - * ice_read_cgu_reg_e822 - Read a CGU register + * ice_read_cgu_reg_e82x - Read a CGU register * @hw: pointer to the HW struct * @addr: Register address to read * @val: storage for register value read * * Read the contents of a register of the Clock Generation Unit. Only - * applicable to E822 devices. + * applicable to E822/E823/E825 devices. */ static int -ice_read_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 *val) +ice_read_cgu_reg_e82x(struct ice_hw *hw, u16 addr, u32 *val) { struct ice_sbq_msg_input cgu_msg; int status; @@ -134,16 +135,16 @@ ice_read_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 *val) } /** - * ice_write_cgu_reg_e822 - Write a CGU register + * ice_write_cgu_reg_e82x - Write a CGU register * @hw: pointer to the HW struct * @addr: Register address to write * @val: value to write into the register * * Write the specified value to a register of the Clock Generation Unit. Only - * applicable to E822 devices. + * applicable to E822/E823/E825 devices. */ static int -ice_write_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 val) +ice_write_cgu_reg_e82x(struct ice_hw *hw, u16 addr, u32 val) { struct ice_sbq_msg_input cgu_msg; int status; @@ -244,15 +245,15 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, return ICE_ERR_PARAM; } - status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val); + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val); if (status) return status; - status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); if (status) return status; - status = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); + status = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); if (status) return status; @@ -267,43 +268,43 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, if (dw24.field.ts_pll_enable) { dw24.field.ts_pll_enable = 0; - status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); if (status) return status; } /* Set the frequency */ dw9.field.time_ref_freq_sel = clk_freq; - status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val); + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val); if (status) return status; /* Configure the TS PLL feedback divisor */ - status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val); + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val); if (status) return status; dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div; dw19.field.tspll_ndivratio = 1; - status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val); + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val); if (status) return status; /* Configure the TS PLL post divisor */ - status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val); + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val); if (status) return status; dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div; dw22.field.time1588clk_sel_div2 = 0; - status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val); + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val); if (status) return status; /* Configure the TS PLL pre divisor and clock source */ - status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); if (status) return status; @@ -311,21 +312,21 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div; dw24.field.time_ref_sel = clk_src; - status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); if (status) return status; /* Finally, enable the PLL */ dw24.field.ts_pll_enable = 1; - status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); if (status) return status; /* Wait to verify if the PLL locks */ ice_msec_delay(1, true); - status = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); + status = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); if (status) return status; @@ -345,36 +346,426 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, } /** - * ice_init_cgu_e822 - Initialize CGU with settings from firmware - * @hw: pointer to the HW structure + * ice_cfg_cgu_pll_e825c - Configure the Clock Generation Unit for E825-C + * @hw: pointer to the HW struct + * @clk_freq: Clock frequency to program + * @clk_src: Clock source to select (TIME_REF, or TCX0) * - * Initialize the Clock Generation Unit of the E822 device. + * Configure the Clock Generation Unit with the desired clock frequency and + * time reference, enabling the PLL which drives the PTP hardware clock. */ -static int ice_init_cgu_e822(struct ice_hw *hw) +int +ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq, + enum ice_clk_src *clk_src) +{ + union tspll_ro_lock_e825c ro_lock; + union nac_cgu_dword23_e825c dw23; + union nac_cgu_dword19 dw19; + union nac_cgu_dword22 dw22; + union nac_cgu_dword24 dw24; + union nac_cgu_dword9 dw9; + int status; + + if (*clk_freq >= NUM_ICE_TIME_REF_FREQ) { + ice_warn(hw, "Invalid TIME_REF frequency %u\n", *clk_freq); + return ICE_ERR_PARAM; + } + + if (*clk_src >= NUM_ICE_CLK_SRC) { + ice_warn(hw, "Invalid clock source %u\n", *clk_src); + return ICE_ERR_PARAM; + } + + if (*clk_src == ICE_CLK_SRC_TCX0 && + *clk_freq != ICE_TIME_REF_FREQ_25_000) { + ice_warn(hw, "TCX0 only supports 25 MHz frequency\n"); + return ICE_ERR_PARAM; + } + + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val); + if (status) + return status; + + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val); + if (status) + return status; + + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, &dw23.val); + if (status) + return status; + + status = ice_read_cgu_reg_e82x(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val); + if (status) + return status; + + /* Log the current clock configuration */ + ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", + dw24.field.ts_pll_enable ? "enabled" : "disabled", + ice_clk_src_str(dw23.field.time_ref_sel), + ice_clk_freq_str(dw9.field.time_ref_freq_sel), + ro_lock.field.plllock_true_lock_cri ? "locked" : "unlocked"); + + /* Disable the PLL before changing the clock source or frequency */ + if (dw23.field.ts_pll_enable) { + dw23.field.ts_pll_enable = 0; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, + dw23.val); + if (status) + return status; + } + + /* Set the frequency */ + dw9.field.time_ref_freq_sel = *clk_freq; + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val); + if (status) + return status; + + /* Configure the TS PLL feedback divisor */ + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val); + if (status) + return status; + + dw19.field.tspll_fbdiv_intgr = e822_cgu_params[*clk_freq].feedback_div; + dw19.field.tspll_ndivratio = 1; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val); + if (status) + return status; + + /* Configure the TS PLL post divisor */ + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val); + if (status) + return status; + + dw22.field.time1588clk_div = e822_cgu_params[*clk_freq].post_pll_div; + dw22.field.time1588clk_sel_div2 = 0; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val); + if (status) + return status; + + /* Configure the TS PLL pre divisor and clock source */ + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, &dw23.val); + if (status) + return status; + + dw23.field.ref1588_ck_div = e822_cgu_params[*clk_freq].refclk_pre_div; + dw23.field.time_ref_sel = *clk_src; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, dw23.val); + if (status) + return status; + + dw24.field.tspll_fbdiv_frac = e822_cgu_params[*clk_freq].frac_n_div; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val); + if (status) + return status; + + /* Finally, enable the PLL */ + dw23.field.ts_pll_enable = 1; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, dw23.val); + if (status) + return status; + + /* Wait to verify if the PLL locks */ + ice_msec_delay(1, true); + + status = ice_read_cgu_reg_e82x(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val); + if (status) + return status; + + if (!ro_lock.field.plllock_true_lock_cri) { + ice_warn(hw, "CGU PLL failed to lock\n"); + return ICE_ERR_NOT_READY; + } + + /* Log the current clock configuration */ + ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", + dw24.field.ts_pll_enable ? "enabled" : "disabled", + ice_clk_src_str(dw23.field.time_ref_sel), + ice_clk_freq_str(dw9.field.time_ref_freq_sel), + ro_lock.field.plllock_true_lock_cri ? "locked" : "unlocked"); + + *clk_freq = (enum ice_time_ref_freq)dw9.field.time_ref_freq_sel; + *clk_src = (enum ice_clk_src)dw23.field.time_ref_sel; + + return 0; +} + +/** + * ice_cfg_cgu_pll_dis_sticky_bits_e822 - disable TS PLL sticky bits + * @hw: pointer to the HW struct + * + * Configure the Clock Generation Unit TS PLL sticky bits so they don't latch on + * losing TS PLL lock, but always show current state. + */ +static int ice_cfg_cgu_pll_dis_sticky_bits_e822(struct ice_hw *hw) { - struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; union tspll_cntr_bist_settings cntr_bist; int status; - status = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, + status = ice_read_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS, &cntr_bist.val); if (status) return status; - /* Disable sticky lock detection so lock status reported is accurate */ cntr_bist.field.i_plllock_sel_0 = 0; cntr_bist.field.i_plllock_sel_1 = 0; - status = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, + status = ice_write_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS, cntr_bist.val); + return status; +} + +/** + * ice_cfg_cgu_pll_dis_sticky_bits_e825c - disable TS PLL sticky bits for E825-C + * @hw: pointer to the HW struct + * + * Configure the Clock Generation Unit TS PLL sticky bits so they don't latch on + * losing TS PLL lock, but always show current state. + */ +static int ice_cfg_cgu_pll_dis_sticky_bits_e825c(struct ice_hw *hw) +{ + union tspll_bw_tdc_e825c bw_tdc; + int status; + + status = ice_read_cgu_reg_e82x(hw, TSPLL_BW_TDC_E825C, + &bw_tdc.val); + if (status) + return status; + + bw_tdc.field.i_plllock_sel_1_0 = 0; + + status = ice_write_cgu_reg_e82x(hw, TSPLL_BW_TDC_E825C, + bw_tdc.val); + return status; +} + +/** + * ice_cgu_ts_pll_lost_lock_e825c - check if TS PLL lost lock + * @hw: pointer to the HW struct + * @lost_lock: output flag for reporting lost lock + */ +int +ice_cgu_ts_pll_lost_lock_e825c(struct ice_hw *hw, bool *lost_lock) +{ + union tspll_ro_lock_e825c ro_lock; + int status; + + status = ice_read_cgu_reg_e82x(hw, TSPLL_RO_LOCK_E825C, &ro_lock.val); + if (status) + return status; + + if (ro_lock.field.pllunlock_flag_cri && + !ro_lock.field.plllock_true_lock_cri) + *lost_lock = true; + else + *lost_lock = false; + + return 0; +} + +/** + * ice_cgu_ts_pll_restart_e825c - trigger TS PLL restart + * @hw: pointer to the HW struct + */ +int ice_cgu_ts_pll_restart_e825c(struct ice_hw *hw) +{ + union nac_cgu_dword23_e825c dw23; + int status; + + /* Read the initial values of DW23 */ + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, &dw23.val); + if (status) + return status; + + /* Disable the PLL */ + dw23.field.ts_pll_enable = 0; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, dw23.val); + if (status) + return status; + + /* Wait 5us before reenabling PLL */ + ice_usec_delay(5, false); + + /* Re-enable the PLL */ + dw23.field.ts_pll_enable = 1; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, dw23.val); + if (status) + return status; + + return 0; +} + +#define E825C_CGU_BYPASS_MUX_OFFSET 3 +/** + * cgu_bypass_mux_port - calculate which output of the mux should be used + * @hw: pointer to the HW struct + * @port: number of the port + */ +static u32 cgu_bypass_mux_port(struct ice_hw *hw, u8 port) +{ + return (port % hw->phy_ports) + + E825C_CGU_BYPASS_MUX_OFFSET; +} + +/** + * ice_cgu_bypass_mux_port_active_e825c - check if the given port is set active + * @hw: pointer to the HW struct + * @port: number of the port + * @active: output flag showing if port is active + */ +int +ice_cgu_bypass_mux_port_active_e825c(struct ice_hw *hw, u8 port, bool *active) +{ + union nac_cgu_dword11_e825c dw11; + int status; + + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD11_E825C, &dw11.val); + if (status) + return status; + + if (dw11.field.synce_s_byp_clk == cgu_bypass_mux_port(hw, port)) + *active = true; + else + *active = false; + + return 0; +} + +/** + * ice_cfg_cgu_bypass_mux_e825c - check if the given port is set active + * @hw: pointer to the HW struct + * @port: number of the port + * @clock_1588: true to enable 1588 reference, false to recover from port + * @ena: true to enable the reference, false if disable + */ +int +ice_cfg_cgu_bypass_mux_e825c(struct ice_hw *hw, u8 port, bool clock_1588, + unsigned int ena) +{ + union nac_cgu_dword11_e825c dw11; + union nac_cgu_dword10_e825c dw10; + int status; + + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD11_E825C, &dw11.val); + if (status) + return status; + + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD10_E825C, &dw10.val); + if (status) + return status; + + /* ref_clk_byp1_div */ + dw10.field.synce_ethclko_sel = 0x1; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD10_E825C, dw10.val); + if (status) + return status; + + if (!ena) + /* net_ref_clk0 */ + dw11.field.synce_s_byp_clk = 0x0; + else + dw11.field.synce_s_byp_clk = cgu_bypass_mux_port(hw, port); + + return ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD11_E825C, dw11.val); +} + +/** + * ice_get_div_e825c - get the divider for the given speed + * @link_speed: link speed of the port + * @divider: output value, calculated divider + */ +static int ice_get_div_e825c(u16 link_speed, u8 *divider) +{ + switch (link_speed) { + case ICE_AQ_LINK_SPEED_100GB: + case ICE_AQ_LINK_SPEED_50GB: + case ICE_AQ_LINK_SPEED_25GB: + *divider = 10; + break; + case ICE_AQ_LINK_SPEED_40GB: + case ICE_AQ_LINK_SPEED_10GB: + *divider = 4; + break; + case ICE_AQ_LINK_SPEED_5GB: + case ICE_AQ_LINK_SPEED_2500MB: + case ICE_AQ_LINK_SPEED_1000MB: + *divider = 2; + break; + case ICE_AQ_LINK_SPEED_100MB: + *divider = 1; + break; + default: + return ICE_ERR_NOT_SUPPORTED; + } + return 0; +} + +/** + * ice_cfg_synce_ethdiv_e825c - set the divider on the mux + * @hw: pointer to the HW struct + * @divider: output parameter, returns used divider value + */ +int ice_cfg_synce_ethdiv_e825c(struct ice_hw *hw, u8 *divider) +{ + union nac_cgu_dword10_e825c dw10; + int status; + u16 link_speed; + + link_speed = hw->port_info->phy.link_info.link_speed; + status = ice_get_div_e825c(link_speed, divider); + if (status) + return status; + + status = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD10_E825C, &dw10.val); + if (status) + return status; + + /* programmable divider value (from 2 to 16) minus 1 for ETHCLKOUT */ + dw10.field.synce_ethdiv_m1 = *divider + 1; + + status = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD10_E825C, + dw10.val); + return status; +} + +/** + * ice_init_cgu_e82x - Initialize CGU with settings from firmware + * @hw: pointer to the HW structure + * + * Initialize the Clock Generation Unit of the E822/E823/E825 device. + */ +static int ice_init_cgu_e82x(struct ice_hw *hw) +{ + struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; + enum ice_time_ref_freq time_ref_freq; + enum ice_clk_src clk_src; + int status; + + /* Disable sticky lock detection so lock status reported is accurate */ + if (ice_is_e825c(hw)) + status = ice_cfg_cgu_pll_dis_sticky_bits_e825c(hw); + else + status = ice_cfg_cgu_pll_dis_sticky_bits_e822(hw); if (status) return status; /* Configure the CGU PLL using the parameters from the function * capabilities. */ - status = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref, - (enum ice_clk_src)ts_info->clk_src); + time_ref_freq = (enum ice_time_ref_freq)ts_info->time_ref; + clk_src = (enum ice_clk_src)ts_info->clk_src; + if (ice_is_e825c(hw)) + status = ice_cfg_cgu_pll_e825c(hw, &time_ref_freq, &clk_src); + else + status = ice_cfg_cgu_pll_e822(hw, time_ref_freq, clk_src); if (status) return status; @@ -1763,7 +2154,7 @@ static int ice_ptp_init_phc_eth56g(struct ice_hw *hw) wr32(hw, PF_SB_REM_DEV_CTL, regval); /* Initialize the Clock Generation Unit */ - status = ice_init_cgu_e822(hw); + status = ice_init_cgu_e82x(hw); return status; } @@ -2453,7 +2844,7 @@ static int ice_ptp_init_phc_e822(struct ice_hw *hw) wr32(hw, PF_SB_REM_DEV_CTL, regval); /* Initialize the Clock Generation Unit */ - status = ice_init_cgu_e822(hw); + status = ice_init_cgu_e82x(hw); if (status) return status; diff --git a/drivers/net/ice/base/ice_ptp_hw.h b/drivers/net/ice/base/ice_ptp_hw.h index 441ad0b77d..e2fb716186 100644 --- a/drivers/net/ice/base/ice_ptp_hw.h +++ b/drivers/net/ice/base/ice_ptp_hw.h @@ -166,6 +166,18 @@ ice_ptp_one_port_cmd_e822(struct ice_hw *hw, u8 port, int ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, enum ice_clk_src clk_src); +int +ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq, + enum ice_clk_src *clk_src); +int +ice_cgu_ts_pll_lost_lock_e825c(struct ice_hw *hw, bool *lost_lock); +int ice_cgu_ts_pll_restart_e825c(struct ice_hw *hw); +int +ice_cgu_bypass_mux_port_active_e825c(struct ice_hw *hw, u8 port, bool *active); +int +ice_cfg_cgu_bypass_mux_e825c(struct ice_hw *hw, u8 port_num, bool clock_1588, + unsigned int ena); +int ice_cfg_synce_ethdiv_e825c(struct ice_hw *hw, u8 *divider); /** * ice_e822_time_ref - Get the current TIME_REF from capabilities -- 2.43.0