diff --git a/common/Makefile b/common/Makefile
index 048df0c..00847ef 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -114,6 +114,7 @@ COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o
 COBJS-$(CONFIG_CMD_MG_DISK) += cmd_mgdisk.o
 COBJS-$(CONFIG_MII) += miiphyutil.o
 COBJS-$(CONFIG_CMD_MII) += miiphyutil.o
+COBJS-$(CONFIG_PHYLIB) += miiphyutil.o
 COBJS-$(CONFIG_CMD_MII) += cmd_mii.o
 COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o
 COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o
diff --git a/common/miiphyutil.c b/common/miiphyutil.c
index e282096..10adb52 100644
--- a/common/miiphyutil.c
+++ b/common/miiphyutil.c
@@ -28,6 +28,7 @@
 
 #include <common.h>
 #include <miiphy.h>
+#include <phy.h>
 
 #include <asm/types.h>
 #include <linux/list.h>
@@ -39,27 +40,18 @@
 
 #undef debug
 #ifdef MII_DEBUG
-#define debug(fmt,args...)	printf (fmt ,##args)
+#define debug(fmt, args...)	printf(fmt, ##args)
 #else
-#define debug(fmt,args...)
+#define debug(fmt, args...)
 #endif /* MII_DEBUG */
 
-struct mii_dev {
-	struct list_head link;
-	const char *name;
-	int (*read) (const char *devname, unsigned char addr,
-		     unsigned char reg, unsigned short *value);
-	int (*write) (const char *devname, unsigned char addr,
-		      unsigned char reg, unsigned short value);
-};
-
 static struct list_head mii_devs;
 static struct mii_dev *current_mii;
 
 /*
  * Lookup the mii_dev struct by the registered device name.
  */
-static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet)
+struct mii_dev *miiphy_get_dev_by_name(const char *devname)
 {
 	struct list_head *entry;
 	struct mii_dev *dev;
@@ -75,8 +67,6 @@ static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet)
 			return dev;
 	}
 
-	if (!quiet)
-		printf("No such device: %s\n", devname);
 	return NULL;
 }
 
@@ -90,70 +80,193 @@ void miiphy_init(void)
 	current_mii = NULL;
 }
 
+static int legacy_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	unsigned short val;
+	int ret;
+	struct legacy_mii_dev *ldev = bus->priv;
+
+	ret = ldev->read(bus->name, addr, reg, &val);
+
+	return ret ? -1 : (int)val;
+}
+
+static int legacy_miiphy_write(struct mii_dev *bus, int addr, int devad,
+				int reg, u16 val)
+{
+	struct legacy_mii_dev *ldev = bus->priv;
+
+	return ldev->write(bus->name, addr, reg, val);
+}
+
 /*****************************************************************************
  *
  * Register read and write MII access routines for the device <name>.
  */
 void miiphy_register(const char *name,
-		      int (*read) (const char *devname, unsigned char addr,
+		      int (*read)(const char *devname, unsigned char addr,
 				   unsigned char reg, unsigned short *value),
-		      int (*write) (const char *devname, unsigned char addr,
+		      int (*write)(const char *devname, unsigned char addr,
 				    unsigned char reg, unsigned short value))
 {
 	struct mii_dev *new_dev;
+	struct legacy_mii_dev *ldev;
 	unsigned int name_len;
 	char *new_name;
 
 	/* check if we have unique name */
-	new_dev = miiphy_get_dev_by_name(name, 1);
+	new_dev = miiphy_get_dev_by_name(name);
 	if (new_dev) {
 		printf("miiphy_register: non unique device name '%s'\n", name);
 		return;
 	}
 
 	/* allocate memory */
-	name_len = strlen (name);
-	new_dev =
-	    (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1);
+	name_len = strlen(name);
+	new_dev = malloc(sizeof(struct mii_dev) + name_len + 1);
+	ldev = malloc(sizeof(*ldev));
 
-	if (new_dev == NULL) {
-		printf ("miiphy_register: cannot allocate memory for '%s'\n",
+	if (new_dev == NULL || ldev == NULL) {
+		printf("miiphy_register: cannot allocate memory for '%s'\n",
 			name);
 		return;
 	}
-	memset (new_dev, 0, sizeof (struct mii_dev) + name_len);
+	memset(new_dev, 0, sizeof(struct mii_dev) + name_len);
 
 	/* initalize mii_dev struct fields */
-	INIT_LIST_HEAD (&new_dev->link);
-	new_dev->read = read;
-	new_dev->write = write;
+	INIT_LIST_HEAD(&new_dev->link);
+	new_dev->read = legacy_miiphy_read;
+	new_dev->write = legacy_miiphy_write;
 	new_dev->name = new_name = (char *)(new_dev + 1);
-	strncpy (new_name, name, name_len);
+	strncpy(new_name, name, name_len);
 	new_name[name_len] = '\0';
+	ldev->read = read;
+	ldev->write = write;
+	new_dev->priv = ldev;
 
-	debug ("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
-	       new_dev->name, new_dev->read, new_dev->write);
+	debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
+	       new_dev->name, ldev->read, ldev->write);
 
 	/* add it to the list */
-	list_add_tail (&new_dev->link, &mii_devs);
+	list_add_tail(&new_dev->link, &mii_devs);
 
 	if (!current_mii)
 		current_mii = new_dev;
 }
 
+struct mii_dev *mdio_alloc(void)
+{
+	struct mii_dev *bus;
+
+	bus = malloc(sizeof(*bus));
+	if (!bus)
+		return bus;
+
+	memset(bus, 0, sizeof(*bus));
+
+	bus->name = malloc(MDIO_NAME_LEN);
+	if (!bus->name) {
+		printf("Could not allocate name for mii_dev\n");
+		free(bus);
+		return NULL;
+	}
+
+	memset(bus->name, 0, MDIO_NAME_LEN);
+
+	/* initalize mii_dev struct fields */
+	INIT_LIST_HEAD(&bus->link);
+
+	return bus;
+}
+
+int mdio_register(struct mii_dev *bus)
+{
+	if (!bus || !bus->name || !bus->read || !bus->write)
+		return -1;
+
+	/* check if we have unique name */
+	if (miiphy_get_dev_by_name(bus->name)) {
+		printf("mdio_register: non unique device name '%s'\n",
+			bus->name);
+		return -1;
+	}
+
+	/* add it to the list */
+	list_add_tail(&bus->link, &mii_devs);
+
+	if (!current_mii)
+		current_mii = bus;
+
+	return 0;
+}
+
+void mdio_list_devices(void)
+{
+	struct list_head *entry;
+
+	list_for_each(entry, &mii_devs) {
+		int i;
+		struct mii_dev *bus = list_entry(entry, struct mii_dev, link);
+
+		printf("%s:\n", bus->name);
+
+		for (i = 0; i < PHY_MAX_ADDR; i++) {
+			struct phy_device *phydev = bus->phymap[i];
+
+			if (phydev) {
+				printf("%d - %s", i, phydev->drv->name);
+
+				if (phydev->dev)
+					printf(" <--> %s\n", phydev->dev->name);
+				else
+					printf("\n");
+			}
+		}
+	}
+}
+
 int miiphy_set_current_dev(const char *devname)
 {
 	struct mii_dev *dev;
 
-	dev = miiphy_get_dev_by_name(devname, 0);
+	dev = miiphy_get_dev_by_name(devname);
 	if (dev) {
 		current_mii = dev;
 		return 0;
 	}
 
+	printf("No such device: %s\n", devname);
+
 	return 1;
 }
 
+struct mii_dev *mdio_get_current_dev(void)
+{
+	return current_mii;
+}
+
+struct phy_device *mdio_phydev_for_ethname(const char *ethname)
+{
+	struct list_head *entry;
+	struct mii_dev *bus;
+
+	list_for_each(entry, &mii_devs) {
+		int i;
+		bus = list_entry(entry, struct mii_dev, link);
+
+		for (i = 0; i < PHY_MAX_ADDR; i++) {
+			if ((!bus->phymap[i]) || (!bus->phymap[i]->dev))
+				continue;
+
+			if (strcmp(bus->phymap[i]->dev->name, ethname) == 0)
+				return bus->phymap[i];
+		}
+	}
+
+	printf("%s is not a known ethernet\n", ethname);
+	return NULL;
+}
+
 const char *miiphy_get_current_dev(void)
 {
 	if (current_mii)
@@ -187,13 +300,15 @@ static struct mii_dev *miiphy_get_active_dev(const char *devname)
 int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
 		 unsigned short *value)
 {
-	struct mii_dev *dev;
+	struct mii_dev *bus;
 
-	dev = miiphy_get_active_dev(devname);
-	if (dev)
-		return dev->read(devname, addr, reg, value);
+	bus = miiphy_get_active_dev(devname);
+	if (bus)
+		*value = bus->read(bus, addr, MDIO_DEVAD_NONE, reg);
+	else
+		return 1;
 
-	return 1;
+	return (*value < 0) ? 1 : 0;
 }
 
 /*****************************************************************************
@@ -207,11 +322,11 @@ int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
 int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
 		  unsigned short value)
 {
-	struct mii_dev *dev;
+	struct mii_dev *bus;
 
-	dev = miiphy_get_active_dev(devname);
-	if (dev)
-		return dev->write(devname, addr, reg, value);
+	bus = miiphy_get_active_dev(devname);
+	if (bus)
+		return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value);
 
 	return 1;
 }
@@ -220,20 +335,20 @@ int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
  *
  * Print out list of registered MII capable devices.
  */
-void miiphy_listdev (void)
+void miiphy_listdev(void)
 {
 	struct list_head *entry;
 	struct mii_dev *dev;
 
-	puts ("MII devices: ");
-	list_for_each (entry, &mii_devs) {
-		dev = list_entry (entry, struct mii_dev, link);
-		printf ("'%s' ", dev->name);
+	puts("MII devices: ");
+	list_for_each(entry, &mii_devs) {
+		dev = list_entry(entry, struct mii_dev, link);
+		printf("'%s' ", dev->name);
 	}
-	puts ("\n");
+	puts("\n");
 
 	if (current_mii)
-		printf ("Current device: '%s'\n", current_mii->name);
+		printf("Current device: '%s'\n", current_mii->name);
 }
 
 /*****************************************************************************
@@ -253,30 +368,30 @@ int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui,
 	unsigned int reg = 0;
 	unsigned short tmp;
 
-	if (miiphy_read (devname, addr, MII_PHYSID2, &tmp) != 0) {
-		debug ("PHY ID register 2 read failed\n");
-		return (-1);
+	if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) {
+		debug("PHY ID register 2 read failed\n");
+		return -1;
 	}
 	reg = tmp;
 
-	debug ("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg);
+	debug("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg);
 
 	if (reg == 0xFFFF) {
 		/* No physical device present at this address */
-		return (-1);
+		return -1;
 	}
 
-	if (miiphy_read (devname, addr, MII_PHYSID1, &tmp) != 0) {
-		debug ("PHY ID register 1 read failed\n");
-		return (-1);
+	if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) {
+		debug("PHY ID register 1 read failed\n");
+		return -1;
 	}
 	reg |= tmp << 16;
-	debug ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
+	debug("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
 
 	*oui = (reg >> 10);
 	*model = (unsigned char)((reg >> 4) & 0x0000003F);
 	*rev = (unsigned char)(reg & 0x0000000F);
-	return (0);
+	return 0;
 }
 
 /*****************************************************************************
@@ -290,16 +405,16 @@ int miiphy_reset(const char *devname, unsigned char addr)
 	unsigned short reg;
 	int timeout = 500;
 
-	if (miiphy_read (devname, addr, MII_BMCR, &reg) != 0) {
-		debug ("PHY status read failed\n");
-		return (-1);
+	if (miiphy_read(devname, addr, MII_BMCR, &reg) != 0) {
+		debug("PHY status read failed\n");
+		return -1;
 	}
-	if (miiphy_write (devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) {
-		debug ("PHY reset failed\n");
-		return (-1);
+	if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) {
+		debug("PHY reset failed\n");
+		return -1;
 	}
 #ifdef CONFIG_PHY_RESET_DELAY
-	udelay (CONFIG_PHY_RESET_DELAY);	/* Intel LXT971A needs this */
+	udelay(CONFIG_PHY_RESET_DELAY);	/* Intel LXT971A needs this */
 #endif
 	/*
 	 * Poll the control register for the reset bit to go to 0 (it is
@@ -315,12 +430,12 @@ int miiphy_reset(const char *devname, unsigned char addr)
 		udelay(1000);
 	}
 	if ((reg & 0x8000) == 0) {
-		return (0);
+		return 0;
 	} else {
-		puts ("PHY reset timed out\n");
-		return (-1);
+		puts("PHY reset timed out\n");
+		return -1;
 	}
-	return (0);
+	return 0;
 }
 
 /*****************************************************************************
@@ -338,33 +453,32 @@ int miiphy_speed(const char *devname, unsigned char addr)
 	 * Check for 1000BASE-X.  If it is supported, then assume that the speed
 	 * is 1000.
 	 */
-	if (miiphy_is_1000base_x (devname, addr)) {
+	if (miiphy_is_1000base_x(devname, addr))
 		return _1000BASET;
-	}
+
 	/*
 	 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
 	 */
 	/* Check for 1000BASE-T. */
-	if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) {
-		printf ("PHY 1000BT status");
+	if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
+		printf("PHY 1000BT status");
 		goto miiphy_read_failed;
 	}
 	if (btsr != 0xFFFF &&
-	    (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) {
+			(btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)))
 		return _1000BASET;
-	}
 #endif /* CONFIG_PHY_GIGE */
 
 	/* Check Basic Management Control Register first. */
-	if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) {
-		printf ("PHY speed");
+	if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
+		printf("PHY speed");
 		goto miiphy_read_failed;
 	}
 	/* Check if auto-negotiation is on. */
 	if (bmcr & BMCR_ANENABLE) {
 		/* Get auto-negotiation results. */
-		if (miiphy_read (devname, addr, MII_LPA, &anlpar)) {
-			printf ("PHY AN speed");
+		if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
+			printf("PHY AN speed");
 			goto miiphy_read_failed;
 		}
 		return (anlpar & LPA_100) ? _100BASET : _10BASET;
@@ -373,7 +487,7 @@ int miiphy_speed(const char *devname, unsigned char addr)
 	return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET;
 
 miiphy_read_failed:
-	printf (" read failed, assuming 10BASE-T\n");
+	printf(" read failed, assuming 10BASE-T\n");
 	return _10BASET;
 }
 
@@ -389,10 +503,10 @@ int miiphy_duplex(const char *devname, unsigned char addr)
 	u16 btsr;
 
 	/* Check for 1000BASE-X. */
-	if (miiphy_is_1000base_x (devname, addr)) {
+	if (miiphy_is_1000base_x(devname, addr)) {
 		/* 1000BASE-X */
-		if (miiphy_read (devname, addr, MII_LPA, &anlpar)) {
-			printf ("1000BASE-X PHY AN duplex");
+		if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
+			printf("1000BASE-X PHY AN duplex");
 			goto miiphy_read_failed;
 		}
 	}
@@ -400,8 +514,8 @@ int miiphy_duplex(const char *devname, unsigned char addr)
 	 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
 	 */
 	/* Check for 1000BASE-T. */
-	if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) {
-		printf ("PHY 1000BT status");
+	if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
+		printf("PHY 1000BT status");
 		goto miiphy_read_failed;
 	}
 	if (btsr != 0xFFFF) {
@@ -414,15 +528,15 @@ int miiphy_duplex(const char *devname, unsigned char addr)
 #endif /* CONFIG_PHY_GIGE */
 
 	/* Check Basic Management Control Register first. */
-	if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) {
-		puts ("PHY duplex");
+	if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
+		puts("PHY duplex");
 		goto miiphy_read_failed;
 	}
 	/* Check if auto-negotiation is on. */
 	if (bmcr & BMCR_ANENABLE) {
 		/* Get auto-negotiation results. */
-		if (miiphy_read (devname, addr, MII_LPA, &anlpar)) {
-			puts ("PHY AN duplex");
+		if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
+			puts("PHY AN duplex");
 			goto miiphy_read_failed;
 		}
 		return (anlpar & (LPA_10FULL | LPA_100FULL)) ?
@@ -432,7 +546,7 @@ int miiphy_duplex(const char *devname, unsigned char addr)
 	return (bmcr & BMCR_FULLDPLX) ? FULL : HALF;
 
 miiphy_read_failed:
-	printf (" read failed, assuming half duplex\n");
+	printf(" read failed, assuming half duplex\n");
 	return HALF;
 }
 
@@ -446,8 +560,8 @@ int miiphy_is_1000base_x(const char *devname, unsigned char addr)
 #if defined(CONFIG_PHY_GIGE)
 	u16 exsr;
 
