ucc_geth: migrate ucc_geth to phylib

migrate ucc_geth to use the common phylib code.

There are several side effects from doing this:

o deprecate 'interface' property specification present
  in some old device tree source files in
  favour of a split 'max-speed' and 'interface-type'
  description to appropriately match definitions
  in include/linux/phy.h.  Note that 'interface' property
  is still honoured if max-speed or interface-type
  are not present (backward compatible).
o compile-time CONFIG_UGETH_HAS_GIGA is eliminated
  in favour of probe time speed derivation logic.
o adjust_link streamlined to only operate on maccfg2
  and upsmr.r10m, instead of reapplying static initial
  values related to the interface-type.
o Addition of UEC MDIO of_platform driver requires
  platform code add 'mdio' type to id list
  prior to calling of_platform_bus_probe (separate patch).
o ucc_struct_init introduced to reduce ucc_geth_startup
  complexity.

Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 639e1e6..d93cfde 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -29,6 +29,7 @@
 #include <linux/fsl_devices.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/phy.h>
 #include <linux/workqueue.h>
 
 #include <asm/of_platform.h>
@@ -41,7 +42,7 @@
 #include <asm/ucc_fast.h>
 
 #include "ucc_geth.h"
-#include "ucc_geth_phy.h"
+#include "ucc_geth_mii.h"
 
 #undef DEBUG
 
@@ -73,22 +74,13 @@
 		    .bd_mem_part = MEM_PART_SYSTEM,
 		    .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
 		    .max_rx_buf_length = 1536,
-/* FIXME: should be changed in run time for 1G and 100M */
-#ifdef CONFIG_UGETH_HAS_GIGA
-		    .urfs = UCC_GETH_URFS_GIGA_INIT,
-		    .urfet = UCC_GETH_URFET_GIGA_INIT,
-		    .urfset = UCC_GETH_URFSET_GIGA_INIT,
-		    .utfs = UCC_GETH_UTFS_GIGA_INIT,
-		    .utfet = UCC_GETH_UTFET_GIGA_INIT,
-		    .utftt = UCC_GETH_UTFTT_GIGA_INIT,
-#else
+		    /* adjusted at startup if max-speed 1000 */
 		    .urfs = UCC_GETH_URFS_INIT,
 		    .urfet = UCC_GETH_URFET_INIT,
 		    .urfset = UCC_GETH_URFSET_INIT,
 		    .utfs = UCC_GETH_UTFS_INIT,
 		    .utfet = UCC_GETH_UTFET_INIT,
 		    .utftt = UCC_GETH_UTFTT_INIT,
-#endif
 		    .ufpt = 256,
 		    .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET,
 		    .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
@@ -217,70 +209,6 @@
 	}
 }
 
