aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/adi
diff options
context:
space:
mode:
authorRichard Cochran <richardcochran@gmail.com>2012-10-31 02:27:24 -0400
committerDavid S. Miller <davem@davemloft.net>2012-11-01 11:41:35 -0400
commitdd87b22f9096863adfd5daf281beb0a83379bd8f (patch)
tree6fe070016ab65b58245cb2910f2166f880dd8c12 /drivers/net/ethernet/adi
parentbc3c5f634de23ca767c2d04d356ddf5bbe2144e2 (diff)
bfin_mac: offer a PTP Hardware Clock.
The BF518 has a PTP time unit that works in a similar way to other MAC based clocks, like gianfar, ixp46x, and igb. This patch adds support for using the blackfin as a PHC. Although the blackfin hardware does offer a few ancillary features, this patch implements only the basic operations. Compile tested only. Signed-off-by: Richard Cochran <richardcochran@gmail.com> Tested-by: Bob Liu <lliubbo@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/adi')
-rw-r--r--drivers/net/ethernet/adi/Kconfig2
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.c170
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.h6
3 files changed, 175 insertions, 3 deletions
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
index 49a30d37ae4a..175c38c077b2 100644
--- a/drivers/net/ethernet/adi/Kconfig
+++ b/drivers/net/ethernet/adi/Kconfig
@@ -61,7 +61,7 @@ config BFIN_RX_DESC_NUM
61 61
62config BFIN_MAC_USE_HWSTAMP 62config BFIN_MAC_USE_HWSTAMP
63 bool "Use IEEE 1588 hwstamp" 63 bool "Use IEEE 1588 hwstamp"
64 depends on BFIN_MAC && BF518 64 depends on BFIN_MAC && BF518 && PTP_1588_CLOCK && !(BFIN_MAC=y && PTP_1588_CLOCK=m)
65 default y 65 default y
66 ---help--- 66 ---help---
67 To support the IEEE 1588 Precision Time Protocol (PTP), select y here 67 To support the IEEE 1588 Precision Time Protocol (PTP), select y here
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index 885fa80e9220..f1c458dc039a 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -552,11 +552,13 @@ static int bfin_mac_ethtool_setwol(struct net_device *dev,
552static int bfin_mac_ethtool_get_ts_info(struct net_device *dev, 552static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
553 struct ethtool_ts_info *info) 553 struct ethtool_ts_info *info)
554{ 554{
555 struct bfin_mac_local *lp = netdev_priv(dev);
556
555 info->so_timestamping = 557 info->so_timestamping =
556 SOF_TIMESTAMPING_TX_HARDWARE | 558 SOF_TIMESTAMPING_TX_HARDWARE |
557 SOF_TIMESTAMPING_RX_HARDWARE | 559 SOF_TIMESTAMPING_RX_HARDWARE |
558 SOF_TIMESTAMPING_RAW_HARDWARE; 560 SOF_TIMESTAMPING_RAW_HARDWARE;
559 info->phc_index = -1; 561 info->phc_index = lp->phc_index;
560 info->tx_types = 562 info->tx_types =
561 (1 << HWTSTAMP_TX_OFF) | 563 (1 << HWTSTAMP_TX_OFF) |
562 (1 << HWTSTAMP_TX_ON); 564 (1 << HWTSTAMP_TX_ON);
@@ -887,7 +889,7 @@ static void bfin_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
887static void bfin_mac_hwtstamp_init(struct net_device *netdev) 889static void bfin_mac_hwtstamp_init(struct net_device *netdev)
888{ 890{
889 struct bfin_mac_local *lp = netdev_priv(netdev); 891 struct bfin_mac_local *lp = netdev_priv(netdev);
890 u64 addend; 892 u64 addend, ppb;
891 u32 input_clk, phc_clk; 893 u32 input_clk, phc_clk;
892 894
893 /* Initialize hardware timer */ 895 /* Initialize hardware timer */
@@ -898,18 +900,175 @@ static void bfin_mac_hwtstamp_init(struct net_device *netdev)
898 bfin_write_EMAC_PTP_ADDEND((u32)addend); 900 bfin_write_EMAC_PTP_ADDEND((u32)addend);
899 901
900 lp->addend = addend; 902 lp->addend = addend;
903 ppb = 1000000000ULL * input_clk;
904 do_div(ppb, phc_clk);
905 lp->max_ppb = ppb - 1000000000ULL - 1ULL;
901 906
902 /* Initialize hwstamp config */ 907 /* Initialize hwstamp config */
903 lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE; 908 lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
904 lp->stamp_cfg.tx_type = HWTSTAMP_TX_OFF; 909 lp->stamp_cfg.tx_type = HWTSTAMP_TX_OFF;
905} 910}
906 911
912static u64 bfin_ptp_time_read(struct bfin_mac_local *lp)
913{
914 u64 ns;
915 u32 lo, hi;
916
917 lo = bfin_read_EMAC_PTP_TIMELO();
918 hi = bfin_read_EMAC_PTP_TIMEHI();
919
920 ns = ((u64) hi) << 32;
921 ns |= lo;
922 ns <<= lp->shift;
923
924 return ns;
925}
926
927static void bfin_ptp_time_write(struct bfin_mac_local *lp, u64 ns)
928{
929 u32 hi, lo;
930
931 ns >>= lp->shift;
932 hi = ns >> 32;
933 lo = ns & 0xffffffff;
934
935 bfin_write_EMAC_PTP_TIMELO(lo);
936 bfin_write_EMAC_PTP_TIMEHI(hi);
937}
938
939/* PTP Hardware Clock operations */
940
941static int bfin_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
942{
943 u64 adj;
944 u32 diff, addend;
945 int neg_adj = 0;
946 struct bfin_mac_local *lp =
947 container_of(ptp, struct bfin_mac_local, caps);
948
949 if (ppb < 0) {
950 neg_adj = 1;
951 ppb = -ppb;
952 }
953 addend = lp->addend;
954 adj = addend;
955 adj *= ppb;
956 diff = div_u64(adj, 1000000000ULL);
957
958 addend = neg_adj ? addend - diff : addend + diff;
959
960 bfin_write_EMAC_PTP_ADDEND(addend);
961
962 return 0;
963}
964
965static int bfin_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
966{
967 s64 now;
968 unsigned long flags;
969 struct bfin_mac_local *lp =
970 container_of(ptp, struct bfin_mac_local, caps);
971
972 spin_lock_irqsave(&lp->phc_lock, flags);
973
974 now = bfin_ptp_time_read(lp);
975 now += delta;
976 bfin_ptp_time_write(lp, now);
977
978 spin_unlock_irqrestore(&lp->phc_lock, flags);
979
980 return 0;
981}
982
983static int bfin_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
984{
985 u64 ns;
986 u32 remainder;
987 unsigned long flags;
988 struct bfin_mac_local *lp =
989 container_of(ptp, struct bfin_mac_local, caps);
990
991 spin_lock_irqsave(&lp->phc_lock, flags);
992
993 ns = bfin_ptp_time_read(lp);
994
995 spin_unlock_irqrestore(&lp->phc_lock, flags);
996
997 ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
998 ts->tv_nsec = remainder;
999 return 0;
1000}
1001
1002static int bfin_ptp_settime(struct ptp_clock_info *ptp,
1003 const struct timespec *ts)
1004{
1005 u64 ns;
1006 unsigned long flags;
1007 struct bfin_mac_local *lp =
1008 container_of(ptp, struct bfin_mac_local, caps);
1009
1010 ns = ts->tv_sec * 1000000000ULL;
1011 ns += ts->tv_nsec;
1012
1013 spin_lock_irqsave(&lp->phc_lock, flags);
1014
1015 bfin_ptp_time_write(lp, ns);
1016
1017 spin_unlock_irqrestore(&lp->phc_lock, flags);
1018
1019 return 0;
1020}
1021
1022static int bfin_ptp_enable(struct ptp_clock_info *ptp,
1023 struct ptp_clock_request *rq, int on)
1024{
1025 return -EOPNOTSUPP;
1026}
1027
1028static struct ptp_clock_info bfin_ptp_caps = {
1029 .owner = THIS_MODULE,
1030 .name = "BF518 clock",
1031 .max_adj = 0,
1032 .n_alarm = 0,
1033 .n_ext_ts = 0,
1034 .n_per_out = 0,
1035 .pps = 0,
1036 .adjfreq = bfin_ptp_adjfreq,
1037 .adjtime = bfin_ptp_adjtime,
1038 .gettime = bfin_ptp_gettime,
1039 .settime = bfin_ptp_settime,
1040 .enable = bfin_ptp_enable,
1041};
1042
1043static int bfin_phc_init(struct net_device *netdev, struct device *dev)
1044{
1045 struct bfin_mac_local *lp = netdev_priv(netdev);
1046
1047 lp->caps = bfin_ptp_caps;
1048 lp->caps.max_adj = lp->max_ppb;
1049 lp->clock = ptp_clock_register(&lp->caps, dev);
1050 if (IS_ERR(lp->clock))
1051 return PTR_ERR(lp->clock);
1052
1053 lp->phc_index = ptp_clock_index(lp->clock);
1054 spin_lock_init(&lp->phc_lock);
1055
1056 return 0;
1057}
1058
1059static void bfin_phc_release(struct bfin_mac_local *lp)
1060{
1061 ptp_clock_unregister(lp->clock);
1062}
1063
907#else 1064#else
908# define bfin_mac_hwtstamp_is_none(cfg) 0 1065# define bfin_mac_hwtstamp_is_none(cfg) 0
909# define bfin_mac_hwtstamp_init(dev) 1066# define bfin_mac_hwtstamp_init(dev)
910# define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP) 1067# define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP)
911# define bfin_rx_hwtstamp(dev, skb) 1068# define bfin_rx_hwtstamp(dev, skb)
912# define bfin_tx_hwtstamp(dev, skb) 1069# define bfin_tx_hwtstamp(dev, skb)
1070# define bfin_phc_init(netdev, dev) 0
1071# define bfin_phc_release(lp)
913#endif 1072#endif
914 1073
915static inline void _tx_reclaim_skb(void) 1074static inline void _tx_reclaim_skb(void)
@@ -1544,12 +1703,17 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
1544 } 1703 }
1545 1704
1546 bfin_mac_hwtstamp_init(ndev); 1705 bfin_mac_hwtstamp_init(ndev);
1706 if (bfin_phc_init(ndev, &pdev->dev)) {
1707 dev_err(&pdev->dev, "Cannot register PHC device!\n");
1708 goto out_err_phc;
1709 }
1547 1710
1548 /* now, print out the card info, in a short format.. */ 1711 /* now, print out the card info, in a short format.. */
1549 netdev_info(ndev, "%s, Version %s\n", DRV_DESC, DRV_VERSION); 1712 netdev_info(ndev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
1550 1713
1551 return 0; 1714 return 0;
1552 1715
1716out_err_phc:
1553out_err_reg_ndev: 1717out_err_reg_ndev:
1554 free_irq(IRQ_MAC_RX, ndev); 1718 free_irq(IRQ_MAC_RX, ndev);
1555out_err_request_irq: 1719out_err_request_irq:
@@ -1568,6 +1732,8 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
1568 struct net_device *ndev = platform_get_drvdata(pdev); 1732 struct net_device *ndev = platform_get_drvdata(pdev);
1569 struct bfin_mac_local *lp = netdev_priv(ndev); 1733 struct bfin_mac_local *lp = netdev_priv(ndev);
1570 1734
1735 bfin_phc_release(lp);
1736
1571 platform_set_drvdata(pdev, NULL); 1737 platform_set_drvdata(pdev, NULL);
1572 1738
1573 lp->mii_bus->priv = NULL; 1739 lp->mii_bus->priv = NULL;
diff --git a/drivers/net/ethernet/adi/bfin_mac.h b/drivers/net/ethernet/adi/bfin_mac.h
index 57f042c3111c..7a07ee07906b 100644
--- a/drivers/net/ethernet/adi/bfin_mac.h
+++ b/drivers/net/ethernet/adi/bfin_mac.h
@@ -11,6 +11,7 @@
11#define _BFIN_MAC_H_ 11#define _BFIN_MAC_H_
12 12
13#include <linux/net_tstamp.h> 13#include <linux/net_tstamp.h>
14#include <linux/ptp_clock_kernel.h>
14#include <linux/timer.h> 15#include <linux/timer.h>
15#include <linux/etherdevice.h> 16#include <linux/etherdevice.h>
16#include <linux/bfin_mac.h> 17#include <linux/bfin_mac.h>
@@ -94,7 +95,12 @@ struct bfin_mac_local {
94#if defined(CONFIG_BFIN_MAC_USE_HWSTAMP) 95#if defined(CONFIG_BFIN_MAC_USE_HWSTAMP)
95 u32 addend; 96 u32 addend;
96 unsigned int shift; 97 unsigned int shift;
98 s32 max_ppb;
97 struct hwtstamp_config stamp_cfg; 99 struct hwtstamp_config stamp_cfg;
100 struct ptp_clock_info caps;
101 struct ptp_clock *clock;
102 int phc_index;
103 spinlock_t phc_lock; /* protects time lo/hi registers */
98#endif 104#endif
99}; 105};
100 106