intel_priv = priv->plat->bsp_priv;
 
+       /* Both internal crosstimestamping and external triggered event
+        * timestamping cannot be run concurrently.
+        */
+       if (priv->plat->ext_snapshot_en)
+               return -EBUSY;
+
+       mutex_lock(&priv->aux_ts_lock);
        /* Enable Internal snapshot trigger */
        acr_value = readl(ptpaddr + PTP_ACR);
        acr_value &= ~PTP_ACR_MASK;
        acr_value = readl(ptpaddr + PTP_ACR);
        acr_value |= PTP_ACR_ATSFC;
        writel(acr_value, ptpaddr + PTP_ACR);
+       /* Release the mutex */
+       mutex_unlock(&priv->aux_ts_lock);
 
        /* Trigger Internal snapshot signal
         * Create a rising edge by just toggle the GPO1 to low
        plat->mdio_bus_data->phy_mask |= 1 << INTEL_MGBE_XPCS_ADDR;
 
        plat->int_snapshot_num = AUX_SNAPSHOT1;
+       plat->ext_snapshot_num = AUX_SNAPSHOT0;
 
        plat->has_crossts = true;
        plat->crosststamp = intel_crosststamp;
 
 #define stmmac_fpe_irq_status(__priv, __args...) \
        stmmac_do_callback(__priv, mac, fpe_irq_status, __args)
 
+struct stmmac_priv;
+
 /* PTP and HW Timer helpers */
 struct stmmac_hwtimestamp {
        void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
                               int add_sub, int gmac4);
        void (*get_systime) (void __iomem *ioaddr, u64 *systime);
        void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
+       void (*timestamp_interrupt)(struct stmmac_priv *priv);
 };
 
 #define stmmac_config_hw_tstamping(__priv, __args...) \
        stmmac_do_void_callback(__priv, ptp, get_systime, __args)
 #define stmmac_get_ptptime(__priv, __args...) \
        stmmac_do_void_callback(__priv, ptp, get_ptptime, __args)
+#define stmmac_timestamp_interrupt(__priv, __args...) \
+       stmmac_do_void_callback(__priv, ptp, timestamp_interrupt, __args)
 
 /* Helpers to manage the descriptors for chain and ring modes */
 struct stmmac_mode_ops {
 
        int use_riwt;
        int irq_wake;
        spinlock_t ptp_lock;
+       /* Protects auxiliary snapshot registers from concurrent access. */
+       struct mutex aux_ts_lock;
+
        void __iomem *mmcaddr;
        void __iomem *ptpaddr;
        unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
 
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/delay.h>
+#include <linux/ptp_clock_kernel.h>
 #include "common.h"
 #include "stmmac_ptp.h"
+#include "dwmac4.h"
+#include "stmmac.h"
 
 static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
 {
        *ptp_time = ns;
 }
 
+static void timestamp_interrupt(struct stmmac_priv *priv)
+{
+       u32 num_snapshot, ts_status, tsync_int;
+       struct ptp_clock_event event;
+       unsigned long flags;
+       u64 ptp_time;
+       int i;
+
+       tsync_int = readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE;
+
+       if (!tsync_int)
+               return;
+
+       /* Read timestamp status to clear interrupt from either external
+        * timestamp or start/end of PPS.
+        */
+       ts_status = readl(priv->ioaddr + GMAC_TIMESTAMP_STATUS);
+
+       if (!priv->plat->ext_snapshot_en)
+               return;
+
+       num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
+                      GMAC_TIMESTAMP_ATSNS_SHIFT;
+
+       for (i = 0; i < num_snapshot; i++) {
+               spin_lock_irqsave(&priv->ptp_lock, flags);
+               get_ptptime(priv->ptpaddr, &ptp_time);
+               spin_unlock_irqrestore(&priv->ptp_lock, flags);
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = 0;
+               event.timestamp = ptp_time;
+               ptp_clock_event(priv->ptp_clock, &event);
+       }
+}
+
 const struct stmmac_hwtimestamp stmmac_ptp = {
        .config_hw_tstamping = config_hw_tstamping,
        .init_systime = init_systime,
        .adjust_systime = adjust_systime,
        .get_systime = get_systime,
        .get_ptptime = get_ptptime,
+       .timestamp_interrupt = timestamp_interrupt,
 };
 
                        else
                                netif_carrier_off(priv->dev);
                }
+
+               stmmac_timestamp_interrupt(priv, priv);
        }
 }
 
 
 {
        struct stmmac_priv *priv =
            container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+       void __iomem *ptpaddr = priv->ptpaddr;
+       void __iomem *ioaddr = priv->hw->pcsr;
        struct stmmac_pps_cfg *cfg;
+       u32 intr_value, acr_value;
        int ret = -EOPNOTSUPP;
        unsigned long flags;
 
                                             priv->systime_flags);
                spin_unlock_irqrestore(&priv->ptp_lock, flags);
                break;
+       case PTP_CLK_REQ_EXTTS:
+               priv->plat->ext_snapshot_en = on;
+               mutex_lock(&priv->aux_ts_lock);
+               acr_value = readl(ptpaddr + PTP_ACR);
+               acr_value &= ~PTP_ACR_MASK;
+               if (on) {
+                       /* Enable External snapshot trigger */
+                       acr_value |= priv->plat->ext_snapshot_num;
+                       acr_value |= PTP_ACR_ATSFC;
+                       netdev_dbg(priv->dev, "Auxiliary Snapshot %d enabled.\n",
+                                  priv->plat->ext_snapshot_num >>
+                                  PTP_ACR_ATSEN_SHIFT);
+                       /* Enable Timestamp Interrupt */
+                       intr_value = readl(ioaddr + GMAC_INT_EN);
+                       intr_value |= GMAC_INT_TSIE;
+                       writel(intr_value, ioaddr + GMAC_INT_EN);
+
+               } else {
+                       netdev_dbg(priv->dev, "Auxiliary Snapshot %d disabled.\n",
+                                  priv->plat->ext_snapshot_num >>
+                                  PTP_ACR_ATSEN_SHIFT);
+                       /* Disable Timestamp Interrupt */
+                       intr_value = readl(ioaddr + GMAC_INT_EN);
+                       intr_value &= ~GMAC_INT_TSIE;
+                       writel(intr_value, ioaddr + GMAC_INT_EN);
+               }
+               writel(acr_value, ptpaddr + PTP_ACR);
+               mutex_unlock(&priv->aux_ts_lock);
+               ret = 0;
+               break;
+
        default:
                break;
        }
        .name = "stmmac ptp",
        .max_adj = 62500000,
        .n_alarm = 0,
-       .n_ext_ts = 0,
+       .n_ext_ts = 0, /* will be overwritten in stmmac_ptp_register */
        .n_per_out = 0, /* will be overwritten in stmmac_ptp_register */
        .n_pins = 0,
        .pps = 0,
                stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
 
        stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
+       stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
 
        spin_lock_init(&priv->ptp_lock);
+       mutex_init(&priv->aux_ts_lock);
        priv->ptp_clock_ops = stmmac_ptp_clock_ops;
 
        priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
                pr_debug("Removed PTP HW clock successfully on %s\n",
                         priv->dev->name);
        }
+
+       mutex_destroy(&priv->aux_ts_lock);
 }
 
 #define        PTP_ACR_ATSEN1          BIT(5)  /* Auxiliary Snapshot 1 Enable */
 #define        PTP_ACR_ATSEN2          BIT(6)  /* Auxiliary Snapshot 2 Enable */
 #define        PTP_ACR_ATSEN3          BIT(7)  /* Auxiliary Snapshot 3 Enable */
+#define        PTP_ACR_ATSEN_SHIFT     5       /* Auxiliary Snapshot shift */
 #define        PTP_ACR_MASK            GENMASK(7, 4)   /* Aux Snapshot Mask */
 #define        PMC_ART_VALUE0          0x01    /* PMC_ART[15:0] timer value */
 #define        PMC_ART_VALUE1          0x02    /* PMC_ART[31:16] timer value */
 
        struct pci_dev *pdev;
        bool has_crossts;
        int int_snapshot_num;
+       int ext_snapshot_num;
+       bool ext_snapshot_en;
        bool multi_msi_en;
        int msi_mac_vec;
        int msi_wol_vec;