Commit 19d857c9 authored by Phil Reid's avatar Phil Reid Committed by David S. Miller

stmmac: Fix calculations for ptp counters when clock input = 50Mhz.

stmmac_config_sub_second_increment set the sub second increment to 20ns.
Driver is configured to use the fine adjustment method where the sub second
register is incremented when the acculumator incremented by the addend
register wraps overflows. This accumulator is update on every ptp clk
cycle. If a ptp clk with a period of greater than 20ns was used the
sub second register would not get updated correctly.

Instead set the sub sec increment to twice the period of the ptp clk.
This result in the addend register being set mid range and overflow
the accumlator every 2 clock cycles.
Signed-off-by: default avatarPhil Reid <preid@electromag.com.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bf171f01
...@@ -439,7 +439,7 @@ struct stmmac_ops { ...@@ -439,7 +439,7 @@ struct stmmac_ops {
/* PTP and HW Timer helpers */ /* PTP and HW Timer helpers */
struct stmmac_hwtimestamp { struct stmmac_hwtimestamp {
void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data); void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
void (*config_sub_second_increment) (void __iomem *ioaddr); u32 (*config_sub_second_increment) (void __iomem *ioaddr, u32 clk_rate);
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec); int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
int (*config_addend) (void __iomem *ioaddr, u32 addend); int (*config_addend) (void __iomem *ioaddr, u32 addend);
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec, int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
......
...@@ -33,22 +33,25 @@ static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data) ...@@ -33,22 +33,25 @@ static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
writel(data, ioaddr + PTP_TCR); writel(data, ioaddr + PTP_TCR);
} }
static void stmmac_config_sub_second_increment(void __iomem *ioaddr) static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr,
u32 ptp_clock)
{ {
u32 value = readl(ioaddr + PTP_TCR); u32 value = readl(ioaddr + PTP_TCR);
unsigned long data; unsigned long data;
/* Convert the ptp_clock to nano second /* Convert the ptp_clock to nano second
* formula = (1/ptp_clock) * 1000000000 * formula = (2/ptp_clock) * 1000000000
* where, ptp_clock = 50MHz. * where, ptp_clock = 50MHz.
*/ */
data = (1000000000ULL / 50000000); data = (2000000000ULL / ptp_clock);
/* 0.465ns accuracy */ /* 0.465ns accuracy */
if (!(value & PTP_TCR_TSCTRLSSR)) if (!(value & PTP_TCR_TSCTRLSSR))
data = (data * 1000) / 465; data = (data * 1000) / 465;
writel(data, ioaddr + PTP_SSIR); writel(data, ioaddr + PTP_SSIR);
return data;
} }
static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include "stmmac.h" #include "stmmac.h"
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include "dwmac1000.h"
#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
...@@ -185,7 +186,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv) ...@@ -185,7 +186,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
priv->clk_csr = STMMAC_CSR_100_150M; priv->clk_csr = STMMAC_CSR_100_150M;
else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M)) else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
priv->clk_csr = STMMAC_CSR_150_250M; priv->clk_csr = STMMAC_CSR_150_250M;
else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M)) else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
priv->clk_csr = STMMAC_CSR_250_300M; priv->clk_csr = STMMAC_CSR_250_300M;
} }
} }
...@@ -435,6 +436,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -435,6 +436,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
u32 ts_master_en = 0; u32 ts_master_en = 0;
u32 ts_event_en = 0; u32 ts_event_en = 0;
u32 value = 0; u32 value = 0;
u32 sec_inc;
if (!(priv->dma_cap.time_stamp || priv->adv_ts)) { if (!(priv->dma_cap.time_stamp || priv->adv_ts)) {
netdev_alert(priv->dev, "No support for HW time stamping\n"); netdev_alert(priv->dev, "No support for HW time stamping\n");
...@@ -598,24 +600,19 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -598,24 +600,19 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
tstamp_all | ptp_v2 | ptp_over_ethernet | tstamp_all | ptp_v2 | ptp_over_ethernet |
ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en | ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
ts_master_en | snap_type_sel); ts_master_en | snap_type_sel);
priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value); priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value);
/* program Sub Second Increment reg */ /* program Sub Second Increment reg */
priv->hw->ptp->config_sub_second_increment(priv->ioaddr); sec_inc = priv->hw->ptp->config_sub_second_increment(
priv->ioaddr, priv->clk_ptp_rate);
temp = div_u64(1000000000ULL, sec_inc);
/* calculate default added value: /* calculate default added value:
* formula is : * formula is :
* addend = (2^32)/freq_div_ratio; * addend = (2^32)/freq_div_ratio;
* where, freq_div_ratio = clk_ptp_ref_i/50MHz * where, freq_div_ratio = 1e9ns/sec_inc
* hence, addend = ((2^32) * 50MHz)/clk_ptp_ref_i; */
* NOTE: clk_ptp_ref_i should be >= 50MHz to temp = (u64)(temp << 32);
* achieve 20ns accuracy.
*
* 2^x * y == (y << x), hence
* 2^32 * 50000000 ==> (50000000 << 32)
*/
temp = (u64) (50000000ULL << 32);
priv->default_addend = div_u64(temp, priv->clk_ptp_rate); priv->default_addend = div_u64(temp, priv->clk_ptp_rate);
priv->hw->ptp->config_addend(priv->ioaddr, priv->hw->ptp->config_addend(priv->ioaddr,
priv->default_addend); priv->default_addend);
......
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