-static int get_interface_details(enum enet_interface enet_interface,
-				 enum enet_speed *speed,
-				 int *r10m,
-				 int *rmm,
-				 int *rpm,
-				 int *tbi, int *limited_to_full_duplex)
-{
-	/* Analyze enet_interface according to Interface Mode
-	Configuration table */
-	switch (enet_interface) {
-	case ENET_10_MII:
-		*speed = ENET_SPEED_10BT;
-		break;
-	case ENET_10_RMII:
-		*speed = ENET_SPEED_10BT;
-		*r10m = 1;
-		*rmm = 1;
-		break;
-	case ENET_10_RGMII:
-		*speed = ENET_SPEED_10BT;
-		*rpm = 1;
-		*r10m = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_100_MII:
-		*speed = ENET_SPEED_100BT;
-		break;
-	case ENET_100_RMII:
-		*speed = ENET_SPEED_100BT;
-		*rmm = 1;
-		break;
-	case ENET_100_RGMII:
-		*speed = ENET_SPEED_100BT;
-		*rpm = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_GMII:
-		*speed = ENET_SPEED_1000BT;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_RGMII:
-		*speed = ENET_SPEED_1000BT;
-		*rpm = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_TBI:
-		*speed = ENET_SPEED_1000BT;
-		*tbi = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_RTBI:
-		*speed = ENET_SPEED_1000BT;
-		*rpm = 1;
-		*tbi = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-
-	return 0;
-}
-
 static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
 {
 	struct sk_buff *skb = NULL;
@@ -758,24 +686,6 @@
 	ugeth_info("hafdup     : addr - 0x%08x, val - 0x%08x",
 		   (u32) & ugeth->ug_regs->hafdup,
 		   in_be32(&ugeth->ug_regs->hafdup));
-	ugeth_info("miimcfg    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimcfg,
-		   in_be32(&ugeth->ug_regs->miimng.miimcfg));
-	ugeth_info("miimcom    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimcom,
-		   in_be32(&ugeth->ug_regs->miimng.miimcom));
-	ugeth_info("miimadd    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimadd,
-		   in_be32(&ugeth->ug_regs->miimng.miimadd));
-	ugeth_info("miimcon    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimcon,
-		   in_be32(&ugeth->ug_regs->miimng.miimcon));
-	ugeth_info("miimstat   : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimstat,
-		   in_be32(&ugeth->ug_regs->miimng.miimstat));
-	ugeth_info("miimmind   : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimind,
-		   in_be32(&ugeth->ug_regs->miimng.miimind));
 	ugeth_info("ifctl      : addr - 0x%08x, val - 0x%08x",
 		   (u32) & ugeth->ug_regs->ifctl,
 		   in_be32(&ugeth->ug_regs->ifctl));
@@ -1425,27 +1335,6 @@
 	return 0;
 }
 
-static int init_mac_duplex_mode(int full_duplex,
-				int limited_to_full_duplex,
-				volatile u32 *maccfg2_register)
-{
-	u32 value = 0;
-
-	/* some interfaces must work in full duplex mode */
-	if ((full_duplex == 0) && (limited_to_full_duplex == 1))
-		return -EINVAL;
-
-	value = in_be32(maccfg2_register);
-
-	if (full_duplex)
-		value |= MACCFG2_FDX;
-	else
-		value &= ~MACCFG2_FDX;
-
-	out_be32(maccfg2_register, value);
-	return 0;
-}
-
 static int init_check_frame_length_mode(int length_check,
 					volatile u32 *maccfg2_register)
 {
@@ -1477,40 +1366,6 @@
 	return 0;
 }
 
-static int init_mii_management_configuration(int reset_mgmt,
-					     int preamble_supress,
-					     volatile u32 *miimcfg_register,
-					     volatile u32 *miimind_register)
-{
-	unsigned int timeout = PHY_INIT_TIMEOUT;
-	u32 value = 0;
-
-	value = in_be32(miimcfg_register);
-	if (reset_mgmt) {
-		value |= MIIMCFG_RESET_MANAGEMENT;
-		out_be32(miimcfg_register, value);
-	}
-
-	value = 0;
-
-	if (preamble_supress)
-		value |= MIIMCFG_NO_PREAMBLE;
-
-	value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT;
-	out_be32(miimcfg_register, value);
-
-	/* Wait until the bus is free */
-	while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--)
-		cpu_relax();
-
-	if (timeout <= 0) {
-		ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__);
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
 static int init_rx_parameters(int reject_broadcast,
 			      int receive_short_frames,
 			      int promiscuous, volatile u32 *upsmr_register)
@@ -1570,10 +1425,8 @@
 	struct ucc_geth_info *ug_info;
 	struct ucc_geth *ug_regs;
 	struct ucc_fast *uf_regs;
-	enum enet_speed speed;
-	int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm =
-	    0, limited_to_full_duplex = 0;
-	u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
+	int ret_val;
+	u32 upsmr, maccfg2, tbiBaseAddress;
 	u16 value;
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -1582,24 +1435,13 @@
 	ug_regs = ugeth->ug_regs;
 	uf_regs = ugeth->uccf->uf_regs;
 
-	/* Analyze enet_interface according to Interface Mode Configuration
-	table */
-	ret_val =
-	    get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm,
-				  &rpm, &tbi, &limited_to_full_duplex);
-	if (ret_val != 0) {
-		ugeth_err
-		  ("%s: half duplex not supported in requested configuration.",
-		     __FUNCTION__);
-		return ret_val;
-	}
-
 	/*                    Set MACCFG2                    */
 	maccfg2 = in_be32(&ug_regs->maccfg2);
 	maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
-	if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT))
+	if ((ugeth->max_speed == SPEED_10) ||
+	    (ugeth->max_speed == SPEED_100))
 		maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
-	else if (speed == ENET_SPEED_1000BT)
+	else if (ugeth->max_speed == SPEED_1000)
 		maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
 	maccfg2 |= ug_info->padAndCrc;
 	out_be32(&ug_regs->maccfg2, maccfg2);
@@ -1607,54 +1449,39 @@
 	/*                    Set UPSMR                      */
 	upsmr = in_be32(&uf_regs->upsmr);
 	upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
-	if (rpm)
+	if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
 		upsmr |= UPSMR_RPM;
