diff options
Diffstat (limited to 'target/linux/coldfire/patches/020-Add-dual-FEC-1588-timer-support.patch')
-rw-r--r-- | target/linux/coldfire/patches/020-Add-dual-FEC-1588-timer-support.patch | 1257 |
1 files changed, 0 insertions, 1257 deletions
diff --git a/target/linux/coldfire/patches/020-Add-dual-FEC-1588-timer-support.patch b/target/linux/coldfire/patches/020-Add-dual-FEC-1588-timer-support.patch deleted file mode 100644 index 43a258f..0000000 --- a/target/linux/coldfire/patches/020-Add-dual-FEC-1588-timer-support.patch +++ /dev/null @@ -1,1257 +0,0 @@ -From 67d56859d24864af530506c76523f0fc3c5cb502 Mon Sep 17 00:00:00 2001 -From: Alison Wang <b18965@freescale.com> -Date: Thu, 4 Aug 2011 09:59:44 +0800 -Subject: [PATCH 20/52] Add dual FEC 1588 timer support - -Add Modelo dual FEC 1588 function with IXXXAT statck. - -Signed-off-by: Alison Wang <b18965@freescale.com> ---- - drivers/net/Kconfig | 6 + - drivers/net/Makefile | 3 + - drivers/net/fec.c | 153 ++++++++++++- - drivers/net/fec.h | 25 ++ - drivers/net/fec_1588.c | 626 ++++++++++++++++++++++++++++++++++++++++++++++++ - drivers/net/fec_1588.h | 195 +++++++++++++++ - 6 files changed, 1006 insertions(+), 2 deletions(-) - create mode 100644 drivers/net/fec_1588.c - create mode 100644 drivers/net/fec_1588.h - ---- a/drivers/net/Kconfig -+++ b/drivers/net/Kconfig -@@ -1958,6 +1958,12 @@ config FEC2 - Say Y here if you want to use the second built-in 10/100 Fast - ethernet controller on some Motorola ColdFire processors. - -+config FEC_1588 -+ bool "Enable 1588 interface(on some ColdFire designs)" -+ depends on M5441X && FEC -+ help -+ Say Y here if 1588 function is enabled. -+ - config FEC_548x - tristate "MCF547x/MCF548x Fast Ethernet Controller support" - depends on M547X_8X ---- a/drivers/net/Makefile -+++ b/drivers/net/Makefile -@@ -123,6 +123,9 @@ obj-$(CONFIG_PCMCIA_PCNET) += 8390.o - obj-$(CONFIG_HP100) += hp100.o - obj-$(CONFIG_SMC9194) += smc9194.o - obj-$(CONFIG_FEC) += fec.o -+ifeq ($(CONFIG_FEC_1588), y) -+obj-$(CONFIG_FEC) += fec_1588.o -+endif - obj-$(CONFIG_FEC_548x) += fec_m547x.o - obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o - ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) ---- a/drivers/net/fec.c -+++ b/drivers/net/fec.c -@@ -53,6 +53,7 @@ - #endif - - #include "fec.h" -+#include "fec_1588.h" - - #if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) - #define FEC_ALIGNMENT 0xf -@@ -135,8 +136,15 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet - #define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ - #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ - #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ -+#define FEC_ENET_TS_AVAIL ((uint)0x00010000) -+#define FEC_ENET_TS_TIMER ((uint)0x00008000) - -+#if defined(CONFIG_FEC_1588) -+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | \ -+ FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER) -+#else - #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) -+#endif - - /* The FEC stores dest/src/type, data, and checksum for receive packets. - */ -@@ -209,6 +217,10 @@ struct fec_enet_private { - int link; - int full_duplex; - struct completion mdio_done; -+#ifdef CONFIG_FEC_1588 -+ struct fec_ptp_private *ptp_priv; -+ uint ptimer_present; -+#endif - }; - - static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); -@@ -252,6 +264,9 @@ fec_enet_start_xmit(struct sk_buff *skb, - struct bufdesc *bdp; - void *bufaddr; - unsigned short status; -+#ifdef CONFIG_FEC_1588 -+ unsigned long estatus; -+#endif - unsigned long flags; - - if (!fep->link) { -@@ -293,6 +308,17 @@ fec_enet_start_xmit(struct sk_buff *skb, - bufaddr = fep->tx_bounce[index]; - } - -+#ifdef CONFIG_FEC_1588 -+ if (fep->ptimer_present) { -+ if (fec_ptp_do_txstamp(skb)) -+ estatus = BD_ENET_TX_TS; -+ else -+ estatus = 0; -+ -+ bdp->cbd_esc = (estatus | BD_ENET_TX_INT); -+ bdp->cbd_bdu = 0; -+ } -+#endif - /* - * Some design made an incorrect assumption on endian mode of - * the system that it's running on. As the result, driver has to -@@ -357,6 +383,9 @@ fec_enet_interrupt(int irq, void * dev_i - { - struct net_device *dev = dev_id; - struct fec_enet_private *fep = netdev_priv(dev); -+#ifdef CONFIG_FEC_1588 -+ struct fec_ptp_private *fpp = fep->ptp_priv; -+#endif - uint int_events; - irqreturn_t ret = IRQ_NONE; - -@@ -364,6 +393,10 @@ fec_enet_interrupt(int irq, void * dev_i - int_events = readl(fep->hwp + FEC_IEVENT); - writel(int_events, fep->hwp + FEC_IEVENT); - -+#ifdef CONFIG_FEC_1588 -+ if (__raw_readb(MCF_DTIM1_DTER) & MCF_DTIM_DTER_REF) -+ __raw_writeb(MCF_DTIM_DTER_REF, MCF_DTIM1_DTER); -+#endif - if (int_events & FEC_ENET_RXF) { - ret = IRQ_HANDLED; - fec_enet_rx(dev); -@@ -378,6 +411,19 @@ fec_enet_interrupt(int irq, void * dev_i - fec_enet_tx(dev); - } - -+#ifdef CONFIG_FEC_1588 -+ if (int_events & FEC_ENET_TS_AVAIL) { -+ ret = IRQ_HANDLED; -+ fec_ptp_store_txstamp(fep->ptp_priv); -+ } -+ -+ if (int_events & FEC_ENET_TS_TIMER) { -+ ret = IRQ_HANDLED; -+ if (fep->ptimer_present) -+ fpp->prtc++; -+ } -+#endif -+ - if (int_events & FEC_ENET_MII) { - ret = IRQ_HANDLED; - complete(&fep->mdio_done); -@@ -394,6 +440,9 @@ fec_enet_tx(struct net_device *dev) - struct fec_enet_private *fep; - struct bufdesc *bdp; - unsigned short status; -+#ifdef CONFIG_FEC_1588 -+ unsigned long estatus; -+#endif - struct sk_buff *skb; - - fep = netdev_priv(dev); -@@ -437,6 +486,13 @@ fec_enet_tx(struct net_device *dev) - if (status & BD_ENET_TX_DEF) - dev->stats.collisions++; - -+#if defined(CONFIG_FEC_1588) -+ if (fep->ptimer_present) { -+ estatus = bdp->cbd_esc; -+ if (estatus & BD_ENET_TX_TS) -+ fec_ptp_store_txstamp(fep->ptp_priv); -+ } -+#endif - /* Free the sk buffer associated with this last transmit */ - dev_kfree_skb_any(skb); - fep->tx_skbuff[fep->skb_dirty] = NULL; -@@ -470,6 +526,9 @@ static void - fec_enet_rx(struct net_device *dev) - { - struct fec_enet_private *fep = netdev_priv(dev); -+#ifdef CONFIG_FEC_1588 -+ struct fec_ptp_private *fpp = fep->ptp_priv; -+#endif - const struct platform_device_id *id_entry = - platform_get_device_id(fep->pdev); - struct bufdesc *bdp; -@@ -554,6 +613,12 @@ fec_enet_rx(struct net_device *dev) - skb_put(skb, pkt_len - 4); /* Make room */ - skb_copy_to_linear_data(skb, data, pkt_len - 4); - skb->protocol = eth_type_trans(skb, dev); -+ -+#ifdef CONFIG_FEC_1588 -+ /* 1588 messeage TS handle */ -+ if (fep->ptimer_present) -+ fec_ptp_store_rxstamp(fpp, skb, bdp); -+#endif - netif_rx(skb); - } - -@@ -567,6 +632,11 @@ rx_processing_done: - status |= BD_ENET_RX_EMPTY; - bdp->cbd_sc = status; - -+#ifdef CONFIG_FEC_1588 -+ bdp->cbd_esc = BD_ENET_RX_INT; -+ bdp->cbd_prot = 0; -+ bdp->cbd_bdu = 0; -+#endif - /* Update BD pointer to next entry */ - if (status & BD_ENET_RX_WRAP) - bdp = fep->rx_bd_base; -@@ -669,8 +739,11 @@ static void fec_enet_adjust_link(struct - fec_stop(dev); - - if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) -- writel(2, fep->hwp + FEC_ECNTRL); -- -+#ifdef CONFIG_FEC_1588 -+ writel(0x00000012, fep->hwp + FEC_ECNTRL); -+#else -+ writel(0x00000002, fep->hwp + FEC_ECNTRL); -+#endif - status_change = 1; - } - -@@ -983,6 +1056,10 @@ static int fec_enet_alloc_buffers(struct - bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data, - FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); - bdp->cbd_sc = BD_ENET_RX_EMPTY; -+ -+#ifdef CONFIG_FEC_1588 -+ bdp->cbd_esc = BD_ENET_RX_INT; -+#endif - bdp++; - } - -@@ -996,6 +1073,9 @@ static int fec_enet_alloc_buffers(struct - - bdp->cbd_sc = 0; - bdp->cbd_bufaddr = 0; -+#ifdef CONFIG_FEC_1588 -+ bdp->cbd_esc = BD_ENET_TX_INT; -+#endif - bdp++; - } - -@@ -1256,8 +1336,12 @@ fec_restart(struct net_device *dev, int - writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); - } - -+#ifdef CONFIG_FEC_1588 -+ writel(0x7fff8000, fep->hwp + FEC_IEVENT); -+#else - /* Clear any outstanding interrupt. */ - writel(0xffc00000, fep->hwp + FEC_IEVENT); -+#endif - - /* Reset all multicast. */ - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); -@@ -1342,8 +1426,25 @@ fec_restart(struct net_device *dev, int - #endif - } - -+#ifdef CONFIG_FEC_1588 -+ if (fep->ptimer_present) { -+ int ret; -+ /* Set Timer count */ -+ ret = fec_ptp_start(fep->ptp_priv); -+ if (ret) { -+ fep->ptimer_present = 0; -+ writel(2, fep->hwp + FEC_ECNTRL); -+ } else { -+ val = readl(fep->hwp + FEC_ECNTRL); -+ val |= 0x00000012; -+ writel(val, fep->hwp + FEC_ECNTRL); -+ } -+ } else -+ writel(2, fep->hwp + FEC_ECNTRL); -+#else - /* And last, enable the transmit and receive processing */ - writel(2, fep->hwp + FEC_ECNTRL); -+#endif - writel(0, fep->hwp + FEC_R_DES_ACTIVE); - - /* Enable interrupts we wish to service */ -@@ -1367,6 +1468,10 @@ fec_stop(struct net_device *dev) - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); - writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); -+#ifdef CONFIG_FEC_1588 -+ if (fep->ptimer_present) -+ fec_ptp_stop(fep->ptp_priv); -+#endif - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); - } - -@@ -1428,6 +1533,24 @@ fec_probe(struct platform_device *pdev) - } - } - -+#ifdef CONFIG_FEC_1588 -+ i = (pdev->id) ? (64 + 64 + 64 + 7) : (64 + 64 + 64); -+ if (request_irq(i + 48, fec_enet_interrupt, IRQF_DISABLED, -+ "1588 TS AVAIL", ndev) != 0) -+ printk(KERN_ERR "FEC: Could not alloc FEC %x 1588 TS AVAIL " -+ "IRQ(%d)!\n", pdev->id, i + 48); -+ -+ if (pdev->id == 0) { -+ printk("setup TS timer interrupt through DMA timer1\n"); -+ __raw_writew(MCF_DTIM_DTMR_RST_RST, MCF_DTIM1_DTMR); -+ -+ if (request_irq(64 + 33, fec_enet_interrupt, IRQF_DISABLED, -+ "1588 TS TIMER", ndev) != 0) -+ printk(KERN_ERR "FEC: Could not alloc FEC %x 1588 TS" -+ " TIMER IRQ(%d)!\n", pdev->id, 64 + 33); -+ } -+#endif -+ - fep->clk = clk_get(&pdev->dev, "fec_clk"); - if (IS_ERR(fep->clk)) { - ret = PTR_ERR(fep->clk); -@@ -1443,6 +1566,20 @@ fec_probe(struct platform_device *pdev) - if (ret) - goto failed_mii_init; - -+#ifdef CONFIG_FEC_1588 -+ fep->ptp_priv = kzalloc(sizeof(struct fec_ptp_private), -+ GFP_KERNEL); -+ if (fep->ptp_priv) { -+ fep->ptp_priv->hwp = fep->hwp; -+ ret = fec_ptp_init(fep->ptp_priv, pdev->id); -+ if (ret) -+ printk(KERN_ERR "IEEE1588: ptp-timer init failed\n"); -+ else -+ fep->ptimer_present = 1; -+ } else -+ printk(KERN_ERR "IEEE1588: failed to malloc memory\n"); -+#endif -+ - /* Carrier starts down, phylib will bring it up */ - netif_carrier_off(ndev); - -@@ -1454,6 +1591,12 @@ fec_probe(struct platform_device *pdev) - - failed_register: - fec_enet_mii_remove(fep); -+#ifdef CONFIG_FEC_1588 -+ if (fep->ptimer_present) -+ fec_ptp_cleanup(fep->ptp_priv); -+ -+ kfree(fep->ptp_priv); -+#endif - failed_mii_init: - failed_init: - clk_disable(fep->clk); -@@ -1485,6 +1628,12 @@ fec_drv_remove(struct platform_device *p - clk_disable(fep->clk); - clk_put(fep->clk); - iounmap((void __iomem *)ndev->base_addr); -+#ifdef CONFIG_FEC_1588 -+ if (fep->ptimer_present) -+ fec_ptp_cleanup(fep->ptp_priv); -+ -+ kfree(fep->ptp_priv); -+#endif - unregister_netdev(ndev); - free_netdev(ndev); - return 0; ---- a/drivers/net/fec.h -+++ b/drivers/net/fec.h -@@ -50,6 +50,16 @@ - #define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */ - #define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */ - -+#if defined(CONFIG_FEC_1588) -+#define FEC_ATIME_CTRL 0x400 -+#define FEC_ATIME 0x404 -+#define FEC_ATIME_EVT_OFFSET 0x408 -+#define FEC_ATIME_EVT_PERIOD 0x40c -+#define FEC_ATIME_CORR 0x410 -+#define FEC_ATIME_INC 0x414 -+#define FEC_TS_TIMESTAMP 0x418 -+#endif -+ - #else - - #define FEC_ECNTRL 0x000 /* Ethernet control reg */ -@@ -78,6 +88,9 @@ - - #endif /* CONFIG_M5272 */ - -+#if defined(CONFIG_FEC_1588) -+#define FEC_ENHANCED_MODE 1 -+#endif - - /* - * Define the buffer descriptor structure. -@@ -93,6 +106,14 @@ struct bufdesc { - unsigned short cbd_sc; /* Control and status info */ - unsigned short cbd_datlen; /* Data length */ - unsigned long cbd_bufaddr; /* Buffer address */ -+ -+#ifdef FEC_ENHANCED_MODE -+ unsigned long cbd_esc; -+ unsigned long cbd_prot; -+ unsigned long cbd_bdu; -+ unsigned long ts; -+ unsigned short res0[4]; -+#endif - }; - #endif - -@@ -128,6 +149,7 @@ struct bufdesc { - #define BD_ENET_RX_OV ((ushort)0x0002) - #define BD_ENET_RX_CL ((ushort)0x0001) - #define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ -+#define BD_ENET_RX_INT 0x00800000 - - /* Buffer descriptor control/status used by Ethernet transmit. - */ -@@ -146,6 +168,9 @@ struct bufdesc { - #define BD_ENET_TX_CSL ((ushort)0x0001) - #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ - -+#define BD_ENET_TX_TS 0x20000000 -+#define BD_ENET_TX_INT 0x40000000 -+#define BD_ENET_TX_BDU 0x80000000 - - /****************************************************************************/ - #endif /* FEC_H */ ---- /dev/null -+++ b/drivers/net/fec_1588.c -@@ -0,0 +1,626 @@ -+/* -+ * drivers/net/fec_1588.c -+ * -+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * Copyright (C) 2009 IXXAT Automation, GmbH -+ * -+ * FEC Ethernet Driver -- IEEE 1588 interface functionality -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#include <linux/io.h> -+#include <linux/device.h> -+#include <linux/fs.h> -+#include <linux/vmalloc.h> -+#include <linux/spinlock.h> -+#include <linux/ip.h> -+#include <linux/udp.h> -+#include <asm/mcf5441x_ccm.h> -+#include <asm/mcf5441x_dtim.h> -+#include <asm/mcfsim.h> -+#include "fec_1588.h" -+ -+static DECLARE_WAIT_QUEUE_HEAD(ptp_rx_ts_wait); -+#define PTP_GET_RX_TIMEOUT (HZ/10) -+#define COLDFIRE_DTIM1_INT (64+32+1) -+ -+static struct fec_ptp_private *ptp_private[2]; -+ -+static void init_DTIM1_for_1588(struct fec_ptp_private *priv) -+{ -+ printk(KERN_INFO "Initializing DTIM1 for 1588 TS timer\n"); -+ -+ __raw_writew(MCF_DTIM_DTMR_RST_RST, MCF_DTIM1_DTMR); -+ -+ /*Enable 1588*/ -+ -+ __raw_writeb(MCF_DTIM_DTXMR_1588EN, MCF_DTIM1_DTXMR); -+ -+ /*Compare to the 1588 timerbase*/ -+ __raw_writel(FEC_T_PERIOD_ONE_SEC - FEC_T_INC_40MHZ, MCF_DTIM1_DTRR); -+ -+ __raw_writeb(MCF_DTIM_DTER_REF, MCF_DTIM1_DTER); -+ -+ MCF_GPIO_PAR_TIMER = (MCF_GPIO_PAR_TIMER & MCF_GPIO_PAR_TIMER_T1IN_MASK) -+ | MCF_GPIO_PAR_TIMER_T1IN_T1OUT; -+} -+ -+static void start_DTIM1(void) -+{ -+ __raw_writew(MCF_DTIM_DTMR_RST_EN | MCF_DTIM_DTMR_ORRI | -+ MCF_DTIM_DTMR_OM, MCF_DTIM1_DTMR); -+} -+ -+static void stop_DTIM1(void) -+{ -+ __raw_writew(MCF_DTIM_DTMR_RST_RST, MCF_DTIM1_DTMR); -+} -+ -+/* Alloc the ring resource */ -+static int fec_ptp_init_circ(struct circ_buf *ptp_buf) -+{ -+ ptp_buf->buf = vmalloc(DEFAULT_PTP_RX_BUF_SZ * -+ sizeof(struct fec_ptp_data_t)); -+ -+ if (!ptp_buf->buf) -+ return 1; -+ ptp_buf->head = 0; -+ ptp_buf->tail = 0; -+ -+ return 0; -+} -+ -+static inline int fec_ptp_calc_index(int size, int curr_index, int offset) -+{ -+ return (curr_index + offset) % size; -+} -+ -+static int fec_ptp_is_empty(struct circ_buf *buf) -+{ -+ return (buf->head == buf->tail); -+} -+ -+static int fec_ptp_nelems(struct circ_buf *buf) -+{ -+ const int front = buf->head; -+ const int end = buf->tail; -+ const int size = DEFAULT_PTP_RX_BUF_SZ; -+ int n_items; -+ -+ if (end > front) -+ n_items = end - front; -+ else if (end < front) -+ n_items = size - (front - end); -+ else -+ n_items = 0; -+ -+ return n_items; -+} -+ -+static int fec_ptp_is_full(struct circ_buf *buf) -+{ -+ if (fec_ptp_nelems(buf) == -+ (DEFAULT_PTP_RX_BUF_SZ - 1)) -+ return 1; -+ else -+ return 0; -+} -+ -+static int fec_ptp_insert(struct circ_buf *ptp_buf, -+ struct fec_ptp_data_t *data, -+ struct fec_ptp_private *priv) -+{ -+ struct fec_ptp_data_t *tmp; -+ -+ if (fec_ptp_is_full(ptp_buf)) -+ return 1; -+ -+ spin_lock(&priv->ptp_lock); -+ tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + ptp_buf->tail; -+ -+ tmp->key = data->key; -+ tmp->ts_time.sec = data->ts_time.sec; -+ tmp->ts_time.nsec = data->ts_time.nsec; -+ -+ ptp_buf->tail = fec_ptp_calc_index(DEFAULT_PTP_RX_BUF_SZ, -+ ptp_buf->tail, 1); -+ spin_unlock(&priv->ptp_lock); -+ -+ return 0; -+} -+ -+static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf, -+ int key, -+ struct fec_ptp_data_t *data, -+ struct fec_ptp_private *priv) -+{ -+ int i; -+ int size = DEFAULT_PTP_RX_BUF_SZ; -+ int end = ptp_buf->tail; -+ unsigned long flags; -+ struct fec_ptp_data_t *tmp; -+ -+ if (fec_ptp_is_empty(ptp_buf)) -+ return 1; -+ -+ i = ptp_buf->head; -+ while (i != end) { -+ tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + i; -+ if (tmp->key == key) -+ break; -+ i = fec_ptp_calc_index(size, i, 1); -+ } -+ -+ spin_lock_irqsave(&priv->ptp_lock, flags); -+ if (i == end) { -+ ptp_buf->head = end; -+ spin_unlock_irqrestore(&priv->ptp_lock, flags); -+ return 1; -+ } -+ -+ data->ts_time.sec = tmp->ts_time.sec; -+ data->ts_time.nsec = tmp->ts_time.nsec; -+ -+ ptp_buf->head = fec_ptp_calc_index(size, i, 1); -+ spin_unlock_irqrestore(&priv->ptp_lock, flags); -+ -+ return 0; -+} -+ -+/* 1588 Module intialization */ -+int fec_ptp_start(struct fec_ptp_private *priv) -+{ -+ struct fec_ptp_private *fpp = priv; -+ -+ MCF_CCM_MISCCR3 = 0x0000; -+ -+ init_DTIM1_for_1588(priv); -+ -+ /* Select 1588 Timer source and enable module for starting Tmr Clock */ -+ fec_writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL); -+ fec_writel(FEC_T_INC_40MHZ << FEC_T_INC_OFFSET, -+ fpp->hwp + FEC_ATIME_INC); -+ fec_writel(FEC_T_PERIOD_ONE_SEC, fpp->hwp + FEC_ATIME_EVT_PERIOD); -+ /* start counter */ -+ fec_writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE | -+ FEC_T_CTRL_PINPER, fpp->hwp + FEC_ATIME_CTRL); -+ -+ start_DTIM1(); -+ -+ return 0; -+} -+ -+/* Cleanup routine for 1588 module. -+ * When PTP is disabled this routing is called */ -+void fec_ptp_stop(struct fec_ptp_private *priv) -+{ -+ struct fec_ptp_private *fpp = priv; -+ -+ fec_writel(0, fpp->hwp + FEC_ATIME_CTRL); -+ fec_writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL); -+ stop_DTIM1(); -+} -+ -+static void fec_get_curr_cnt(struct fec_ptp_private *priv, -+ struct ptp_rtc_time *curr_time) -+{ -+ u32 tempval; -+ -+ fec_writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL); -+ fec_writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL); -+ curr_time->rtc_time.nsec = fec_readl(priv->hwp + FEC_ATIME); -+ curr_time->rtc_time.sec = priv->prtc; -+ -+ fec_writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL); -+ tempval = fec_readl(priv->hwp + FEC_ATIME); -+ if (tempval < curr_time->rtc_time.nsec) { -+ curr_time->rtc_time.nsec = tempval; -+ curr_time->rtc_time.sec = priv->prtc; -+ } -+} -+ -+/* Set the 1588 timer counter registers */ -+static void fec_set_1588cnt(struct fec_ptp_private *priv, -+ struct ptp_rtc_time *fec_time) -+{ -+ u32 tempval; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&priv->cnt_lock, flags); -+ -+ priv->prtc = fec_time->rtc_time.sec; -+ -+ tempval = fec_time->rtc_time.nsec; -+ fec_writel(tempval, priv->hwp + FEC_ATIME); -+ spin_unlock_irqrestore(&priv->cnt_lock, flags); -+} -+ -+/* Set the BD to ptp */ -+int fec_ptp_do_txstamp(struct sk_buff *skb) -+{ -+ struct iphdr *iph; -+ struct udphdr *udph; -+ -+ if (skb->len > 44) { -+ /* Check if port is 319 for PTP Event, and check for UDP */ -+ iph = ip_hdr(skb); -+ if (iph == NULL || iph->protocol != FEC_PACKET_TYPE_UDP) -+ return 0; -+ -+ udph = udp_hdr(skb); -+ if (udph != NULL && ntohs(udph->source) == 319) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+void fec_ptp_store_txstamp(struct fec_ptp_private *priv) -+{ -+ struct fec_ptp_private *fpp = priv; -+ unsigned int reg; -+ -+ reg = fec_readl(fpp->hwp + FEC_TS_TIMESTAMP); -+ fpp->txstamp.nsec = reg; -+ fpp->txstamp.sec = fpp->prtc; -+} -+ -+void fec_ptp_store_rxstamp(struct fec_ptp_private *priv, -+ struct sk_buff *skb, -+ struct bufdesc *bdp) -+{ -+ int msg_type, seq_id, control; -+ struct fec_ptp_data_t tmp_rx_time; -+ struct fec_ptp_private *fpp = priv; -+ struct iphdr *iph; -+ struct udphdr *udph; -+ -+ /* Check for UDP, and Check if port is 319 for PTP Event */ -+ iph = (struct iphdr *)(skb->data + FEC_PTP_IP_OFFS); -+ if (iph->protocol != FEC_PACKET_TYPE_UDP) -+ return; -+ -+ udph = (struct udphdr *)(skb->data + FEC_PTP_UDP_OFFS); -+ if (ntohs(udph->source) != 319) -+ return; -+ -+ seq_id = *((u16 *)(skb->data + FEC_PTP_SEQ_ID_OFFS)); -+ control = *((u8 *)(skb->data + FEC_PTP_CTRL_OFFS)); -+ -+ tmp_rx_time.key = ntohs(seq_id); -+ tmp_rx_time.ts_time.sec = fpp->prtc; -+ tmp_rx_time.ts_time.nsec = bdp->ts; -+ -+ switch (control) { -+ -+ case PTP_MSG_SYNC: -+ fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time, priv); -+ break; -+ -+ case PTP_MSG_DEL_REQ: -+ fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time, priv); -+ break; -+ -+ /* clear transportSpecific field*/ -+ case PTP_MSG_ALL_OTHER: -+ msg_type = (*((u8 *)(skb->data + -+ FEC_PTP_MSG_TYPE_OFFS))) & 0x0F; -+ switch (msg_type) { -+ case PTP_MSG_P_DEL_REQ: -+ fec_ptp_insert(&(priv->rx_time_pdel_req), -+ &tmp_rx_time, priv); -+ break; -+ case PTP_MSG_P_DEL_RESP: -+ fec_ptp_insert(&(priv->rx_time_pdel_resp), -+ &tmp_rx_time, priv); -+ break; -+ default: -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ wake_up_interruptible(&ptp_rx_ts_wait); -+} -+ -+static void fec_get_tx_timestamp(struct fec_ptp_private *priv, -+ struct ptp_time *tx_time) -+{ -+ tx_time->sec = priv->txstamp.sec; -+ tx_time->nsec = priv->txstamp.nsec; -+} -+ -+static uint8_t fec_get_rx_time(struct fec_ptp_private *priv, -+ struct ptp_ts_data *pts, -+ struct ptp_time *rx_time) -+{ -+ struct fec_ptp_data_t tmp; -+ int key, flag; -+ u8 mode; -+ -+ key = pts->seq_id; -+ mode = pts->message_type; -+ switch (mode) { -+ case PTP_MSG_SYNC: -+ flag = fec_ptp_find_and_remove(&(priv->rx_time_sync), -+ key, &tmp, priv); -+ break; -+ case PTP_MSG_DEL_REQ: -+ flag = fec_ptp_find_and_remove(&(priv->rx_time_del_req), -+ key, &tmp, priv); -+ break; -+ -+ case PTP_MSG_P_DEL_REQ: -+ flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_req), -+ key, &tmp, priv); -+ break; -+ case PTP_MSG_P_DEL_RESP: -+ flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_resp), -+ key, &tmp, priv); -+ break; -+ -+ default: -+ flag = 1; -+ printk(KERN_ERR "ERROR\n"); -+ break; -+ } -+ -+ if (!flag) { -+ rx_time->sec = tmp.ts_time.sec; -+ rx_time->nsec = tmp.ts_time.nsec; -+ return 0; -+ } else { -+ wait_event_interruptible_timeout(ptp_rx_ts_wait, 0, -+ PTP_GET_RX_TIMEOUT); -+ -+ switch (mode) { -+ case PTP_MSG_SYNC: -+ flag = fec_ptp_find_and_remove(&(priv->rx_time_sync), -+ key, &tmp, priv); -+ break; -+ case PTP_MSG_DEL_REQ: -+ flag = fec_ptp_find_and_remove( -+ &(priv->rx_time_del_req), key, &tmp, priv); -+ break; -+ case PTP_MSG_P_DEL_REQ: -+ flag = fec_ptp_find_and_remove( -+ &(priv->rx_time_pdel_req), key, &tmp, priv); -+ break; -+ case PTP_MSG_P_DEL_RESP: -+ flag = fec_ptp_find_and_remove( -+ &(priv->rx_time_pdel_resp), key, &tmp, priv); -+ break; -+ } -+ -+ if (flag == 0) { -+ rx_time->sec = tmp.ts_time.sec; -+ rx_time->nsec = tmp.ts_time.nsec; -+ return 0; -+ } -+ -+ return -1; -+ } -+} -+ -+static void fec_handle_ptpdrift( -+ struct ptp_set_comp *comp, -+ struct ptp_time_correct *ptc) -+{ -+ u32 ndrift; -+ u32 i; -+ u32 tmp, tmp_ns, tmp_prid; -+ u32 min_ns, min_prid, miss_ns; -+ -+ ndrift = comp->drift; -+ if (ndrift == 0) { -+ ptc->corr_inc = 0; -+ ptc->corr_period = 0; -+ return; -+ } -+ -+ if (ndrift >= FEC_ATIME_40MHZ) { -+ ptc->corr_inc = (u32)(ndrift / FEC_ATIME_40MHZ); -+ ptc->corr_period = 1; -+ return; -+ } -+ -+ min_ns = 1; -+ tmp = FEC_ATIME_40MHZ % ndrift; -+ tmp_prid = (u32)(FEC_ATIME_40MHZ / ndrift); -+ min_prid = tmp_prid; -+ miss_ns = tmp / tmp_prid; -+ for (i = 2; i <= FEC_T_INC_40MHZ; i++) { -+ tmp = (FEC_ATIME_40MHZ * i) % ndrift; -+ tmp_prid = (FEC_ATIME_40MHZ * i) / ndrift; -+ tmp_ns = tmp / tmp_prid; -+ if (tmp_ns <= 10) { -+ min_ns = i; -+ min_prid = tmp_prid; -+ break; -+ } -+ -+ if (tmp_ns < miss_ns) { -+ min_ns = i; -+ min_prid = tmp_prid; -+ miss_ns = tmp_ns; -+ } -+ } -+ -+ ptc->corr_inc = min_ns; -+ ptc->corr_period = min_prid; -+} -+ -+static void fec_set_drift(struct fec_ptp_private *priv, -+ struct ptp_set_comp *comp) -+{ -+ struct ptp_time_correct tc; -+ struct fec_ptp_private *fpp = priv; -+ u32 tmp, corr_ns; -+ -+ fec_handle_ptpdrift(comp, &tc); -+ if (tc.corr_inc == 0) -+ return; -+ -+ if (comp->o_ops == TRUE) -+ corr_ns = FEC_T_INC_40MHZ + tc.corr_inc; -+ else -+ corr_ns = FEC_T_INC_40MHZ - tc.corr_inc; -+ -+ tmp = fec_readl(fpp->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK; -+ tmp |= corr_ns << FEC_T_INC_CORR_OFFSET; -+ fec_writel(tmp, fpp->hwp + FEC_ATIME_INC); -+ -+ fec_writel(tc.corr_period, fpp->hwp + FEC_ATIME_CORR); -+} -+ -+static int ptp_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int ptp_release(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static long ptp_unlocked_ioctl( -+ struct file *file, -+ unsigned int cmd, -+ unsigned long arg) -+{ -+ struct ptp_rtc_time *cnt; -+ struct ptp_rtc_time curr_time; -+ struct ptp_time rx_time, tx_time; -+ struct ptp_ts_data *p_ts; -+ struct ptp_set_comp *p_comp; -+ struct fec_ptp_private *priv; -+ struct inode *inode = file->f_mapping->host; -+ unsigned int minor = MINOR(inode->i_rdev); -+ long retval = 0; -+ -+ priv = (struct fec_ptp_private *) ptp_private[minor]; -+ switch (cmd) { -+ case PTP_GET_RX_TIMESTAMP: -+ p_ts = (struct ptp_ts_data *)arg; -+ retval = fec_get_rx_time(priv, p_ts, &rx_time); -+ if (retval == 0) -+ copy_to_user((void __user *)(&(p_ts->ts)), &rx_time, -+ sizeof(rx_time)); -+ break; -+ case PTP_GET_TX_TIMESTAMP: -+ p_ts = (struct ptp_ts_data *)arg; -+ fec_get_tx_timestamp(priv, &tx_time); -+ copy_to_user((void __user *)(&(p_ts->ts)), &tx_time, -+ sizeof(tx_time)); -+ break; -+ case PTP_GET_CURRENT_TIME: -+ fec_get_curr_cnt(priv, &curr_time); -+ copy_to_user((void __user *)arg, &curr_time, sizeof(curr_time)); -+ break; -+ case PTP_SET_RTC_TIME: -+ cnt = (struct ptp_rtc_time *)arg; -+ fec_set_1588cnt(priv, cnt); -+ break; -+ case PTP_FLUSH_TIMESTAMP: -+ /* reset sync buffer */ -+ priv->rx_time_sync.head = 0; -+ priv->rx_time_sync.tail = 0; -+ /* reset delay_req buffer */ -+ priv->rx_time_del_req.head = 0; -+ priv->rx_time_del_req.tail = 0; -+ /* reset pdelay_req buffer */ -+ priv->rx_time_pdel_req.head = 0; -+ priv->rx_time_pdel_req.tail = 0; -+ /* reset pdelay_resp buffer */ -+ priv->rx_time_pdel_resp.head = 0; -+ priv->rx_time_pdel_resp.tail = 0; -+ break; -+ case PTP_SET_COMPENSATION: -+ p_comp = (struct ptp_set_comp *)arg; -+ fec_set_drift(priv, p_comp); -+ break; -+ case PTP_GET_ORIG_COMP: -+ ((struct ptp_get_comp *)arg)->dw_origcomp = FEC_PTP_ORIG_COMP; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return retval; -+} -+ -+static const struct file_operations ptp_fops = { -+ .owner = THIS_MODULE, -+ .llseek = NULL, -+ .read = NULL, -+ .write = NULL, -+ .unlocked_ioctl = ptp_unlocked_ioctl, -+ .open = ptp_open, -+ .release = ptp_release, -+}; -+ -+static int init_ptp(void) -+{ -+ if (register_chrdev(PTP_MAJOR, "ptp", &ptp_fops)) -+ printk(KERN_ERR "Unable to register PTP deivce as char\n"); -+ -+ return 0; -+} -+ -+static void ptp_free(void) -+{ -+ /*unregister the PTP device*/ -+ unregister_chrdev(PTP_MAJOR, "ptp"); -+} -+ -+ -+ -+/* -+ * Resource required for accessing 1588 Timer Registers. -+ */ -+int fec_ptp_init(struct fec_ptp_private *priv, int id) -+{ -+ fec_ptp_init_circ(&(priv->rx_time_sync)); -+ fec_ptp_init_circ(&(priv->rx_time_del_req)); -+ fec_ptp_init_circ(&(priv->rx_time_pdel_req)); -+ fec_ptp_init_circ(&(priv->rx_time_pdel_resp)); -+ -+ spin_lock_init(&priv->ptp_lock); -+ spin_lock_init(&priv->cnt_lock); -+ ptp_private[id] = priv; -+ if (id == 0) -+ init_ptp(); -+ return 0; -+} -+EXPORT_SYMBOL(fec_ptp_init); -+ -+void fec_ptp_cleanup(struct fec_ptp_private *priv) -+{ -+ -+ if (priv->rx_time_sync.buf) -+ vfree(priv->rx_time_sync.buf); -+ if (priv->rx_time_del_req.buf) -+ vfree(priv->rx_time_del_req.buf); -+ if (priv->rx_time_pdel_req.buf) -+ vfree(priv->rx_time_pdel_req.buf); -+ if (priv->rx_time_pdel_resp.buf) -+ vfree(priv->rx_time_pdel_resp.buf); -+ -+ ptp_free(); -+} -+EXPORT_SYMBOL(fec_ptp_cleanup); ---- /dev/null -+++ b/drivers/net/fec_1588.h -@@ -0,0 +1,195 @@ -+/* -+ * drivers/net/fec_1588.h -+ * -+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#ifndef FEC_1588_H -+#define FEC_1588_H -+ -+#include <linux/circ_buf.h> -+#include "fec.h" -+ -+#define fec_readl(addr) \ -+ ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; }) -+ -+#define fec_writel(b, addr) (void)((*(volatile unsigned int *) (addr)) = (b)) -+ -+#define FALSE 0 -+#define TRUE 1 -+ -+/* FEC 1588 register bits */ -+#define FEC_T_CTRL_CAPTURE 0x00000800 -+#define FEC_T_CTRL_RESTART 0x00000200 -+#define FEC_T_CTRL_PERIOD_RST 0x00000010 -+#define FEC_T_CTRL_PINPER 0x00000080 -+#define FEC_T_CTRL_ENABLE 0x00000001 -+ -+#define FEC_T_INC_MASK 0x0000007f -+#define FEC_T_INC_OFFSET 0 -+#define FEC_T_INC_CORR_MASK 0x00007f00 -+#define FEC_T_INC_CORR_OFFSET 8 -+ -+#define FEC_T_INC_40MHZ 8 -+#define FEC_ATIME_40MHZ 125000000 -+ -+#define FEC_T_PERIOD_ONE_SEC 0x3B9ACA00 -+ -+/* IEEE 1588 definition */ -+#define FEC_ECNTRL_TS_EN 0x10 -+#define PTP_MAJOR 232 /*the temporary major number -+ *used by PTP driver, the major -+ *number 232~239 is unassigned*/ -+ -+#define DEFAULT_PTP_RX_BUF_SZ 2048 -+#define PTP_MSG_SYNC 0x0 -+#define PTP_MSG_DEL_REQ 0x1 -+#define PTP_MSG_P_DEL_REQ 0x2 -+#define PTP_MSG_P_DEL_RESP 0x3 -+#define PTP_MSG_DEL_RESP 0x4 -+#define PTP_MSG_ALL_OTHER 0x5 -+ -+#define PTP_GET_TX_TIMESTAMP 0x1 -+#define PTP_GET_RX_TIMESTAMP 0x9 -+#define PTP_SET_RTC_TIME 0x3 -+#define PTP_SET_COMPENSATION 0x4 -+#define PTP_GET_CURRENT_TIME 0x5 -+#define PTP_FLUSH_TIMESTAMP 0x6 -+#define PTP_ADJ_ADDEND 0x7 -+#define PTP_GET_ORIG_COMP 0x8 -+#define PTP_GET_ADDEND 0xB -+#define PTP_GET_RX_TIMESTAMP_PDELAY_REQ 0xC -+#define PTP_GET_RX_TIMESTAMP_PDELAY_RESP 0xD -+ -+#define FEC_PTP_DOMAIN_DLFT 0xe0000181 -+#define FEC_PTP_IP_OFFS 0x0 -+#define FEC_PTP_UDP_OFFS 0x14 -+#define FEC_PTP_MSG_TYPE_OFFS 0x1C -+#define FEC_PTP_SEQ_ID_OFFS 0x3A -+#define FEC_PTP_COR_NS 0x24 -+#define FEC_PTP_CTRL_OFFS 0x3C -+#define FEC_PACKET_TYPE_UDP 0x11 -+ -+#define FEC_PTP_ORIG_COMP 0x15555 -+ -+/* PTP standard time representation structure */ -+struct ptp_time { -+ u64 sec; /* seconds */ -+ u32 nsec; /* nanoseconds */ -+}; -+ -+/* Structure for PTP Time Stamp */ -+struct fec_ptp_data_t { -+ int key; -+ struct ptp_time ts_time; -+}; -+ -+/* interface for PTP driver command GET_TX_TIME */ -+struct ptp_ts_data { -+ /* PTP version */ -+ u8 version; -+ /* PTP source port ID */ -+ u8 spid[10]; -+ /* PTP sequence ID */ -+ u16 seq_id; -+ /* PTP message type */ -+ u8 message_type; -+ /* PTP timestamp */ -+ struct ptp_time ts; -+}; -+ -+/* interface for PTP driver command SET_RTC_TIME/GET_CURRENT_TIME */ -+struct ptp_rtc_time { -+ struct ptp_time rtc_time; -+}; -+ -+/* interface for PTP driver command SET_COMPENSATION */ -+struct ptp_set_comp { -+ u32 drift; -+ u32 o_ops; -+}; -+ -+/* interface for PTP driver command GET_ORIG_COMP */ -+struct ptp_get_comp { -+ /* the initial compensation value */ -+ u32 dw_origcomp; -+ /* the minimum compensation value */ -+ u32 dw_mincomp; -+ /*the max compensation value*/ -+ u32 dw_maxcomp; -+ /*the min drift applying min compensation value in ppm*/ -+ u32 dw_mindrift; -+ /*the max drift applying max compensation value in ppm*/ -+ u32 dw_maxdrift; -+}; -+ -+struct ptp_time_correct { -+ u32 corr_period; -+ u32 corr_inc; -+}; -+ -+/* PTP message version */ -+#define PTP_1588_MSG_VER_1 1 -+#define PTP_1588_MSG_VER_2 2 -+ -+struct fec_ptp_private { -+ void __iomem *hwp; -+ -+ struct circ_buf rx_time_sync; -+ struct circ_buf rx_time_del_req; -+ struct circ_buf rx_time_pdel_req; -+ struct circ_buf rx_time_pdel_resp; -+ spinlock_t ptp_lock; -+ spinlock_t cnt_lock; -+ -+ u64 prtc; -+ struct ptp_time txstamp; -+}; -+ -+#ifdef CONFIG_FEC_1588 -+extern int fec_ptp_init(struct fec_ptp_private *priv, int id); -+extern void fec_ptp_cleanup(struct fec_ptp_private *priv); -+extern int fec_ptp_start(struct fec_ptp_private *priv); -+extern void fec_ptp_stop(struct fec_ptp_private *priv); -+extern int fec_ptp_do_txstamp(struct sk_buff *skb); -+extern void fec_ptp_store_txstamp(struct fec_ptp_private *priv); -+extern void fec_ptp_store_rxstamp(struct fec_ptp_private *priv, -+ struct sk_buff *skb, -+ struct bufdesc *bdp); -+#else -+static inline int fec_ptp_init(struct fec_ptp_private *priv, int id) -+{ -+ return 1; -+} -+static inline void fec_ptp_cleanup(struct fec_ptp_private *priv) { } -+static inline int fec_ptp_start(struct fec_ptp_private *priv) -+{ -+ return 1; -+} -+static inline void fec_ptp_stop(struct fec_ptp_private *priv) {} -+static inline int fec_ptp_do_txstamp(struct sk_buff *skb) -+{ -+ return 0; -+} -+static inline void fec_ptp_store_txstamp(struct fec_ptp_private *priv) {} -+static inline void fec_ptp_store_rxstamp(struct fec_ptp_private *priv, -+ struct sk_buff *skb, -+ struct bufdesc *bdp) {} -+#endif /* 1588 */ -+ -+#endif |