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

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
...@@ -878,6 +878,199 @@ ice_dpll_output_direction(const struct dpll_pin *pin, void *pin_priv, ...@@ -878,6 +878,199 @@ ice_dpll_output_direction(const struct dpll_pin *pin, void *pin_priv,
return 0; 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 * ice_dpll_rclk_state_on_pin_set - set a state on rclk pin
* @pin: pointer to a pin * @pin: pointer to a pin
...@@ -993,6 +1186,9 @@ static const struct dpll_pin_ops ice_dpll_input_ops = { ...@@ -993,6 +1186,9 @@ static const struct dpll_pin_ops ice_dpll_input_ops = {
.prio_get = ice_dpll_input_prio_get, .prio_get = ice_dpll_input_prio_get,
.prio_set = ice_dpll_input_prio_set, .prio_set = ice_dpll_input_prio_set,
.direction_get = ice_dpll_input_direction, .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 = { static const struct dpll_pin_ops ice_dpll_output_ops = {
...@@ -1001,6 +1197,8 @@ 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_get = ice_dpll_output_state_get,
.state_on_dpll_set = ice_dpll_output_state_set, .state_on_dpll_set = ice_dpll_output_state_set,
.direction_get = ice_dpll_output_direction, .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 = { static const struct dpll_device_ops ice_dpll_ops = {
...@@ -1031,6 +1229,8 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) ...@@ -1031,6 +1229,8 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
*/ */
static void ice_dpll_notify_changes(struct ice_dpll *d) static void ice_dpll_notify_changes(struct ice_dpll *d)
{ {
bool pin_notified = false;
if (d->prev_dpll_state != d->dpll_state) { if (d->prev_dpll_state != d->dpll_state) {
d->prev_dpll_state = d->dpll_state; d->prev_dpll_state = d->dpll_state;
dpll_device_change_ntf(d->dpll); dpll_device_change_ntf(d->dpll);
...@@ -1039,7 +1239,14 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) ...@@ -1039,7 +1239,14 @@ static void ice_dpll_notify_changes(struct ice_dpll *d)
if (d->prev_input) if (d->prev_input)
dpll_pin_change_ntf(d->prev_input); dpll_pin_change_ntf(d->prev_input);
d->prev_input = d->active_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); 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) ...@@ -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, ret = ice_get_cgu_state(&pf->hw, d->dpll_idx, d->prev_dpll_state,
&d->input_idx, &d->ref_state, &d->eec_mode, &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), dev_dbg(ice_pf_to_dev(pf),
"update dpll=%d, prev_src_idx:%u, src_idx:%u, state:%d, prev:%d mode:%d\n", "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, ...@@ -1656,6 +1863,15 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
return ret; return ret;
pins[i].prop.capabilities |= pins[i].prop.capabilities |=
DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE; 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 |= pins[i].prop.capabilities |=
DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* @state: state of a pin * @state: state of a pin
* @prop: pin properties * @prop: pin properties
* @freq: current frequency of a pin * @freq: current frequency of a pin
* @phase_adjust: current phase adjust value
*/ */
struct ice_dpll_pin { struct ice_dpll_pin {
struct dpll_pin *pin; struct dpll_pin *pin;
...@@ -30,6 +31,7 @@ struct ice_dpll_pin { ...@@ -30,6 +31,7 @@ struct ice_dpll_pin {
u8 state[ICE_DPLL_RCLK_NUM_MAX]; u8 state[ICE_DPLL_RCLK_NUM_MAX];
struct dpll_pin_properties prop; struct dpll_pin_properties prop;
u32 freq; u32 freq;
s32 phase_adjust;
}; };
/** ice_dpll - store info required for DPLL control /** ice_dpll - store info required for DPLL control
...@@ -40,7 +42,8 @@ struct ice_dpll_pin { ...@@ -40,7 +42,8 @@ struct ice_dpll_pin {
* @prev_input_idx: previously selected input index * @prev_input_idx: previously selected input index
* @ref_state: state of dpll reference signals * @ref_state: state of dpll reference signals
* @eec_mode: eec_mode dpll is configured for * @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 * @input_prio: priorities of each input
* @dpll_state: current dpll sync state * @dpll_state: current dpll sync state
* @prev_dpll_state: last dpll sync state * @prev_dpll_state: last dpll sync state
...@@ -55,7 +58,8 @@ struct ice_dpll { ...@@ -55,7 +58,8 @@ struct ice_dpll {
u8 prev_input_idx; u8 prev_input_idx;
u8 ref_state; u8 ref_state;
u8 eec_mode; u8 eec_mode;
s64 phase_shift; s64 phase_offset;
s64 prev_phase_offset;
u8 *input_prio; u8 *input_prio;
enum dpll_lock_status dpll_state; enum dpll_lock_status dpll_state;
enum dpll_lock_status prev_dpll_state; enum dpll_lock_status prev_dpll_state;
...@@ -78,6 +82,8 @@ struct ice_dpll { ...@@ -78,6 +82,8 @@ struct ice_dpll {
* @cgu_state_acq_err_num: number of errors returned during periodic work * @cgu_state_acq_err_num: number of errors returned during periodic work
* @base_rclk_idx: idx of first pin used for clock revocery pins * @base_rclk_idx: idx of first pin used for clock revocery pins
* @clock_id: clock_id of dplls * @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 ice_dplls {
struct kthread_worker *kworker; struct kthread_worker *kworker;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment