1 From 67d56859d24864af530506c76523f0fc3c5cb502 Mon Sep 17 00:00:00 2001
2 From: Alison Wang <b18965@freescale.com>
3 Date: Thu, 4 Aug 2011 09:59:44 +0800
4 Subject: [PATCH 20/52] Add dual FEC 1588 timer support
6 Add Modelo dual FEC 1588 function with IXXXAT statck.
8 Signed-off-by: Alison Wang <b18965@freescale.com>
10 drivers/net/Kconfig | 6 +
11 drivers/net/Makefile | 3 +
12 drivers/net/fec.c | 153 ++++++++++++-
13 drivers/net/fec.h | 25 ++
14 drivers/net/fec_1588.c | 626 ++++++++++++++++++++++++++++++++++++++++++++++++
15 drivers/net/fec_1588.h | 195 +++++++++++++++
16 6 files changed, 1006 insertions(+), 2 deletions(-)
17 create mode 100644 drivers/net/fec_1588.c
18 create mode 100644 drivers/net/fec_1588.h
20 --- a/drivers/net/Kconfig
21 +++ b/drivers/net/Kconfig
22 @@ -1958,6 +1958,12 @@ config FEC2
23 Say Y here if you want to use the second built-in 10/100 Fast
24 ethernet controller on some Motorola ColdFire processors.
27 + bool "Enable 1588 interface(on some ColdFire designs)"
28 + depends on M5441X && FEC
30 + Say Y here if 1588 function is enabled.
33 tristate "MCF547x/MCF548x Fast Ethernet Controller support"
35 --- a/drivers/net/Makefile
36 +++ b/drivers/net/Makefile
37 @@ -123,6 +123,9 @@ obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
38 obj-$(CONFIG_HP100) += hp100.o
39 obj-$(CONFIG_SMC9194) += smc9194.o
40 obj-$(CONFIG_FEC) += fec.o
41 +ifeq ($(CONFIG_FEC_1588), y)
42 +obj-$(CONFIG_FEC) += fec_1588.o
44 obj-$(CONFIG_FEC_548x) += fec_m547x.o
45 obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
46 ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
47 --- a/drivers/net/fec.c
48 +++ b/drivers/net/fec.c
53 +#include "fec_1588.h"
55 #if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
56 #define FEC_ALIGNMENT 0xf
57 @@ -135,8 +136,15 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet
58 #define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
59 #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
60 #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
61 +#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
62 +#define FEC_ENET_TS_TIMER ((uint)0x00008000)
64 +#if defined(CONFIG_FEC_1588)
65 +#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | \
66 + FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER)
68 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
71 /* The FEC stores dest/src/type, data, and checksum for receive packets.
73 @@ -209,6 +217,10 @@ struct fec_enet_private {
76 struct completion mdio_done;
77 +#ifdef CONFIG_FEC_1588
78 + struct fec_ptp_private *ptp_priv;
79 + uint ptimer_present;
83 static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
84 @@ -252,6 +264,9 @@ fec_enet_start_xmit(struct sk_buff *skb,
87 unsigned short status;
88 +#ifdef CONFIG_FEC_1588
89 + unsigned long estatus;
94 @@ -293,6 +308,17 @@ fec_enet_start_xmit(struct sk_buff *skb,
95 bufaddr = fep->tx_bounce[index];
98 +#ifdef CONFIG_FEC_1588
99 + if (fep->ptimer_present) {
100 + if (fec_ptp_do_txstamp(skb))
101 + estatus = BD_ENET_TX_TS;
105 + bdp->cbd_esc = (estatus | BD_ENET_TX_INT);
110 * Some design made an incorrect assumption on endian mode of
111 * the system that it's running on. As the result, driver has to
112 @@ -357,6 +383,9 @@ fec_enet_interrupt(int irq, void * dev_i
114 struct net_device *dev = dev_id;
115 struct fec_enet_private *fep = netdev_priv(dev);
116 +#ifdef CONFIG_FEC_1588
117 + struct fec_ptp_private *fpp = fep->ptp_priv;
120 irqreturn_t ret = IRQ_NONE;
122 @@ -364,6 +393,10 @@ fec_enet_interrupt(int irq, void * dev_i
123 int_events = readl(fep->hwp + FEC_IEVENT);
124 writel(int_events, fep->hwp + FEC_IEVENT);
126 +#ifdef CONFIG_FEC_1588
127 + if (__raw_readb(MCF_DTIM1_DTER) & MCF_DTIM_DTER_REF)
128 + __raw_writeb(MCF_DTIM_DTER_REF, MCF_DTIM1_DTER);
130 if (int_events & FEC_ENET_RXF) {
133 @@ -378,6 +411,19 @@ fec_enet_interrupt(int irq, void * dev_i
137 +#ifdef CONFIG_FEC_1588
138 + if (int_events & FEC_ENET_TS_AVAIL) {
140 + fec_ptp_store_txstamp(fep->ptp_priv);
143 + if (int_events & FEC_ENET_TS_TIMER) {
145 + if (fep->ptimer_present)
150 if (int_events & FEC_ENET_MII) {
152 complete(&fep->mdio_done);
153 @@ -394,6 +440,9 @@ fec_enet_tx(struct net_device *dev)
154 struct fec_enet_private *fep;
156 unsigned short status;
157 +#ifdef CONFIG_FEC_1588
158 + unsigned long estatus;
162 fep = netdev_priv(dev);
163 @@ -437,6 +486,13 @@ fec_enet_tx(struct net_device *dev)
164 if (status & BD_ENET_TX_DEF)
165 dev->stats.collisions++;
167 +#if defined(CONFIG_FEC_1588)
168 + if (fep->ptimer_present) {
169 + estatus = bdp->cbd_esc;
170 + if (estatus & BD_ENET_TX_TS)
171 + fec_ptp_store_txstamp(fep->ptp_priv);
174 /* Free the sk buffer associated with this last transmit */
175 dev_kfree_skb_any(skb);
176 fep->tx_skbuff[fep->skb_dirty] = NULL;
177 @@ -470,6 +526,9 @@ static void
178 fec_enet_rx(struct net_device *dev)
180 struct fec_enet_private *fep = netdev_priv(dev);
181 +#ifdef CONFIG_FEC_1588
182 + struct fec_ptp_private *fpp = fep->ptp_priv;
184 const struct platform_device_id *id_entry =
185 platform_get_device_id(fep->pdev);
187 @@ -554,6 +613,12 @@ fec_enet_rx(struct net_device *dev)
188 skb_put(skb, pkt_len - 4); /* Make room */
189 skb_copy_to_linear_data(skb, data, pkt_len - 4);
190 skb->protocol = eth_type_trans(skb, dev);
192 +#ifdef CONFIG_FEC_1588
193 + /* 1588 messeage TS handle */
194 + if (fep->ptimer_present)
195 + fec_ptp_store_rxstamp(fpp, skb, bdp);
200 @@ -567,6 +632,11 @@ rx_processing_done:
201 status |= BD_ENET_RX_EMPTY;
202 bdp->cbd_sc = status;
204 +#ifdef CONFIG_FEC_1588
205 + bdp->cbd_esc = BD_ENET_RX_INT;
209 /* Update BD pointer to next entry */
210 if (status & BD_ENET_RX_WRAP)
211 bdp = fep->rx_bd_base;
212 @@ -669,8 +739,11 @@ static void fec_enet_adjust_link(struct
215 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
216 - writel(2, fep->hwp + FEC_ECNTRL);
218 +#ifdef CONFIG_FEC_1588
219 + writel(0x00000012, fep->hwp + FEC_ECNTRL);
221 + writel(0x00000002, fep->hwp + FEC_ECNTRL);
226 @@ -983,6 +1056,10 @@ static int fec_enet_alloc_buffers(struct
227 bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data,
228 FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
229 bdp->cbd_sc = BD_ENET_RX_EMPTY;
231 +#ifdef CONFIG_FEC_1588
232 + bdp->cbd_esc = BD_ENET_RX_INT;
237 @@ -996,6 +1073,9 @@ static int fec_enet_alloc_buffers(struct
240 bdp->cbd_bufaddr = 0;
241 +#ifdef CONFIG_FEC_1588
242 + bdp->cbd_esc = BD_ENET_TX_INT;
247 @@ -1256,8 +1336,12 @@ fec_restart(struct net_device *dev, int
248 writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
251 +#ifdef CONFIG_FEC_1588
252 + writel(0x7fff8000, fep->hwp + FEC_IEVENT);
254 /* Clear any outstanding interrupt. */
255 writel(0xffc00000, fep->hwp + FEC_IEVENT);
258 /* Reset all multicast. */
259 writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
260 @@ -1342,8 +1426,25 @@ fec_restart(struct net_device *dev, int
264 +#ifdef CONFIG_FEC_1588
265 + if (fep->ptimer_present) {
267 + /* Set Timer count */
268 + ret = fec_ptp_start(fep->ptp_priv);
270 + fep->ptimer_present = 0;
271 + writel(2, fep->hwp + FEC_ECNTRL);
273 + val = readl(fep->hwp + FEC_ECNTRL);
275 + writel(val, fep->hwp + FEC_ECNTRL);
278 + writel(2, fep->hwp + FEC_ECNTRL);
280 /* And last, enable the transmit and receive processing */
281 writel(2, fep->hwp + FEC_ECNTRL);
283 writel(0, fep->hwp + FEC_R_DES_ACTIVE);
285 /* Enable interrupts we wish to service */
286 @@ -1367,6 +1468,10 @@ fec_stop(struct net_device *dev)
287 writel(1, fep->hwp + FEC_ECNTRL);
289 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
290 +#ifdef CONFIG_FEC_1588
291 + if (fep->ptimer_present)
292 + fec_ptp_stop(fep->ptp_priv);
294 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
297 @@ -1428,6 +1533,24 @@ fec_probe(struct platform_device *pdev)
301 +#ifdef CONFIG_FEC_1588
302 + i = (pdev->id) ? (64 + 64 + 64 + 7) : (64 + 64 + 64);
303 + if (request_irq(i + 48, fec_enet_interrupt, IRQF_DISABLED,
304 + "1588 TS AVAIL", ndev) != 0)
305 + printk(KERN_ERR "FEC: Could not alloc FEC %x 1588 TS AVAIL "
306 + "IRQ(%d)!\n", pdev->id, i + 48);
308 + if (pdev->id == 0) {
309 + printk("setup TS timer interrupt through DMA timer1\n");
310 + __raw_writew(MCF_DTIM_DTMR_RST_RST, MCF_DTIM1_DTMR);
312 + if (request_irq(64 + 33, fec_enet_interrupt, IRQF_DISABLED,
313 + "1588 TS TIMER", ndev) != 0)
314 + printk(KERN_ERR "FEC: Could not alloc FEC %x 1588 TS"
315 + " TIMER IRQ(%d)!\n", pdev->id, 64 + 33);
319 fep->clk = clk_get(&pdev->dev, "fec_clk");
320 if (IS_ERR(fep->clk)) {
321 ret = PTR_ERR(fep->clk);
322 @@ -1443,6 +1566,20 @@ fec_probe(struct platform_device *pdev)
324 goto failed_mii_init;
326 +#ifdef CONFIG_FEC_1588
327 + fep->ptp_priv = kzalloc(sizeof(struct fec_ptp_private),
329 + if (fep->ptp_priv) {
330 + fep->ptp_priv->hwp = fep->hwp;
331 + ret = fec_ptp_init(fep->ptp_priv, pdev->id);
333 + printk(KERN_ERR "IEEE1588: ptp-timer init failed\n");
335 + fep->ptimer_present = 1;
337 + printk(KERN_ERR "IEEE1588: failed to malloc memory\n");
340 /* Carrier starts down, phylib will bring it up */
341 netif_carrier_off(ndev);
343 @@ -1454,6 +1591,12 @@ fec_probe(struct platform_device *pdev)
346 fec_enet_mii_remove(fep);
347 +#ifdef CONFIG_FEC_1588
348 + if (fep->ptimer_present)
349 + fec_ptp_cleanup(fep->ptp_priv);
351 + kfree(fep->ptp_priv);
355 clk_disable(fep->clk);
356 @@ -1485,6 +1628,12 @@ fec_drv_remove(struct platform_device *p
357 clk_disable(fep->clk);
359 iounmap((void __iomem *)ndev->base_addr);
360 +#ifdef CONFIG_FEC_1588
361 + if (fep->ptimer_present)
362 + fec_ptp_cleanup(fep->ptp_priv);
364 + kfree(fep->ptp_priv);
366 unregister_netdev(ndev);
369 --- a/drivers/net/fec.h
370 +++ b/drivers/net/fec.h
372 #define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
373 #define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
375 +#if defined(CONFIG_FEC_1588)
376 +#define FEC_ATIME_CTRL 0x400
377 +#define FEC_ATIME 0x404
378 +#define FEC_ATIME_EVT_OFFSET 0x408
379 +#define FEC_ATIME_EVT_PERIOD 0x40c
380 +#define FEC_ATIME_CORR 0x410
381 +#define FEC_ATIME_INC 0x414
382 +#define FEC_TS_TIMESTAMP 0x418
387 #define FEC_ECNTRL 0x000 /* Ethernet control reg */
390 #endif /* CONFIG_M5272 */
392 +#if defined(CONFIG_FEC_1588)
393 +#define FEC_ENHANCED_MODE 1
397 * Define the buffer descriptor structure.
398 @@ -93,6 +106,14 @@ struct bufdesc {
399 unsigned short cbd_sc; /* Control and status info */
400 unsigned short cbd_datlen; /* Data length */
401 unsigned long cbd_bufaddr; /* Buffer address */
403 +#ifdef FEC_ENHANCED_MODE
404 + unsigned long cbd_esc;
405 + unsigned long cbd_prot;
406 + unsigned long cbd_bdu;
408 + unsigned short res0[4];
413 @@ -128,6 +149,7 @@ struct bufdesc {
414 #define BD_ENET_RX_OV ((ushort)0x0002)
415 #define BD_ENET_RX_CL ((ushort)0x0001)
416 #define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
417 +#define BD_ENET_RX_INT 0x00800000
419 /* Buffer descriptor control/status used by Ethernet transmit.
421 @@ -146,6 +168,9 @@ struct bufdesc {
422 #define BD_ENET_TX_CSL ((ushort)0x0001)
423 #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */
425 +#define BD_ENET_TX_TS 0x20000000
426 +#define BD_ENET_TX_INT 0x40000000
427 +#define BD_ENET_TX_BDU 0x80000000
429 /****************************************************************************/
432 +++ b/drivers/net/fec_1588.c
435 + * drivers/net/fec_1588.c
437 + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
438 + * Copyright (C) 2009 IXXAT Automation, GmbH
440 + * FEC Ethernet Driver -- IEEE 1588 interface functionality
442 + * This program is free software; you can redistribute it and/or modify
443 + * it under the terms of the GNU General Public License as published by
444 + * the Free Software Foundation; either version 2 of the License, or
445 + * (at your option) any later version.
447 + * This program is distributed in the hope that it will be useful,
448 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
449 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
450 + * GNU General Public License for more details.
452 + * You should have received a copy of the GNU General Public License along
453 + * with this program; if not, write to the Free Software Foundation, Inc.,
454 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
458 +#include <linux/io.h>
459 +#include <linux/device.h>
460 +#include <linux/fs.h>
461 +#include <linux/vmalloc.h>
462 +#include <linux/spinlock.h>
463 +#include <linux/ip.h>
464 +#include <linux/udp.h>
465 +#include <asm/mcf5441x_ccm.h>
466 +#include <asm/mcf5441x_dtim.h>
467 +#include <asm/mcfsim.h>
468 +#include "fec_1588.h"
470 +static DECLARE_WAIT_QUEUE_HEAD(ptp_rx_ts_wait);
471 +#define PTP_GET_RX_TIMEOUT (HZ/10)
472 +#define COLDFIRE_DTIM1_INT (64+32+1)
474 +static struct fec_ptp_private *ptp_private[2];
476 +static void init_DTIM1_for_1588(struct fec_ptp_private *priv)
478 + printk(KERN_INFO "Initializing DTIM1 for 1588 TS timer\n");
480 + __raw_writew(MCF_DTIM_DTMR_RST_RST, MCF_DTIM1_DTMR);
484 + __raw_writeb(MCF_DTIM_DTXMR_1588EN, MCF_DTIM1_DTXMR);
486 + /*Compare to the 1588 timerbase*/
487 + __raw_writel(FEC_T_PERIOD_ONE_SEC - FEC_T_INC_40MHZ, MCF_DTIM1_DTRR);
489 + __raw_writeb(MCF_DTIM_DTER_REF, MCF_DTIM1_DTER);
491 + MCF_GPIO_PAR_TIMER = (MCF_GPIO_PAR_TIMER & MCF_GPIO_PAR_TIMER_T1IN_MASK)
492 + | MCF_GPIO_PAR_TIMER_T1IN_T1OUT;
495 +static void start_DTIM1(void)
497 + __raw_writew(MCF_DTIM_DTMR_RST_EN | MCF_DTIM_DTMR_ORRI |
498 + MCF_DTIM_DTMR_OM, MCF_DTIM1_DTMR);
501 +static void stop_DTIM1(void)
503 + __raw_writew(MCF_DTIM_DTMR_RST_RST, MCF_DTIM1_DTMR);
506 +/* Alloc the ring resource */
507 +static int fec_ptp_init_circ(struct circ_buf *ptp_buf)
509 + ptp_buf->buf = vmalloc(DEFAULT_PTP_RX_BUF_SZ *
510 + sizeof(struct fec_ptp_data_t));
520 +static inline int fec_ptp_calc_index(int size, int curr_index, int offset)
522 + return (curr_index + offset) % size;
525 +static int fec_ptp_is_empty(struct circ_buf *buf)
527 + return (buf->head == buf->tail);
530 +static int fec_ptp_nelems(struct circ_buf *buf)
532 + const int front = buf->head;
533 + const int end = buf->tail;
534 + const int size = DEFAULT_PTP_RX_BUF_SZ;
538 + n_items = end - front;
539 + else if (end < front)
540 + n_items = size - (front - end);
547 +static int fec_ptp_is_full(struct circ_buf *buf)
549 + if (fec_ptp_nelems(buf) ==
550 + (DEFAULT_PTP_RX_BUF_SZ - 1))
556 +static int fec_ptp_insert(struct circ_buf *ptp_buf,
557 + struct fec_ptp_data_t *data,
558 + struct fec_ptp_private *priv)
560 + struct fec_ptp_data_t *tmp;
562 + if (fec_ptp_is_full(ptp_buf))
565 + spin_lock(&priv->ptp_lock);
566 + tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + ptp_buf->tail;
568 + tmp->key = data->key;
569 + tmp->ts_time.sec = data->ts_time.sec;
570 + tmp->ts_time.nsec = data->ts_time.nsec;
572 + ptp_buf->tail = fec_ptp_calc_index(DEFAULT_PTP_RX_BUF_SZ,
574 + spin_unlock(&priv->ptp_lock);
579 +static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
581 + struct fec_ptp_data_t *data,
582 + struct fec_ptp_private *priv)
585 + int size = DEFAULT_PTP_RX_BUF_SZ;
586 + int end = ptp_buf->tail;
587 + unsigned long flags;
588 + struct fec_ptp_data_t *tmp;
590 + if (fec_ptp_is_empty(ptp_buf))
595 + tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + i;
596 + if (tmp->key == key)
598 + i = fec_ptp_calc_index(size, i, 1);
601 + spin_lock_irqsave(&priv->ptp_lock, flags);
603 + ptp_buf->head = end;
604 + spin_unlock_irqrestore(&priv->ptp_lock, flags);
608 + data->ts_time.sec = tmp->ts_time.sec;
609 + data->ts_time.nsec = tmp->ts_time.nsec;
611 + ptp_buf->head = fec_ptp_calc_index(size, i, 1);
612 + spin_unlock_irqrestore(&priv->ptp_lock, flags);
617 +/* 1588 Module intialization */
618 +int fec_ptp_start(struct fec_ptp_private *priv)
620 + struct fec_ptp_private *fpp = priv;
622 + MCF_CCM_MISCCR3 = 0x0000;
624 + init_DTIM1_for_1588(priv);
626 + /* Select 1588 Timer source and enable module for starting Tmr Clock */
627 + fec_writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL);
628 + fec_writel(FEC_T_INC_40MHZ << FEC_T_INC_OFFSET,
629 + fpp->hwp + FEC_ATIME_INC);
630 + fec_writel(FEC_T_PERIOD_ONE_SEC, fpp->hwp + FEC_ATIME_EVT_PERIOD);
631 + /* start counter */
632 + fec_writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE |
633 + FEC_T_CTRL_PINPER, fpp->hwp + FEC_ATIME_CTRL);
640 +/* Cleanup routine for 1588 module.
641 + * When PTP is disabled this routing is called */
642 +void fec_ptp_stop(struct fec_ptp_private *priv)
644 + struct fec_ptp_private *fpp = priv;
646 + fec_writel(0, fpp->hwp + FEC_ATIME_CTRL);
647 + fec_writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL);
651 +static void fec_get_curr_cnt(struct fec_ptp_private *priv,
652 + struct ptp_rtc_time *curr_time)
656 + fec_writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
657 + fec_writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
658 + curr_time->rtc_time.nsec = fec_readl(priv->hwp + FEC_ATIME);
659 + curr_time->rtc_time.sec = priv->prtc;
661 + fec_writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
662 + tempval = fec_readl(priv->hwp + FEC_ATIME);
663 + if (tempval < curr_time->rtc_time.nsec) {
664 + curr_time->rtc_time.nsec = tempval;
665 + curr_time->rtc_time.sec = priv->prtc;
669 +/* Set the 1588 timer counter registers */
670 +static void fec_set_1588cnt(struct fec_ptp_private *priv,
671 + struct ptp_rtc_time *fec_time)
674 + unsigned long flags;
676 + spin_lock_irqsave(&priv->cnt_lock, flags);
678 + priv->prtc = fec_time->rtc_time.sec;
680 + tempval = fec_time->rtc_time.nsec;
681 + fec_writel(tempval, priv->hwp + FEC_ATIME);
682 + spin_unlock_irqrestore(&priv->cnt_lock, flags);
685 +/* Set the BD to ptp */
686 +int fec_ptp_do_txstamp(struct sk_buff *skb)
689 + struct udphdr *udph;
691 + if (skb->len > 44) {
692 + /* Check if port is 319 for PTP Event, and check for UDP */
694 + if (iph == NULL || iph->protocol != FEC_PACKET_TYPE_UDP)
697 + udph = udp_hdr(skb);
698 + if (udph != NULL && ntohs(udph->source) == 319)
705 +void fec_ptp_store_txstamp(struct fec_ptp_private *priv)
707 + struct fec_ptp_private *fpp = priv;
710 + reg = fec_readl(fpp->hwp + FEC_TS_TIMESTAMP);
711 + fpp->txstamp.nsec = reg;
712 + fpp->txstamp.sec = fpp->prtc;
715 +void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
716 + struct sk_buff *skb,
717 + struct bufdesc *bdp)
719 + int msg_type, seq_id, control;
720 + struct fec_ptp_data_t tmp_rx_time;
721 + struct fec_ptp_private *fpp = priv;
723 + struct udphdr *udph;
725 + /* Check for UDP, and Check if port is 319 for PTP Event */
726 + iph = (struct iphdr *)(skb->data + FEC_PTP_IP_OFFS);
727 + if (iph->protocol != FEC_PACKET_TYPE_UDP)
730 + udph = (struct udphdr *)(skb->data + FEC_PTP_UDP_OFFS);
731 + if (ntohs(udph->source) != 319)
734 + seq_id = *((u16 *)(skb->data + FEC_PTP_SEQ_ID_OFFS));
735 + control = *((u8 *)(skb->data + FEC_PTP_CTRL_OFFS));
737 + tmp_rx_time.key = ntohs(seq_id);
738 + tmp_rx_time.ts_time.sec = fpp->prtc;
739 + tmp_rx_time.ts_time.nsec = bdp->ts;
744 + fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time, priv);
747 + case PTP_MSG_DEL_REQ:
748 + fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time, priv);
751 + /* clear transportSpecific field*/
752 + case PTP_MSG_ALL_OTHER:
753 + msg_type = (*((u8 *)(skb->data +
754 + FEC_PTP_MSG_TYPE_OFFS))) & 0x0F;
755 + switch (msg_type) {
756 + case PTP_MSG_P_DEL_REQ:
757 + fec_ptp_insert(&(priv->rx_time_pdel_req),
758 + &tmp_rx_time, priv);
760 + case PTP_MSG_P_DEL_RESP:
761 + fec_ptp_insert(&(priv->rx_time_pdel_resp),
762 + &tmp_rx_time, priv);
772 + wake_up_interruptible(&ptp_rx_ts_wait);
775 +static void fec_get_tx_timestamp(struct fec_ptp_private *priv,
776 + struct ptp_time *tx_time)
778 + tx_time->sec = priv->txstamp.sec;
779 + tx_time->nsec = priv->txstamp.nsec;
782 +static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
783 + struct ptp_ts_data *pts,
784 + struct ptp_time *rx_time)
786 + struct fec_ptp_data_t tmp;
791 + mode = pts->message_type;
794 + flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
797 + case PTP_MSG_DEL_REQ:
798 + flag = fec_ptp_find_and_remove(&(priv->rx_time_del_req),
802 + case PTP_MSG_P_DEL_REQ:
803 + flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_req),
806 + case PTP_MSG_P_DEL_RESP:
807 + flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_resp),
813 + printk(KERN_ERR "ERROR\n");
818 + rx_time->sec = tmp.ts_time.sec;
819 + rx_time->nsec = tmp.ts_time.nsec;
822 + wait_event_interruptible_timeout(ptp_rx_ts_wait, 0,
823 + PTP_GET_RX_TIMEOUT);
827 + flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
830 + case PTP_MSG_DEL_REQ:
831 + flag = fec_ptp_find_and_remove(
832 + &(priv->rx_time_del_req), key, &tmp, priv);
834 + case PTP_MSG_P_DEL_REQ:
835 + flag = fec_ptp_find_and_remove(
836 + &(priv->rx_time_pdel_req), key, &tmp, priv);
838 + case PTP_MSG_P_DEL_RESP:
839 + flag = fec_ptp_find_and_remove(
840 + &(priv->rx_time_pdel_resp), key, &tmp, priv);
845 + rx_time->sec = tmp.ts_time.sec;
846 + rx_time->nsec = tmp.ts_time.nsec;
854 +static void fec_handle_ptpdrift(
855 + struct ptp_set_comp *comp,
856 + struct ptp_time_correct *ptc)
860 + u32 tmp, tmp_ns, tmp_prid;
861 + u32 min_ns, min_prid, miss_ns;
863 + ndrift = comp->drift;
866 + ptc->corr_period = 0;
870 + if (ndrift >= FEC_ATIME_40MHZ) {
871 + ptc->corr_inc = (u32)(ndrift / FEC_ATIME_40MHZ);
872 + ptc->corr_period = 1;
877 + tmp = FEC_ATIME_40MHZ % ndrift;
878 + tmp_prid = (u32)(FEC_ATIME_40MHZ / ndrift);
879 + min_prid = tmp_prid;
880 + miss_ns = tmp / tmp_prid;
881 + for (i = 2; i <= FEC_T_INC_40MHZ; i++) {
882 + tmp = (FEC_ATIME_40MHZ * i) % ndrift;
883 + tmp_prid = (FEC_ATIME_40MHZ * i) / ndrift;
884 + tmp_ns = tmp / tmp_prid;
885 + if (tmp_ns <= 10) {
887 + min_prid = tmp_prid;
891 + if (tmp_ns < miss_ns) {
893 + min_prid = tmp_prid;
898 + ptc->corr_inc = min_ns;
899 + ptc->corr_period = min_prid;
902 +static void fec_set_drift(struct fec_ptp_private *priv,
903 + struct ptp_set_comp *comp)
905 + struct ptp_time_correct tc;
906 + struct fec_ptp_private *fpp = priv;
909 + fec_handle_ptpdrift(comp, &tc);
910 + if (tc.corr_inc == 0)
913 + if (comp->o_ops == TRUE)
914 + corr_ns = FEC_T_INC_40MHZ + tc.corr_inc;
916 + corr_ns = FEC_T_INC_40MHZ - tc.corr_inc;
918 + tmp = fec_readl(fpp->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
919 + tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
920 + fec_writel(tmp, fpp->hwp + FEC_ATIME_INC);
922 + fec_writel(tc.corr_period, fpp->hwp + FEC_ATIME_CORR);
925 +static int ptp_open(struct inode *inode, struct file *file)
930 +static int ptp_release(struct inode *inode, struct file *file)
935 +static long ptp_unlocked_ioctl(
940 + struct ptp_rtc_time *cnt;
941 + struct ptp_rtc_time curr_time;
942 + struct ptp_time rx_time, tx_time;
943 + struct ptp_ts_data *p_ts;
944 + struct ptp_set_comp *p_comp;
945 + struct fec_ptp_private *priv;
946 + struct inode *inode = file->f_mapping->host;
947 + unsigned int minor = MINOR(inode->i_rdev);
950 + priv = (struct fec_ptp_private *) ptp_private[minor];
952 + case PTP_GET_RX_TIMESTAMP:
953 + p_ts = (struct ptp_ts_data *)arg;
954 + retval = fec_get_rx_time(priv, p_ts, &rx_time);
956 + copy_to_user((void __user *)(&(p_ts->ts)), &rx_time,
959 + case PTP_GET_TX_TIMESTAMP:
960 + p_ts = (struct ptp_ts_data *)arg;
961 + fec_get_tx_timestamp(priv, &tx_time);
962 + copy_to_user((void __user *)(&(p_ts->ts)), &tx_time,
965 + case PTP_GET_CURRENT_TIME:
966 + fec_get_curr_cnt(priv, &curr_time);
967 + copy_to_user((void __user *)arg, &curr_time, sizeof(curr_time));
969 + case PTP_SET_RTC_TIME:
970 + cnt = (struct ptp_rtc_time *)arg;
971 + fec_set_1588cnt(priv, cnt);
973 + case PTP_FLUSH_TIMESTAMP:
974 + /* reset sync buffer */
975 + priv->rx_time_sync.head = 0;
976 + priv->rx_time_sync.tail = 0;
977 + /* reset delay_req buffer */
978 + priv->rx_time_del_req.head = 0;
979 + priv->rx_time_del_req.tail = 0;
980 + /* reset pdelay_req buffer */
981 + priv->rx_time_pdel_req.head = 0;
982 + priv->rx_time_pdel_req.tail = 0;
983 + /* reset pdelay_resp buffer */
984 + priv->rx_time_pdel_resp.head = 0;
985 + priv->rx_time_pdel_resp.tail = 0;
987 + case PTP_SET_COMPENSATION:
988 + p_comp = (struct ptp_set_comp *)arg;
989 + fec_set_drift(priv, p_comp);
991 + case PTP_GET_ORIG_COMP:
992 + ((struct ptp_get_comp *)arg)->dw_origcomp = FEC_PTP_ORIG_COMP;
1000 +static const struct file_operations ptp_fops = {
1001 + .owner = THIS_MODULE,
1005 + .unlocked_ioctl = ptp_unlocked_ioctl,
1007 + .release = ptp_release,
1010 +static int init_ptp(void)
1012 + if (register_chrdev(PTP_MAJOR, "ptp", &ptp_fops))
1013 + printk(KERN_ERR "Unable to register PTP deivce as char\n");
1018 +static void ptp_free(void)
1020 + /*unregister the PTP device*/
1021 + unregister_chrdev(PTP_MAJOR, "ptp");
1027 + * Resource required for accessing 1588 Timer Registers.
1029 +int fec_ptp_init(struct fec_ptp_private *priv, int id)
1031 + fec_ptp_init_circ(&(priv->rx_time_sync));
1032 + fec_ptp_init_circ(&(priv->rx_time_del_req));
1033 + fec_ptp_init_circ(&(priv->rx_time_pdel_req));
1034 + fec_ptp_init_circ(&(priv->rx_time_pdel_resp));
1036 + spin_lock_init(&priv->ptp_lock);
1037 + spin_lock_init(&priv->cnt_lock);
1038 + ptp_private[id] = priv;
1043 +EXPORT_SYMBOL(fec_ptp_init);
1045 +void fec_ptp_cleanup(struct fec_ptp_private *priv)
1048 + if (priv->rx_time_sync.buf)
1049 + vfree(priv->rx_time_sync.buf);
1050 + if (priv->rx_time_del_req.buf)
1051 + vfree(priv->rx_time_del_req.buf);
1052 + if (priv->rx_time_pdel_req.buf)
1053 + vfree(priv->rx_time_pdel_req.buf);
1054 + if (priv->rx_time_pdel_resp.buf)
1055 + vfree(priv->rx_time_pdel_resp.buf);
1059 +EXPORT_SYMBOL(fec_ptp_cleanup);
1061 +++ b/drivers/net/fec_1588.h
1064 + * drivers/net/fec_1588.h
1066 + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
1068 + * This program is free software; you can redistribute it and/or modify
1069 + * it under the terms of the GNU General Public License as published by
1070 + * the Free Software Foundation; either version 2 of the License, or
1071 + * (at your option) any later version.
1073 + * This program is distributed in the hope that it will be useful,
1074 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1075 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1076 + * GNU General Public License for more details.
1078 + * You should have received a copy of the GNU General Public License along
1079 + * with this program; if not, write to the Free Software Foundation, Inc.,
1080 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1087 +#include <linux/circ_buf.h>
1090 +#define fec_readl(addr) \
1091 + ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
1093 +#define fec_writel(b, addr) (void)((*(volatile unsigned int *) (addr)) = (b))
1098 +/* FEC 1588 register bits */
1099 +#define FEC_T_CTRL_CAPTURE 0x00000800
1100 +#define FEC_T_CTRL_RESTART 0x00000200
1101 +#define FEC_T_CTRL_PERIOD_RST 0x00000010
1102 +#define FEC_T_CTRL_PINPER 0x00000080
1103 +#define FEC_T_CTRL_ENABLE 0x00000001
1105 +#define FEC_T_INC_MASK 0x0000007f
1106 +#define FEC_T_INC_OFFSET 0
1107 +#define FEC_T_INC_CORR_MASK 0x00007f00
1108 +#define FEC_T_INC_CORR_OFFSET 8
1110 +#define FEC_T_INC_40MHZ 8
1111 +#define FEC_ATIME_40MHZ 125000000
1113 +#define FEC_T_PERIOD_ONE_SEC 0x3B9ACA00
1115 +/* IEEE 1588 definition */
1116 +#define FEC_ECNTRL_TS_EN 0x10
1117 +#define PTP_MAJOR 232 /*the temporary major number
1118 + *used by PTP driver, the major
1119 + *number 232~239 is unassigned*/
1121 +#define DEFAULT_PTP_RX_BUF_SZ 2048
1122 +#define PTP_MSG_SYNC 0x0
1123 +#define PTP_MSG_DEL_REQ 0x1
1124 +#define PTP_MSG_P_DEL_REQ 0x2
1125 +#define PTP_MSG_P_DEL_RESP 0x3
1126 +#define PTP_MSG_DEL_RESP 0x4
1127 +#define PTP_MSG_ALL_OTHER 0x5
1129 +#define PTP_GET_TX_TIMESTAMP 0x1
1130 +#define PTP_GET_RX_TIMESTAMP 0x9
1131 +#define PTP_SET_RTC_TIME 0x3
1132 +#define PTP_SET_COMPENSATION 0x4
1133 +#define PTP_GET_CURRENT_TIME 0x5
1134 +#define PTP_FLUSH_TIMESTAMP 0x6
1135 +#define PTP_ADJ_ADDEND 0x7
1136 +#define PTP_GET_ORIG_COMP 0x8
1137 +#define PTP_GET_ADDEND 0xB
1138 +#define PTP_GET_RX_TIMESTAMP_PDELAY_REQ 0xC
1139 +#define PTP_GET_RX_TIMESTAMP_PDELAY_RESP 0xD
1141 +#define FEC_PTP_DOMAIN_DLFT 0xe0000181
1142 +#define FEC_PTP_IP_OFFS 0x0
1143 +#define FEC_PTP_UDP_OFFS 0x14
1144 +#define FEC_PTP_MSG_TYPE_OFFS 0x1C
1145 +#define FEC_PTP_SEQ_ID_OFFS 0x3A
1146 +#define FEC_PTP_COR_NS 0x24
1147 +#define FEC_PTP_CTRL_OFFS 0x3C
1148 +#define FEC_PACKET_TYPE_UDP 0x11
1150 +#define FEC_PTP_ORIG_COMP 0x15555
1152 +/* PTP standard time representation structure */
1154 + u64 sec; /* seconds */
1155 + u32 nsec; /* nanoseconds */
1158 +/* Structure for PTP Time Stamp */
1159 +struct fec_ptp_data_t {
1161 + struct ptp_time ts_time;
1164 +/* interface for PTP driver command GET_TX_TIME */
1165 +struct ptp_ts_data {
1168 + /* PTP source port ID */
1170 + /* PTP sequence ID */
1172 + /* PTP message type */
1174 + /* PTP timestamp */
1175 + struct ptp_time ts;
1178 +/* interface for PTP driver command SET_RTC_TIME/GET_CURRENT_TIME */
1179 +struct ptp_rtc_time {
1180 + struct ptp_time rtc_time;
1183 +/* interface for PTP driver command SET_COMPENSATION */
1184 +struct ptp_set_comp {
1189 +/* interface for PTP driver command GET_ORIG_COMP */
1190 +struct ptp_get_comp {
1191 + /* the initial compensation value */
1193 + /* the minimum compensation value */
1195 + /*the max compensation value*/
1197 + /*the min drift applying min compensation value in ppm*/
1199 + /*the max drift applying max compensation value in ppm*/
1203 +struct ptp_time_correct {
1208 +/* PTP message version */
1209 +#define PTP_1588_MSG_VER_1 1
1210 +#define PTP_1588_MSG_VER_2 2
1212 +struct fec_ptp_private {
1213 + void __iomem *hwp;
1215 + struct circ_buf rx_time_sync;
1216 + struct circ_buf rx_time_del_req;
1217 + struct circ_buf rx_time_pdel_req;
1218 + struct circ_buf rx_time_pdel_resp;
1219 + spinlock_t ptp_lock;
1220 + spinlock_t cnt_lock;
1223 + struct ptp_time txstamp;
1226 +#ifdef CONFIG_FEC_1588
1227 +extern int fec_ptp_init(struct fec_ptp_private *priv, int id);
1228 +extern void fec_ptp_cleanup(struct fec_ptp_private *priv);
1229 +extern int fec_ptp_start(struct fec_ptp_private *priv);
1230 +extern void fec_ptp_stop(struct fec_ptp_private *priv);
1231 +extern int fec_ptp_do_txstamp(struct sk_buff *skb);
1232 +extern void fec_ptp_store_txstamp(struct fec_ptp_private *priv);
1233 +extern void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
1234 + struct sk_buff *skb,
1235 + struct bufdesc *bdp);
1237 +static inline int fec_ptp_init(struct fec_ptp_private *priv, int id)
1241 +static inline void fec_ptp_cleanup(struct fec_ptp_private *priv) { }
1242 +static inline int fec_ptp_start(struct fec_ptp_private *priv)
1246 +static inline void fec_ptp_stop(struct fec_ptp_private *priv) {}
1247 +static inline int fec_ptp_do_txstamp(struct sk_buff *skb)
1251 +static inline void fec_ptp_store_txstamp(struct fec_ptp_private *priv) {}
1252 +static inline void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
1253 + struct sk_buff *skb,
1254 + struct bufdesc *bdp) {}