summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
diff options
context:
space:
mode:
authorJose Abreu2018-05-31 19:01:27 +0200
committerDavid S. Miller2018-06-04 16:13:16 +0200
commit9a8a02c9d46dcd4c663dac39e6518b6bb7ac1631 (patch)
tree924a4f7b5eb4eea0a21154e301d85488f8cdf8e0 /drivers/net/ethernet/stmicro/stmmac/dwmac5.c
parentMerge branch 'qed-next' (diff)
downloadkernel-qcow2-linux-9a8a02c9d46dcd4c663dac39e6518b6bb7ac1631.tar.gz
kernel-qcow2-linux-9a8a02c9d46dcd4c663dac39e6518b6bb7ac1631.tar.xz
kernel-qcow2-linux-9a8a02c9d46dcd4c663dac39e6518b6bb7ac1631.zip
net: stmmac: Add Flexible PPS support
This adds support for Flexible PPS output (which is equivalent to per_out output of PTP subsystem). Tested using an oscilloscope and the following commands: 1) Start PTP4L: # ptp4l -A -4 -H -m -i eth0 & 2) Set Flexible PPS frequency: # echo <idx> <ts> <tns> <ps> <pns> > /sys/class/ptp/ptpX/period Where, ts/tns is start time and ps/pns is period time, and ptpX is ptp of eth0. Signed-off-by: Jose Abreu <joabreu@synopsys.com> Cc: David S. Miller <davem@davemloft.net> Cc: Joao Pinto <jpinto@synopsys.com> Cc: Vitor Soares <soares@synopsys.com> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com> Cc: Alexandre Torgue <alexandre.torgue@st.com> Cc: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac/dwmac5.c')
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index b2becb80a697..3f4f3132e16b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -8,6 +8,7 @@
#include "dwmac4.h"
#include "dwmac5.h"
#include "stmmac.h"
+#include "stmmac_ptp.h"
struct dwmac5_error_desc {
bool valid;
@@ -494,3 +495,57 @@ re_enable:
writel(old_val, ioaddr + GMAC_CONFIG);
return ret;
}
+
+int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
+ struct stmmac_pps_cfg *cfg, bool enable,
+ u32 sub_second_inc, u32 systime_flags)
+{
+ u32 tnsec = readl(ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
+ u32 val = readl(ioaddr + MAC_PPS_CONTROL);
+ u64 period;
+
+ if (!cfg->available)
+ return -EINVAL;
+ if (tnsec & TRGTBUSY0)
+ return -EBUSY;
+ if (!sub_second_inc || !systime_flags)
+ return -EINVAL;
+
+ val &= ~PPSx_MASK(index);
+
+ if (!enable) {
+ val |= PPSCMDx(index, 0x5);
+ writel(val, ioaddr + MAC_PPS_CONTROL);
+ return 0;
+ }
+
+ val |= PPSCMDx(index, 0x2);
+ val |= TRGTMODSELx(index, 0x2);
+ val |= PPSEN0;
+
+ writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index));
+
+ if (!(systime_flags & PTP_TCR_TSCTRLSSR))
+ cfg->start.tv_nsec = (cfg->start.tv_nsec * 1000) / 465;
+ writel(cfg->start.tv_nsec, ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
+
+ period = cfg->period.tv_sec * 1000000000;
+ period += cfg->period.tv_nsec;
+
+ do_div(period, sub_second_inc);
+
+ if (period <= 1)
+ return -EINVAL;
+
+ writel(period - 1, ioaddr + MAC_PPSx_INTERVAL(index));
+
+ period >>= 1;
+ if (period <= 1)
+ return -EINVAL;
+
+ writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index));
+
+ /* Finally, activate it */
+ writel(val, ioaddr + MAC_PPS_CONTROL);
+ return 0;
+}