]> www.infradead.org Git - users/hch/misc.git/commitdiff
ptp: netc: add external trigger stamp support
authorF.S. Peng <fushi.peng@nxp.com>
Fri, 29 Aug 2025 05:06:08 +0000 (13:06 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 2 Sep 2025 11:13:34 +0000 (13:13 +0200)
The NETC Timer is capable of recording the timestamp on receipt of an
external pulse on a GPIO pin. It supports two such external triggers.
The recorded value is saved in a 16 entry FIFO accessed by
TMR_ETTSa_H/L. An interrupt can be generated when the trigger occurs,
when the FIFO reaches a threshold or overflows.

Signed-off-by: F.S. Peng <fushi.peng@nxp.com>
Signed-off-by: Wei Fang <wei.fang@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20250829050615.1247468-8-wei.fang@nxp.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/ptp/ptp_netc.c

index 8f3efdf6f2bb5d3e04c44fef37df593592697b68..8c5fea1f43fae4b3594222f2041df761ff85b341 100644 (file)
@@ -18,6 +18,7 @@
 #define NETC_TMR_CTRL                  0x0080
 #define  TMR_CTRL_CK_SEL               GENMASK(1, 0)
 #define  TMR_CTRL_TE                   BIT(2)
+#define  TMR_ETEP(i)                   BIT(8 + (i))
 #define  TMR_COMP_MODE                 BIT(15)
 #define  TMR_CTRL_TCLK_PERIOD          GENMASK(25, 16)
 #define  TMR_CTRL_FS                   BIT(28)
 #define  TMR_TEVNET_PPEN(i)            BIT(7 - (i))
 #define  TMR_TEVENT_PPEN_ALL           GENMASK(7, 5)
 #define  TMR_TEVENT_ALMEN(i)           BIT(16 + (i))
+#define  TMR_TEVENT_ETS_THREN(i)       BIT(20 + (i))
+#define  TMR_TEVENT_ETSEN(i)           BIT(24 + (i))
+#define  TMR_TEVENT_ETS_OVEN(i)                BIT(28 + (i))
+#define  TMR_TEVENT_ETS(i)             (TMR_TEVENT_ETS_THREN(i) | \
+                                        TMR_TEVENT_ETSEN(i) | \
+                                        TMR_TEVENT_ETS_OVEN(i))
 
 #define NETC_TMR_TEMASK                        0x0088
+#define NETC_TMR_STAT                  0x0094
+#define  TMR_STAT_ETS_VLD(i)           BIT(24 + (i))
+
 #define NETC_TMR_CNT_L                 0x0098
 #define NETC_TMR_CNT_H                 0x009c
 #define NETC_TMR_ADD                   0x00a0
 #define NETC_TMR_PRSC                  0x00a8
+#define NETC_TMR_ECTRL                 0x00ac
 #define NETC_TMR_OFF_L                 0x00b0
 #define NETC_TMR_OFF_H                 0x00b4
 
@@ -49,6 +60,9 @@
 #define  FIPER_CTRL_PW(i)              (GENMASK(4, 0) << (i) * 8)
 #define  FIPER_CTRL_SET_PW(i, v)       (((v) & GENMASK(4, 0)) << 8 * (i))
 
+/* i = 0, 1, i indicates the index of TMR_ETTS */
+#define NETC_TMR_ETTS_L(i)             (0x00e0 + (i) * 8)
+#define NETC_TMR_ETTS_H(i)             (0x00e4 + (i) * 8)
 #define NETC_TMR_CUR_TIME_L            0x00f0
 #define NETC_TMR_CUR_TIME_H            0x00f4
 
@@ -65,6 +79,7 @@
 #define NETC_TMR_DEFAULT_FIPER         GENMASK(31, 0)
 #define NETC_TMR_FIPER_MAX_PW          GENMASK(4, 0)
 #define NETC_TMR_ALARM_NUM             2
+#define NETC_TMR_DEFAULT_ETTF_THR      7
 
 /* 1588 timer reference clock source select */
 #define NETC_TMR_CCM_TIMER1            0 /* enet_timer1_clk_root, from CCM */
@@ -476,6 +491,64 @@ unlock_spinlock:
        return err;
 }
 
+static void netc_timer_handle_etts_event(struct netc_timer *priv, int index,
+                                        bool update_event)
+{
+       struct ptp_clock_event event;
+       u32 etts_l = 0, etts_h = 0;
+
+       while (netc_timer_rd(priv, NETC_TMR_STAT) & TMR_STAT_ETS_VLD(index)) {
+               etts_l = netc_timer_rd(priv, NETC_TMR_ETTS_L(index));
+               etts_h = netc_timer_rd(priv, NETC_TMR_ETTS_H(index));
+       }
+
+       /* Invalid time stamp */
+       if (!etts_l && !etts_h)
+               return;
+
+       if (update_event) {
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = index;
+               event.timestamp = (u64)etts_h << 32;
+               event.timestamp |= etts_l;
+               ptp_clock_event(priv->clock, &event);
+       }
+}
+
+static int netc_timer_enable_extts(struct netc_timer *priv,
+                                  struct ptp_clock_request *rq, int on)
+{
+       int index = rq->extts.index;
+       unsigned long flags;
+       u32 tmr_ctrl;
+
+       /* Reject requests to enable time stamping on both edges */
+       if ((rq->extts.flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES)
+               return -EOPNOTSUPP;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       netc_timer_handle_etts_event(priv, rq->extts.index, false);
+       if (on) {
+               tmr_ctrl = netc_timer_rd(priv, NETC_TMR_CTRL);
+               if (rq->extts.flags & PTP_FALLING_EDGE)
+                       tmr_ctrl |= TMR_ETEP(index);
+               else
+                       tmr_ctrl &= ~TMR_ETEP(index);
+
+               netc_timer_wr(priv, NETC_TMR_CTRL, tmr_ctrl);
+               priv->tmr_emask |= TMR_TEVENT_ETS(index);
+       } else {
+               priv->tmr_emask &= ~TMR_TEVENT_ETS(index);
+       }
+
+       netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
 static void netc_timer_disable_fiper(struct netc_timer *priv)
 {
        u32 fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
@@ -529,6 +602,8 @@ static int netc_timer_enable(struct ptp_clock_info *ptp,
                return netc_timer_enable_pps(priv, rq, on);
        case PTP_CLK_REQ_PEROUT:
                return net_timer_enable_perout(priv, rq, on);
+       case PTP_CLK_REQ_EXTTS:
+               return netc_timer_enable_extts(priv, rq, on);
        default:
                return -EOPNOTSUPP;
        }
@@ -641,6 +716,9 @@ static const struct ptp_clock_info netc_timer_ptp_caps = {
        .n_alarm        = 2,
        .pps            = 1,
        .n_per_out      = 3,
+       .n_ext_ts       = 2,
+       .supported_extts_flags = PTP_RISING_EDGE | PTP_FALLING_EDGE |
+                                PTP_STRICT_FLAGS,
        .adjfine        = netc_timer_adjfine,
        .adjtime        = netc_timer_adjtime,
        .gettimex64     = netc_timer_gettimex64,
@@ -673,6 +751,7 @@ static void netc_timer_init(struct netc_timer *priv)
                fiper_ctrl &= ~FIPER_CTRL_PG(i);
        }
        netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl);
+       netc_timer_wr(priv, NETC_TMR_ECTRL, NETC_TMR_DEFAULT_ETTF_THR);
 
        ktime_get_real_ts64(&now);
        ns = timespec64_to_ns(&now);
@@ -806,6 +885,12 @@ static irqreturn_t netc_timer_isr(int irq, void *data)
                ptp_clock_event(priv->clock, &event);
        }
 
+       if (tmr_event & TMR_TEVENT_ETS(0))
+               netc_timer_handle_etts_event(priv, 0, true);
+
+       if (tmr_event & TMR_TEVENT_ETS(1))
+               netc_timer_handle_etts_event(priv, 1, true);
+
        spin_unlock(&priv->lock);
 
        return IRQ_HANDLED;