@@ -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_ */
@@ -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
@@ -266,6 +266,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,
new file mode 100644
@@ -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_ */
@@ -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)
+enum ice_status
+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;
+ enum ice_status 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 ICE_SUCCESS;
+}
+
+/**
+ * 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 enum ice_status 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 enum ice_status ice_cfg_cgu_pll_dis_sticky_bits_e825c(struct ice_hw *hw)
+{
+ union tspll_bw_tdc_e825c bw_tdc;
+ enum ice_status 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
+ */
+enum ice_status
+ice_cgu_ts_pll_lost_lock_e825c(struct ice_hw *hw, bool *lost_lock)
+{
+ union tspll_ro_lock_e825c ro_lock;
+ enum ice_status 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 ICE_SUCCESS;
+}
+
+/**
+ * ice_cgu_ts_pll_restart_e825c - trigger TS PLL restart
+ * @hw: pointer to the HW struct
+ */
+enum ice_status ice_cgu_ts_pll_restart_e825c(struct ice_hw *hw)
+{
+ union nac_cgu_dword23_e825c dw23;
+ enum ice_status 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 ICE_SUCCESS;
+}
+
+#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
+ */
+enum ice_status
+ice_cgu_bypass_mux_port_active_e825c(struct ice_hw *hw, u8 port, bool *active)
+{
+ union nac_cgu_dword11_e825c dw11;
+ enum ice_status 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 ICE_SUCCESS;
+}
+
+/**
+ * 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
+ */
+enum ice_status
+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;
+ enum ice_status 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 enum ice_status 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 ICE_SUCCESS;
+}
+
+/**
+ * ice_cfg_synce_ethdiv_e825c - set the divider on the mux
+ * @hw: pointer to the HW struct
+ * @divider: output parameter, returns used divider value
+ */
+enum ice_status ice_cfg_synce_ethdiv_e825c(struct ice_hw *hw, u8 *divider)
+{
+ union nac_cgu_dword10_e825c dw10;
+ enum ice_status 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 enum ice_status 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;
+ enum ice_status 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;
@@ -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);
+enum ice_status
+ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
+ enum ice_clk_src *clk_src);
+enum ice_status
+ice_cgu_ts_pll_lost_lock_e825c(struct ice_hw *hw, bool *lost_lock);
+enum ice_status ice_cgu_ts_pll_restart_e825c(struct ice_hw *hw);
+enum ice_status
+ice_cgu_bypass_mux_port_active_e825c(struct ice_hw *hw, u8 port, bool *active);
+enum ice_status
+ice_cfg_cgu_bypass_mux_e825c(struct ice_hw *hw, u8 port_num, bool clock_1588,
+ unsigned int ena);
+enum ice_status ice_cfg_synce_ethdiv_e825c(struct ice_hw *hw, u8 *divider);
/**
* ice_e822_time_ref - Get the current TIME_REF from capabilities