Allow the user to get and set configuration of Embedded SYNC feature
on the ice driver dpll pins.

Reviewed-by: Aleksandr Loktionov <[email protected]>
Signed-off-by: Arkadiusz Kubalewski <[email protected]>
---
 drivers/net/ethernet/intel/ice/ice_dpll.c | 241 +++++++++++++++++++++-
 drivers/net/ethernet/intel/ice/ice_dpll.h |   1 +
 2 files changed, 239 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c 
b/drivers/net/ethernet/intel/ice/ice_dpll.c
index e92be6f130a3..0664bbe98769 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -394,8 +394,8 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct 
ice_dpll_pin *pin,
 
        switch (pin_type) {
        case ICE_DPLL_PIN_TYPE_INPUT:
-               ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL,
-                                              NULL, &pin->flags[0],
+               ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, &pin->status,
+                                              NULL, NULL, &pin->flags[0],
                                               &pin->freq, &pin->phase_adjust);
                if (ret)
                        goto err;
@@ -430,7 +430,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct 
ice_dpll_pin *pin,
                        goto err;
 
                parent &= ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL;
-               if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) {
+               if (ICE_AQC_GET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) {
                        pin->state[pf->dplls.eec.dpll_idx] =
                                parent == pf->dplls.eec.dpll_idx ?
                                DPLL_PIN_STATE_CONNECTED :
@@ -1098,6 +1098,237 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, 
void *pin_priv,
        return 0;
 }
 
+/**
+ * ice_dpll_output_e_sync_set - callback for setting embedded sync
+ * @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
+ * @e_sync_freq: requested embedded sync frequency
+ * @extack: error reporting
+ *
+ * Dpll subsystem callback. Handler for setting embedded sync frequency value
+ * on output pin.
+ *
+ * Context: Acquires pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+static int
+ice_dpll_output_e_sync_set(const struct dpll_pin *pin, void *pin_priv,
+                          const struct dpll_device *dpll, void *dpll_priv,
+                          u64 e_sync_freq, struct netlink_ext_ack *extack)
+{
+       struct ice_dpll_pin *p = pin_priv;
+       struct ice_dpll *d = dpll_priv;
+       struct ice_pf *pf = d->pf;
+       u8 flags = 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_OUT_CFG_OUT_EN)
+               flags = ICE_AQC_SET_CGU_OUT_CFG_OUT_EN;
+       if (e_sync_freq == DPLL_PIN_FREQUENCY_1_HZ) {
+               if (p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) {
+                       ret = 0;
+               } else {
+                       flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN;
+                       ret = ice_aq_set_output_pin_cfg(&pf->hw, p->idx, flags,
+                                                       0, 0, 0);
+               }
+       } else {
+               if (!(p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN)) {
+                       ret = 0;
+               } else {
+                       flags &= ~ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN;
+                       ret = ice_aq_set_output_pin_cfg(&pf->hw, p->idx, flags,
+                                                       0, 0, 0);
+               }
+       }
+       mutex_unlock(&pf->dplls.lock);
+       if (ret)
+               NL_SET_ERR_MSG_FMT(extack,
+                                  "err:%d %s failed to set e-sync freq\n",
+                                  ret,
+                                  ice_aq_str(pf->hw.adminq.sq_last_status));
+       return ret;
+}
+
+/**
+ * ice_dpll_output_e_sync_get - callback for getting embedded sync config
+ * @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
+ * @e_sync_freq: on success holds embedded sync frequency of a pin
+ * @e_sync_range: on success holds embedded sync frequency range for a pin
+ * @pulse: on success holds embedded sync pulse type
+ * @extack: error reporting
+ *
+ * Dpll subsystem callback. Handler for getting embedded sync frequency value
+ * and capabilities on output pin.
+ *
+ * Context: Acquires pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+static int
+ice_dpll_output_e_sync_get(const struct dpll_pin *pin, void *pin_priv,
+                          const struct dpll_device *dpll, void *dpll_priv,
+                          u64 *e_sync_freq,
+                          struct dpll_pin_frequency *e_sync_range,
+                          enum dpll_pin_e_sync_pulse *pulse,
+                          struct netlink_ext_ack *extack)
+{
+       struct ice_dpll_pin *p = pin_priv;
+       struct ice_dpll *d = dpll_priv;
+       struct ice_pf *pf = d->pf;
+
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+       mutex_lock(&pf->dplls.lock);
+       if (!(p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_ABILITY)) {
+               mutex_unlock(&pf->dplls.lock);
+               return -EOPNOTSUPP;
+       }
+       *pulse = DPLL_PIN_E_SYNC_PULSE_NONE;
+       e_sync_range->min = 0;
+       if (p->freq == DPLL_PIN_FREQUENCY_10_MHZ) {
+               e_sync_range->max = DPLL_PIN_FREQUENCY_1_HZ;
+               if (p->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) {
+                       *e_sync_freq = DPLL_PIN_FREQUENCY_1_HZ;
+                       *pulse = DPLL_PIN_E_SYNC_PULSE_25_75;
+               } else {
+                       *e_sync_freq = 0;
+               }
+       } else {
+               e_sync_range->max = 0;
+               *e_sync_freq = 0;
+       }
+       mutex_unlock(&pf->dplls.lock);
+       return 0;
+}
+
+/**
+ * ice_dpll_input_e_sync_set - callback for setting embedded sync
+ * @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
+ * @e_sync_freq: requested embedded sync frequency
+ * @extack: error reporting
+ *
+ * Dpll subsystem callback. Handler for setting embedded sync frequency value
+ * on input pin.
+ *
+ * Context: Acquires pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+static int
+ice_dpll_input_e_sync_set(const struct dpll_pin *pin, void *pin_priv,
+                         const struct dpll_device *dpll, void *dpll_priv,
+                         u64 e_sync_freq, struct netlink_ext_ack *extack)
+{
+       struct ice_dpll_pin *p = pin_priv;
+       struct ice_dpll *d = dpll_priv;
+       struct ice_pf *pf = d->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 (e_sync_freq == DPLL_PIN_FREQUENCY_1_HZ) {
+               if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) {
+                       ret = 0;
+               } else {
+                       flags_en |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN;
+                       ret = ice_aq_set_input_pin_cfg(&pf->hw, p->idx, 0,
+                                                      flags_en, 0, 0);
+               }
+       } else {
+               if (!(p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN)) {
+                       ret = 0;
+               } else {
+                       flags_en &= ~ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN;
+                       ret = ice_aq_set_input_pin_cfg(&pf->hw, p->idx, 0,
+                                                      flags_en, 0, 0);
+               }
+       }
+       mutex_unlock(&pf->dplls.lock);
+       if (ret)
+               NL_SET_ERR_MSG_FMT(extack,
+                                  "err:%d %s failed to set e-sync freq\n",
+                                  ret,
+                                  ice_aq_str(pf->hw.adminq.sq_last_status));
+
+       return ret;
+}
+
+/**
+ * ice_dpll_input_e_sync_get - callback for getting embedded sync config
+ * @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
+ * @e_sync_freq: on success holds embedded sync frequency of a pin
+ * @e_sync_range: on success holds embedded sync frequency range for a pin
+ * @pulse: on success holds embedded sync pulse type
+ * @extack: error reporting
+ *
+ * Dpll subsystem callback. Handler for getting embedded sync frequency value
+ * and capabilities on input pin.
+ *
+ * Context: Acquires pf->dplls.lock
+ * Return:
+ * * 0 - success
+ * * negative - error
+ */
+static int
+ice_dpll_input_e_sync_get(const struct dpll_pin *pin, void *pin_priv,
+                         const struct dpll_device *dpll, void *dpll_priv,
+                         u64 *e_sync_freq,
+                         struct dpll_pin_frequency *e_sync_range,
+                         enum dpll_pin_e_sync_pulse *pulse,
+                         struct netlink_ext_ack *extack)
+{
+       struct ice_dpll_pin *p = pin_priv;
+       struct ice_dpll *d = dpll_priv;
+       struct ice_pf *pf = d->pf;
+
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+       mutex_lock(&pf->dplls.lock);
+       if (!(p->status & ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_CAP)) {
+               mutex_unlock(&pf->dplls.lock);
+               return -EOPNOTSUPP;
+       }
+       *pulse = DPLL_PIN_E_SYNC_PULSE_NONE;
+       e_sync_range->min = 0;
+       if (p->freq == DPLL_PIN_FREQUENCY_10_MHZ) {
+               e_sync_range->max = DPLL_PIN_FREQUENCY_1_HZ;
+               if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) {
+                       *e_sync_freq = DPLL_PIN_FREQUENCY_1_HZ;
+                       *pulse = DPLL_PIN_E_SYNC_PULSE_25_75;
+               } else {
+                       *e_sync_freq = 0;
+               }
+       } else {
+               e_sync_range->max = 0;
+               *e_sync_freq = 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
@@ -1222,6 +1453,8 @@ static const struct dpll_pin_ops ice_dpll_input_ops = {
        .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,
+       .e_sync_set = ice_dpll_input_e_sync_set,
+       .e_sync_get = ice_dpll_input_e_sync_get,
 };
 
 static const struct dpll_pin_ops ice_dpll_output_ops = {
@@ -1232,6 +1465,8 @@ static const struct dpll_pin_ops ice_dpll_output_ops = {
        .direction_get = ice_dpll_output_direction,
        .phase_adjust_get = ice_dpll_pin_phase_adjust_get,
        .phase_adjust_set = ice_dpll_output_phase_adjust_set,
+       .e_sync_set = ice_dpll_output_e_sync_set,
+       .e_sync_get = ice_dpll_output_e_sync_get,
 };
 
 static const struct dpll_device_ops ice_dpll_ops = {
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h 
b/drivers/net/ethernet/intel/ice/ice_dpll.h
index 93172e93995b..c320f1bf7d6d 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.h
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.h
@@ -31,6 +31,7 @@ struct ice_dpll_pin {
        struct dpll_pin_properties prop;
        u32 freq;
        s32 phase_adjust;
+       u8 status;
 };
 
 /** ice_dpll - store info required for DPLL control
-- 
2.38.1

Reply via email to