-	if (miiphy_read (devname, addr, MII_ESTATUS, &exsr)) {
-		printf ("PHY extended status read failed, assuming no "
+	if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) {
+		printf("PHY extended status read failed, assuming no "
 			"1000BASE-X\n");
 		return 0;
 	}
@@ -467,17 +581,17 @@ int miiphy_link(const char *devname, unsigned char addr)
 	unsigned short reg;
 
 	/* dummy read; needed to latch some phys */
-	(void)miiphy_read (devname, addr, MII_BMSR, &reg);
-	if (miiphy_read (devname, addr, MII_BMSR, &reg)) {
-		puts ("MII_BMSR read failed, assuming no link\n");
-		return (0);
+	(void)miiphy_read(devname, addr, MII_BMSR, &reg);
+	if (miiphy_read(devname, addr, MII_BMSR, &reg)) {
+		puts("MII_BMSR read failed, assuming no link\n");
+		return 0;
 	}
 
 	/* Determine if a link is active */
 	if ((reg & BMSR_LSTATUS) != 0) {
-		return (1);
+		return 1;
 	} else {
-		return (0);
+		return 0;
 	}
 }
 #endif
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index bba8901..7cb1094 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -27,6 +27,7 @@ LIB	:= $(obj)libphy.o
 
 COBJS-$(CONFIG_BITBANGMII) += miiphybb.o
 COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
+COBJS-$(CONFIG_PHYLIB) += phy.o
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
new file mode 100644
index 0000000..fc34271
--- /dev/null
+++ b/drivers/net/phy/phy.c
@@ -0,0 +1,719 @@
+/*
+ * Generic PHY Management code
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * author Andy Fleming
+ *
+ * Based loosely off of Linux's PHY Lib
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <errno.h>
+
+int phy_read(struct phy_device *phydev, int devad, int regnum)
+{
+	struct mii_dev *bus = phydev->bus;
+
+	return bus->read(bus, phydev->addr, devad, regnum);
+}
+
+int phy_write(struct phy_device *phydev, int devad, int regnum, u16 val)
+{
+	struct mii_dev *bus = phydev->bus;
+
+	return bus->write(bus, phydev->addr, devad, regnum, val);
+}
+
+
+int gen10g_shutdown(struct phy_device *phydev)
+{
+	return 0;
+}
+
+int gen10g_startup(struct phy_device *phydev)
+{
+	int devad, reg;
+	u32 mmd_mask = phydev->mmds;
+
+	phydev->link = 1;
+
+	/* For now just lie and say it's 10G all the time */
+	phydev->speed = SPEED_10000;
+	phydev->duplex = DUPLEX_FULL;
+
+	for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) {
+		if (!mmd_mask & 1)
+			continue;
+
+		/* Read twice because link state is latched and a
+		 * read moves the current state into the register */
+		phy_read(phydev, devad, MDIO_STAT1);
+		reg = phy_read(phydev, devad, MDIO_STAT1);
+		if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
+			phydev->link = 0;
+	}
+
+	return 0;
+}
+
+int gen10g_config(struct phy_device *phydev)
+{
+	int mmd, stat2, devs1, devs2;
+
+	phydev->supported = phydev->advertising = SUPPORTED_10000baseT_Full;
+
+	/* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY
+	 * XS or DTE XS; give up if none is present. */
+	for (mmd = 1; mmd <= 5; mmd++) {
+		/* Is this MMD present? */
+		stat2 = phy_read(phydev, mmd, MDIO_STAT2);
+		if (stat2 < 0 ||
+			(stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL)
+			continue;
+
+		/* It should tell us about all the other MMDs */
+		devs1 = phy_read(phydev, mmd, MDIO_DEVS1);
+		devs2 = phy_read(phydev, mmd, MDIO_DEVS2);
+		if (devs1 < 0 || devs2 < 0)
+			continue;
+
+		phydev->mmds = devs1 | (devs2 << 16);
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static struct phy_driver gen10g_driver = {
+	.uid		= 0xffffffff,
+	.mask		= 0xffffffff,
+	.name		= "Generic 10G PHY",
+	.features	= 0,
+	.config		= gen10g_config,
+	.startup	= gen10g_startup,
+	.shutdown	= gen10g_shutdown,
+};
+
+/* Generic PHY support and helper functions */
+
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotation parameters
+ * @phydev: target phy_device struct
+ *
+ * Description: Writes MII_ADVERTISE with the appropriate values,
+ *   after sanitizing the values to make sure we only advertise
+ *   what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
+ *   hasn't changed, and > 0 if it has changed.
+ */
+int genphy_config_advert(struct phy_device *phydev)
+{
+	u32 advertise;
+	int oldadv, adv;
+	int err, changed = 0;
+
+	/* Only allow advertising what
+	 * this PHY supports */
+	phydev->advertising &= phydev->supported;
+	advertise = phydev->advertising;
+
+	/* Setup standard advertisement */
+	oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+
+	if (adv < 0)
+		return adv;
+
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+		 ADVERTISE_PAUSE_ASYM);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |= ADVERTISE_100FULL;
+	if (advertise & ADVERTISED_Pause)
+		adv |= ADVERTISE_PAUSE_CAP;
+	if (advertise & ADVERTISED_Asym_Pause)
+		adv |= ADVERTISE_PAUSE_ASYM;
+
+	if (adv != oldadv) {
+		err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv);
+
+		if (err < 0)
+			return err;
+		changed = 1;
+	}
+
+	/* Configure gigabit if it's supported */
+	if (phydev->supported & (SUPPORTED_1000baseT_Half |
+				SUPPORTED_1000baseT_Full)) {
+		oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+
+		if (adv < 0)
+			return adv;
+
+		adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+		if (advertise & SUPPORTED_1000baseT_Half)
+			adv |= ADVERTISE_1000HALF;
+		if (advertise & SUPPORTED_1000baseT_Full)
+			adv |= ADVERTISE_1000FULL;
+
+		if (adv != oldadv) {
+			err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
+					adv);
+
+			if (err < 0)
+				return err;
+			changed = 1;
+		}
+	}
+
+	return changed;
+}
+
+
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Configures MII_BMCR to force speed/duplex
+ *   to the values in phydev. Assumes that the values are valid.
+ */
+int genphy_setup_forced(struct phy_device *phydev)
+{
+	int err;
+	int ctl = 0;
+
+	phydev->pause = phydev->asym_pause = 0;
+
+	if (SPEED_1000 == phydev->speed)
+		ctl |= BMCR_SPEED1000;
+	else if (SPEED_100 == phydev->speed)
+		ctl |= BMCR_SPEED100;
+
+	if (DUPLEX_FULL == phydev->duplex)
+		ctl |= BMCR_FULLDPLX;
+
+	err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
+
+	return err;
+}
+
+
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
+int genphy_restart_aneg(struct phy_device *phydev)
+{
+	int ctl;
+
+	ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+	if (ctl < 0)
+		return ctl;
+
+	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+	/* Don't isolate the PHY if we're negotiating */
+	ctl &= ~(BMCR_ISOLATE);
+
+	ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
+
+	return ctl;
+}
+
+
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ *   advertising, and then restart auto-negotiation.  If it is not
+ *   enabled, then we write the BMCR.
+ */
+int genphy_config_aneg(struct phy_device *phydev)
+{
+	int result;
+
+	if (AUTONEG_ENABLE != phydev->autoneg)
+		return genphy_setup_forced(phydev);
+
+	result = genphy_config_advert(phydev);
+
+	if (result < 0) /* error */
+		return result;
+
+	if (result == 0) {
+		/* Advertisment hasn't changed, but maybe aneg was never on to
+		 * begin with?  Or maybe phy was isolated? */
+		int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+		if (ctl < 0)
+			return ctl;
+
+		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
+			result = 1; /* do restart aneg */
+	}
+
+	/* Only restart aneg if we are advertising something different
+	 * than we were before.	 */
+	if (result > 0)
+		result = genphy_restart_aneg(phydev);
+
+	return result;
+}
+
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Update the value in phydev->link to reflect the
+ *   current link value.  In order to do this, we need to read
+ *   the status register twice, keeping the second value.
+ */
+int genphy_update_link(struct phy_device *phydev)
+{
+	unsigned int mii_reg;
+
+	/*
+	 * Wait if the link is up, and autonegotiation is in progress
+	 * (ie - we're capable and it's not done)
+	 */
+	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+	/*
+	 * If we already saw the link up, and it hasn't gone down, then
+	 * we don't need to wait for autoneg again
+	 */
+	if (phydev->link && mii_reg & BMSR_LSTATUS)
+		return 0;
+
+	if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+		int i = 0;
+
+		printf("%s Waiting for PHY auto negotiation to complete",
+			phydev->dev->name);
+		while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
+			/*
+			 * Timeout reached ?
+			 */
+			if (i > PHY_ANEG_TIMEOUT) {
+				printf(" TIMEOUT !\n");
+				phydev->link = 0;
+				return 0;
+			}
+
+			if (ctrlc()) {
+				puts("user interrupt!\n");
+				phydev->link = 0;
+				return -EINTR;
+			}
+
+			if ((i++ % 500) == 0)
+				printf(".");
+
+			udelay(1000);	/* 1 ms */
+			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+		}
+		printf(" done\n");
+		phydev->link = 1;
+	} else {
+		/* Read the link a second time to clear the latched state */
+		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+		if (mii_reg & BMSR_LSTATUS)
+			phydev->link = 1;
+		else
+			phydev->link = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * Generic function which updates the speed and duplex.  If
+ * autonegotiation is enabled, it uses the AND of the link
+ * partner's advertised capabilities and our advertised
+ * capabilities.  If autonegotiation is disabled, we use the
+ * appropriate bits in the control register.
+ *
+ * Stolen from Linux's mii.c and phy_device.c
+ */
+static int genphy_parse_link(struct phy_device *phydev)
+{
+	int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+	/* We're using autonegotiation */
+	if (mii_reg & BMSR_ANEGCAPABLE) {
+		u32 lpa = 0;
+		u32 gblpa = 0;
+
+		/* Check for gigabit capability */
+		if (mii_reg & BMSR_ERCAP) {
+			/* We want a list of states supported by
+			 * both PHYs in the link
+			 */
+			gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
+			gblpa &= phy_read(phydev,
+					MDIO_DEVAD_NONE, MII_CTRL1000) << 2;
+		}
+
+		/* Set the baseline so we only have to set them
+		 * if they're different
+		 */
+		phydev->speed = SPEED_10;
+		phydev->duplex = DUPLEX_HALF;
+
+		/* Check the gigabit fields */
+		if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
+			phydev->speed = SPEED_1000;
+
+			if (gblpa & PHY_1000BTSR_1000FD)
+				phydev->duplex = DUPLEX_FULL;
+
+			/* We're done! */
+			return 0;
+		}
+
+		lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+		lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
+
+		if (lpa & (LPA_100FULL | LPA_100HALF)) {
+			phydev->speed = SPEED_100;
+
+			if (lpa & LPA_100FULL)
+				phydev->duplex = DUPLEX_FULL;
+
+		} else if (lpa & LPA_10FULL)
+			phydev->duplex = DUPLEX_FULL;
+	} else {
+		u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+		phydev->speed = SPEED_10;
+		phydev->duplex = DUPLEX_HALF;
+
+		if (bmcr & BMCR_FULLDPLX)
+			phydev->duplex = DUPLEX_FULL;
+
+		if (bmcr & BMCR_SPEED1000)
+			phydev->speed = SPEED_1000;
+		else if (bmcr & BMCR_SPEED100)
+			phydev->speed = SPEED_100;
+	}
+
+	return 0;
+}
+
+int genphy_config(struct phy_device *phydev)
+{
+	int val;
+	u32 features;
+
+	/* For now, I'll claim that the generic driver supports
+	 * all possible port types */
+	features = (SUPPORTED_TP | SUPPORTED_MII
+			| SUPPORTED_AUI | SUPPORTED_FIBRE |
+			SUPPORTED_BNC);
+
+	/* Do we support autonegotiation? */
+	val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+
+	if (val < 0)
+		return val;
+
+	if (val & BMSR_ANEGCAPABLE)
+		features |= SUPPORTED_Autoneg;
+
+	if (val & BMSR_100FULL)
+		features |= SUPPORTED_100baseT_Full;
+	if (val & BMSR_100HALF)
+		features |= SUPPORTED_100baseT_Half;
+	if (val & BMSR_10FULL)
+		features |= SUPPORTED_10baseT_Full;
+	if (val & BMSR_10HALF)
+		features |= SUPPORTED_10baseT_Half;
+
+	if (val & BMSR_ESTATEN) {
+		val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS);
+
+		if (val < 0)
+			return val;
+
+		if (val & ESTATUS_1000_TFULL)
+			features |= SUPPORTED_1000baseT_Full;
+		if (val & ESTATUS_1000_THALF)
+			features |= SUPPORTED_1000baseT_Half;
+	}
+
+	phydev->supported = features;
+	phydev->advertising = features;
+
+	genphy_config_aneg(phydev);
+
+	return 0;
+}
+
+int genphy_startup(struct phy_device *phydev)
+{
+	genphy_update_link(phydev);
+	genphy_parse_link(phydev);
+
+	return 0;
+}
+
+int genphy_shutdown(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static struct phy_driver genphy_driver = {
+	.uid		= 0xffffffff,
+	.mask		= 0xffffffff,
+	.name		= "Generic PHY",
+	.features	= 0,
+	.config		= genphy_config,
+	.startup	= genphy_startup,
+	.shutdown	= genphy_shutdown,
+};
+
+static struct list_head phy_drivers;
+
+int phy_init(void)
+{
+	INIT_LIST_HEAD(&phy_drivers);
+
+	return 0;
+}
+
+int phy_register(struct phy_driver *drv)
+{
+	INIT_LIST_HEAD(&drv->list);
+	list_add_tail(&drv->list, &phy_drivers);
+
+	return 0;
+}
+
+int phy_probe(struct phy_device *phydev)
+{
+	int err = 0;
+
+	phydev->advertising = phydev->supported = phydev->drv->features;
+
+	if (phydev->drv->probe)
+		err = phydev->drv->probe(phydev);
+
+	return err;
+}
+
+struct phy_driver *get_phy_driver(struct phy_device *phydev,
+				phy_interface_t interface)
+{
+	struct list_head *entry;
+	int phy_id = phydev->phy_id;
+	struct phy_driver *drv = NULL;
+
+	list_for_each(entry, &phy_drivers) {
+		drv = list_entry(entry, struct phy_driver, list);
+		if ((drv->uid & drv->mask) == (phy_id & drv->mask))
+			return drv;
+	}
+
+	/* If we made it here, there's no driver for this PHY */
+	if (interface == PHY_INTERFACE_MODE_XGMII)
+		return &gen10g_driver;
+	else
+		return &genphy_driver;
+}
+
+struct phy_device *phy_device_create(struct mii_dev *bus, int addr, int phy_id,
+					phy_interface_t interface)
+{
+	struct phy_device *dev;
+
+	/* We allocate the device, and initialize the
+	 * default values */
+	dev = malloc(sizeof(*dev));
+	if (!dev) {
+		printf("Failed to allocate PHY device for %s:%d\n",
+			bus->name, addr);
+		return NULL;
+	}
+
+	memset(dev, 0, sizeof(*dev));
+
+	dev->duplex = -1;
+	dev->link = 1;
+	dev->interface = interface;
+
+	dev->autoneg = AUTONEG_ENABLE;
+
+	dev->addr = addr;
+	dev->phy_id = phy_id;
+	dev->bus = bus;
+
+	dev->drv = get_phy_driver(dev, interface);
+
+	phy_probe(dev);
+
+	return dev;
+}
+
+/**
+ * get_phy_id - reads the specified addr for its ID.
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ * @phy_id: where to store the ID retrieved.
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ *   @bus, stores it in @phy_id and returns zero on success.
+ */
+int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
+{
+	int phy_reg;
+
+	/* Grab the bits from PHYIR1, and put them
+	 * in the upper half */
+	phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
+
+	if (phy_reg < 0)
+		return -EIO;
+
+	*phy_id = (phy_reg & 0xffff) << 16;
+
+	/* Grab the bits from PHYIR2, and put them in the lower half */
+	phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
+
+	if (phy_reg < 0)
+		return -EIO;
+
+	*phy_id |= (phy_reg & 0xffff);
+
+	return 0;
+}
+
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ *   @bus, then allocates and returns the phy_device to represent it.
+ */
+struct phy_device *get_phy_device(struct mii_dev *bus, int addr,
+				phy_interface_t interface)
+{
+	u32 phy_id = 0x1fffffff;
+	int i;
+	int r;
+
+	/* Try Standard (ie Clause 22) access */
+	r = get_phy_id(bus, addr, MDIO_DEVAD_NONE, &phy_id);
+	if (r)
+		return NULL;
+
+	/* If the PHY ID is mostly f's, we didn't find anything */
+	if ((phy_id & 0x1fffffff) != 0x1fffffff)
+		return phy_device_create(bus, addr, phy_id, interface);
+
+	/* Otherwise we have to try Clause 45 */
+	for (i = 1; i < 5; i++) {
+		r = get_phy_id(bus, addr, i, &phy_id);
+		if (r)
+			return NULL;
+
+		/* If the phy_id is mostly Fs, there is no device there */
+		if ((phy_id & 0x1fffffff) != 0x1fffffff)
+			break;
+	}
+
+	return phy_device_create(bus, addr, phy_id, interface);
+}
+
+struct phy_device *phy_connect(struct mii_dev *bus, int addr,
+				struct eth_device *dev,
+				phy_interface_t interface)
+{
+	/* Reset the bus */
+	bus->reset(bus);
+
+	/* If the PHY is not in the map, probe the PHY to id it */
+	if (!bus->phymap[addr]) {
+		bus->phymap[addr] = get_phy_device(bus, addr, interface);
+
+		if (!bus->phymap[addr])
+			printf("Could not get PHY for %s:%d\n", bus->name,
+				addr);
+	}
+
+	if (bus->phymap[addr]->dev)
+		printf("%s:%d is connected to %s.  Reconnecting to %s\n",
+			bus->name, addr, bus->phymap[addr]->dev->name,
+			dev->name);
+
+	bus->phymap[addr]->dev = dev;
+
+	printf("%s connected to %s\n", dev->name,
+		bus->phymap[addr]->drv->name);
+
+	return bus->phymap[addr];
+}
+
+int phy_startup(struct phy_device *phydev)
+{
+	if (phydev->drv->startup)
+		phydev->drv->startup(phydev);
+
+	return 0;
+}
+
+static int __board_phy_config(struct phy_device *phydev)
+{
+	return 0;
+}
+
+int board_phy_config(struct phy_device *phydev)
+	__attribute__((weak, alias("__board_phy_config")));
+
+int phy_config(struct phy_device *phydev)
+{
+	if (phydev->drv->config)
+		phydev->drv->config(phydev);
+
+	/* Invoke an optional board-specific helper */
+	board_phy_config(phydev);
+
+	return 0;
+}
+
+int phy_shutdown(struct phy_device *phydev)
+{
+	if (phydev->drv->shutdown)
+		phydev->drv->shutdown(phydev);
+
+	return 0;
+}
diff --git a/include/miiphy.h b/include/miiphy.h
index 42dc127..00db2dc 100644
--- a/include/miiphy.h
+++ b/include/miiphy.h
@@ -34,35 +34,66 @@
 #ifndef _miiphy_h_
 #define _miiphy_h_
 
+#include <common.h>
 #include <linux/mii.h>
+#include <linux/list.h>
 #include <net.h>
+#include <phy.h>
 
-int miiphy_read (const char *devname, unsigned char addr, unsigned char reg,
+struct legacy_mii_dev {
+	int (*read)(const char *devname, unsigned char addr,
+		     unsigned char reg, unsigned short *value);
+	int (*write)(const char *devname, unsigned char addr,
+		      unsigned char reg, unsigned short value);
+};
+
+#define MDIO_NAME_LEN 32
+
+struct mii_dev {
+	struct list_head link;
+	char *name;
+	void *priv;
+	int (*read)(struct mii_dev *bus, int addr, int devad, int reg);
+	int (*write)(struct mii_dev *bus, int addr, int devad, int reg,
+			u16 val);
+	int (*reset)(struct mii_dev *bus);
+	struct phy_device *phymap[PHY_MAX_ADDR];
+	u32 phy_mask;
+};
+
+int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
 		 unsigned short *value);
-int miiphy_write (const char *devname, unsigned char addr, unsigned char reg,
+int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
 		  unsigned short value);
-int miiphy_info (const char *devname, unsigned char addr, unsigned int *oui,
+int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui,
 		 unsigned char *model, unsigned char *rev);
-int miiphy_reset (const char *devname, unsigned char addr);
-int miiphy_speed (const char *devname, unsigned char addr);
-int miiphy_duplex (const char *devname, unsigned char addr);
-int miiphy_is_1000base_x (const char *devname, unsigned char addr);
+int miiphy_reset(const char *devname, unsigned char addr);
+int miiphy_speed(const char *devname, unsigned char addr);
+int miiphy_duplex(const char *devname, unsigned char addr);
+int miiphy_is_1000base_x(const char *devname, unsigned char addr);
 #ifdef CONFIG_SYS_FAULT_ECHO_LINK_DOWN
-int miiphy_link (const char *devname, unsigned char addr);
+int miiphy_link(const char *devname, unsigned char addr);
 #endif
 
-void miiphy_init (void);
+void miiphy_init(void);
 
-void miiphy_register (const char *devname,
-		      int (*read) (const char *devname, unsigned char addr,
+void miiphy_register(const char *devname,
+		      int (*read)(const char *devname, unsigned char addr,
 				   unsigned char reg, unsigned short *value),
-		      int (*write) (const char *devname, unsigned char addr,
+		      int (*write)(const char *devname, unsigned char addr,
 				    unsigned char reg, unsigned short value));
 
-int miiphy_set_current_dev (const char *devname);
-const char *miiphy_get_current_dev (void);
+int miiphy_set_current_dev(const char *devname);
+const char *miiphy_get_current_dev(void);
+struct mii_dev *mdio_get_current_dev(void);
+struct mii_dev *miiphy_get_dev_by_name(const char *devname);
+struct phy_device *mdio_phydev_for_ethname(const char *devname);
+
+void miiphy_listdev(void);
 
-void miiphy_listdev (void);
+struct mii_dev *mdio_alloc(void);
+int mdio_register(struct mii_dev *bus);
+void mdio_list_devices(void);
 
 #ifdef CONFIG_BITBANGMII
 
@@ -85,10 +116,10 @@ struct bb_miiphy_bus {
 extern struct bb_miiphy_bus bb_miiphy_buses[];
 extern int bb_miiphy_buses_num;
 
-void bb_miiphy_init (void);
-int bb_miiphy_read (const char *devname, unsigned char addr,
+void bb_miiphy_init(void);
+int bb_miiphy_read(const char *devname, unsigned char addr,
 		    unsigned char reg, unsigned short *value);
-int bb_miiphy_write (const char *devname, unsigned char addr,
+int bb_miiphy_write(const char *devname, unsigned char addr,
 		     unsigned char reg, unsigned short value);
 #endif
 
diff --git a/include/phy.h b/include/phy.h
new file mode 100644
index 0000000..1053a9d
--- /dev/null
+++ b/include/phy.h
@@ -0,0 +1,489 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *	Andy Fleming <afleming@freescale.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * This file pretty much stolen from Linux's mii.h/ethtool.h/phy.h
+ */
+
+#ifndef _PHY_H
+#define _PHY_H
+
+#include <linux/list.h>
+#include <linux/mii.h>
+
+/* MDIO Manageable Devices (MMDs). */
+#define MDIO_MMD_PMAPMD		1	/* Physical Medium Attachment/
+					 * Physical Medium Dependent */
+#define MDIO_MMD_WIS		2	/* WAN Interface Sublayer */
+#define MDIO_MMD_PCS		3	/* Physical Coding Sublayer */
+#define MDIO_MMD_PHYXS		4	/* PHY Extender Sublayer */
+#define MDIO_MMD_DTEXS		5	/* DTE Extender Sublayer */
+#define MDIO_MMD_TC		6	/* Transmission Convergence */
+#define MDIO_MMD_AN		7	/* Auto-Negotiation */
+#define MDIO_MMD_C22EXT		29	/* Clause 22 extension */
+#define MDIO_MMD_VEND1		30	/* Vendor specific 1 */
+#define MDIO_MMD_VEND2		31	/* Vendor specific 2 */
+
+/* Generic MDIO registers. */
+#define MDIO_CTRL1		MII_BMCR
+#define MDIO_STAT1		MII_BMSR
+#define MDIO_DEVID1		MII_PHYSID1
+#define MDIO_DEVID2		MII_PHYSID2
+#define MDIO_SPEED		4	/* Speed ability */
+#define MDIO_DEVS1		5	/* Devices in package */
+#define MDIO_DEVS2		6
+#define MDIO_CTRL2		7	/* 10G control 2 */
+#define MDIO_STAT2		8	/* 10G status 2 */
+#define MDIO_PMA_TXDIS		9	/* 10G PMA/PMD transmit disable */
+#define MDIO_PMA_RXDET		10	/* 10G PMA/PMD receive signal detect */
+#define MDIO_PMA_EXTABLE	11	/* 10G PMA/PMD extended ability */
+#define MDIO_PKGID1		14	/* Package identifier */
+#define MDIO_PKGID2		15
+#define MDIO_AN_ADVERTISE	16	/* AN advertising (base page) */
+#define MDIO_AN_LPA		19	/* AN LP abilities (base page) */
+#define MDIO_PHYXS_LNSTAT	24	/* PHY XGXS lane state */
+
+/* Media-dependent registers. */
+#define MDIO_PMA_10GBT_SWAPPOL	130	/* 10GBASE-T pair swap & polarity */
+#define MDIO_PMA_10GBT_TXPWR	131	/* 10GBASE-T TX power control */
+#define MDIO_PMA_10GBT_SNR	133	/* 10GBASE-T SNR margin, lane A.
+					 * Lanes B-D are numbered 134-136. */
+#define MDIO_PMA_10GBR_FECABLE	170	/* 10GBASE-R FEC ability */
+#define MDIO_PCS_10GBX_STAT1	24	/* 10GBASE-X PCS status 1 */
+#define MDIO_PCS_10GBRT_STAT1	32	/* 10GBASE-R/-T PCS status 1 */
+#define MDIO_PCS_10GBRT_STAT2	33	/* 10GBASE-R/-T PCS status 2 */
+#define MDIO_AN_10GBT_CTRL	32	/* 10GBASE-T auto-negotiation control */
+#define MDIO_AN_10GBT_STAT	33	/* 10GBASE-T auto-negotiation status */
+
+/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */
+#define MDIO_PMA_LASI_RXCTRL	0x9000	/* RX_ALARM control */
+#define MDIO_PMA_LASI_TXCTRL	0x9001	/* TX_ALARM control */
+#define MDIO_PMA_LASI_CTRL	0x9002	/* LASI control */
+#define MDIO_PMA_LASI_RXSTAT	0x9003	/* RX_ALARM status */
+#define MDIO_PMA_LASI_TXSTAT	0x9004	/* TX_ALARM status */
+#define MDIO_PMA_LASI_STAT	0x9005	/* LASI status */
+
+/* Control register 1. */
+/* Enable extended speed selection */
+#define MDIO_CTRL1_SPEEDSELEXT		(BMCR_SPEED1000 | BMCR_SPEED100)
+/* All speed selection bits */
+#define MDIO_CTRL1_SPEEDSEL		(MDIO_CTRL1_SPEEDSELEXT | 0x003c)
+#define MDIO_CTRL1_FULLDPLX		BMCR_FULLDPLX
+#define MDIO_CTRL1_LPOWER		BMCR_PDOWN
+#define MDIO_CTRL1_RESET		BMCR_RESET
+#define MDIO_PMA_CTRL1_LOOPBACK		0x0001
+#define MDIO_PMA_CTRL1_SPEED1000	BMCR_SPEED1000
+#define MDIO_PMA_CTRL1_SPEED100		BMCR_SPEED100
+#define MDIO_PCS_CTRL1_LOOPBACK		BMCR_LOOPBACK
+#define MDIO_PHYXS_CTRL1_LOOPBACK	BMCR_LOOPBACK
+#define MDIO_AN_CTRL1_RESTART		BMCR_ANRESTART
+#define MDIO_AN_CTRL1_ENABLE		BMCR_ANENABLE
+#define MDIO_AN_CTRL1_XNP		0x2000	/* Enable extended next page */
+
+/* 10 Gb/s */
+#define MDIO_CTRL1_SPEED10G		(MDIO_CTRL1_SPEEDSELEXT | 0x00)
+/* 10PASS-TS/2BASE-TL */
+#define MDIO_CTRL1_SPEED10P2B		(MDIO_CTRL1_SPEEDSELEXT | 0x04)
+
+/* Status register 1. */
+#define MDIO_STAT1_LPOWERABLE		0x0002	/* Low-power ability */
+#define MDIO_STAT1_LSTATUS		BMSR_LSTATUS
+#define MDIO_STAT1_FAULT		0x0080	/* Fault */
+#define MDIO_AN_STAT1_LPABLE		0x0001	/* Link partner AN ability */
+#define MDIO_AN_STAT1_ABLE		BMSR_ANEGCAPABLE
+#define MDIO_AN_STAT1_RFAULT		BMSR_RFAULT
+#define MDIO_AN_STAT1_COMPLETE		BMSR_ANEGCOMPLETE
+#define MDIO_AN_STAT1_PAGE		0x0040	/* Page received */
+#define MDIO_AN_STAT1_XNP		0x0080	/* Extended next page status */
+
+/* Speed register. */
+#define MDIO_SPEED_10G			0x0001	/* 10G capable */
+#define MDIO_PMA_SPEED_2B		0x0002	/* 2BASE-TL capable */
+#define MDIO_PMA_SPEED_10P		0x0004	/* 10PASS-TS capable */
+#define MDIO_PMA_SPEED_1000		0x0010	/* 1000M capable */
+#define MDIO_PMA_SPEED_100		0x0020	/* 100M capable */
+#define MDIO_PMA_SPEED_10		0x0040	/* 10M capable */
+#define MDIO_PCS_SPEED_10P2B		0x0002	/* 10PASS-TS/2BASE-TL capable */
+
+/* Device present registers. */
+#define MDIO_DEVS_PRESENT(devad)	(1 << (devad))
+#define MDIO_DEVS_PMAPMD		MDIO_DEVS_PRESENT(MDIO_MMD_PMAPMD)
+#define MDIO_DEVS_WIS			MDIO_DEVS_PRESENT(MDIO_MMD_WIS)
+#define MDIO_DEVS_PCS			MDIO_DEVS_PRESENT(MDIO_MMD_PCS)
+#define MDIO_DEVS_PHYXS			MDIO_DEVS_PRESENT(MDIO_MMD_PHYXS)
+#define MDIO_DEVS_DTEXS			MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS)
+#define MDIO_DEVS_TC			MDIO_DEVS_PRESENT(MDIO_MMD_TC)
+#define MDIO_DEVS_AN			MDIO_DEVS_PRESENT(MDIO_MMD_AN)
+#define MDIO_DEVS_C22EXT		MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT)
+#define MDIO_DEVS_VEND1			MDIO_DEVS_PRESENT(MDIO_MMD_VEND1)
+#define MDIO_DEVS_VEND2			MDIO_DEVS_PRESENT(MDIO_MMD_VEND2)
+
+/* Control register 2. */
+#define MDIO_PMA_CTRL2_TYPE		0x000f	/* PMA/PMD type selection */
+#define MDIO_PMA_CTRL2_10GBCX4		0x0000	/* 10GBASE-CX4 type */
+#define MDIO_PMA_CTRL2_10GBEW		0x0001	/* 10GBASE-EW type */
+#define MDIO_PMA_CTRL2_10GBLW		0x0002	/* 10GBASE-LW type */
+#define MDIO_PMA_CTRL2_10GBSW		0x0003	/* 10GBASE-SW type */
+#define MDIO_PMA_CTRL2_10GBLX4		0x0004	/* 10GBASE-LX4 type */
+#define MDIO_PMA_CTRL2_10GBER		0x0005	/* 10GBASE-ER type */
+#define MDIO_PMA_CTRL2_10GBLR		0x0006	/* 10GBASE-LR type */
+#define MDIO_PMA_CTRL2_10GBSR		0x0007	/* 10GBASE-SR type */
+#define MDIO_PMA_CTRL2_10GBLRM		0x0008	/* 10GBASE-LRM type */
+#define MDIO_PMA_CTRL2_10GBT		0x0009	/* 10GBASE-T type */
+#define MDIO_PMA_CTRL2_10GBKX4		0x000a	/* 10GBASE-KX4 type */
+#define MDIO_PMA_CTRL2_10GBKR		0x000b	/* 10GBASE-KR type */
+#define MDIO_PMA_CTRL2_1000BT		0x000c	/* 1000BASE-T type */
+#define MDIO_PMA_CTRL2_1000BKX		0x000d	/* 1000BASE-KX type */
+#define MDIO_PMA_CTRL2_100BTX		0x000e	/* 100BASE-TX type */
+#define MDIO_PMA_CTRL2_10BT		0x000f	/* 10BASE-T type */
+#define MDIO_PCS_CTRL2_TYPE		0x0003	/* PCS type selection */
+#define MDIO_PCS_CTRL2_10GBR		0x0000	/* 10GBASE-R type */
+#define MDIO_PCS_CTRL2_10GBX		0x0001	/* 10GBASE-X type */
+#define MDIO_PCS_CTRL2_10GBW		0x0002	/* 10GBASE-W type */
+#define MDIO_PCS_CTRL2_10GBT		0x0003	/* 10GBASE-T type */
+
+/* Status register 2. */
+#define MDIO_STAT2_RXFAULT		0x0400	/* Receive fault */
+#define MDIO_STAT2_TXFAULT		0x0800	/* Transmit fault */
+#define MDIO_STAT2_DEVPRST		0xc000	/* Device present */
+#define MDIO_STAT2_DEVPRST_VAL		0x8000	/* Device present value */
+#define MDIO_PMA_STAT2_LBABLE		0x0001	/* PMA loopback ability */
+#define MDIO_PMA_STAT2_10GBEW		0x0002	/* 10GBASE-EW ability */
+#define MDIO_PMA_STAT2_10GBLW		0x0004	/* 10GBASE-LW ability */
+#define MDIO_PMA_STAT2_10GBSW		0x0008	/* 10GBASE-SW ability */
+#define MDIO_PMA_STAT2_10GBLX4		0x0010	/* 10GBASE-LX4 ability */
+#define MDIO_PMA_STAT2_10GBER		0x0020	/* 10GBASE-ER ability */
+#define MDIO_PMA_STAT2_10GBLR		0x0040	/* 10GBASE-LR ability */
+#define MDIO_PMA_STAT2_10GBSR		0x0080	/* 10GBASE-SR ability */
+#define MDIO_PMD_STAT2_TXDISAB		0x0100	/* PMD TX disable ability */
+#define MDIO_PMA_STAT2_EXTABLE		0x0200	/* Extended abilities */
+#define MDIO_PMA_STAT2_RXFLTABLE	0x1000	/* Receive fault ability */
+#define MDIO_PMA_STAT2_TXFLTABLE	0x2000	/* Transmit fault ability */
+#define MDIO_PCS_STAT2_10GBR		0x0001	/* 10GBASE-R capable */
+#define MDIO_PCS_STAT2_10GBX		0x0002	/* 10GBASE-X capable */
+#define MDIO_PCS_STAT2_10GBW		0x0004	/* 10GBASE-W capable */
+#define MDIO_PCS_STAT2_RXFLTABLE	0x1000	/* Receive fault ability */
+#define MDIO_PCS_STAT2_TXFLTABLE	0x2000	/* Transmit fault ability */
+
+/* Transmit disable register. */
+#define MDIO_PMD_TXDIS_GLOBAL		0x0001	/* Global PMD TX disable */
+#define MDIO_PMD_TXDIS_0		0x0002	/* PMD TX disable 0 */
+#define MDIO_PMD_TXDIS_1		0x0004	/* PMD TX disable 1 */
+#define MDIO_PMD_TXDIS_2		0x0008	/* PMD TX disable 2 */
+#define MDIO_PMD_TXDIS_3		0x0010	/* PMD TX disable 3 */
+
+/* Receive signal detect register. */
+#define MDIO_PMD_RXDET_GLOBAL		0x0001 /* Global PMD RX signal detect */
+#define MDIO_PMD_RXDET_0		0x0002	/* PMD RX signal detect 0 */
+#define MDIO_PMD_RXDET_1		0x0004	/* PMD RX signal detect 1 */
+#define MDIO_PMD_RXDET_2		0x0008	/* PMD RX signal detect 2 */
+#define MDIO_PMD_RXDET_3		0x0010	/* PMD RX signal detect 3 */
+
+/* Extended abilities register. */
+#define MDIO_PMA_EXTABLE_10GCX4		0x0001	/* 10GBASE-CX4 ability */
+#define MDIO_PMA_EXTABLE_10GBLRM	0x0002	/* 10GBASE-LRM ability */
+#define MDIO_PMA_EXTABLE_10GBT		0x0004	/* 10GBASE-T ability */
+#define MDIO_PMA_EXTABLE_10GBKX4	0x0008	/* 10GBASE-KX4 ability */
+#define MDIO_PMA_EXTABLE_10GBKR		0x0010	/* 10GBASE-KR ability */
+#define MDIO_PMA_EXTABLE_1000BT		0x0020	/* 1000BASE-T ability */
+#define MDIO_PMA_EXTABLE_1000BKX	0x0040	/* 1000BASE-KX ability */
+#define MDIO_PMA_EXTABLE_100BTX		0x0080	/* 100BASE-TX ability */
+#define MDIO_PMA_EXTABLE_10BT		0x0100	/* 10BASE-T ability */
+
+/* PHY XGXS lane state register. */
+#define MDIO_PHYXS_LNSTAT_SYNC0		0x0001
+#define MDIO_PHYXS_LNSTAT_SYNC1		0x0002
+#define MDIO_PHYXS_LNSTAT_SYNC2		0x0004
+#define MDIO_PHYXS_LNSTAT_SYNC3		0x0008
+#define MDIO_PHYXS_LNSTAT_ALIGN		0x1000
+
+/* PMA 10GBASE-T pair swap & polarity */
+#define MDIO_PMA_10GBT_SWAPPOL_ABNX	0x0001	/* Pair A/B uncrossed */
+#define MDIO_PMA_10GBT_SWAPPOL_CDNX	0x0002	/* Pair C/D uncrossed */
+#define MDIO_PMA_10GBT_SWAPPOL_AREV	0x0100	/* Pair A polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_BREV	0x0200	/* Pair B polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_CREV	0x0400	/* Pair C polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_DREV	0x0800	/* Pair D polarity reversed */
+
+/* PMA 10GBASE-T TX power register. */
+#define MDIO_PMA_10GBT_TXPWR_SHORT	0x0001	/* Short-reach mode */
+
+/* PMA 10GBASE-T SNR registers. */
+/* Value is SNR margin in dB, clamped to range [-127, 127], plus 0x8000. */
+#define MDIO_PMA_10GBT_SNR_BIAS		0x8000
+#define MDIO_PMA_10GBT_SNR_MAX		127
+
+/* PMA 10GBASE-R FEC ability register. */
+#define MDIO_PMA_10GBR_FECABLE_ABLE	0x0001	/* FEC ability */
+#define MDIO_PMA_10GBR_FECABLE_ERRABLE	0x0002	/* FEC error indic. ability */
+
+/* PCS 10GBASE-R/-T status register 1. */
+#define MDIO_PCS_10GBRT_STAT1_BLKLK	0x0001	/* Block lock attained */
+
+/* PCS 10GBASE-R/-T status register 2. */
+#define MDIO_PCS_10GBRT_STAT2_ERR	0x00ff
+#define MDIO_PCS_10GBRT_STAT2_BER	0x3f00
+
+/* AN 10GBASE-T control register. */
+#define MDIO_AN_10GBT_CTRL_ADV10G	0x1000	/* Advertise 10GBASE-T */
+
+/* AN 10GBASE-T status register. */
+#define MDIO_AN_10GBT_STAT_LPTRR	0x0200	/* LP training reset req. */
+#define MDIO_AN_10GBT_STAT_LPLTABLE	0x0400	/* LP loop timing ability */
+#define MDIO_AN_10GBT_STAT_LP10G	0x0800	/* LP is 10GBT capable */
+#define MDIO_AN_10GBT_STAT_REMOK	0x1000	/* Remote OK */
+#define MDIO_AN_10GBT_STAT_LOCOK	0x2000	/* Local OK */
+#define MDIO_AN_10GBT_STAT_MS		0x4000	/* Master/slave config */
+#define MDIO_AN_10GBT_STAT_MSFLT	0x8000	/* Master/slave config fault */
+
+/* LASI RX_ALARM control/status registers. */
+#define MDIO_PMA_LASI_RX_PHYXSLFLT	0x0001	/* PHY XS RX local fault */
+#define MDIO_PMA_LASI_RX_PCSLFLT	0x0008	/* PCS RX local fault */
+#define MDIO_PMA_LASI_RX_PMALFLT	0x0010	/* PMA/PMD RX local fault */
+#define MDIO_PMA_LASI_RX_OPTICPOWERFLT	0x0020	/* RX optical power fault */
+#define MDIO_PMA_LASI_RX_WISLFLT	0x0200	/* WIS local fault */
+
+/* LASI TX_ALARM control/status registers. */
+#define MDIO_PMA_LASI_TX_PHYXSLFLT	0x0001	/* PHY XS TX local fault */
+#define MDIO_PMA_LASI_TX_PCSLFLT	0x0008	/* PCS TX local fault */
+#define MDIO_PMA_LASI_TX_PMALFLT	0x0010	/* PMA/PMD TX local fault */
+#define MDIO_PMA_LASI_TX_LASERPOWERFLT	0x0080	/* Laser output power fault */
+#define MDIO_PMA_LASI_TX_LASERTEMPFLT	0x0100	/* Laser temperature fault */
+#define MDIO_PMA_LASI_TX_LASERBICURRFLT	0x0200	/* Laser bias current fault */
+
+/* LASI control/status registers. */
+#define MDIO_PMA_LASI_LSALARM		0x0001	/* LS_ALARM enable/status */
+#define MDIO_PMA_LASI_TXALARM		0x0002	/* TX_ALARM enable/status */
+#define MDIO_PMA_LASI_RXALARM		0x0004	/* RX_ALARM enable/status */
+
+/* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */
+
+#define MDIO_PHY_ID_C45			0x8000
+#define MDIO_PHY_ID_PRTAD		0x03e0
+#define MDIO_PHY_ID_DEVAD		0x001f
+#define MDIO_PHY_ID_C45_MASK						\
+	(MDIO_PHY_ID_C45 | MDIO_PHY_ID_PRTAD | MDIO_PHY_ID_DEVAD)
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half		(1 << 0)
+#define SUPPORTED_10baseT_Full		(1 << 1)
+#define SUPPORTED_100baseT_Half		(1 << 2)
+#define SUPPORTED_100baseT_Full		(1 << 3)
+#define SUPPORTED_1000baseT_Half	(1 << 4)
+#define SUPPORTED_1000baseT_Full	(1 << 5)
+#define SUPPORTED_Autoneg		(1 << 6)
+#define SUPPORTED_TP			(1 << 7)
+#define SUPPORTED_AUI			(1 << 8)
+#define SUPPORTED_MII			(1 << 9)
+#define SUPPORTED_FIBRE			(1 << 10)
+#define SUPPORTED_BNC			(1 << 11)
+#define SUPPORTED_10000baseT_Full	(1 << 12)
+#define SUPPORTED_Pause			(1 << 13)
+#define SUPPORTED_Asym_Pause		(1 << 14)
+#define SUPPORTED_2500baseX_Full	(1 << 15)
+#define SUPPORTED_Backplane		(1 << 16)
+#define SUPPORTED_1000baseKX_Full	(1 << 17)
+#define SUPPORTED_10000baseKX4_Full	(1 << 18)
+#define SUPPORTED_10000baseKR_Full	(1 << 19)
+#define SUPPORTED_10000baseR_FEC	(1 << 20)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half		(1 << 0)
+#define ADVERTISED_10baseT_Full		(1 << 1)
+#define ADVERTISED_100baseT_Half	(1 << 2)
+#define ADVERTISED_100baseT_Full	(1 << 3)
+#define ADVERTISED_1000baseT_Half	(1 << 4)
+#define ADVERTISED_1000baseT_Full	(1 << 5)
+#define ADVERTISED_Autoneg		(1 << 6)
+#define ADVERTISED_TP			(1 << 7)
+#define ADVERTISED_AUI			(1 << 8)
+#define ADVERTISED_MII			(1 << 9)
+#define ADVERTISED_FIBRE		(1 << 10)
+#define ADVERTISED_BNC			(1 << 11)
+#define ADVERTISED_10000baseT_Full	(1 << 12)
+#define ADVERTISED_Pause		(1 << 13)
+#define ADVERTISED_Asym_Pause		(1 << 14)
+#define ADVERTISED_2500baseX_Full	(1 << 15)
+#define ADVERTISED_Backplane		(1 << 16)
+#define ADVERTISED_1000baseKX_Full	(1 << 17)
+#define ADVERTISED_10000baseKX4_Full	(1 << 18)
+#define ADVERTISED_10000baseKR_Full	(1 << 19)
+#define ADVERTISED_10000baseR_FEC	(1 << 20)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things.  When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10		10
+#define SPEED_100		100
+#define SPEED_1000		1000
+#define SPEED_2500		2500
+#define SPEED_10000		10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF		0x00
+#define DUPLEX_FULL		0x01
+
+/* Which connector port. */
+#define PORT_TP			0x00
+#define PORT_AUI		0x01
+#define PORT_MII		0x02
+#define PORT_FIBRE		0x03
+#define PORT_BNC		0x04
+#define PORT_DA			0x05
+#define PORT_NONE		0xef
+#define PORT_OTHER		0xff
+
+/* Which transceiver to use. */
+#define XCVR_INTERNAL		0x00
+#define XCVR_EXTERNAL		0x01
+#define XCVR_DUMMY1		0x02
+#define XCVR_DUMMY2		0x03
+#define XCVR_DUMMY3		0x04
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+
+#define MDIO_DEVAD_NONE -1
+#define PHY_MAX_ADDR 32
+
+#define PHY_BASIC_FEATURES	(SUPPORTED_10baseT_Half | \
+				 SUPPORTED_10baseT_Full | \
+				 SUPPORTED_100baseT_Half | \
+				 SUPPORTED_100baseT_Full | \
+				 SUPPORTED_Autoneg | \
+				 SUPPORTED_TP | \
+				 SUPPORTED_MII)
+
+#define PHY_GBIT_FEATURES	(PHY_BASIC_FEATURES | \
+				 SUPPORTED_1000baseT_Half | \
+				 SUPPORTED_1000baseT_Full)
+
+#define PHY_10G_FEATURES	(PHY_GBIT_FEATURES | \
+				SUPPORTED_10000baseT_Full)
+
+#define PHY_ANEG_TIMEOUT	4000
+
+
+typedef enum {
+	PHY_INTERFACE_MODE_MII,
+	PHY_INTERFACE_MODE_GMII,
+	PHY_INTERFACE_MODE_SGMII,
+	PHY_INTERFACE_MODE_TBI,
+	PHY_INTERFACE_MODE_RMII,
+	PHY_INTERFACE_MODE_RGMII,
+	PHY_INTERFACE_MODE_RGMII_ID,
+	PHY_INTERFACE_MODE_RGMII_RXID,
+	PHY_INTERFACE_MODE_RGMII_TXID,
+	PHY_INTERFACE_MODE_RTBI,
+	PHY_INTERFACE_MODE_XGMII
+} phy_interface_t;
+
+struct phy_device;
+
+/* struct phy_driver: a structure which defines PHY behavior
+ *
+ * uid will contain a number which represents the PHY.  During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is.  The 32-bit result
+ * gotten from the PHY will be masked to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ */
+struct phy_driver {
+	char *name;
+	unsigned int uid;
+	unsigned int mask;
+
+	u32 features;
+
+	/* Called to do any driver startup necessities */
+	/* Will be called during phy_connect */
+	int (*probe)(struct phy_device *phydev);
+
+	/* Called to configure the PHY, and modify the controller
+	 * based on the results.  Should be called after phy_connect */
+	int (*config)(struct phy_device *phydev);
+
+	/* Called when starting up the controller */
+	int (*startup)(struct phy_device *phydev);
+
+	/* Called when bringing down the controller */
+	int (*shutdown)(struct phy_device *phydev);
+
+	struct list_head list;
+};
+
+struct phy_device {
+	/* Information about the PHY type */
+	/* And management functions */
+	struct mii_dev *bus;
+	struct phy_driver *drv;
+	void *priv;
+
+	struct eth_device *dev;
+
+	/* forced speed & duplex (no autoneg)
+	 * partner speed & duplex & pause (autoneg)
+	 */
+	int speed;
+	int duplex;
+
+	/* The most recently read link state */
+	int link;
+	int port;
+	phy_interface_t interface;
+
+	u32 advertising;
+	u32 supported;
+	u32 mmds;
+
+	int autoneg;
+	int addr;
+	int pause;
+	int asym_pause;
+	u32 phy_id;
+	u32 flags;
+};
+
+int phy_init(void);
+struct phy_device *phy_connect(struct mii_dev *bus, int addr,
+				struct eth_device *dev,
+				phy_interface_t interface);
+int phy_startup(struct phy_device *phydev);
+int phy_config(struct phy_device *phydev);
+int phy_shutdown(struct phy_device *phydev);
+int phy_write(struct phy_device *phydev, int devad, int reg, u16 val);
+int phy_read(struct phy_device *phydev, int devad, int reg);
+int phy_register(struct phy_driver *drv);
+int genphy_config_aneg(struct phy_device *phydev);
+int genphy_update_link(struct phy_device *phydev);
+int genphy_config(struct phy_device *phydev);
+int genphy_startup(struct phy_device *phydev);
+int genphy_shutdown(struct phy_device *phydev);
+int gen10g_config(struct phy_device *phydev);
+int gen10g_startup(struct phy_device *phydev);
+int gen10g_shutdown(struct phy_device *phydev);
+#endif
diff --git a/net/eth.c b/net/eth.c
index 3a7ff50..6523834 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -25,6 +25,7 @@
 #include <command.h>
 #include <net.h>
 #include <miiphy.h>
+#include <phy.h>
 
 void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
 {
@@ -217,6 +218,11 @@ int eth_initialize(bd_t *bis)
 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 	miiphy_init();
 #endif
+
+#ifdef CONFIG_PHYLIB
+	phy_init();
+#endif
+
 	/*
 	 * If board-specific initialization exists, call it.
 	 * If not, call a CPU-specific one