-	if (r10m)
-		upsmr |= UPSMR_R10M;
-	if (tbi)
+		switch (ugeth->max_speed) {
+		case SPEED_10:
+			upsmr |= UPSMR_R10M;
+			/* FALLTHROUGH */
+		case SPEED_100:
+			if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
+				upsmr |= UPSMR_RMM;
+		}
+	}
+	if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
 		upsmr |= UPSMR_TBIM;
-	if (rmm)
-		upsmr |= UPSMR_RMM;
+	}
 	out_be32(&uf_regs->upsmr, upsmr);
 
-	/*                    Set UTBIPAR                    */
-	utbipar = in_be32(&ug_regs->utbipar);
-	utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
-	if (tbi)
-		utbipar |=
-		    (ug_info->phy_address +
-		     ugeth->ug_info->uf_info.
-		     ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
-	else
-		utbipar |=
-		    (0x10 +
-		     ugeth->ug_info->uf_info.
-		     ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
-	out_be32(&ug_regs->utbipar, utbipar);
-
 	/* Disable autonegotiation in tbi mode, because by default it
 	comes up in autonegotiation mode. */
 	/* Note that this depends on proper setting in utbipar register. */
-	if (tbi) {
+	if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
 		tbiBaseAddress = in_be32(&ug_regs->utbipar);
 		tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
 		tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
-		value =
-		    ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress,
-					       ENET_TBI_MII_CR);
+		value = ugeth->phydev->bus->read(ugeth->phydev->bus,
+				(u8) tbiBaseAddress, ENET_TBI_MII_CR);
 		value &= ~0x1000;	/* Turn off autonegotiation */
-		ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress,
-					    ENET_TBI_MII_CR, value);
-	}
-
-	ret_val = init_mac_duplex_mode(1,
-				       limited_to_full_duplex,
-				       &ug_regs->maccfg2);
-	if (ret_val != 0) {
-		ugeth_err
-		("%s: half duplex not supported in requested configuration.",
-		     __FUNCTION__);
-		return ret_val;
+		ugeth->phydev->bus->write(ugeth->phydev->bus,
+				(u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
 	}
 
 	init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
@@ -1676,76 +1503,88 @@
  * function converts those variables into the appropriate
  * register values, and can bring down the device if needed.
  */
+
 static void adjust_link(struct net_device *dev)
 {
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
 	struct ucc_geth *ug_regs;
-	u32 tempval;
-	struct ugeth_mii_info *mii_info = ugeth->mii_info;
+	struct ucc_fast *uf_regs;
+	struct phy_device *phydev = ugeth->phydev;
+	unsigned long flags;
+	int new_state = 0;
 
 	ug_regs = ugeth->ug_regs;
+	uf_regs = ugeth->uccf->uf_regs;
 
-	if (mii_info->link) {
+	spin_lock_irqsave(&ugeth->lock, flags);
+
+	if (phydev->link) {
+		u32 tempval = in_be32(&ug_regs->maccfg2);
+		u32 upsmr = in_be32(&uf_regs->upsmr);
 		/* Now we make sure that we can be in full duplex mode.
 		 * If not, we operate in half-duplex mode. */
-		if (mii_info->duplex != ugeth->oldduplex) {
-			if (!(mii_info->duplex)) {
-				tempval = in_be32(&ug_regs->maccfg2);
+		if (phydev->duplex != ugeth->oldduplex) {
+			new_state = 1;
+			if (!(phydev->duplex))
 				tempval &= ~(MACCFG2_FDX);
-				out_be32(&ug_regs->maccfg2, tempval);
-
-				ugeth_info("%s: Half Duplex", dev->name);
-			} else {
-				tempval = in_be32(&ug_regs->maccfg2);
+			else
 				tempval |= MACCFG2_FDX;
-				out_be32(&ug_regs->maccfg2, tempval);
-
-				ugeth_info("%s: Full Duplex", dev->name);
-			}
-
-			ugeth->oldduplex = mii_info->duplex;
+			ugeth->oldduplex = phydev->duplex;
 		}
 
-		if (mii_info->speed != ugeth->oldspeed) {
-			switch (mii_info->speed) {
-			case 1000:
-				ugeth->ug_info->enet_interface = ENET_1000_RGMII;
+		if (phydev->speed != ugeth->oldspeed) {
+			new_state = 1;
+			switch (phydev->speed) {
+			case SPEED_1000:
+				tempval = ((tempval &
+					    ~(MACCFG2_INTERFACE_MODE_MASK)) |
+					    MACCFG2_INTERFACE_MODE_BYTE);
 				break;
-			case 100:
-				ugeth->ug_info->enet_interface = ENET_100_RGMII;
-				break;
-			case 10:
-				ugeth->ug_info->enet_interface = ENET_10_RGMII;
+			case SPEED_100:
+			case SPEED_10:
+				tempval = ((tempval &
+					    ~(MACCFG2_INTERFACE_MODE_MASK)) |
+					    MACCFG2_INTERFACE_MODE_NIBBLE);
+				/* if reduced mode, re-set UPSMR.R10M */
+				if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+				    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+				    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+				    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
+					if (phydev->speed == SPEED_10)
+						upsmr |= UPSMR_R10M;
+					else
+						upsmr &= ~(UPSMR_R10M);
+				}
 				break;
 			default:
-				ugeth_warn
-				    ("%s: Ack!  Speed (%d) is not 10/100/1000!",
-				     dev->name, mii_info->speed);
+				if (netif_msg_link(ugeth))
+					ugeth_warn(
+						"%s: Ack!  Speed (%d) is not 10/100/1000!",
+						dev->name, phydev->speed);
 				break;
 			}
-			adjust_enet_interface(ugeth);
-
-			ugeth_info("%s: Speed %dBT", dev->name,
-				   mii_info->speed);
-
-			ugeth->oldspeed = mii_info->speed;
+			ugeth->oldspeed = phydev->speed;
 		}
 
+		out_be32(&ug_regs->maccfg2, tempval);
+		out_be32(&uf_regs->upsmr, upsmr);
+
 		if (!ugeth->oldlink) {
-			ugeth_info("%s: Link is up", dev->name);
+			new_state = 1;
 			ugeth->oldlink = 1;
-			netif_carrier_on(dev);
 			netif_schedule(dev);
 		}
-	} else {
-		if (ugeth->oldlink) {
-			ugeth_info("%s: Link is down", dev->name);
+	} else if (ugeth->oldlink) {
+			new_state = 1;
 			ugeth->oldlink = 0;
 			ugeth->oldspeed = 0;
 			ugeth->oldduplex = -1;
-			netif_carrier_off(dev);
-		}
 	}
+
+	if (new_state && netif_msg_link(ugeth))
+		phy_print_status(phydev);
+
+	spin_unlock_irqrestore(&ugeth->lock, flags);
 }
 
 /* Configure the PHY for dev.
@@ -1753,94 +1592,40 @@
  */
 static int init_phy(struct net_device *dev)
 {
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-	struct phy_info *curphy;
-	struct ucc_mii_mng *mii_regs;
-	struct ugeth_mii_info *mii_info;
-	int err;
+	struct ucc_geth_private *priv = netdev_priv(dev);
+	struct phy_device *phydev;
+	char phy_id[BUS_ID_SIZE];
 
-	mii_regs = &ugeth->ug_regs->miimng;
+	priv->oldlink = 0;
+	priv->oldspeed = 0;
+	priv->oldduplex = -1;
 
-	ugeth->oldlink = 0;
-	ugeth->oldspeed = 0;
-	ugeth->oldduplex = -1;
+	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus,
+			priv->ug_info->phy_address);
 
-	mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
+	phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
 
-	if (NULL == mii_info) {
-		ugeth_err("%s: Could not allocate mii_info", dev->name);
-		return -ENOMEM;
+	if (IS_ERR(phydev)) {
+		printk("%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
 	}
 
-	mii_info->mii_regs = mii_regs;
-	mii_info->speed = SPEED_1000;
-	mii_info->duplex = DUPLEX_FULL;
-	mii_info->pause = 0;
-	mii_info->link = 0;
-
-	mii_info->advertising = (ADVERTISED_10baseT_Half |
+	phydev->supported &= (ADVERTISED_10baseT_Half |
 				 ADVERTISED_10baseT_Full |
 				 ADVERTISED_100baseT_Half |
-				 ADVERTISED_100baseT_Full |
-				 ADVERTISED_1000baseT_Full);
-	mii_info->autoneg = 1;
+				 ADVERTISED_100baseT_Full);
 
-	mii_info->mii_id = ugeth->ug_info->phy_address;
+	if (priv->max_speed == SPEED_1000)
+		phydev->supported |= ADVERTISED_1000baseT_Full;
 
-	mii_info->dev = dev;
+	phydev->advertising = phydev->supported;
 
-	mii_info->mdio_read = &read_phy_reg;
-	mii_info->mdio_write = &write_phy_reg;
-
-	spin_lock_init(&mii_info->mdio_lock);
-
-	ugeth->mii_info = mii_info;
-
-	spin_lock_irq(&ugeth->lock);
-
-	/* Set this UCC to be the master of the MII managment */
-	ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
-	if (init_mii_management_configuration(1,
-					      ugeth->ug_info->
-					      miiPreambleSupress,
-					      &mii_regs->miimcfg,
-					      &mii_regs->miimind)) {
-		ugeth_err("%s: The MII Bus is stuck!", dev->name);
-		err = -1;
-		goto bus_fail;
-	}
-
-	spin_unlock_irq(&ugeth->lock);
-
-	/* get info for this PHY */
-	curphy = get_phy_info(ugeth->mii_info);
-
-	if (curphy == NULL) {
-		ugeth_err("%s: No PHY found", dev->name);
-		err = -1;
-		goto no_phy;
-	}
-
-	mii_info->phyinfo = curphy;
-
-	/* Run the commands which initialize the PHY */
-	if (curphy->init) {
-		err = curphy->init(ugeth->mii_info);
-		if (err)
-			goto phy_init_fail;
-	}
+	priv->phydev = phydev;
 
 	return 0;
-
-      phy_init_fail:
-      no_phy:
-      bus_fail:
-	kfree(mii_info);
-
-	return err;
 }
 
+
 #ifdef CONFIG_UGETH_TX_ON_DEMOND
 static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth)
 {
@@ -2487,6 +2272,7 @@
 static void ucc_geth_stop(struct ucc_geth_private *ugeth)
 {
 	struct ucc_geth *ug_regs = ugeth->ug_regs;
+	struct phy_device *phydev = ugeth->phydev;
 	u32 tempval;
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -2495,8 +2281,7 @@
 	ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
 
 	/* Tell the kernel the link is down */
-	ugeth->mii_info->link = 0;
-	adjust_link(ugeth->dev);
+	phy_stop(phydev);
 
 	/* Mask all interrupts */
 	out_be32(ugeth->uccf->p_ucce, 0x00000000);
@@ -2509,46 +2294,16 @@
 	tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
 	out_be32(&ug_regs->maccfg1, tempval);
 
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-		/* Clear any pending interrupts */
-		mii_clear_phy_interrupt(ugeth->mii_info);
-
-		/* Disable PHY Interrupts */
-		mii_configure_phy_interrupt(ugeth->mii_info,
-					    MII_INTERRUPT_DISABLED);
-	}
-
 	free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
 
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-		free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev);
-	} else {
-		del_timer_sync(&ugeth->phy_info_timer);
-	}
-
 	ucc_geth_memclean(ugeth);
 }
 
-static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+static int ucc_struct_init(struct ucc_geth_private *ugeth)
 {
-	struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
-	struct ucc_geth_init_pram *p_init_enet_pram;
-	struct ucc_fast_private *uccf;
 	struct ucc_geth_info *ug_info;
 	struct ucc_fast_info *uf_info;
-	struct ucc_fast *uf_regs;
-	struct ucc_geth *ug_regs;
-	int ret_val = -EINVAL;
-	u32 remoder = UCC_GETH_REMODER_INIT;
-	u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
-	u32 ifstat, i, j, size, l2qt, l3qt, length;
-	u16 temoder = UCC_GETH_TEMODER_INIT;
-	u16 test;
-	u8 function_code = 0;
-	u8 *bd, *endOfRing;
-	u8 numThreadsRxNumerical, numThreadsTxNumerical;
-
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	int i;
 
 	ug_info = ugeth->ug_info;
 	uf_info = &ug_info->uf_info;
@@ -2647,12 +2402,42 @@
 	for (i = 0; i < ug_info->numQueuesTx; i++)
 		uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
 	/* Initialize the general fast UCC block. */
-	if (ucc_fast_init(uf_info, &uccf)) {
+	if (ucc_fast_init(uf_info, &ugeth->uccf)) {
 		ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
-	ugeth->uccf = uccf;
+
+	ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
+
+	return 0;
+}
+
+static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+{
+	struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+	struct ucc_geth_init_pram *p_init_enet_pram;
+	struct ucc_fast_private *uccf;
+	struct ucc_geth_info *ug_info;
+	struct ucc_fast_info *uf_info;
+	struct ucc_fast *uf_regs;
+	struct ucc_geth *ug_regs;
+	int ret_val = -EINVAL;
+	u32 remoder = UCC_GETH_REMODER_INIT;
+	u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+	u32 ifstat, i, j, size, l2qt, l3qt, length;
+	u16 temoder = UCC_GETH_TEMODER_INIT;
+	u16 test;
+	u8 function_code = 0;
+	u8 *bd, *endOfRing;
+	u8 numThreadsRxNumerical, numThreadsTxNumerical;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+	uccf = ugeth->uccf;
+	ug_info = ugeth->ug_info;
+	uf_info = &ug_info->uf_info;
+	uf_regs = uccf->uf_regs;
+	ug_regs = ugeth->ug_regs;
 
 	switch (ug_info->numThreadsRx) {
 	case UCC_GETH_NUM_OF_THREADS_1:
@@ -2711,10 +2496,6 @@
 	    || (ug_info->vlanOperationNonTagged !=
 		UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
 
-	uf_regs = uccf->uf_regs;
-	ug_regs = (struct ucc_geth *) (uccf->uf_regs);
-	ugeth->ug_regs = ug_regs;
-
 	init_default_reg_vals(&uf_regs->upsmr,
 			      &ug_regs->maccfg1, &ug_regs->maccfg2);
 
@@ -3841,128 +3622,6 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t phy_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-	ugeth_vdbg("%s: IN", __FUNCTION__);
-
-	/* Clear the interrupt */
-	mii_clear_phy_interrupt(ugeth->mii_info);
-
-	/* Disable PHY interrupts */
-	mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED);
-
-	/* Schedule the phy change */
-	schedule_work(&ugeth->tq);
-
-	return IRQ_HANDLED;
-}
-
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void ugeth_phy_change(struct work_struct *work)
-{
-	struct ucc_geth_private *ugeth =
-		container_of(work, struct ucc_geth_private, tq);
-	struct net_device *dev = ugeth->dev;
-	struct ucc_geth *ug_regs;
-	int result = 0;
-
-	ugeth_vdbg("%s: IN", __FUNCTION__);
-
-	ug_regs = ugeth->ug_regs;
-
-	/* Delay to give the PHY a chance to change the
-	 * register state */
-	msleep(1);
-
-	/* Update the link, speed, duplex */
-	result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
-
-	/* Adjust the known status as long as the link
-	 * isn't still coming up */
-	if ((0 == result) || (ugeth->mii_info->link == 0))
-		adjust_link(dev);
-
-	/* Reenable interrupts, if needed */
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
-		mii_configure_phy_interrupt(ugeth->mii_info,
-					    MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void ugeth_phy_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-	schedule_work(&ugeth->tq);
-
-	mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * If, after GFAR_AN_TIMEOUT seconds, it has not
- * finished, we switch to forced.
- * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
- * using ugeth_phy_timer to check status */
-static void ugeth_phy_startup_timer(unsigned long data)
-{
-	struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
-	struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev);
-	static int secondary = UGETH_AN_TIMEOUT;
-	int result;
-
-	/* Configure the Auto-negotiation */
-	result = mii_info->phyinfo->config_aneg(mii_info);
-
-	/* If autonegotiation failed to start, and
-	 * we haven't timed out, reset the timer, and return */
-	if (result && secondary--) {
-		mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
-		return;
-	} else if (result) {
-		/* Couldn't start autonegotiation.
-		 * Try switching to forced */
-		mii_info->autoneg = 0;
-		result = mii_info->phyinfo->config_aneg(mii_info);
-
-		/* Forcing failed!  Give up */
-		if (result) {
-			ugeth_err("%s: Forcing failed!", mii_info->dev->name);
-			return;
-		}
-	}
-
-	/* Kill the timer so it can be restarted */
-	del_timer_sync(&ugeth->phy_info_timer);
-
-	/* Grab the PHY interrupt, if necessary/possible */
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-		if (request_irq(ugeth->ug_info->phy_interrupt,
-				phy_interrupt, IRQF_SHARED,
-				"phy_interrupt", mii_info->dev) < 0) {
-			ugeth_err("%s: Can't get IRQ %d (PHY)",
-				  mii_info->dev->name,
-				  ugeth->ug_info->phy_interrupt);
-		} else {
-			mii_configure_phy_interrupt(ugeth->mii_info,
-						    MII_INTERRUPT_ENABLED);
-			return;
-		}
-	}
-
-	/* Start the timer again, this time in order to
-	 * handle a change in status */
-	init_timer(&ugeth->phy_info_timer);
-	ugeth->phy_info_timer.function = &ugeth_phy_timer;
-	ugeth->phy_info_timer.data = (unsigned long)mii_info->dev;
-	mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
 /* Called when something needs to use the ethernet device */
 /* Returns 0 for success. */
 static int ucc_geth_open(struct net_device *dev)
@@ -3979,6 +3638,12 @@
 		return -EINVAL;
 	}
 
+	err = ucc_struct_init(ugeth);
+	if (err) {
+		ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
+		return err;
+	}
+
 	err = ucc_geth_startup(ugeth);
 	if (err) {
 		ugeth_err("%s: Cannot configure net device, aborting.",
@@ -4006,9 +3671,12 @@
 
 	err = init_phy(dev);
 	if (err) {
-		ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name);
+		ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
 		return err;
 	}
+
+	phy_start(ugeth->phydev);
+
 #ifndef CONFIG_UGETH_NAPI
 	err =
 	    request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
@@ -4021,14 +3689,6 @@
 	}
 #endif				/* CONFIG_UGETH_NAPI */
 
-	/* Set up the PHY change work queue */
-	INIT_WORK(&ugeth->tq, ugeth_phy_change);
-
-	init_timer(&ugeth->phy_info_timer);
-	ugeth->phy_info_timer.function = &ugeth_phy_startup_timer;
-	ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info;
-	mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
-
 	err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
 	if (err) {
 		ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
@@ -4050,11 +3710,8 @@
 
 	ucc_geth_stop(ugeth);
 
-	/* Shutdown the PHY */
-	if (ugeth->mii_info->phyinfo->close)
-		ugeth->mii_info->phyinfo->close(ugeth->mii_info);
-
-	kfree(ugeth->mii_info);
+	phy_disconnect(ugeth->phydev);
+	ugeth->phydev = NULL;
 
 	netif_stop_queue(dev);
 
@@ -4063,20 +3720,53 @@
 
 const struct ethtool_ops ucc_geth_ethtool_ops = { };
 
+static phy_interface_t to_phy_interface(const char *interface_type)
+{
+	if (strcasecmp(interface_type, "mii") == 0)
+		return PHY_INTERFACE_MODE_MII;
+	if (strcasecmp(interface_type, "gmii") == 0)
+		return PHY_INTERFACE_MODE_GMII;
+	if (strcasecmp(interface_type, "tbi") == 0)
+		return PHY_INTERFACE_MODE_TBI;
+	if (strcasecmp(interface_type, "rmii") == 0)
+		return PHY_INTERFACE_MODE_RMII;
+	if (strcasecmp(interface_type, "rgmii") == 0)
+		return PHY_INTERFACE_MODE_RGMII;
+	if (strcasecmp(interface_type, "rgmii-id") == 0)
+		return PHY_INTERFACE_MODE_RGMII_ID;
+	if (strcasecmp(interface_type, "rtbi") == 0)
+		return PHY_INTERFACE_MODE_RTBI;
+
+	return PHY_INTERFACE_MODE_MII;
+}
+
 static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
 {
 	struct device *device = &ofdev->dev;
 	struct device_node *np = ofdev->node;
+	struct device_node *mdio;
 	struct net_device *dev = NULL;
 	struct ucc_geth_private *ugeth = NULL;
 	struct ucc_geth_info *ug_info;
 	struct resource res;
 	struct device_node *phy;
-	int err, ucc_num, phy_interface;
-	static int mii_mng_configured = 0;
+	int err, ucc_num, max_speed = 0;
 	const phandle *ph;
 	const unsigned int *prop;
 	const void *mac_addr;
+	phy_interface_t phy_interface;
+	static const int enet_to_speed[] = {
+		SPEED_10, SPEED_10, SPEED_10,
+		SPEED_100, SPEED_100, SPEED_100,
+		SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000,
+	};
+	static const phy_interface_t enet_to_phy_interface[] = {
+		PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII,
+		PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII,
+		PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
+		PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
+		PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
+	};
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
@@ -4087,6 +3777,7 @@
 
 	ug_info = &ugeth_info[ucc_num];
 	ug_info->uf_info.ucc_num = ucc_num;
+
 	prop = get_property(np, "rx-clock", NULL);
 	ug_info->uf_info.rx_clock = *prop;
 	prop = get_property(np, "tx-clock", NULL);
@@ -4104,13 +3795,72 @@
 	if (phy == NULL)
 		return -ENODEV;
 
+	/* set the PHY address */
 	prop = get_property(phy, "reg", NULL);
+	if (prop == NULL)
+		return -1;
 	ug_info->phy_address = *prop;
-	prop = get_property(phy, "interface", NULL);
-	ug_info->enet_interface = *prop;
-	ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0);
-	ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)?
-			0:FSL_UGETH_BRD_HAS_PHY_INTR;
+
+	/* get the phy interface type, or default to MII */
+	prop = get_property(np, "interface-type", NULL);
+	if (!prop) {
+		/* handle interface property present in old trees */
+		prop = get_property(phy, "interface", NULL);
+		if (prop != NULL)
+			phy_interface = enet_to_phy_interface[*prop];
+		else
+			phy_interface = PHY_INTERFACE_MODE_MII;
+	} else {
+		phy_interface = to_phy_interface((const char *)prop);
+	}
+
+	/* get speed, or derive from interface */
+	prop = get_property(np, "max-speed", NULL);
+	if (!prop) {
+		/* handle interface property present in old trees */
+		prop = get_property(phy, "interface", NULL);
+		if (prop != NULL)
+			max_speed = enet_to_speed[*prop];
+	} else {
+		max_speed = *prop;
+	}
+	if (!max_speed) {
+		switch (phy_interface) {
+		case PHY_INTERFACE_MODE_GMII:
+		case PHY_INTERFACE_MODE_RGMII:
+		case PHY_INTERFACE_MODE_RGMII_ID:
+		case PHY_INTERFACE_MODE_TBI:
+		case PHY_INTERFACE_MODE_RTBI:
+			max_speed = SPEED_1000;
+			break;
+		default:
+			max_speed = SPEED_100;
+			break;
+		}
+	}
+
+	if (max_speed == SPEED_1000) {
+		ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT;
+		ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT;
+		ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT;
+		ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT;
+		ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT;
+		ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT;
+	}
+
+	/* Set the bus id */
+	mdio = of_get_parent(phy);
+
+	if (mdio == NULL)
+		return -1;
+
+	err = of_address_to_resource(mdio, 0, &res);
+	of_node_put(mdio);
+
+	if (err)
+		return -1;
+
+	ug_info->mdio_bus = res.start;
 
 	printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
 		ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
@@ -4122,43 +3872,6 @@
 		return -ENODEV;
 	}
 
-	/* FIXME: Work around for early chip rev.               */
-	/* There's a bug in initial chip rev(s) in the RGMII ac */
-	/* timing.						*/
-	/* The following compensates by writing to the reserved */
-	/* QE Port Output Hold Registers (CPOH1?).              */
-	prop = get_property(phy, "interface", NULL);
-	phy_interface = *prop;
-	if ((phy_interface == ENET_1000_RGMII) ||
-			(phy_interface == ENET_100_RGMII) ||
-			(phy_interface == ENET_10_RGMII)) {
-		struct device_node *soc;
-		phys_addr_t immrbase = -1;
-		u32 *tmp_reg;
-		u32 tmp_val;
-
-		soc = of_find_node_by_type(NULL, "soc");
-		if (soc) {
-			unsigned int size;
-			const void *prop = get_property(soc, "reg", &size);
-			immrbase = of_translate_address(soc, prop);
-			of_node_put(soc);
-		};
-
-		tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4);
-		tmp_val = in_be32(tmp_reg);
-		if (ucc_num == 1)
-			out_be32(tmp_reg, tmp_val | 0x00003000);
-		else if (ucc_num == 2)
-			out_be32(tmp_reg, tmp_val | 0x0c000000);
-		iounmap(tmp_reg);
-	}
-
-	if (!mii_mng_configured) {
-		ucc_set_qe_mux_mii_mng(ucc_num);
-		mii_mng_configured = 1;
-	}
-
 	/* Create an ethernet device instance */
 	dev = alloc_etherdev(sizeof(*ugeth));
 
@@ -4192,6 +3905,10 @@
 	dev->set_multicast_list = ucc_geth_set_multi;
 	dev->ethtool_ops = &ucc_geth_ethtool_ops;
 
+	ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+	ugeth->phy_interface = phy_interface;
+	ugeth->max_speed = max_speed;
+
 	err = register_netdev(dev);
 	if (err) {
 		ugeth_err("%s: Cannot register net device, aborting.",
@@ -4200,13 +3917,13 @@
 		return err;
 	}
 
-	ugeth->ug_info = ug_info;
-	ugeth->dev = dev;
-
 	mac_addr = of_get_mac_address(np);
 	if (mac_addr)
 		memcpy(dev->dev_addr, mac_addr, 6);
 
+	ugeth->ug_info = ug_info;
+	ugeth->dev = dev;
+
 	return 0;
 }
 
@@ -4242,19 +3959,30 @@
 
 static int __init ucc_geth_init(void)
 {
-	int i;
+	int i, ret;
+
+	ret = uec_mdio_init();
+
+	if (ret)
+		return ret;
 
 	printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
 	for (i = 0; i < 8; i++)
 		memcpy(&(ugeth_info[i]), &ugeth_primary_info,
 		       sizeof(ugeth_primary_info));
 
-	return of_register_platform_driver(&ucc_geth_driver);
+	ret = of_register_platform_driver(&ucc_geth_driver);
+
+	if (ret)
+		uec_mdio_exit();
+
+	return ret;
 }
 
 static void __exit ucc_geth_exit(void)
 {
 	of_unregister_platform_driver(&ucc_geth_driver);
+	uec_mdio_exit();
 }
 
 module_init(ucc_geth_init);