diff options
author | Giuseppe CAVALLARO <peppe.cavallaro@st.com> | 2014-08-27 04:37:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-29 22:54:36 -0400 |
commit | 5566401f2f10556776fd199c11d6a02a5e0b7b95 (patch) | |
tree | b9127a13d0c5df4939c72be2fc618e38e9afaf5c /drivers/net/ethernet/stmicro | |
parent | 2b78d348f1bc3396ca1662c6a6177a7fb1ca62ff (diff) |
stmmac: ptp: fix the reference clock
The PTP reference clock, used for setting the addend in the Timestamp Addend
Register, was erroneously hard-coded (as reported in the databook just as
example).
The patch removes the macro named: STMMAC_SYSCLOCK and allows to use a
reference clock (clk_ptp_ref_i) that can be passed from the platform.
If not passed, the main driver clock will be used as default; note that
this can be fine on some platforms.
Note that, prior this patch, using the old STMMAC_SYSCLOCK on some platforms,
as side effect, the ptp clock can move faster/slower than the system clock.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/stmicro')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 2 |
3 files changed, 18 insertions, 6 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index ca01035634a7..128a0b723a00 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h | |||
@@ -105,6 +105,8 @@ struct stmmac_priv { | |||
105 | struct ptp_clock *ptp_clock; | 105 | struct ptp_clock *ptp_clock; |
106 | struct ptp_clock_info ptp_clock_ops; | 106 | struct ptp_clock_info ptp_clock_ops; |
107 | unsigned int default_addend; | 107 | unsigned int default_addend; |
108 | struct clk *clk_ptp_ref; | ||
109 | unsigned int clk_ptp_rate; | ||
108 | u32 adv_ts; | 110 | u32 adv_ts; |
109 | int use_riwt; | 111 | int use_riwt; |
110 | int irq_wake; | 112 | int irq_wake; |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 51a89d4bb125..03652891fcbf 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | |||
@@ -603,16 +603,16 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) | |||
603 | /* calculate default added value: | 603 | /* calculate default added value: |
604 | * formula is : | 604 | * formula is : |
605 | * addend = (2^32)/freq_div_ratio; | 605 | * addend = (2^32)/freq_div_ratio; |
606 | * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz | 606 | * where, freq_div_ratio = clk_ptp_ref_i/50MHz |
607 | * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK; | 607 | * hence, addend = ((2^32) * 50MHz)/clk_ptp_ref_i; |
608 | * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to | 608 | * NOTE: clk_ptp_ref_i should be >= 50MHz to |
609 | * achive 20ns accuracy. | 609 | * achive 20ns accuracy. |
610 | * | 610 | * |
611 | * 2^x * y == (y << x), hence | 611 | * 2^x * y == (y << x), hence |
612 | * 2^32 * 50000000 ==> (50000000 << 32) | 612 | * 2^32 * 50000000 ==> (50000000 << 32) |
613 | */ | 613 | */ |
614 | temp = (u64) (50000000ULL << 32); | 614 | temp = (u64) (50000000ULL << 32); |
615 | priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK); | 615 | priv->default_addend = div_u64(temp, priv->clk_ptp_rate); |
616 | priv->hw->ptp->config_addend(priv->ioaddr, | 616 | priv->hw->ptp->config_addend(priv->ioaddr, |
617 | priv->default_addend); | 617 | priv->default_addend); |
618 | 618 | ||
@@ -638,6 +638,16 @@ static int stmmac_init_ptp(struct stmmac_priv *priv) | |||
638 | if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) | 638 | if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) |
639 | return -EOPNOTSUPP; | 639 | return -EOPNOTSUPP; |
640 | 640 | ||
641 | /* Fall-back to main clock in case of no PTP ref is passed */ | ||
642 | priv->clk_ptp_ref = devm_clk_get(priv->device, "clk_ptp_ref"); | ||
643 | if (IS_ERR(priv->clk_ptp_ref)) { | ||
644 | priv->clk_ptp_rate = clk_get_rate(priv->stmmac_clk); | ||
645 | priv->clk_ptp_ref = NULL; | ||
646 | } else { | ||
647 | clk_prepare_enable(priv->clk_ptp_ref); | ||
648 | priv->clk_ptp_rate = clk_get_rate(priv->clk_ptp_ref); | ||
649 | } | ||
650 | |||
641 | priv->adv_ts = 0; | 651 | priv->adv_ts = 0; |
642 | if (priv->dma_cap.atime_stamp && priv->extend_desc) | 652 | if (priv->dma_cap.atime_stamp && priv->extend_desc) |
643 | priv->adv_ts = 1; | 653 | priv->adv_ts = 1; |
@@ -657,6 +667,8 @@ static int stmmac_init_ptp(struct stmmac_priv *priv) | |||
657 | 667 | ||
658 | static void stmmac_release_ptp(struct stmmac_priv *priv) | 668 | static void stmmac_release_ptp(struct stmmac_priv *priv) |
659 | { | 669 | { |
670 | if (priv->clk_ptp_ref) | ||
671 | clk_disable_unprepare(priv->clk_ptp_ref); | ||
660 | stmmac_ptp_unregister(priv); | 672 | stmmac_ptp_unregister(priv); |
661 | } | 673 | } |
662 | 674 | ||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h index 3dbc047622fa..4535df37c227 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | |||
@@ -25,8 +25,6 @@ | |||
25 | #ifndef __STMMAC_PTP_H__ | 25 | #ifndef __STMMAC_PTP_H__ |
26 | #define __STMMAC_PTP_H__ | 26 | #define __STMMAC_PTP_H__ |
27 | 27 | ||
28 | #define STMMAC_SYSCLOCK 62500000 | ||
29 | |||
30 | /* IEEE 1588 PTP register offsets */ | 28 | /* IEEE 1588 PTP register offsets */ |
31 | #define PTP_TCR 0x0700 /* Timestamp Control Reg */ | 29 | #define PTP_TCR 0x0700 /* Timestamp Control Reg */ |
32 | #define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */ | 30 | #define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */ |