aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/fec.c
diff options
context:
space:
mode:
authorZeng Zhaoming <b32542@freescale.com>2011-07-05 09:19:52 +0800
committerEric Miao <eric.miao@canonical.com>2011-11-10 07:38:04 +0800
commit725bba66a9f5df8619ac7c5f38d51601e1587001 (patch)
treec8e216d93a034bcfbdb16a8a61114bb048ee291e /drivers/net/fec.c
parent9939169b50df57df9211acf5b1cab6096dbbe72a (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.c108
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)
{