Commit 90e1c907 authored by Arkadiusz Kubalewski's avatar Arkadiusz Kubalewski Committed by David S. Miller
Browse files

ice: dpll: implement phase related callbacks



Implement new callback ops related to measurement and adjustment of
signal phase for pin-dpll in ice driver.

Signed-off-by: default avatarArkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d7fbc0b7
Loading
Loading
Loading
Loading
+218 −2
Original line number Diff line number Diff line
@@ -878,6 +878,199 @@ ice_dpll_output_direction(const struct dpll_pin *pin, void *pin_priv,
	return 0;
}

/**
 * ice_dpll_pin_phase_adjust_get - callback for get pin phase adjust value
 * @pin: pointer to a pin
 * @pin_priv: private data pointer passed on pin registration
 * @dpll: registered dpll pointer
 * @dpll_priv: private data pointer passed on dpll registration
 * @phase_adjust: on success holds pin phase_adjust value
 * @extack: error reporting
 *
 * Dpll subsystem callback. Handler for getting phase adjust value of a pin.
 *
 * Context: Acquires pf->dplls.lock
 * Return:
 * * 0 - success
 * * negative - error
 */
static int
ice_dpll_pin_phase_adjust_get(const struct dpll_pin *pin, void *pin_priv,
			      const struct dpll_device *dpll, void *dpll_priv,
			      s32 *phase_adjust,
			      struct netlink_ext_ack *extack)
{
	struct ice_dpll_pin *p = pin_priv;
	struct ice_pf *pf = p->pf;

	mutex_lock(&pf->dplls.lock);
	*phase_adjust = p->phase_adjust;
	mutex_unlock(&pf->dplls.lock);

	return 0;
}

/**
 * ice_dpll_pin_phase_adjust_set - helper for setting a pin phase adjust value
 * @pin: pointer to a pin
 * @pin_priv: private data pointer passed on pin registration
 * @dpll: registered dpll pointer
 * @dpll_priv: private data pointer passed on dpll registration
 * @phase_adjust: phase_adjust to be set
 * @extack: error reporting
 * @type: type of a pin
 *
 * Helper for dpll subsystem callback. Handler for setting phase adjust value
 * of a pin.
 *
 * Context: Acquires pf->dplls.lock
 * Return:
 * * 0 - success
 * * negative - error
 */
static int
ice_dpll_pin_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv,
			      const struct dpll_device *dpll, void *dpll_priv,
			      s32 phase_adjust,
			      struct netlink_ext_ack *extack,
			      enum ice_dpll_pin_type type)
{
	struct ice_dpll_pin *p = pin_priv;
	struct ice_dpll *d = dpll_priv;
	struct ice_pf *pf = d->pf;
	u8 flag, flags_en = 0;
	int ret;

	mutex_lock(&pf->dplls.lock);
	switch (type) {
	case ICE_DPLL_PIN_TYPE_INPUT:
		flag = ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_DELAY;
		if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN)
			flags_en |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN;
		if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN)
			flags_en |= ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN;
		ret = ice_aq_set_input_pin_cfg(&pf->hw, p->idx, flag, flags_en,
					       0, phase_adjust);
		break;
	case ICE_DPLL_PIN_TYPE_OUTPUT:
		flag = ICE_AQC_SET_CGU_OUT_CFG_UPDATE_PHASE;
		if (p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_OUT_EN)
			flag |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN;
		if (p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN)
			flag |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN;
		ret = ice_aq_set_output_pin_cfg(&pf->hw, p->idx, flag, 0, 0,
						phase_adjust);
		break;
	default:
		ret = -EINVAL;
	}
	if (!ret)
		p->phase_adjust = phase_adjust;
	mutex_unlock(&pf->dplls.lock);
	if (ret)
		NL_SET_ERR_MSG_FMT(extack,
				   "err:%d %s failed to set pin phase_adjust:%d for pin:%u on dpll:%u\n",
				   ret,
				   ice_aq_str(pf->hw.adminq.sq_last_status),
				   phase_adjust, p->idx, d->dpll_idx);

	return ret;
}

