ice: Move CGU block

Move CGU block to the beginning of ice_ptp_hw.c

Signed-off-by: Sergey Temerkhanov <sergey.temerkhanov@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://lore.kernel.org/r/20240528-next-2024-05-28-ptp-refactors-v1-5-c082739bb6f6@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Sergey Temerkhanov
2024-05-28 16:03:55 -07:00
committed by Jakub Kicinski
parent c199b31a04
commit 39ecb29df8
2 changed files with 290 additions and 287 deletions

View File

@@ -226,6 +226,293 @@ static u64 ice_ptp_read_src_incval(struct ice_hw *hw)
return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo;
}
/**
* 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.
*
* Return: 0 on success, other error codes when failed to read from CGU
*/
static int ice_read_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 *val)
{
struct ice_sbq_msg_input cgu_msg = {
.opcode = ice_sbq_msg_rd,
.dest_dev = cgu,
.msg_addr_low = addr
};
int err;
err = ice_sbq_rw_reg(hw, &cgu_msg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n",
addr, err);
return err;
}
*val = cgu_msg.data;
return 0;
}
/**
* 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.
*
* Return: 0 on success, other error codes when failed to write to CGU
*/
static int ice_write_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 val)
{
struct ice_sbq_msg_input cgu_msg = {
.opcode = ice_sbq_msg_wr,
.dest_dev = cgu,
.msg_addr_low = addr,
.data = val
};
int err;
err = ice_sbq_rw_reg(hw, &cgu_msg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n",
addr, err);
return err;
}
return err;
}
/**
* ice_clk_freq_str - Convert time_ref_freq to string
* @clk_freq: Clock frequency
*
* Return: specified TIME_REF clock frequency converted to a string
*/
static const char *ice_clk_freq_str(enum ice_time_ref_freq clk_freq)
{
switch (clk_freq) {
case ICE_TIME_REF_FREQ_25_000:
return "25 MHz";
case ICE_TIME_REF_FREQ_122_880:
return "122.88 MHz";
case ICE_TIME_REF_FREQ_125_000:
return "125 MHz";
case ICE_TIME_REF_FREQ_153_600:
return "153.6 MHz";
case ICE_TIME_REF_FREQ_156_250:
return "156.25 MHz";
case ICE_TIME_REF_FREQ_245_760:
return "245.76 MHz";
default:
return "Unknown";
}
}
/**
* ice_clk_src_str - Convert time_ref_src to string
* @clk_src: Clock source
*
* Return: specified clock source converted to its string name
*/
static const char *ice_clk_src_str(enum ice_clk_src clk_src)
{
switch (clk_src) {
case ICE_CLK_SRC_TCX0:
return "TCX0";
case ICE_CLK_SRC_TIME_REF:
return "TIME_REF";
default:
return "Unknown";
}
}
/**
* ice_cfg_cgu_pll_e82x - Configure the Clock Generation Unit
* @hw: pointer to the HW struct
* @clk_freq: Clock frequency to program
* @clk_src: Clock source to select (TIME_REF, or TCX0)
*
* 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 TS PLL
* * %other - CGU read/write failure
*/
static int ice_cfg_cgu_pll_e82x(struct ice_hw *hw,
enum ice_time_ref_freq clk_freq,
enum ice_clk_src clk_src)
{
union tspll_ro_bwm_lf bwm_lf;
union nac_cgu_dword19 dw19;
union nac_cgu_dword22 dw22;
union nac_cgu_dword24 dw24;
union nac_cgu_dword9 dw9;
int err;
if (clk_freq >= NUM_ICE_TIME_REF_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_TCX0 &&
clk_freq != ICE_TIME_REF_FREQ_25_000) {
dev_warn(ice_hw_to_dev(hw),
"TCX0 only supports 25 MHz frequency\n");
return -EINVAL;
}
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val);
if (err)
return err;
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val);
if (err)
return err;
err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
if (err)
return err;
/* 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(dw24.field.time_ref_sel),
ice_clk_freq_str(dw9.field.time_ref_freq_sel),
bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
/* Disable the PLL before changing the clock source or frequency */
if (dw24.field.ts_pll_enable) {
dw24.field.ts_pll_enable = 0;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
}
/* Set the frequency */
dw9.field.time_ref_freq_sel = clk_freq;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val);
if (err)
return err;
/* Configure the TS PLL feedback divisor */
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val);
if (err)
return err;
dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div;
dw19.field.tspll_ndivratio = 1;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val);
if (err)
return err;
/* Configure the TS PLL post divisor */
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val);
if (err)
return err;
dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div;
dw22.field.time1588clk_sel_div2 = 0;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val);
if (err)
return err;
/* Configure the TS PLL pre divisor and clock source */
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val);
if (err)
return err;
dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div;
dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div;
dw24.field.time_ref_sel = clk_src;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
/* Finally, enable the PLL */
dw24.field.ts_pll_enable = 1;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
/* Wait to verify if the PLL locks */
usleep_range(1000, 5000);
err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
if (err)
return err;
if (!bwm_lf.field.plllock_true_lock_cri) {
dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n");
return -EBUSY;
}
/* 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(dw24.field.time_ref_sel),
ice_clk_freq_str(dw9.field.time_ref_freq_sel),
bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
return 0;
}
/**
* ice_init_cgu_e82x - Initialize CGU with settings from firmware
* @hw: pointer to the HW structure
*
* Initialize the Clock Generation Unit of the E822 device.
*
* Return: 0 on success, other error codes when failed to read/write/cfg CGU
*/
static int ice_init_cgu_e82x(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 err;
err = ice_read_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS,
&cntr_bist.val);
if (err)
return err;
/* Disable sticky lock detection so lock err reported is accurate */
cntr_bist.field.i_plllock_sel_0 = 0;
cntr_bist.field.i_plllock_sel_1 = 0;
err = ice_write_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS,
cntr_bist.val);
if (err)
return err;
/* Configure the CGU PLL using the parameters from the function
* capabilities.
*/
return ice_cfg_cgu_pll_e82x(hw, ts_info->time_ref,
(enum ice_clk_src)ts_info->clk_src);
}
/**
* ice_ptp_tmr_cmd_to_src_reg - Convert to source timer command value
* @hw: pointer to HW struct
@@ -623,8 +910,7 @@ ice_write_40b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
low_addr);
return -EINVAL;
}
low = (u32)(val & P_REG_40B_LOW_M);
low = FIELD_GET(P_REG_40B_LOW_M, val);
high = (u32)(val >> P_REG_40B_HIGH_S);
err = ice_write_phy_reg_e82x(hw, port, low_addr, low);
@@ -834,7 +1120,7 @@ ice_read_phy_tstamp_e82x(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
* lower 8 bits in the low register, and the upper 32 bits in the high
* register.
*/
*tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);
*tstamp = FIELD_PREP(TS_PHY_HIGH_M, hi) | FIELD_PREP(TS_PHY_LOW_M, lo);
return 0;
}
@@ -903,289 +1189,6 @@ static void ice_ptp_reset_ts_memory_e82x(struct ice_hw *hw)
ice_ptp_reset_ts_memory_quad_e82x(hw, quad);
}
/**
* 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.
*/
static int
ice_read_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 *val)
{
struct ice_sbq_msg_input cgu_msg;
int err;
cgu_msg.opcode = ice_sbq_msg_rd;
cgu_msg.dest_dev = cgu;
cgu_msg.msg_addr_low = addr;
cgu_msg.msg_addr_high = 0x0;
err = ice_sbq_rw_reg(hw, &cgu_msg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n",
addr, err);
return err;
}
*val = cgu_msg.data;
return err;
}
/**
* 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.
*/
static int
ice_write_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 val)
{
struct ice_sbq_msg_input cgu_msg;
int err;
cgu_msg.opcode = ice_sbq_msg_wr;
cgu_msg.dest_dev = cgu;
cgu_msg.msg_addr_low = addr;
cgu_msg.msg_addr_high = 0x0;
cgu_msg.data = val;
err = ice_sbq_rw_reg(hw, &cgu_msg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n",
addr, err);
return err;
}
return err;
}
/**
* ice_clk_freq_str - Convert time_ref_freq to string
* @clk_freq: Clock frequency
*
* Convert the specified TIME_REF clock frequency to a string.
*/
static const char *ice_clk_freq_str(u8 clk_freq)
{
switch ((enum ice_time_ref_freq)clk_freq) {
case ICE_TIME_REF_FREQ_25_000:
return "25 MHz";
case ICE_TIME_REF_FREQ_122_880:
return "122.88 MHz";
case ICE_TIME_REF_FREQ_125_000:
return "125 MHz";
case ICE_TIME_REF_FREQ_153_600:
return "153.6 MHz";
case ICE_TIME_REF_FREQ_156_250:
return "156.25 MHz";
case ICE_TIME_REF_FREQ_245_760:
return "245.76 MHz";
default:
return "Unknown";
}
}
/**
* ice_clk_src_str - Convert time_ref_src to string
* @clk_src: Clock source
*
* Convert the specified clock source to its string name.
*/
static const char *ice_clk_src_str(u8 clk_src)
{
switch ((enum ice_clk_src)clk_src) {
case ICE_CLK_SRC_TCX0:
return "TCX0";
case ICE_CLK_SRC_TIME_REF:
return "TIME_REF";
default:
return "Unknown";
}
}
/**
* ice_cfg_cgu_pll_e82x - Configure the Clock Generation Unit
* @hw: pointer to the HW struct
* @clk_freq: Clock frequency to program
* @clk_src: Clock source to select (TIME_REF, or TCX0)
*
* 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_cfg_cgu_pll_e82x(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
enum ice_clk_src clk_src)
{
union tspll_ro_bwm_lf bwm_lf;
union nac_cgu_dword19 dw19;
union nac_cgu_dword22 dw22;
union nac_cgu_dword24 dw24;
union nac_cgu_dword9 dw9;
int err;
if (clk_freq >= NUM_ICE_TIME_REF_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_TCX0 &&
clk_freq != ICE_TIME_REF_FREQ_25_000) {
dev_warn(ice_hw_to_dev(hw),
"TCX0 only supports 25 MHz frequency\n");
return -EINVAL;
}
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val);
if (err)
return err;
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val);
if (err)
return err;
err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
if (err)
return err;
/* 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(dw24.field.time_ref_sel),
ice_clk_freq_str(dw9.field.time_ref_freq_sel),
bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
/* Disable the PLL before changing the clock source or frequency */
if (dw24.field.ts_pll_enable) {
dw24.field.ts_pll_enable = 0;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
}
/* Set the frequency */
dw9.field.time_ref_freq_sel = clk_freq;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val);
if (err)
return err;
/* Configure the TS PLL feedback divisor */
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val);
if (err)
return err;
dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div;
dw19.field.tspll_ndivratio = 1;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val);
if (err)
return err;
/* Configure the TS PLL post divisor */
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val);
if (err)
return err;
dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div;
dw22.field.time1588clk_sel_div2 = 0;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val);
if (err)
return err;
/* Configure the TS PLL pre divisor and clock source */
err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val);
if (err)
return err;
dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div;
dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div;
dw24.field.time_ref_sel = clk_src;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
/* Finally, enable the PLL */
dw24.field.ts_pll_enable = 1;
err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
/* Wait to verify if the PLL locks */
usleep_range(1000, 5000);
err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
if (err)
return err;
if (!bwm_lf.field.plllock_true_lock_cri) {
dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n");
return -EBUSY;
}
/* 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(dw24.field.time_ref_sel),
ice_clk_freq_str(dw9.field.time_ref_freq_sel),
bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
return 0;
}
/**
* ice_init_cgu_e82x - Initialize CGU with settings from firmware
* @hw: pointer to the HW structure
*
* Initialize the Clock Generation Unit of the E822 device.
*/
static int ice_init_cgu_e82x(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 err;
err = ice_read_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS,
&cntr_bist.val);
if (err)
return err;
/* Disable sticky lock detection so lock err reported is accurate */
cntr_bist.field.i_plllock_sel_0 = 0;
cntr_bist.field.i_plllock_sel_1 = 0;
err = ice_write_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS,
cntr_bist.val);
if (err)
return err;
/* Configure the CGU PLL using the parameters from the function
* capabilities.
*/
err = ice_cfg_cgu_pll_e82x(hw, ts_info->time_ref,
(enum ice_clk_src)ts_info->clk_src);
if (err)
return err;
return 0;
}
/**
* ice_ptp_set_vernier_wl - Set the window length for vernier calibration
* @hw: pointer to the HW struct

View File

@@ -377,7 +377,7 @@ int ice_cgu_get_output_pin_state_caps(struct ice_hw *hw, u8 pin_id,
#define P_REG_TIMETUS_L 0x410
#define P_REG_TIMETUS_U 0x414
#define P_REG_40B_LOW_M 0xFF
#define P_REG_40B_LOW_M GENMASK(7, 0)
#define P_REG_40B_HIGH_S 8
/* PHY window length registers */