diff options
Diffstat (limited to 'drivers/net/fec.c')
-rw-r--r-- | drivers/net/fec.c | 409 |
1 files changed, 323 insertions, 86 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index edfff92a6d8e..d0e2e690b66e 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -17,6 +17,9 @@ * * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. + * + * Support for FEC IEEE 1588. + * Copyright (C) 2010 Freescale Semiconductor, Inc. */ #include <linux/module.h> @@ -40,34 +43,29 @@ #include <linux/irq.h> #include <linux/clk.h> #include <linux/platform_device.h> +#include <linux/swab.h> #include <linux/phy.h> #include <linux/fec.h> #include <asm/cacheflush.h> #ifndef CONFIG_ARCH_MXC +#ifndef CONFIG_ARCH_MXS #include <asm/coldfire.h> #include <asm/mcfsim.h> #endif +#endif #include "fec.h" +#include "fec_1588.h" -#ifdef CONFIG_ARCH_MXC -#include <mach/hardware.h> +#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_ARCH_MXS) #define FEC_ALIGNMENT 0xf #else #define FEC_ALIGNMENT 0x3 #endif -/* - * Define the fixed address of the FEC hardware. - */ #if defined(CONFIG_M5272) - -static unsigned char fec_mac_default[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - /* * Some hardware gets it MAC address out of local flash memory. * if this is non-zero then assume it is the address to get MAC from. @@ -117,6 +115,15 @@ static unsigned char fec_mac_default[] = { #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) && defined(CONFIG_ARCH_MX28) +#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. */ @@ -131,7 +138,8 @@ static unsigned char fec_mac_default[] = { * account when setting it. */ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ + defined(CONFIG_ARCH_MXC) || defined(CONFIG_ARCH_MXS) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -187,8 +195,18 @@ struct fec_enet_private { int index; int link; int full_duplex; + struct completion mdio_done; + + struct fec_ptp_private *ptp_priv; + uint ptimer_present; }; +/* + * Define the fixed address of the FEC hardware. + */ +static unsigned char fec_mac_default[ETH_ALEN]; +static struct mii_bus *fec_mii_bus; + static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); @@ -205,11 +223,24 @@ static void fec_stop(struct net_device *dev); #define FEC_MMFR_TA (2 << 16) #define FEC_MMFR_DATA(v) (v & 0xffff) -#define FEC_MII_TIMEOUT 10000 +#define FEC_MII_TIMEOUT 1000 /* Transmitter timeout */ #define TX_TIMEOUT (2 * HZ) +#ifdef CONFIG_ARCH_MXS +static void *swap_buffer(void *bufaddr, int len) +{ + int i; + unsigned int *buf = bufaddr; + + for (i = 0; i < (len + 3) / 4; i++, buf++) + *buf = __swab32(*buf); + + return bufaddr; +} +#endif + static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -217,10 +248,12 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) struct bufdesc *bdp; void *bufaddr; unsigned short status; + unsigned long estatus; unsigned long flags; if (!fep->link) { /* Link is down or autonegotiation is in progress. */ + netif_stop_queue(dev); return NETDEV_TX_BUSY; } @@ -258,6 +291,21 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) bufaddr = fep->tx_bounce[index]; } + if (fep->ptimer_present) { + if (fec_ptp_do_txstamp(skb)) { + estatus = BD_ENET_TX_TS; + status |= BD_ENET_TX_PTP; + } else + estatus = 0; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = (estatus | BD_ENET_TX_INT); + bdp->cbd_bdu = 0; +#endif + } + +#ifdef CONFIG_ARCH_MXS + swap_buffer(bufaddr, skb->len); +#endif /* Save skb pointer */ fep->tx_skbuff[fep->skb_cur] = skb; @@ -314,6 +362,7 @@ fec_enet_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; struct fec_enet_private *fep = netdev_priv(dev); + struct fec_ptp_private *fpp = fep->ptp_priv; uint int_events; irqreturn_t ret = IRQ_NONE; @@ -334,6 +383,17 @@ fec_enet_interrupt(int irq, void * dev_id) ret = IRQ_HANDLED; fec_enet_tx(dev); } + + if (int_events & FEC_ENET_TS_TIMER) { + ret = IRQ_HANDLED; + if (fep->ptimer_present && fpp) + fpp->prtc++; + } + + if (int_events & FEC_ENET_MII) { + ret = IRQ_HANDLED; + complete(&fep->mdio_done); + } } while (int_events); return ret; @@ -344,11 +404,14 @@ static void fec_enet_tx(struct net_device *dev) { struct fec_enet_private *fep; + struct fec_ptp_private *fpp; struct bufdesc *bdp; unsigned short status; + unsigned long estatus; struct sk_buff *skb; fep = netdev_priv(dev); + fpp = fep->ptp_priv; spin_lock(&fep->hw_lock); bdp = fep->dirty_tx; @@ -388,6 +451,19 @@ fec_enet_tx(struct net_device *dev) if (status & BD_ENET_TX_DEF) dev->stats.collisions++; +#if defined(CONFIG_ENHANCED_BD) + if (fep->ptimer_present) { + estatus = bdp->cbd_esc; + if (estatus & BD_ENET_TX_TS) + fec_ptp_store_txstamp(fpp, skb, bdp); + } +#elif defined(CONFIG_IN_BAND) + if (fep->ptimer_present) { + if (status & BD_ENET_TX_PTP) + fec_ptp_store_txstamp(fpp, skb, bdp); + } +#endif + /* Free the sk buffer associated with this last transmit */ dev_kfree_skb_any(skb); fep->tx_skbuff[fep->skb_dirty] = NULL; @@ -421,6 +497,7 @@ static void fec_enet_rx(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); + struct fec_ptp_private *fpp = fep->ptp_priv; struct bufdesc *bdp; unsigned short status; struct sk_buff *skb; @@ -483,7 +560,9 @@ fec_enet_rx(struct net_device *dev) dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen, DMA_FROM_DEVICE); - +#ifdef CONFIG_ARCH_MXS + swap_buffer(data, pkt_len); +#endif /* This does 16 byte alignment, exactly what we need. * The packet length includes FCS, but we don't want to * include that when passing upstream as it messes up @@ -499,6 +578,9 @@ fec_enet_rx(struct net_device *dev) skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pkt_len - 4); /* Make room */ skb_copy_to_linear_data(skb, data, pkt_len - 4); + /* 1588 messeage TS handle */ + if (fep->ptimer_present) + fec_ptp_store_rxstamp(fpp, skb, bdp); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); } @@ -512,6 +594,11 @@ rx_processing_done: /* Mark the buffer empty */ status |= BD_ENET_RX_EMPTY; bdp->cbd_sc = status; +#ifdef CONFIG_ENHANCED_BD + 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) @@ -530,12 +617,13 @@ rx_processing_done: } /* ------------------------------------------------------------------------- */ -#ifdef CONFIG_M5272 static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); unsigned char *iap, tmpaddr[ETH_ALEN]; + static int index; +#ifdef CONFIG_M5272 if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. @@ -548,19 +636,26 @@ static void __inline__ fec_get_mac(struct net_device *dev) if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) iap = fec_mac_default; - } else { - *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW); - *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16); + } +#else + if (is_valid_ether_addr(fec_mac_default)) { + iap = fec_mac_default; + } +#endif + else { + *((unsigned long *) &tmpaddr[0]) = be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW)); + *((unsigned short *) &tmpaddr[4]) = be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16); iap = &tmpaddr[0]; } memcpy(dev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) - dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; + if (iap == fec_mac_default) { + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + index; + index++; +} } -#endif /* ------------------------------------------------------------------------- */ @@ -594,8 +689,15 @@ static void fec_enet_adjust_link(struct net_device *dev) /* Link on or off change */ if (phy_dev->link != fep->link) { fep->link = phy_dev->link; - if (phy_dev->link) + if (phy_dev->link) { fec_restart(dev, phy_dev->duplex); + + /* if link becomes up and tx be stopped, start it */ + if (netif_queue_stopped(dev)) { + netif_start_queue(dev); + netif_wake_queue(dev); + } + } else fec_stop(dev); status_change = 1; @@ -608,18 +710,13 @@ spin_unlock: phy_print_status(phy_dev); } -/* - * NOTE: a MII transaction is during around 25 us, so polling it... - */ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { struct fec_enet_private *fep = bus->priv; - int timeout = FEC_MII_TIMEOUT; + unsigned long time_left; fep->mii_timeout = 0; - - /* clear MII end of transfer bit*/ - writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); + init_completion(&fep->mdio_done); /* start a read op */ writel(FEC_MMFR_ST | FEC_MMFR_OP_READ | @@ -627,15 +724,13 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) FEC_MMFR_TA, fep->hwp + FEC_MII_DATA); /* wait for end of transfer */ - while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) { - cpu_relax(); - if (timeout-- < 0) { - fep->mii_timeout = 1; - printk(KERN_ERR "FEC: MDIO read timeout\n"); - return -ETIMEDOUT; - } + time_left = wait_for_completion_timeout(&fep->mdio_done, + usecs_to_jiffies(FEC_MII_TIMEOUT)); + if (time_left == 0) { + fep->mii_timeout = 1; + printk(KERN_ERR "FEC: MDIO read timeout\n"); + return -ETIMEDOUT; } - /* return value */ return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); } @@ -644,27 +739,24 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { struct fec_enet_private *fep = bus->priv; - int timeout = FEC_MII_TIMEOUT; + unsigned long time_left; fep->mii_timeout = 0; + init_completion(&fep->mdio_done); - /* clear MII end of transfer bit*/ - writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); - - /* start a read op */ - writel(FEC_MMFR_ST | FEC_MMFR_OP_READ | + /* start a write op */ + writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE | FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | FEC_MMFR_TA | FEC_MMFR_DATA(value), fep->hwp + FEC_MII_DATA); /* wait for end of transfer */ - while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) { - cpu_relax(); - if (timeout-- < 0) { - fep->mii_timeout = 1; - printk(KERN_ERR "FEC: MDIO write timeout\n"); - return -ETIMEDOUT; - } + time_left = wait_for_completion_timeout(&fep->mdio_done, + usecs_to_jiffies(FEC_MII_TIMEOUT)); + if (time_left == 0) { + fep->mii_timeout = 1; + printk(KERN_ERR "FEC: MDIO write timeout\n"); + return -ETIMEDOUT; } return 0; @@ -680,12 +772,15 @@ static int fec_enet_mii_probe(struct net_device *dev) struct fec_enet_private *fep = netdev_priv(dev); struct phy_device *phy_dev = NULL; int phy_addr; + int fec_index = fep->pdev->id > 0 ? fep->pdev->id : 0; fep->phy_dev = NULL; - /* find the first phy */ + /* find the phy, assuming fec index corresponds to addr */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { if (fep->mii_bus->phy_map[phy_addr]) { + if (fec_index--) + continue; phy_dev = fep->mii_bus->phy_map[phy_addr]; break; } @@ -699,7 +794,7 @@ static int fec_enet_mii_probe(struct net_device *dev) /* attach the mac to the phy */ phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &fec_enet_adjust_link, 0, - PHY_INTERFACE_MODE_MII); + fep->phy_interface); if (IS_ERR(phy_dev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); return PTR_ERR(phy_dev); @@ -721,7 +816,7 @@ static int fec_enet_mii_probe(struct net_device *dev) return 0; } -static int fec_enet_mii_init(struct platform_device *pdev) +static struct mii_bus *fec_enet_mii_init(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(dev); @@ -733,6 +828,10 @@ static int fec_enet_mii_init(struct platform_device *pdev) * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed) */ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; +#ifdef CONFIG_ARCH_MXS + /* Can't get phy(8720) ID when set to 2.5M on MX28, lower it*/ + fep->phy_speed <<= 2; +#endif writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); fep->mii_bus = mdiobus_alloc(); @@ -763,14 +862,14 @@ static int fec_enet_mii_init(struct platform_device *pdev) if (mdiobus_register(fep->mii_bus)) goto err_out_free_mdio_irq; - return 0; + return fep->mii_bus; err_out_free_mdio_irq: kfree(fep->mii_bus->irq); err_out_free_mdiobus: mdiobus_free(fep->mii_bus); err_out: - return err; + return ERR_PTR(err); } static void fec_enet_mii_remove(struct fec_enet_private *fep) @@ -834,7 +933,7 @@ static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!phydev) return -ENODEV; - return phy_mii_ioctl(phydev, if_mii(rq), cmd); + return phy_mii_ioctl(phydev, rq, cmd); } static void fec_enet_free_buffers(struct net_device *dev) @@ -880,6 +979,9 @@ static int fec_enet_alloc_buffers(struct net_device *dev) 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_ENHANCED_BD + bdp->cbd_esc = BD_ENET_RX_INT; +#endif bdp++; } @@ -893,6 +995,9 @@ static int fec_enet_alloc_buffers(struct net_device *dev) bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = BD_ENET_TX_INT; +#endif bdp++; } @@ -912,7 +1017,7 @@ fec_enet_open(struct net_device *dev) /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ - + clk_enable(fep->clk); ret = fec_enet_alloc_buffers(dev); if (ret) return ret; @@ -924,7 +1029,7 @@ fec_enet_open(struct net_device *dev) return ret; } phy_start(fep->phy_dev); - netif_start_queue(dev); + fec_restart(dev, fep->phy_dev->duplex); fep->opened = 1; return 0; } @@ -936,13 +1041,14 @@ fec_enet_close(struct net_device *dev) /* Don't know what to do yet. */ fep->opened = 0; - netif_stop_queue(dev); fec_stop(dev); - if (fep->phy_dev) + if (fep->phy_dev) { + phy_stop(fep->phy_dev); phy_disconnect(fep->phy_dev); - + } fec_enet_free_buffers(dev); + clk_disable(fep->clk); return 0; } @@ -1058,6 +1164,31 @@ static const struct net_device_ops fec_netdev_ops = { .ndo_do_ioctl = fec_enet_ioctl, }; +static int fec_mac_addr_setup(char *mac_addr) +{ + char *ptr, *p = mac_addr; + unsigned long tmp; + int i = 0, ret = 0; + + while (p && (*p) && i < 6) { + ptr = strchr(p, ':'); + if (ptr) + *ptr++ = '\0'; + + if (strlen(p)) { + ret = strict_strtoul(p, 16, &tmp); + if (ret < 0 || tmp > 0xff) + break; + fec_mac_default[i++] = tmp; + } + p = ptr; + } + + return 0; +} + +__setup("fec_mac=", fec_mac_addr_setup); + /* * XXX: We need to clean up on failure exits here. * @@ -1085,21 +1216,7 @@ static int fec_enet_init(struct net_device *dev, int index) fep->netdev = dev; /* Set the Ethernet address */ -#ifdef CONFIG_M5272 fec_get_mac(dev); -#else - { - unsigned long l; - l = readl(fep->hwp + FEC_ADDR_LOW); - dev->dev_addr[0] = (unsigned char)((l & 0xFF000000) >> 24); - dev->dev_addr[1] = (unsigned char)((l & 0x00FF0000) >> 16); - dev->dev_addr[2] = (unsigned char)((l & 0x0000FF00) >> 8); - dev->dev_addr[3] = (unsigned char)((l & 0x000000FF) >> 0); - l = readl(fep->hwp + FEC_ADDR_HIGH); - dev->dev_addr[4] = (unsigned char)((l & 0xFF000000) >> 24); - dev->dev_addr[5] = (unsigned char)((l & 0x00FF0000) >> 16); - } -#endif /* Set receive and transmit descriptor base. */ fep->rx_bd_base = cbd_base; @@ -1151,11 +1268,20 @@ fec_restart(struct net_device *dev, int duplex) { struct fec_enet_private *fep = netdev_priv(dev); int i; + uint ret = 0; + u32 temp_mac[2]; + unsigned long reg; + int val; /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); udelay(10); + /* Reset fec will reset MAC to zero, reconfig it again */ + memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); + writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); + writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); + /* Clear any outstanding interrupt. */ writel(0xffc00000, fep->hwp + FEC_IEVENT); @@ -1199,9 +1325,46 @@ fec_restart(struct net_device *dev, int duplex) } fep->full_duplex = duplex; +#ifdef CONFIG_ARCH_MXS + + reg = readl(fep->hwp + FEC_R_CNTRL); + + /* Enable flow control and length check */ + reg |= (0x40000000 | 0x00000020); + + /* Check MII or RMII */ + if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) + reg |= 0x00000100; + else + reg &= ~0x00000100; + + /* Check 10M or 100M */ + if (fep->phy_dev && fep->phy_dev->speed == SPEED_100) + reg &= ~0x00000200; /* 100M */ + else + reg |= 0x00000200; /* 10M */ + + writel(reg, fep->hwp + FEC_R_CNTRL); + +#endif /* Set MII speed */ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + if (fep->ptimer_present) { + /* Set Timer count */ + ret = fec_ptp_start(fep->ptp_priv); + if (ret) { + fep->ptimer_present = 0; + reg = 0x0; + } else +#ifdef CONFIG_ARCH_MX28 + reg = 0x00000010; +#else + reg = 0x0; +#endif + } else + reg = 0x0; + #ifdef FEC_MIIGSK_ENR if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { /* disable the gasket and wait */ @@ -1210,7 +1373,10 @@ fec_restart(struct net_device *dev, int duplex) udelay(1); /* configure the gasket: RMII, 50 MHz, no loopback, no echo */ - writel(1, fep->hwp + FEC_MIIGSK_CFGR); + val = 1; + if (fep->phy_dev && fep->phy_dev->speed == SPEED_10) + val |= 1 << 6; + writel(val, fep->hwp + FEC_MIIGSK_CFGR); /* re-enable the gasket */ writel(2, fep->hwp + FEC_MIIGSK_ENR); @@ -1218,11 +1384,12 @@ fec_restart(struct net_device *dev, int duplex) #endif /* And last, enable the transmit and receive processing */ - writel(2, fep->hwp + FEC_ECNTRL); + reg |= 0x00000002; + writel(reg, fep->hwp + FEC_ECNTRL); writel(0, fep->hwp + FEC_R_DES_ACTIVE); /* Enable interrupts we wish to service */ - writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK); + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); } static void @@ -1242,10 +1409,24 @@ fec_stop(struct net_device *dev) writel(1, fep->hwp + FEC_ECNTRL); udelay(10); +#ifdef CONFIG_ARCH_MXS + /* Check MII or RMII */ + if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) + writel(readl(fep->hwp + FEC_R_CNTRL) | 0x100, + fep->hwp + FEC_R_CNTRL); + else + writel(readl(fep->hwp + FEC_R_CNTRL) & ~0x100, + fep->hwp + FEC_R_CNTRL); +#endif /* Clear outstanding MII command interrupts. */ writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); - writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + if (fep->ptimer_present) + fec_ptp_stop(fep->ptp_priv); + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + + netif_stop_queue(dev); + fep->link = 0; } static int __devinit @@ -1290,6 +1471,9 @@ fec_probe(struct platform_device *pdev) if (pdata) fep->phy_interface = pdata->phy; + if (pdata && !is_valid_ether_addr(fec_mac_default)) + memcpy(fec_mac_default, pdata->mac, sizeof(fec_mac_default)); + /* This device has up to three irqs on some platforms */ for (i = 0; i < 3; i++) { irq = platform_get_irq(pdev, i); @@ -1313,22 +1497,63 @@ fec_probe(struct platform_device *pdev) } clk_enable(fep->clk); + /* PHY reset should be done during clock on */ + if (pdata && pdata->init) + ret = pdata->init(); + if (ret) + goto failed_platform_init; + /* + * The priority for getting MAC address is: + * (1) kernel command line fec_mac = xx:xx:xx... + * (2) platform data mac field got from fuse etc + * (3) bootloader set the FEC mac register + */ + + if (pdata && !is_valid_ether_addr(fec_mac_default) && + pdata->mac && is_valid_ether_addr(pdata->mac)) + memcpy(fec_mac_default, pdata->mac, + sizeof(fec_mac_default)); + ret = fec_enet_init(ndev, 0); if (ret) goto failed_init; - ret = fec_enet_mii_init(pdev); - if (ret) + if (pdev->id == 0) { + fec_mii_bus = fec_enet_mii_init(pdev); + if (IS_ERR(fec_mii_bus)) { + ret = -ENOMEM; goto failed_mii_init; + } + } else { + fep->mii_bus = fec_mii_bus; + } + + if (fec_ptp_malloc_priv(&(fep->ptp_priv))) { + if (fep->ptp_priv) { + fep->ptp_priv->hwp = fep->hwp; + ret = fec_ptp_init(fep->ptp_priv, pdev->id); + if (ret) + printk(KERN_WARNING + "IEEE1588: ptp-timer is unavailable\n"); + else + fep->ptimer_present = 1; + } else + printk(KERN_ERR "IEEE1588: failed to malloc memory\n"); + } ret = register_netdev(ndev); if (ret) goto failed_register; + clk_disable(fep->clk); + return 0; failed_register: fec_enet_mii_remove(fep); + if (fep->ptimer_present) + fec_ptp_cleanup(fep->ptp_priv); + kfree(fep->ptp_priv); failed_mii_init: failed_init: clk_disable(fep->clk); @@ -1342,6 +1567,7 @@ failed_clk: failed_irq: iounmap((void __iomem *)ndev->base_addr); failed_ioremap: +failed_platform_init: free_netdev(ndev); return ret; @@ -1352,14 +1578,20 @@ fec_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_platform_data *pdata = pdev->dev.platform_data; platform_set_drvdata(pdev, NULL); fec_stop(ndev); fec_enet_mii_remove(fep); + if (pdata && pdata->uninit) + pdata->uninit(); clk_disable(fep->clk); clk_put(fep->clk); iounmap((void __iomem *)ndev->base_addr); + if (fep->ptimer_present) + fec_ptp_cleanup(fep->ptp_priv); + kfree(fep->ptp_priv); unregister_netdev(ndev); free_netdev(ndev); return 0; @@ -1373,9 +1605,12 @@ fec_suspend(struct platform_device *dev, pm_message_t state) if (ndev) { fep = netdev_priv(ndev); - if (netif_running(ndev)) - fec_enet_close(ndev); - clk_disable(fep->clk); + if (netif_running(ndev)) { + netif_device_detach(ndev); + fec_stop(ndev); + netif_carrier_off(ndev); + clk_disable(fep->clk); + } } return 0; } @@ -1388,9 +1623,11 @@ fec_resume(struct platform_device *dev) if (ndev) { fep = netdev_priv(ndev); - clk_enable(fep->clk); - if (netif_running(ndev)) - fec_enet_open(ndev); + if (netif_running(ndev)) { + clk_enable(fep->clk); + fec_restart(ndev, fep->full_duplex); + netif_device_attach(ndev); + } } return 0; } |