aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale/fec.c
diff options
context:
space:
mode:
authorFrank Li <Frank.Li@freescale.com>2012-10-30 14:25:31 -0400
committerDavid S. Miller <davem@davemloft.net>2012-11-01 12:28:44 -0400
commit6605b730c061f67c44113391e5af5125d0672e99 (patch)
treef590a2528231b7ca20a9ca32457eb0128e1e107c /drivers/net/ethernet/freescale/fec.c
parentd6e0d9fcbb01edc7a342b15f077a217d46f3b608 (diff)
FEC: Add time stamping code and a PTP hardware clock
This patch adds a driver for the FEC(MX6) that offers time stamping and a PTP haderware clock. Because FEC\ENET(MX6) hardware frequency adjustment is complex, we have implemented this in software by changing the multiplication factor of the timecounter. Signed-off-by: Frank Li <Frank.Li@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale/fec.c')
-rw-r--r--drivers/net/ethernet/freescale/fec.c88
1 files changed, 87 insertions, 1 deletions
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index d0e1b331e8e6..2665162ff4e5 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -280,6 +280,17 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
280 | BD_ENET_TX_LAST | BD_ENET_TX_TC); 280 | BD_ENET_TX_LAST | BD_ENET_TX_TC);
281 bdp->cbd_sc = status; 281 bdp->cbd_sc = status;
282 282
283#ifdef CONFIG_FEC_PTP
284 bdp->cbd_bdu = 0;
285 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
286 fep->hwts_tx_en)) {
287 bdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
288 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
289 } else {
290
291 bdp->cbd_esc = BD_ENET_TX_INT;
292 }
293#endif
283 /* Trigger transmission start */ 294 /* Trigger transmission start */
284 writel(0, fep->hwp + FEC_X_DES_ACTIVE); 295 writel(0, fep->hwp + FEC_X_DES_ACTIVE);
285 296
@@ -437,10 +448,17 @@ fec_restart(struct net_device *ndev, int duplex)
437 writel(1 << 8, fep->hwp + FEC_X_WMRK); 448 writel(1 << 8, fep->hwp + FEC_X_WMRK);
438 } 449 }
439 450
451#ifdef CONFIG_FEC_PTP
452 ecntl |= (1 << 4);
453#endif
454
440 /* And last, enable the transmit and receive processing */ 455 /* And last, enable the transmit and receive processing */
441 writel(ecntl, fep->hwp + FEC_ECNTRL); 456 writel(ecntl, fep->hwp + FEC_ECNTRL);
442 writel(0, fep->hwp + FEC_R_DES_ACTIVE); 457 writel(0, fep->hwp + FEC_R_DES_ACTIVE);
443 458
459#ifdef CONFIG_FEC_PTP
460 fec_ptp_start_cyclecounter(ndev);
461#endif
444 /* Enable interrupts we wish to service */ 462 /* Enable interrupts we wish to service */
445 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 463 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
446} 464}
@@ -526,6 +544,19 @@ fec_enet_tx(struct net_device *ndev)
526 ndev->stats.tx_packets++; 544 ndev->stats.tx_packets++;
527 } 545 }
528 546
547#ifdef CONFIG_FEC_PTP
548 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
549 struct skb_shared_hwtstamps shhwtstamps;
550 unsigned long flags;
551
552 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
553 spin_lock_irqsave(&fep->tmreg_lock, flags);
554 shhwtstamps.hwtstamp = ns_to_ktime(
555 timecounter_cyc2time(&fep->tc, bdp->ts));
556 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
557 skb_tstamp_tx(skb, &shhwtstamps);
558 }
559#endif
529 if (status & BD_ENET_TX_READY) 560 if (status & BD_ENET_TX_READY)
530 printk("HEY! Enet xmit interrupt and TX_READY.\n"); 561 printk("HEY! Enet xmit interrupt and TX_READY.\n");
531 562
@@ -652,6 +683,21 @@ fec_enet_rx(struct net_device *ndev)
652 skb_put(skb, pkt_len - 4); /* Make room */ 683 skb_put(skb, pkt_len - 4); /* Make room */
653 skb_copy_to_linear_data(skb, data, pkt_len - 4); 684 skb_copy_to_linear_data(skb, data, pkt_len - 4);
654 skb->protocol = eth_type_trans(skb, ndev); 685 skb->protocol = eth_type_trans(skb, ndev);
686#ifdef CONFIG_FEC_PTP
687 /* Get receive timestamp from the skb */
688 if (fep->hwts_rx_en) {
689 struct skb_shared_hwtstamps *shhwtstamps =
690 skb_hwtstamps(skb);
691 unsigned long flags;
692
693 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
694
695 spin_lock_irqsave(&fep->tmreg_lock, flags);
696 shhwtstamps->hwtstamp = ns_to_ktime(
697 timecounter_cyc2time(&fep->tc, bdp->ts));
698 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
699 }
700#endif
655 if (!skb_defer_rx_timestamp(skb)) 701 if (!skb_defer_rx_timestamp(skb))
656 netif_rx(skb); 702 netif_rx(skb);
657 } 703 }
@@ -666,6 +712,12 @@ rx_processing_done:
666 status |= BD_ENET_RX_EMPTY; 712 status |= BD_ENET_RX_EMPTY;
667 bdp->cbd_sc = status; 713 bdp->cbd_sc = status;
668 714
715#ifdef CONFIG_FEC_PTP
716 bdp->cbd_esc = BD_ENET_RX_INT;
717 bdp->cbd_prot = 0;
718 bdp->cbd_bdu = 0;
719#endif
720
669 /* Update BD pointer to next entry */ 721 /* Update BD pointer to next entry */
670 if (status & BD_ENET_RX_WRAP) 722 if (status & BD_ENET_RX_WRAP)
671 bdp = fep->rx_bd_base; 723 bdp = fep->rx_bd_base;
@@ -1105,6 +1157,10 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
1105 if (!phydev) 1157 if (!phydev)
1106 return -ENODEV; 1158 return -ENODEV;
1107 1159
1160#ifdef CONFIG_FEC_PTP
1161 if (cmd == SIOCSHWTSTAMP)
1162 return fec_ptp_ioctl(ndev, rq, cmd);
1163#endif
1108 return phy_mii_ioctl(phydev, rq, cmd); 1164 return phy_mii_ioctl(phydev, rq, cmd);
1109} 1165}
1110 1166
@@ -1151,6 +1207,9 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
1151 bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, 1207 bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
1152 FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); 1208 FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
1153 bdp->cbd_sc = BD_ENET_RX_EMPTY; 1209 bdp->cbd_sc = BD_ENET_RX_EMPTY;
1210#ifdef CONFIG_FEC_PTP
1211 bdp->cbd_esc = BD_ENET_RX_INT;
1212#endif
1154 bdp++; 1213 bdp++;
1155 } 1214 }
1156 1215
@@ -1164,6 +1223,10 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
1164 1223
1165 bdp->cbd_sc = 0; 1224 bdp->cbd_sc = 0;
1166 bdp->cbd_bufaddr = 0; 1225 bdp->cbd_bufaddr = 0;
1226
1227#ifdef CONFIG_FEC_PTP
1228 bdp->cbd_esc = BD_ENET_RX_INT;
1229#endif
1167 bdp++; 1230 bdp++;
1168 } 1231 }
1169 1232
@@ -1565,9 +1628,19 @@ fec_probe(struct platform_device *pdev)
1565 goto failed_clk; 1628 goto failed_clk;
1566 } 1629 }
1567 1630
1631#ifdef CONFIG_FEC_PTP
1632 fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
1633 if (IS_ERR(fep->clk_ptp)) {
1634 ret = PTR_ERR(fep->clk_ptp);
1635 goto failed_clk;
1636 }
1637#endif
1638
1568 clk_prepare_enable(fep->clk_ahb); 1639 clk_prepare_enable(fep->clk_ahb);
1569 clk_prepare_enable(fep->clk_ipg); 1640 clk_prepare_enable(fep->clk_ipg);
1570 1641#ifdef CONFIG_FEC_PTP
1642 clk_prepare_enable(fep->clk_ptp);
1643#endif
1571 reg_phy = devm_regulator_get(&pdev->dev, "phy"); 1644 reg_phy = devm_regulator_get(&pdev->dev, "phy");
1572 if (!IS_ERR(reg_phy)) { 1645 if (!IS_ERR(reg_phy)) {
1573 ret = regulator_enable(reg_phy); 1646 ret = regulator_enable(reg_phy);
@@ -1595,6 +1668,10 @@ fec_probe(struct platform_device *pdev)
1595 if (ret) 1668 if (ret)
1596 goto failed_register; 1669 goto failed_register;
1597 1670
1671#ifdef CONFIG_FEC_PTP
1672 fec_ptp_init(ndev, pdev);
1673#endif
1674
1598 return 0; 1675 return 0;
1599 1676
1600failed_register: 1677failed_register:
@@ -1604,6 +1681,9 @@ failed_init:
1604failed_regulator: 1681failed_regulator:
1605 clk_disable_unprepare(fep->clk_ahb); 1682 clk_disable_unprepare(fep->clk_ahb);
1606 clk_disable_unprepare(fep->clk_ipg); 1683 clk_disable_unprepare(fep->clk_ipg);
1684#ifdef CONFIG_FEC_PTP
1685 clk_disable_unprepare(fep->clk_ptp);
1686#endif
1607failed_pin: 1687failed_pin:
1608failed_clk: 1688failed_clk:
1609 for (i = 0; i < FEC_IRQ_NUM; i++) { 1689 for (i = 0; i < FEC_IRQ_NUM; i++) {
@@ -1636,6 +1716,12 @@ fec_drv_remove(struct platform_device *pdev)
1636 if (irq > 0) 1716 if (irq > 0)
1637 free_irq(irq, ndev); 1717 free_irq(irq, ndev);
1638 } 1718 }
1719#ifdef CONFIG_FEC_PTP
1720 del_timer_sync(&fep->time_keep);
1721 clk_disable_unprepare(fep->clk_ptp);
1722 if (fep->ptp_clock)
1723 ptp_clock_unregister(fep->ptp_clock);
1724#endif
1639 clk_disable_unprepare(fep->clk_ahb); 1725 clk_disable_unprepare(fep->clk_ahb);
1640 clk_disable_unprepare(fep->clk_ipg); 1726 clk_disable_unprepare(fep->clk_ipg);
1641 iounmap(fep->hwp); 1727 iounmap(fep->hwp);