Commit 5bcea241 authored by Arkadiusz Kubalewski's avatar Arkadiusz Kubalewski Committed by Jakub Kicinski
Browse files

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: default avatarMilena Olech <milena.olech@intel.com>
Signed-off-by: default avatarArkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Link: https://patch.msgid.link/20250626135219.1769350-4-arkadiusz.kubalewski@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 58256a26
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+284 −0
Original line number Diff line number Diff line
@@ -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);
	}
+2 −0
Original line number Diff line number Diff line
@@ -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;
};