#define GLV_UPRCL(_i)                          (0x003B2000 + ((_i) * 8))
 #define GLV_UPTCL(_i)                          (0x0030A000 + ((_i) * 8))
 #define PRTRPB_RDPC                            0x000AC260
+#define GLHH_ART_CTL                           0x000A41D4
+#define GLHH_ART_CTL_ACTIVE_M                  BIT(0)
+#define GLHH_ART_TIME_H                                0x000A41D8
+#define GLHH_ART_TIME_L                                0x000A41DC
 #define GLTSYN_AUX_IN_0(_i)                    (0x000889D8 + ((_i) * 4))
 #define GLTSYN_AUX_IN_0_INT_ENA_M              BIT(4)
 #define GLTSYN_AUX_OUT_0(_i)                   (0x00088998 + ((_i) * 4))
 #define GLTSYN_ENA_TSYN_ENA_M                  BIT(0)
 #define GLTSYN_EVNT_H_0(_i)                    (0x00088970 + ((_i) * 4))
 #define GLTSYN_EVNT_L_0(_i)                    (0x00088968 + ((_i) * 4))
+#define GLTSYN_HHTIME_H(_i)                    (0x00088900 + ((_i) * 4))
+#define GLTSYN_HHTIME_L(_i)                    (0x000888F8 + ((_i) * 4))
 #define GLTSYN_INCVAL_H(_i)                    (0x00088920 + ((_i) * 4))
 #define GLTSYN_INCVAL_L(_i)                    (0x00088918 + ((_i) * 4))
 #define GLTSYN_SHADJ_H(_i)                     (0x00088910 + ((_i) * 4))
 #define GLTSYN_TGT_L_0(_i)                     (0x00088928 + ((_i) * 4))
 #define GLTSYN_TIME_H(_i)                      (0x000888D8 + ((_i) * 4))
 #define GLTSYN_TIME_L(_i)                      (0x000888D0 + ((_i) * 4))
+#define PFHH_SEM                               0x000A4200 /* Reset Source: PFR */
+#define PFHH_SEM_BUSY_M                                BIT(0)
 #define PFTSYN_SEM                             0x00088880
 #define PFTSYN_SEM_BUSY_M                      BIT(0)
 #define VSIQF_FD_CNT(_VSI)                     (0x00464000 + ((_VSI) * 4))
 
        return 0;
 }
 
+#ifdef CONFIG_ICE_HWTS
+/**
+ * ice_ptp_get_syncdevicetime - Get the cross time stamp info
+ * @device: Current device time
+ * @system: System counter value read synchronously with device time
+ * @ctx: Context provided by timekeeping code
+ *
+ * Read device and system (ART) clock simultaneously and return the corrected
+ * clock values in ns.
+ */
+static int
+ice_ptp_get_syncdevicetime(ktime_t *device,
+                          struct system_counterval_t *system,
+                          void *ctx)
+{
+       struct ice_pf *pf = (struct ice_pf *)ctx;
+       struct ice_hw *hw = &pf->hw;
+       u32 hh_lock, hh_art_ctl;
+       int i;
+
+       /* Get the HW lock */
+       hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
+       if (hh_lock & PFHH_SEM_BUSY_M) {
+               dev_err(ice_pf_to_dev(pf), "PTP failed to get hh lock\n");
+               return -EFAULT;
+       }
+
+       /* Start the ART and device clock sync sequence */
+       hh_art_ctl = rd32(hw, GLHH_ART_CTL);
+       hh_art_ctl = hh_art_ctl | GLHH_ART_CTL_ACTIVE_M;
+       wr32(hw, GLHH_ART_CTL, hh_art_ctl);
+
+#define MAX_HH_LOCK_TRIES 100
+
+       for (i = 0; i < MAX_HH_LOCK_TRIES; i++) {
+               /* Wait for sync to complete */
+               hh_art_ctl = rd32(hw, GLHH_ART_CTL);
+               if (hh_art_ctl & GLHH_ART_CTL_ACTIVE_M) {
+                       udelay(1);
+                       continue;
+               } else {
+                       u32 hh_ts_lo, hh_ts_hi, tmr_idx;
+                       u64 hh_ts;
+
+                       tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
+                       /* Read ART time */
+                       hh_ts_lo = rd32(hw, GLHH_ART_TIME_L);
+                       hh_ts_hi = rd32(hw, GLHH_ART_TIME_H);
+                       hh_ts = ((u64)hh_ts_hi << 32) | hh_ts_lo;
+                       *system = convert_art_ns_to_tsc(hh_ts);
+                       /* Read Device source clock time */
+                       hh_ts_lo = rd32(hw, GLTSYN_HHTIME_L(tmr_idx));
+                       hh_ts_hi = rd32(hw, GLTSYN_HHTIME_H(tmr_idx));
+                       hh_ts = ((u64)hh_ts_hi << 32) | hh_ts_lo;
+                       *device = ns_to_ktime(hh_ts);
+                       break;
+               }
+       }
+       /* Release HW lock */
+       hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
+       hh_lock = hh_lock & ~PFHH_SEM_BUSY_M;
+       wr32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), hh_lock);
+
+       if (i == MAX_HH_LOCK_TRIES)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+/**
+ * ice_ptp_getcrosststamp_e822 - Capture a device cross timestamp
+ * @info: the driver's PTP info structure
+ * @cts: The memory to fill the cross timestamp info
+ *
+ * Capture a cross timestamp between the ART and the device PTP hardware
+ * clock. Fill the cross timestamp information and report it back to the
+ * caller.
+ *
+ * This is only valid for E822 devices which have support for generating the
+ * cross timestamp via PCIe PTM.
+ *
+ * In order to correctly correlate the ART timestamp back to the TSC time, the
+ * CPU must have X86_FEATURE_TSC_KNOWN_FREQ.
+ */
+static int
+ice_ptp_getcrosststamp_e822(struct ptp_clock_info *info,
+                           struct system_device_crosststamp *cts)
+{
+       struct ice_pf *pf = ptp_info_to_pf(info);
+
+       return get_device_system_crosststamp(ice_ptp_get_syncdevicetime,
+                                            pf, NULL, cts);
+}
+#endif /* CONFIG_ICE_HWTS */
+
 /**
  * ice_ptp_get_ts_config - ioctl interface to read the timestamping config
  * @pf: Board private structure
        info->n_ext_ts = N_EXT_TS_E810;
 }
 
+/**
+ * ice_ptp_set_funcs_e822 - Set specialized functions for E822 support
+ * @pf: Board private structure
+ * @info: PTP info to fill
+ *
+ * Assign functions to the PTP capabiltiies structure for E822 devices.
+ * Functions which operate across all device families should be set directly
+ * in ice_ptp_set_caps. Only add functions here which are distinct for E822
+ * devices.
+ */
+static void
+ice_ptp_set_funcs_e822(struct ice_pf *pf, struct ptp_clock_info *info)
+{
+#ifdef CONFIG_ICE_HWTS
+       if (boot_cpu_has(X86_FEATURE_ART) &&
+           boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ))
+               info->getcrosststamp = ice_ptp_getcrosststamp_e822;
+#endif /* CONFIG_ICE_HWTS */
+}
+
 /**
  * ice_ptp_set_funcs_e810 - Set specialized functions for E810 support
  * @pf: Board private structure
 
        if (ice_is_e810(&pf->hw))
                ice_ptp_set_funcs_e810(pf, info);
+       else
+               ice_ptp_set_funcs_e822(pf, info);
 }
 
 /**