/**
 * ice_dpll_input_phase_adjust_set - callback for set input pin phase adjust
 * @pin: pointer to a pin
 * @pin_priv: private data pointer passed on pin registration
 * @dpll: registered dpll pointer
 * @dpll_priv: private data pointer passed on dpll registration
 * @phase_adjust: phase_adjust to be set
 * @extack: error reporting
 *
 * Dpll subsystem callback. Wraps a handler for setting phase adjust on input
 * pin.
 *
 * Context: Calls a function which acquires pf->dplls.lock
 * Return:
 * * 0 - success
 * * negative - error
 */
static int
ice_dpll_input_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv,
				const struct dpll_device *dpll, void *dpll_priv,
				s32 phase_adjust,
				struct netlink_ext_ack *extack)
{
	return ice_dpll_pin_phase_adjust_set(pin, pin_priv, dpll, dpll_priv,
					     phase_adjust, extack,
					     ICE_DPLL_PIN_TYPE_INPUT);
}

/**
 * ice_dpll_output_phase_adjust_set - callback for set output pin phase adjust
 * @pin: pointer to a pin
 * @pin_priv: private data pointer passed on pin registration
 * @dpll: registered dpll pointer
 * @dpll_priv: private data pointer passed on dpll registration
 * @phase_adjust: phase_adjust to be set
 * @extack: error reporting
 *
 * Dpll subsystem callback. Wraps a handler for setting phase adjust on output
 * pin.
 *
 * Context: Calls a function which acquires pf->dplls.lock
 * Return:
 * * 0 - success
 * * negative - error
 */
static int
ice_dpll_output_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv,
				 const struct dpll_device *dpll, void *dpll_priv,
				 s32 phase_adjust,
				 struct netlink_ext_ack *extack)
{
	return ice_dpll_pin_phase_adjust_set(pin, pin_priv, dpll, dpll_priv,
					     phase_adjust, extack,
					     ICE_DPLL_PIN_TYPE_OUTPUT);
}

#define ICE_DPLL_PHASE_OFFSET_DIVIDER	100
#define ICE_DPLL_PHASE_OFFSET_FACTOR		\
	(DPLL_PHASE_OFFSET_DIVIDER / ICE_DPLL_PHASE_OFFSET_DIVIDER)
/**
 * ice_dpll_phase_offset_get - callback for get dpll phase shift value
 * @pin: pointer to a pin
 * @pin_priv: private data pointer passed on pin registration
 * @dpll: registered dpll pointer
 * @dpll_priv: private data pointer passed on dpll registration
 * @phase_offset: on success holds pin phase_offset value
 * @extack: error reporting
 *
 * Dpll subsystem callback. Handler for getting phase shift value between
 * dpll's input and output.
 *
 * Context: Acquires pf->dplls.lock
 * Return:
 * * 0 - success
 * * negative - error
 */
static int
ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
			  const struct dpll_device *dpll, void *dpll_priv,
			  s64 *phase_offset, struct netlink_ext_ack *extack)
{
	struct ice_dpll *d = dpll_priv;
	struct ice_pf *pf = d->pf;

	mutex_lock(&pf->dplls.lock);
	if (d->active_input == pin)
		*phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
	else
		*phase_offset = 0;
	mutex_unlock(&pf->dplls.lock);

	return 0;
}

/**
 * ice_dpll_rclk_state_on_pin_set - set a state on rclk pin
 * @pin: pointer to a pin
@@ -993,6 +1186,9 @@ static const struct dpll_pin_ops ice_dpll_input_ops = {
	.prio_get = ice_dpll_input_prio_get,
	.prio_set = ice_dpll_input_prio_set,
	.direction_get = ice_dpll_input_direction,
	.phase_adjust_get = ice_dpll_pin_phase_adjust_get,
	.phase_adjust_set = ice_dpll_input_phase_adjust_set,
	.phase_offset_get = ice_dpll_phase_offset_get,
};

static const struct dpll_pin_ops ice_dpll_output_ops = {
@@ -1001,6 +1197,8 @@ static const struct dpll_pin_ops ice_dpll_output_ops = {
	.state_on_dpll_get = ice_dpll_output_state_get,
	.state_on_dpll_set = ice_dpll_output_state_set,
	.direction_get = ice_dpll_output_direction,
	.phase_adjust_get = ice_dpll_pin_phase_adjust_get,
	.phase_adjust_set = ice_dpll_output_phase_adjust_set,
};

static const struct dpll_device_ops ice_dpll_ops = {
@@ -1031,6 +1229,8 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
 */
