diff options
author | Zeng Zhaoming <b32542@freescale.com> | 2011-07-05 09:19:52 +0800 |
---|---|---|
committer | Eric Miao <eric.miao@canonical.com> | 2011-11-10 07:38:04 +0800 |
commit | 725bba66a9f5df8619ac7c5f38d51601e1587001 (patch) | |
tree | c8e216d93a034bcfbdb16a8a61114bb048ee291e /drivers/net/fec.c | |
parent | 9939169b50df57df9211acf5b1cab6096dbbe72a (diff) |
ENGR00152528-2 ENET: add enet support for mx6q.
Enabled all speed mode, 10M/100M/1G.
add "fec_mac" kernel parameter to set mac address.
Since clock and board rework issue, some hard code
stays to make it work.
Signed-off-by: Zeng Zhaoming <b32542@freescale.com>
Diffstat (limited to 'drivers/net/fec.c')
-rw-r--r-- | drivers/net/fec.c | 108 |
1 files changed, 101 insertions, 7 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index cd0282d5d40..3261fd4db0a 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -18,7 +18,7 @@ * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. * - * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. */ #include <linux/module.h> @@ -68,10 +68,18 @@ #define FEC_QUIRK_SWAP_FRAME (1 << 1) static struct platform_device_id fec_devtype[] = { +#ifdef CONFIG_SOC_IMX6Q + { + .name = DRIVER_NAME, + .driver_data = FEC_QUIRK_ENET_MAC, + }, +#else { .name = DRIVER_NAME, .driver_data = 0, - }, { + }, +#endif + { .name = "imx28-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, }, @@ -722,6 +730,31 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, return 0; } +#ifdef CONFIG_MACH_MX6Q_SABREAUTO + +static int mx6_sabreauto_rework(struct mii_bus *bus) +{ + unsigned short val; + + /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ + fec_enet_mdio_write(bus, 0, 0xd, 0x7); + fec_enet_mdio_write(bus, 0, 0xe, 0x8016); + fec_enet_mdio_write(bus, 0, 0xd, 0x4007); + val = fec_enet_mdio_read(bus, 0, 0xe); + + val &= 0xffe3; + val |= 0x18; + fec_enet_mdio_write(bus, 0, 0xe, val); + + /* introduce tx clock delay */ + fec_enet_mdio_write(bus, 0, 0x1d, 0x5); + val = fec_enet_mdio_read(bus, 0, 0x1e); + val |= 0x0100; + fec_enet_mdio_write(bus, 0, 0x1e, val); + + return 0; +} +#endif static int fec_enet_mdio_reset(struct mii_bus *bus) { @@ -762,14 +795,19 @@ static int fec_enet_mii_probe(struct net_device *dev) snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); phy_dev = phy_connect(dev, phy_name, &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); } /* mask with MAC supported features */ - phy_dev->supported &= PHY_BASIC_FEATURES; + if (cpu_is_mx6q()) + phy_dev->supported &= PHY_GBIT_FEATURES; + else + phy_dev->supported &= PHY_BASIC_FEATURES; + phy_dev->advertising = phy_dev->supported; fep->phy_dev = phy_dev; @@ -821,6 +859,11 @@ 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_MACH_MX6Q_SABREAUTO + /* FIXME: hard code to 0x1a for clock issue */ + fep->phy_speed = 0x11a; +#endif writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); fep->mii_bus = mdiobus_alloc(); @@ -837,6 +880,10 @@ static int fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->priv = fep; fep->mii_bus->parent = &pdev->dev; +#ifdef CONFIG_MACH_MX6Q_SABREAUTO + mx6_sabreauto_rework(fep->mii_bus); +#endif + fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!fep->mii_bus->irq) { err = -ENOMEM; @@ -1015,6 +1062,7 @@ fec_enet_open(struct net_device *dev) fec_enet_free_buffers(dev); return ret; } + phy_start(fep->phy_dev); netif_start_queue(dev); fep->opened = 1; @@ -1299,7 +1347,9 @@ fec_restart(struct net_device *dev, int duplex) val = readl(fep->hwp + FEC_R_CNTRL); /* MII or RMII */ - if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) + if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII) + val |= (1 << 6); + else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) val |= (1 << 8); else val &= ~(1 << 8); @@ -1331,8 +1381,22 @@ fec_restart(struct net_device *dev, int duplex) #endif } - /* And last, enable the transmit and receive processing */ - writel(2, fep->hwp + FEC_ECNTRL); + /* ENET enable */ + val = (0x1 << 1); + + /* if phy work at 1G mode, set ENET RGMII speed to 1G */ + if (fep->phy_dev && fep->phy_dev->supported == PHY_GBIT_FEATURES && + fep->phy_dev->speed == SPEED_1000) + val |= (0x1 << 5); + + if (cpu_is_mx6q()) { + /* enable endian swap */ + val |= (0x1 << 8); + /* enable ENET store and forward mode */ + writel(0x1 << 8, fep->hwp + FEC_X_WMRK); + } + writel(val, fep->hwp + FEC_ECNTRL); + writel(0, fep->hwp + FEC_R_DES_ACTIVE); /* Enable interrupts we wish to service */ @@ -1355,6 +1419,11 @@ fec_stop(struct net_device *dev) /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); udelay(10); + + if (cpu_is_mx6q()) + /* FIXME: we have to enable enet to keep mii interrupt works. */ + writel(2, fep->hwp + FEC_ECNTRL); + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); } @@ -1537,6 +1606,31 @@ static struct platform_driver fec_driver = { .remove = __devexit_p(fec_drv_remove), }; +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; + macaddr[i++] = tmp; + } + p = ptr; + } + + return 0; +} + +__setup("fec_mac=", fec_mac_addr_setup); + static int __init fec_enet_module_init(void) { |