/** * ice_tspll_clk_freq_str - Convert time_ref_freq to string * @clk_freq: Clock frequency * * Return: specified TIME_REF clock frequency converted to a string.
*/ staticconstchar *ice_tspll_clk_freq_str(enum ice_tspll_freq clk_freq)
{ switch (clk_freq) { case ICE_TSPLL_FREQ_25_000: return"25 MHz"; case ICE_TSPLL_FREQ_122_880: return"122.88 MHz"; case ICE_TSPLL_FREQ_125_000: return"125 MHz"; case ICE_TSPLL_FREQ_153_600: return"153.6 MHz"; case ICE_TSPLL_FREQ_156_250: return"156.25 MHz"; case ICE_TSPLL_FREQ_245_760: return"245.76 MHz"; default: return"Unknown";
}
}
/** * 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.
*/ staticenum 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.
*/ staticbool 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); returnfalse;
}
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"); returnfalse;
}
returntrue;
}
/** * ice_tspll_clk_src_str - Convert time_ref_src to string * @clk_src: Clock source * * Return: specified clock source converted to its string name
*/ staticconstchar *ice_tspll_clk_src_str(enum ice_clk_src clk_src)
{ switch (clk_src) { case ICE_CLK_SRC_TCXO: return"TCXO"; case ICE_CLK_SRC_TIME_REF: return"TIME_REF"; default: return"Unknown";
}
}
/** * ice_tspll_log_cfg - Log current/new TSPLL configuration * @hw: Pointer to the HW struct * @enable: CGU enabled/disabled * @clk_src: Current clock source * @tspll_freq: Current clock frequency * @lock: CGU lock status * @new_cfg: true if this is a new config
*/ staticvoid ice_tspll_log_cfg(struct ice_hw *hw, bool enable, u8 clk_src,
u8 tspll_freq, bool lock, bool new_cfg)
{
dev_dbg(ice_hw_to_dev(hw), "%s TSPLL configuration -- %s, src %s, freq %s, PLL %s\n",
new_cfg ? "New" : "Current", str_enabled_disabled(enable),
ice_tspll_clk_src_str((enum ice_clk_src)clk_src),
ice_tspll_clk_freq_str((enum ice_tspll_freq)tspll_freq),
lock ? "locked" : "unlocked");
}
/** * ice_tspll_cfg_e82x - 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 PLL which drives the PTP hardware clock. * * Return: * * %0 - success * * %-EINVAL - input parameters are incorrect * * %-EBUSY - failed to lock TSPLL * * %other - CGU read/write failure
*/ staticint ice_tspll_cfg_e82x(struct ice_hw *hw, enum ice_tspll_freq clk_freq, enum ice_clk_src clk_src)
{
u32 val, r9, r24; int err;
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;
err = ice_read_cgu_reg(hw, ICE_CGU_RO_BWM_LF, &val); if (err) return err;
/* Disable the PLL before changing the clock source or frequency */ 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, r24); if (err) return err;
}
/* Set the frequency */
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, &val); if (err) return err;
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, val); if (err) return err;
/* Configure the TSPLL post divisor */
err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val); if (err) return err;
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, val); if (err) return err;
/* Configure the TSPLL pre divisor and clock source */
err = ice_read_cgu_reg(hw, ICE_CGU_R24, &r24); if (err) return err;
/** * ice_tspll_dis_sticky_bits_e82x - 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, other error codes when failed to read/write CGU.
*/ staticint ice_tspll_dis_sticky_bits_e82x(struct ice_hw *hw)
{
u32 val; int err;
err = ice_read_cgu_reg(hw, ICE_CGU_CNTR_BIST, &val); if (err) return err;
val &= ~(ICE_CGU_CNTR_BIST_PLLLOCK_SEL_0 |
ICE_CGU_CNTR_BIST_PLLLOCK_SEL_1);
/** * ice_tspll_cfg_e825c - Configure the TSPLL for E825-C * @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 PLL which drives the PTP hardware clock. * * Return: * * %0 - success * * %-EINVAL - input parameters are incorrect * * %-EBUSY - failed to lock TSPLL * * %other - CGU read/write failure
*/ staticint ice_tspll_cfg_e825c(struct ice_hw *hw, enum ice_tspll_freq clk_freq, enum ice_clk_src clk_src)
{
u32 val, r9, r23; int err;
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;
err = ice_read_cgu_reg(hw, ICE_CGU_RO_LOCK, &val); if (err) return err;
/* Disable the PLL before changing the clock source or frequency */ 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, r23); if (err) return err;
}
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;
}
/* 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 */
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, &val); if (err) return err;
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, val); if (err) return err;
/* Configure the TSPLL post divisor, these two are constant */
err = ice_read_cgu_reg(hw, ICE_CGU_R22, &val); if (err) return err;
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, val); if (err) return err;
/* Configure the TSPLL pre divisor (constant) and clock source */
err = ice_read_cgu_reg(hw, ICE_CGU_R23, &r23); if (err) return err;
/** * ice_tspll_dis_sticky_bits_e825c - disable TSPLL sticky bits for E825-C * @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, other error codes when failed to read/write CGU.
*/ staticint ice_tspll_dis_sticky_bits_e825c(struct ice_hw *hw)
{
u32 val; int err;
err = ice_read_cgu_reg(hw, ICE_CGU_BW_TDC, &val); if (err) return err;
/** * ice_tspll_cfg_pps_out_e825c - Enable/disable 1PPS output and set amplitude * @hw: pointer to the HW struct * @enable: true to enable 1PPS output, false to disable it * * Return: 0 on success, other negative error code when CGU read/write failed.
*/ int ice_tspll_cfg_pps_out_e825c(struct ice_hw *hw, bool enable)
{
u32 val; int err;
err = ice_read_cgu_reg(hw, ICE_CGU_R9, &val); if (err) return err;
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.
*/ staticint 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.
*/ staticint 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;
}
}
/** * ice_tspll_init - Initialize TSPLL with settings from firmware * @hw: Pointer to the HW structure * * Initialize the Clock Generation Unit of the E82X/E825 device. * * Return: 0 on success, other error codes when failed to read/write/cfg CGU.
*/ 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;
/* 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;
/* 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.
*/
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;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.