ice: add ref-sync dpll pins

Implement reference sync input pin get/set callbacks, allow user space
control over dpll pin pairs capable of reference sync support.

Reviewed-by: Milena Olech <milena.olech@intel.com>
Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Link: https://patch.msgid.link/20250626135219.1769350-4-arkadiusz.kubalewski@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Arkadiusz Kubalewski 2025-06-26 15:52:19 +02:00 committed by Jakub Kicinski
parent 58256a26bf
commit 5bcea24133
3 changed files with 288 additions and 0 deletions

View File

@ -2304,6 +2304,8 @@ struct ice_aqc_get_cgu_abilities {
u8 rsvd[3];
};
#define ICE_AQC_CGU_IN_CFG_FLG2_REFSYNC_EN BIT(7)
/* Set CGU input config (direct 0x0C62) */
struct ice_aqc_set_cgu_input_config {
u8 input_idx;

View File

@ -36,6 +36,19 @@
#define ICE_DPLL_PIN_SW_2_OUTPUT_ABS_IDX \
(ICE_DPLL_PIN_SW_OUTPUT_ABS(ICE_DPLL_PIN_SW_2_IDX))
#define ICE_SR_PFA_DPLL_DEFAULTS 0x152
#define ICE_DPLL_PFA_REF_SYNC_TYPE 0x2420
#define ICE_DPLL_PFA_REF_SYNC_TYPE2 0x2424
#define ICE_DPLL_PFA_END 0xFFFF
#define ICE_DPLL_PFA_HEADER_LEN 4
#define ICE_DPLL_PFA_ENTRY_LEN 3
#define ICE_DPLL_PFA_MAILBOX_REF_SYNC_PIN_S 4
#define ICE_DPLL_PFA_MASK_OFFSET 1
#define ICE_DPLL_PFA_VALUE_OFFSET 2
#define ICE_DPLL_E810C_SFP_NC_PINS 2
#define ICE_DPLL_E810C_SFP_NC_START 4
/**
* enum ice_dpll_pin_type - enumerate ice pin types:
* @ICE_DPLL_PIN_INVALID: invalid pin type
@ -2107,6 +2120,149 @@ ice_dpll_sw_esync_get(const struct dpll_pin *pin, void *pin_priv,
extack);
}
/*
* ice_dpll_input_ref_sync_set - callback for setting reference sync feature
* @pin: pointer to a pin
* @pin_priv: private data pointer passed on pin registration
* @ref_pin: pin pointer for reference sync pair
* @ref_pin_priv: private data pointer of ref_pin
* @state: requested state for reference sync for pin pair
* @extack: error reporting
*
* Dpll subsystem callback. Handler for setting reference sync frequency
* feature for input pin.
*
* Context: Acquires and releases pf->dplls.lock
* Return:
* * 0 - success
* * negative - error
*/
static int
ice_dpll_input_ref_sync_set(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *ref_pin, void *ref_pin_priv,
const enum dpll_pin_state state,
struct netlink_ext_ack *extack)
{
struct ice_dpll_pin *p = pin_priv;
struct ice_pf *pf = p->pf;
u8 flags_en = 0;
int ret;
if (ice_dpll_is_reset(pf, extack))
return -EBUSY;
mutex_lock(&pf->dplls.lock);
if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN)
flags_en = ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN;
if (state == DPLL_PIN_STATE_CONNECTED)
flags_en |= ICE_AQC_CGU_IN_CFG_FLG2_REFSYNC_EN;
ret = ice_aq_set_input_pin_cfg(&pf->hw, p->idx, 0, flags_en, 0, 0);
if (!ret)
ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_INPUT,
extack);
mutex_unlock(&pf->dplls.lock);
return ret;
}
/**
* ice_dpll_input_ref_sync_get - callback for getting reference sync config
* @pin: pointer to a pin
* @pin_priv: private data pointer passed on pin registration
* @ref_pin: pin pointer for reference sync pair
* @ref_pin_priv: private data pointer of ref_pin
* @state: on success holds reference sync state for pin pair
* @extack: error reporting
*
* Dpll subsystem callback. Handler for setting reference sync frequency
* feature for input pin.
*
* Context: Acquires and releases pf->dplls.lock
* Return:
* * 0 - success
* * negative - error
*/
static int
ice_dpll_input_ref_sync_get(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *ref_pin, void *ref_pin_priv,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack)
{
struct ice_dpll_pin *p = pin_priv;
struct ice_pf *pf = p->pf;
if (ice_dpll_is_reset(pf, extack))
return -EBUSY;
mutex_lock(&pf->dplls.lock);
if (p->flags[0] & ICE_AQC_CGU_IN_CFG_FLG2_REFSYNC_EN)
*state = DPLL_PIN_STATE_CONNECTED;
else
*state = DPLL_PIN_STATE_DISCONNECTED;
mutex_unlock(&pf->dplls.lock);
return 0;
}
/*
* ice_dpll_sw_input_ref_sync_set - callback for setting reference sync feature
* @pin: pointer to a pin
* @pin_priv: private data pointer passed on pin registration
* @ref_pin: pin pointer for reference sync pair
* @ref_pin_priv: private data pointer of ref_pin
* @state: requested state for reference sync for pin pair
* @extack: error reporting
*
* Dpll subsystem callback. Handler for setting reference sync
* feature for input pins.
*
* Context: Calls a function which acquires and releases pf->dplls.lock
* Return:
* * 0 - success
* * negative - error
*/
static int
ice_dpll_sw_input_ref_sync_set(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *ref_pin,
void *ref_pin_priv,
const enum dpll_pin_state state,
struct netlink_ext_ack *extack)
{
struct ice_dpll_pin *p = pin_priv;
return ice_dpll_input_ref_sync_set(pin, p->input, ref_pin, ref_pin_priv,
state, extack);
}
/**
* ice_dpll_sw_input_ref_sync_get - callback for getting reference sync config
* @pin: pointer to a pin
* @pin_priv: private data pointer passed on pin registration
* @ref_pin: pin pointer for reference sync pair
* @ref_pin_priv: private data pointer of ref_pin
* @state: on success holds reference sync state for pin pair
* @extack: error reporting
*
* Dpll subsystem callback. Handler for setting reference sync feature for
* input pins.
*
* Context: Calls a function which acquires and releases pf->dplls.lock
* Return:
* * 0 - success
* * negative - error
*/
static int
ice_dpll_sw_input_ref_sync_get(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *ref_pin,
void *ref_pin_priv,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack)
{
struct ice_dpll_pin *p = pin_priv;
return ice_dpll_input_ref_sync_get(pin, p->input, ref_pin, ref_pin_priv,
state, extack);
}
/**
* ice_dpll_rclk_state_on_pin_set - set a state on rclk pin
* @pin: pointer to a pin
@ -2234,6 +2390,8 @@ static const struct dpll_pin_ops ice_dpll_pin_sma_ops = {
.phase_offset_get = ice_dpll_phase_offset_get,
.esync_set = ice_dpll_sw_esync_set,
.esync_get = ice_dpll_sw_esync_get,
.ref_sync_set = ice_dpll_sw_input_ref_sync_set,
.ref_sync_get = ice_dpll_sw_input_ref_sync_get,
};
static const struct dpll_pin_ops ice_dpll_pin_ufl_ops = {
@ -2262,6 +2420,8 @@ static const struct dpll_pin_ops ice_dpll_input_ops = {
.phase_offset_get = ice_dpll_phase_offset_get,
.esync_set = ice_dpll_input_esync_set,
.esync_get = ice_dpll_input_esync_get,
.ref_sync_set = ice_dpll_input_ref_sync_set,
.ref_sync_get = ice_dpll_input_ref_sync_get,
};
static const struct dpll_pin_ops ice_dpll_output_ops = {
@ -2560,6 +2720,88 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
msecs_to_jiffies(500));
}
/**
* ice_dpll_init_ref_sync_inputs - initialize reference sync pin pairs
* @pf: pf private structure
*
* Read DPLL TLV capabilities and initialize reference sync pin pairs in
* dpll subsystem.
*
* Return:
* * 0 - success or nothing to do (no ref-sync tlv are present)
* * negative - AQ failure
*/
static int ice_dpll_init_ref_sync_inputs(struct ice_pf *pf)
{
struct ice_dpll_pin *inputs = pf->dplls.inputs;
struct ice_hw *hw = &pf->hw;
u16 addr, len, end, hdr;
int ret;
ret = ice_get_pfa_module_tlv(hw, &hdr, &len, ICE_SR_PFA_DPLL_DEFAULTS);
if (ret) {
dev_err(ice_pf_to_dev(pf),
"Failed to read PFA dpll defaults TLV ret=%d\n", ret);
return ret;
}
end = hdr + len;
for (addr = hdr + ICE_DPLL_PFA_HEADER_LEN; addr < end;
addr += ICE_DPLL_PFA_ENTRY_LEN) {
unsigned long bit, ul_mask, offset;
u16 pin, mask, buf;
bool valid = false;
ret = ice_read_sr_word(hw, addr, &buf);
if (ret)
return ret;
switch (buf) {
case ICE_DPLL_PFA_REF_SYNC_TYPE:
case ICE_DPLL_PFA_REF_SYNC_TYPE2:
{
u16 mask_addr = addr + ICE_DPLL_PFA_MASK_OFFSET;
u16 val_addr = addr + ICE_DPLL_PFA_VALUE_OFFSET;
ret = ice_read_sr_word(hw, mask_addr, &mask);
if (ret)
return ret;
ret = ice_read_sr_word(hw, val_addr, &pin);
if (ret)
return ret;
if (buf == ICE_DPLL_PFA_REF_SYNC_TYPE)
pin >>= ICE_DPLL_PFA_MAILBOX_REF_SYNC_PIN_S;
valid = true;
break;
}
case ICE_DPLL_PFA_END:
addr = end;
break;
default:
continue;
}
if (!valid)
continue;
ul_mask = mask;
offset = 0;
for_each_set_bit(bit, &ul_mask, BITS_PER_TYPE(u16)) {
int i, j;
if (hw->device_id == ICE_DEV_ID_E810C_SFP &&
pin > ICE_DPLL_E810C_SFP_NC_START)
offset = -ICE_DPLL_E810C_SFP_NC_PINS;
i = pin + offset;
j = bit + offset;
if (i < 0 || j < 0)
return -ERANGE;
inputs[i].ref_sync = j;
}
}
return 0;
}
/**
* ice_dpll_release_pins - release pins resources from dpll subsystem
* @pins: pointer to pins array
@ -2634,6 +2876,36 @@ ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins,
dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]);
}
/**
* ice_dpll_pin_ref_sync_register - register reference sync pins
* @pins: pointer to pins array
* @count: number of pins
*
* Register reference sync pins in dpll subsystem.
*
* Return:
* * 0 - success
* * negative - registration failure reason
*/
static int
ice_dpll_pin_ref_sync_register(struct ice_dpll_pin *pins, int count)
{
int ret, i;
for (i = 0; i < count; i++) {
if (!pins[i].hidden && pins[i].ref_sync) {
int j = pins[i].ref_sync;
ret = dpll_pin_ref_sync_pair_add(pins[i].pin,
pins[j].pin);
if (ret)
return ret;
}
}
return 0;
}
/**
* ice_dpll_register_pins - register pins with a dpll
* @dpll: dpll pointer to register pins with
@ -2922,6 +3194,14 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu)
goto deinit_sma;
count += ICE_DPLL_PIN_SW_NUM;
}
ret = ice_dpll_pin_ref_sync_register(pf->dplls.inputs,
pf->dplls.num_inputs);
if (ret)
goto deinit_ufl;
ret = ice_dpll_pin_ref_sync_register(pf->dplls.sma,
ICE_DPLL_PIN_SW_NUM);
if (ret)
goto deinit_ufl;
} else {
count += pf->dplls.num_outputs + 2 * ICE_DPLL_PIN_SW_NUM;
}
@ -3219,6 +3499,8 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
pins[i].prop.freq_supported_num = freq_supp_num;
pins[i].pf = pf;
}
if (input)
ret = ice_dpll_init_ref_sync_inputs(pf);
return ret;
}
@ -3284,6 +3566,8 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
pin->pf = pf;
pin->prop.board_label = ice_dpll_sw_pin_sma[i];
pin->input = &d->inputs[pin_abs_idx];
if (pin->input->ref_sync)
pin->ref_sync = pin->input->ref_sync - pin_abs_idx;
pin->output = &d->outputs[ICE_DPLL_PIN_SW_OUTPUT_ABS(i)];
ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max);
}

View File

@ -32,6 +32,7 @@ enum ice_dpll_pin_sw {
* @freq: current frequency of a pin
* @phase_adjust: current phase adjust value
* @phase_offset: monitored phase offset value
* @ref_sync: store id of reference sync pin
*/
struct ice_dpll_pin {
struct dpll_pin *pin;
@ -49,6 +50,7 @@ struct ice_dpll_pin {
enum dpll_pin_direction direction;
s64 phase_offset;
u8 status;
u8 ref_sync;
bool active;
bool hidden;
};