Commit b78aba49 authored by Grygorii Strashko's avatar Grygorii Strashko Committed by David S. Miller

net: ethernet: ti: cpts: add support for HW_TS_PUSH events

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: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Acked-by: default avatarRichard Cochran <richardcochran@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 85624412
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "cpsw_sl.h" #include "cpsw_sl.h"
#include "davinci_cpdma.h" #include "davinci_cpdma.h"
#define CPTS_N_ETX_TS 4
int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv); int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv);
void cpsw_intr_enable(struct cpsw_common *cpsw) void cpsw_intr_enable(struct cpsw_common *cpsw)
...@@ -522,7 +524,8 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, ...@@ -522,7 +524,8 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs,
if (!cpts_node) if (!cpts_node)
cpts_node = cpsw->dev->of_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)) { if (IS_ERR(cpsw->cpts)) {
ret = PTR_ERR(cpsw->cpts); ret = PTR_ERR(cpsw->cpts);
cpdma_ctlr_destroy(cpsw->dma); cpdma_ctlr_destroy(cpsw->dma);
......
...@@ -32,6 +32,11 @@ struct cpts_skb_cb_data { ...@@ -32,6 +32,11 @@ struct cpts_skb_cb_data {
#define cpts_read32(c, r) readl_relaxed(&c->reg->r) #define cpts_read32(c, r) readl_relaxed(&c->reg->r)
#define cpts_write32(c, v, r) writel_relaxed(v, &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) static int event_expired(struct cpts_event *event)
{ {
return time_after(jiffies, event->tmo); return time_after(jiffies, event->tmo);
...@@ -99,6 +104,7 @@ static void cpts_purge_txq(struct cpts *cpts) ...@@ -99,6 +104,7 @@ static void cpts_purge_txq(struct cpts *cpts)
*/ */
static int cpts_fifo_read(struct cpts *cpts, int match) static int cpts_fifo_read(struct cpts *cpts, int match)
{ {
struct ptp_clock_event pevent;
bool need_schedule = false; bool need_schedule = false;
struct cpts_event *event; struct cpts_event *event;
unsigned long flags; unsigned long flags;
...@@ -146,7 +152,12 @@ static int cpts_fifo_read(struct cpts *cpts, int match) ...@@ -146,7 +152,12 @@ static int cpts_fifo_read(struct cpts *cpts, int match)
break; break;
case CPTS_EV_ROLL: case CPTS_EV_ROLL:
case CPTS_EV_HALF: case CPTS_EV_HALF:
break;
case CPTS_EV_HW: 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; break;
default: default:
dev_err(cpts->dev, "cpts: unknown event type\n"); dev_err(cpts->dev, "cpts: unknown event type\n");
...@@ -273,9 +284,42 @@ static int cpts_ptp_settime(struct ptp_clock_info *ptp, ...@@ -273,9 +284,42 @@ static int cpts_ptp_settime(struct ptp_clock_info *ptp,
return 0; 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, static int cpts_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on) 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; return -EOPNOTSUPP;
} }
...@@ -716,7 +760,7 @@ static int cpts_of_parse(struct cpts *cpts, struct device_node *node) ...@@ -716,7 +760,7 @@ static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
} }
struct cpts *cpts_create(struct device *dev, void __iomem *regs, 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; struct cpts *cpts;
int ret; int ret;
...@@ -755,6 +799,9 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs, ...@@ -755,6 +799,9 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
cpts->cc.mask = CLOCKSOURCE_MASK(32); cpts->cc.mask = CLOCKSOURCE_MASK(32);
cpts->info = cpts_info; cpts->info = cpts_info;
if (n_ext_ts)
cpts->info.n_ext_ts = n_ext_ts;
cpts_calc_mult_shift(cpts); cpts_calc_mult_shift(cpts);
/* save cc.mult original value as it can be modified /* save cc.mult original value as it can be modified
* by cpts_ptp_adjfreq(). * by cpts_ptp_adjfreq().
......
...@@ -120,6 +120,7 @@ struct cpts { ...@@ -120,6 +120,7 @@ struct cpts {
struct mutex ptp_clk_mutex; /* sync PTP interface and worker */ struct mutex ptp_clk_mutex; /* sync PTP interface and worker */
bool irq_poll; bool irq_poll;
struct completion ts_push_complete; struct completion ts_push_complete;
u32 hw_ts_enable;
}; };
void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb); 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); ...@@ -127,7 +128,7 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
int cpts_register(struct cpts *cpts); int cpts_register(struct cpts *cpts);
void cpts_unregister(struct cpts *cpts); void cpts_unregister(struct cpts *cpts);
struct cpts *cpts_create(struct device *dev, void __iomem *regs, 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_release(struct cpts *cpts);
void cpts_misc_interrupt(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) ...@@ -158,7 +159,7 @@ static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
static inline static inline
struct cpts *cpts_create(struct device *dev, void __iomem *regs, struct cpts *cpts_create(struct device *dev, void __iomem *regs,
struct device_node *node) struct device_node *node, u32 n_ext_ts)
{ {
return NULL; return NULL;
} }
......
...@@ -3716,7 +3716,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, ...@@ -3716,7 +3716,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
if (!cpts_node) if (!cpts_node)
cpts_node = of_node_get(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); of_node_put(cpts_node);
if (IS_ENABLED(CONFIG_TI_CPTS) && IS_ERR(gbe_dev->cpts)) { if (IS_ENABLED(CONFIG_TI_CPTS) && IS_ERR(gbe_dev->cpts)) {
ret = PTR_ERR(gbe_dev->cpts); ret = PTR_ERR(gbe_dev->cpts);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment