+static int
+ice_timesync_enable(struct rte_eth_dev *dev)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ int ret;
+
+ if (dev->data->dev_started && !(dev->data->dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_TIMESTAMP)) {
+ PMD_DRV_LOG(ERR, "Rx timestamp offload not configured");
+ return -1;
+ }
+
+ if (hw->func_caps.ts_func_info.src_tmr_owned) {
+ ret = ice_ptp_init_phc(hw);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to initialize PHC");
+ return -1;
+ }
+
+ ret = ice_ptp_write_incval(hw, ICE_PTP_NOMINAL_INCVAL_E810);
+ if (ret) {
+ PMD_DRV_LOG(ERR,
+ "Failed to write PHC increment time value");
+ return -1;
+ }
+ }
+
+ /* Initialize cycle counters for system time/RX/TX timestamp */
+ memset(&ad->systime_tc, 0, sizeof(struct rte_timecounter));
+ memset(&ad->rx_tstamp_tc, 0, sizeof(struct rte_timecounter));
+ memset(&ad->tx_tstamp_tc, 0, sizeof(struct rte_timecounter));
+
+ ad->systime_tc.cc_mask = ICE_CYCLECOUNTER_MASK;
+ ad->systime_tc.cc_shift = 0;
+ ad->systime_tc.nsec_mask = 0;
+
+ ad->rx_tstamp_tc.cc_mask = ICE_CYCLECOUNTER_MASK;
+ ad->rx_tstamp_tc.cc_shift = 0;
+ ad->rx_tstamp_tc.nsec_mask = 0;
+
+ ad->tx_tstamp_tc.cc_mask = ICE_CYCLECOUNTER_MASK;
+ ad->tx_tstamp_tc.cc_shift = 0;
+ ad->tx_tstamp_tc.nsec_mask = 0;
+
+ ad->ptp_ena = 1;
+
+ return 0;
+}
+
+static int
+ice_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
+ struct timespec *timestamp, uint32_t flags)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ struct ice_rx_queue *rxq;
+ uint32_t ts_high;
+ uint64_t ts_ns, ns;
+
+ rxq = dev->data->rx_queues[flags];
+
+ ts_high = rxq->time_high;
+ ts_ns = ice_tstamp_convert_32b_64b(hw, ts_high);
+ ns = rte_timecounter_update(&ad->rx_tstamp_tc, ts_ns);
+ *timestamp = rte_ns_to_timespec(ns);
+
+ return 0;
+}
+
+static int
+ice_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
+ struct timespec *timestamp)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint8_t lport;
+ uint64_t ts_ns, ns, tstamp;
+ const uint64_t mask = 0xFFFFFFFF;
+ int ret;
+
+ lport = hw->port_info->lport;
+
+ ret = ice_read_phy_tstamp(hw, lport, 0, &tstamp);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to read phy timestamp");
+ return -1;
+ }
+
+ ts_ns = ice_tstamp_convert_32b_64b(hw, (tstamp >> 8) & mask);
+ ns = rte_timecounter_update(&ad->tx_tstamp_tc, ts_ns);
+ *timestamp = rte_ns_to_timespec(ns);
+
+ return 0;
+}
+
+static int
+ice_timesync_adjust_time(struct rte_eth_dev *dev, int64_t delta)
+{
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+ ad->systime_tc.nsec += delta;
+ ad->rx_tstamp_tc.nsec += delta;
+ ad->tx_tstamp_tc.nsec += delta;
+
+ return 0;
+}
+
+static int
+ice_timesync_write_time(struct rte_eth_dev *dev, const struct timespec *ts)
+{
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint64_t ns;
+
+ ns = rte_timespec_to_ns(ts);
+
+ ad->systime_tc.nsec = ns;
+ ad->rx_tstamp_tc.nsec = ns;
+ ad->tx_tstamp_tc.nsec = ns;
+
+ return 0;
+}
+
+static int
+ice_timesync_read_time(struct rte_eth_dev *dev, struct timespec *ts)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint32_t hi, lo, lo2;
+ uint64_t time, ns;
+
+ lo = ICE_READ_REG(hw, GLTSYN_TIME_L(0));
+ hi = ICE_READ_REG(hw, GLTSYN_TIME_H(0));
+ lo2 = ICE_READ_REG(hw, GLTSYN_TIME_L(0));
+
+ if (lo2 < lo) {
+ lo = ICE_READ_REG(hw, GLTSYN_TIME_L(0));
+ hi = ICE_READ_REG(hw, GLTSYN_TIME_H(0));
+ }
+
+ time = ((uint64_t)hi << 32) | lo;
+ ns = rte_timecounter_update(&ad->systime_tc, time);
+ *ts = rte_ns_to_timespec(ns);
+
+ return 0;
+}
+
+static int
+ice_timesync_disable(struct rte_eth_dev *dev)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint64_t val;
+ uint8_t lport;
+
+ lport = hw->port_info->lport;
+
+ ice_clear_phy_tstamp(hw, lport, 0);
+
+ val = ICE_READ_REG(hw, GLTSYN_ENA(0));
+ val &= ~GLTSYN_ENA_TSYN_ENA_M;
+ ICE_WRITE_REG(hw, GLTSYN_ENA(0), val);
+
+ ICE_WRITE_REG(hw, GLTSYN_INCVAL_L(0), 0);
+ ICE_WRITE_REG(hw, GLTSYN_INCVAL_H(0), 0);
+
+ ad->ptp_ena = 0;
+
+ return 0;
+}
+