static void ice_dpll_notify_changes(struct ice_dpll *d)
{
	bool pin_notified = false;

	if (d->prev_dpll_state != d->dpll_state) {
		d->prev_dpll_state = d->dpll_state;
		dpll_device_change_ntf(d->dpll);
@@ -1039,7 +1239,14 @@ static void ice_dpll_notify_changes(struct ice_dpll *d)
		if (d->prev_input)
			dpll_pin_change_ntf(d->prev_input);
		d->prev_input = d->active_input;
		if (d->active_input)
		if (d->active_input) {
			dpll_pin_change_ntf(d->active_input);
			pin_notified = true;
		}
	}
	if (d->prev_phase_offset != d->phase_offset) {
		d->prev_phase_offset = d->phase_offset;
		if (!pin_notified && d->active_input)
			dpll_pin_change_ntf(d->active_input);
	}
}
@@ -1065,7 +1272,7 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init)

	ret = ice_get_cgu_state(&pf->hw, d->dpll_idx, d->prev_dpll_state,
				&d->input_idx, &d->ref_state, &d->eec_mode,
				&d->phase_shift, &d->dpll_state);
				&d->phase_offset, &d->dpll_state);

	dev_dbg(ice_pf_to_dev(pf),
		"update dpll=%d, prev_src_idx:%u, src_idx:%u, state:%d, prev:%d mode:%d\n",
@@ -1656,6 +1863,15 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
				return ret;
			pins[i].prop.capabilities |=
				DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE;
			pins[i].prop.phase_range.min =
				pf->dplls.input_phase_adj_max;
			pins[i].prop.phase_range.max =
				-pf->dplls.input_phase_adj_max;
		} else {
			pins[i].prop.phase_range.min =
				pf->dplls.output_phase_adj_max;
			pins[i].prop.phase_range.max =
				-pf->dplls.output_phase_adj_max;
		}
		pins[i].prop.capabilities |=
			DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+8 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
 * @state: state of a pin
 * @prop: pin properties
 * @freq: current frequency of a pin
 * @phase_adjust: current phase adjust value
 */
struct ice_dpll_pin {
	struct dpll_pin *pin;
@@ -30,6 +31,7 @@ struct ice_dpll_pin {
	u8 state[ICE_DPLL_RCLK_NUM_MAX];
	struct dpll_pin_properties prop;
	u32 freq;
	s32 phase_adjust;
};

/** ice_dpll - store info required for DPLL control
@@ -40,7 +42,8 @@ struct ice_dpll_pin {
 * @prev_input_idx: previously selected input index
 * @ref_state: state of dpll reference signals
 * @eec_mode: eec_mode dpll is configured for
 * @phase_shift: phase shift delay of a dpll
 * @phase_offset: phase offset of active pin vs dpll signal
 * @prev_phase_offset: previous phase offset of active pin vs dpll signal
 * @input_prio: priorities of each input
 * @dpll_state: current dpll sync state
 * @prev_dpll_state: last dpll sync state
@@ -55,7 +58,8 @@ struct ice_dpll {
	u8 prev_input_idx;
	u8 ref_state;
	u8 eec_mode;
	s64 phase_shift;
	s64 phase_offset;
	s64 prev_phase_offset;
	u8 *input_prio;
	enum dpll_lock_status dpll_state;
	enum dpll_lock_status prev_dpll_state;
@@ -78,6 +82,8 @@ struct ice_dpll {
 * @cgu_state_acq_err_num: number of errors returned during periodic work
 * @base_rclk_idx: idx of first pin used for clock revocery pins
 * @clock_id: clock_id of dplls
 * @input_phase_adj_max: max phase adjust value for an input pins
 * @output_phase_adj_max: max phase adjust value for an output pins
 */
struct ice_dplls {
	struct kthread_worker *kworker;