net: ethernet: ti: cpts: add support for HW_TS_PUSH events
authorGrygorii Strashko <grygorii.strashko@ti.com>
Thu, 23 Apr 2020 14:20:21 +0000 (17:20 +0300)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 Apr 2020 19:50:21 +0000 (12:50 -0700)
Hence CPTS IRQ support is in place the W_TS_PUSH events can be added.
PWM capable DmTimers can be used to generete input signals for CPTS on TI
AM335x/AM437x/DRA7 SoCs to be timestamped:
AM335x/AM437x: timer4 - timer7
DRA7/AM57xx: timer13 - timer16

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ti/cpsw_priv.c
drivers/net/ethernet/ti/cpts.c
drivers/net/ethernet/ti/cpts.h
drivers/net/ethernet/ti/netcp_ethss.c

index 97a058ca60ac9b177f7945e3b9be9ccfe9eb070e..0992089274008538d6b54984ff0979329622d666 100644 (file)
@@ -28,6 +28,8 @@
 #include "cpsw_sl.h"
 #include "davinci_cpdma.h"
 
+#define CPTS_N_ETX_TS 4
+
 int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv);
 
 void cpsw_intr_enable(struct cpsw_common *cpsw)
@@ -522,7 +524,8 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs,
        if (!cpts_node)
                cpts_node = cpsw->dev->of_node;
 
-       cpsw->cpts = cpts_create(cpsw->dev, cpts_regs, cpts_node);
+       cpsw->cpts = cpts_create(cpsw->dev, cpts_regs, cpts_node,
+                                CPTS_N_ETX_TS);
        if (IS_ERR(cpsw->cpts)) {
                ret = PTR_ERR(cpsw->cpts);
                cpdma_ctlr_destroy(cpsw->dma);
index 339796c87bf60207d2652f404d38cb61bc94f7d8..7c55d395de2ce799366181ba01833e23fb8c8ea6 100644 (file)
@@ -32,6 +32,11 @@ struct cpts_skb_cb_data {
 #define cpts_read32(c, r)      readl_relaxed(&c->reg->r)
 #define cpts_write32(c, v, r)  writel_relaxed(v, &c->reg->r)
 
+static int cpts_event_port(struct cpts_event *event)
+{
+       return (event->high >> PORT_NUMBER_SHIFT) & PORT_NUMBER_MASK;
+}
+
 static int event_expired(struct cpts_event *event)
 {
        return time_after(jiffies, event->tmo);
@@ -99,6 +104,7 @@ static void cpts_purge_txq(struct cpts *cpts)
  */
 static int cpts_fifo_read(struct cpts *cpts, int match)
 {
+       struct ptp_clock_event pevent;
        bool need_schedule = false;
        struct cpts_event *event;
        unsigned long flags;
@@ -146,7 +152,12 @@ static int cpts_fifo_read(struct cpts *cpts, int match)
                        break;
                case CPTS_EV_ROLL:
                case CPTS_EV_HALF:
+                       break;
                case CPTS_EV_HW:
+                       pevent.timestamp = event->timestamp;
+                       pevent.type = PTP_CLOCK_EXTTS;
+                       pevent.index = cpts_event_port(event) - 1;
+                       ptp_clock_event(cpts->clock, &pevent);
                        break;
                default:
                        dev_err(cpts->dev, "cpts: unknown event type\n");
@@ -273,9 +284,42 @@ static int cpts_ptp_settime(struct ptp_clock_info *ptp,
        return 0;
 }
 
+static int cpts_extts_enable(struct cpts *cpts, u32 index, int on)
+{
+       u32 v;
+
+       if (((cpts->hw_ts_enable & BIT(index)) >> index) == on)
+               return 0;
+
+       mutex_lock(&cpts->ptp_clk_mutex);
+
+       v = cpts_read32(cpts, control);
+       if (on) {
+               v |= BIT(8 + index);
+               cpts->hw_ts_enable |= BIT(index);
+       } else {
+               v &= ~BIT(8 + index);
+               cpts->hw_ts_enable &= ~BIT(index);
+       }
+       cpts_write32(cpts, v, control);
+
+       mutex_unlock(&cpts->ptp_clk_mutex);
+
+       return 0;
+}
+
 static int cpts_ptp_enable(struct ptp_clock_info *ptp,
                           struct ptp_clock_request *rq, int on)
 {
+       struct cpts *cpts = container_of(ptp, struct cpts, info);
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               return cpts_extts_enable(cpts, rq->extts.index, on);
+       default:
+               break;
+       }
+
        return -EOPNOTSUPP;
 }
 
@@ -716,7 +760,7 @@ of_error:
 }
 
 struct cpts *cpts_create(struct device *dev, void __iomem *regs,
-                        struct device_node *node)
+                        struct device_node *node, u32 n_ext_ts)
 {
        struct cpts *cpts;
        int ret;
@@ -755,6 +799,9 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
        cpts->cc.mask = CLOCKSOURCE_MASK(32);
        cpts->info = cpts_info;
 
+       if (n_ext_ts)
+               cpts->info.n_ext_ts = n_ext_ts;
+
        cpts_calc_mult_shift(cpts);
        /* save cc.mult original value as it can be modified
         * by cpts_ptp_adjfreq().
index 473d0622e8611c80883d529efe6b54d97508d4c1..07222f651d2eedbc73bfca5c1e750ce668cc25a0 100644 (file)
@@ -120,6 +120,7 @@ struct cpts {
        struct mutex ptp_clk_mutex; /* sync PTP interface and worker */
        bool irq_poll;
        struct completion       ts_push_complete;
+       u32 hw_ts_enable;
 };
 
 void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
@@ -127,7 +128,7 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
 int cpts_register(struct cpts *cpts);
 void cpts_unregister(struct cpts *cpts);
 struct cpts *cpts_create(struct device *dev, void __iomem *regs,
-                        struct device_node *node);
+                        struct device_node *node, u32 n_ext_ts);
 void cpts_release(struct cpts *cpts);
 void cpts_misc_interrupt(struct cpts *cpts);
 
@@ -158,7 +159,7 @@ static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 
 static inline
 struct cpts *cpts_create(struct device *dev, void __iomem *regs,
-                        struct device_node *node)
+                        struct device_node *node, u32 n_ext_ts)
 {
        return NULL;
 }
index fb36115e9c510c7315eb13e0992575a59d091dc4..9d6e27fb710ef46c664975d4c951e60fefd02692 100644 (file)
@@ -3716,7 +3716,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        if (!cpts_node)
                cpts_node = of_node_get(node);
 
-       gbe_dev->cpts = cpts_create(gbe_dev->dev, gbe_dev->cpts_reg, cpts_node);
+       gbe_dev->cpts = cpts_create(gbe_dev->dev, gbe_dev->cpts_reg,
+                                   cpts_node, 0);
        of_node_put(cpts_node);
        if (IS_ENABLED(CONFIG_TI_CPTS) && IS_ERR(gbe_dev->cpts)) {
                ret = PTR_ERR(gbe_dev->cpts);