#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
                                                 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
        .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 = {
        .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 = {
                                   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
                        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
                                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;
        }
                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;
 }
                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);
        }