Merge branch 'powerpc-next' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc
diff --git a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
index cda7a7d..6f12f1c 100644
--- a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
+++ b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
@@ -237,6 +237,17 @@
 according to the bit numbers in the GPIO control registers. The second cell
 is for flags which is currently unsused.
 
+8) FEC nodes
+The FEC node can specify one of the following properties to configure
+the MII link:
+"fsl,7-wire-mode" - An empty property that specifies the link uses 7-wire
+                    mode instead of MII
+"current-speed"   - Specifies that the MII should be configured for a fixed
+                    speed.  This property should contain two cells.  The
+                    first cell specifies the speed in Mbps and the second
+                    should be '0' for half duplex and '1' for full duplex
+"phy-handle"      - Contains a phandle to an Ethernet PHY.
+
 IV - Extra Notes
 ================
 
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index d21b7ab..5f9c42e 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -43,6 +43,29 @@
 
 #define DRIVER_NAME "mpc52xx-fec"
 
+#define FEC5200_PHYADDR_NONE	(-1)
+#define FEC5200_PHYADDR_7WIRE	(-2)
+
+/* Private driver data structure */
+struct mpc52xx_fec_priv {
+	int duplex;
+	int speed;
+	int r_irq;
+	int t_irq;
+	struct mpc52xx_fec __iomem *fec;
+	struct bcom_task *rx_dmatsk;
+	struct bcom_task *tx_dmatsk;
+	spinlock_t lock;
+	int msg_enable;
+
+	/* MDIO link details */
+	int phy_addr;
+	unsigned int phy_speed;
+	struct phy_device *phydev;
+	enum phy_state link;
+};
+
+
 static irqreturn_t mpc52xx_fec_interrupt(int, void *);
 static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
 static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
@@ -223,7 +246,7 @@
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 	int err;
 
-	if (!priv->has_phy)
+	if (priv->phy_addr < 0)
 		return 0;
 
 	err = mpc52xx_fec_init_phy(dev);
@@ -243,7 +266,7 @@
 {
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 
-	if (!priv->has_phy)
+	if (!priv->phydev)
 		return;
 
 	phy_disconnect(priv->phydev);
@@ -255,7 +278,7 @@
 static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
 		struct mii_ioctl_data *mii_data, int cmd)
 {
-	if (!priv->has_phy)
+	if (!priv->phydev)
 		return -ENOTSUPP;
 
 	return phy_mii_ioctl(priv->phydev, mii_data, cmd);
@@ -265,7 +288,7 @@
 {
 	struct mpc52xx_fec __iomem *fec = priv->fec;
 
-	if (!priv->has_phy)
+	if (priv->phydev)
 		return;
 
 	out_be32(&fec->mii_speed, priv->phy_speed);
@@ -704,7 +727,7 @@
 	rcntrl = FEC_RX_BUFFER_SIZE << 16;	/* max frame length */
 	rcntrl |= FEC_RCNTRL_FCE;
 
-	if (priv->has_phy)
+	if (priv->phy_addr != FEC5200_PHYADDR_7WIRE)
 		rcntrl |= FEC_RCNTRL_MII_MODE;
 
 	if (priv->duplex == DUPLEX_FULL)
@@ -864,7 +887,10 @@
 	struct net_device *ndev;
 	struct mpc52xx_fec_priv *priv = NULL;
 	struct resource mem;
-	const phandle *ph;
+	struct device_node *phy_node;
+	const phandle *phy_handle;
+	const u32 *prop;
+	int prop_size;
 
 	phys_addr_t rx_fifo;
 	phys_addr_t tx_fifo;
@@ -948,26 +974,37 @@
 		mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
 
 	priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
-	priv->duplex = DUPLEX_FULL;
 
-	/* is the phy present in device tree? */
-	ph = of_get_property(op->node, "phy-handle", NULL);
-	if (ph) {
-		const unsigned int *prop;
-		struct device_node *phy_dn;
-		priv->has_phy = 1;
+	/*
+	 * Link mode configuration
+	 */
 
-		phy_dn = of_find_node_by_phandle(*ph);
-		prop = of_get_property(phy_dn, "reg", NULL);
-		priv->phy_addr = *prop;
+	/* Start with safe defaults for link connection */
+	priv->phy_addr = FEC5200_PHYADDR_NONE;
+	priv->speed = 100;
+	priv->duplex = DUPLEX_HALF;
+	priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
 
-		of_node_put(phy_dn);
+	/* the 7-wire property means don't use MII mode */
+	if (of_find_property(op->node, "fsl,7-wire-mode", NULL))
+		priv->phy_addr = FEC5200_PHYADDR_7WIRE;
 
-		/* Phy speed */
-		priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
-	} else {
-		dev_info(&ndev->dev, "can't find \"phy-handle\" in device"
-				" tree, using 7-wire mode\n");
+	/* The current speed preconfigures the speed of the MII link */
+	prop = of_get_property(op->node, "current-speed", &prop_size);
+	if (prop && (prop_size >= sizeof(u32) * 2)) {
+		priv->speed = prop[0];
+		priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
+	}
+
+	/* If there is a phy handle, setup link to that phy */
+	phy_handle = of_get_property(op->node, "phy-handle", &prop_size);
+	if (phy_handle && (prop_size >= sizeof(phandle))) {
+		phy_node = of_find_node_by_phandle(*phy_handle);
+		prop = of_get_property(phy_node, "reg", &prop_size);
+		if (prop && (prop_size >= sizeof(u32)))
+			if ((*prop >= 0) && (*prop < PHY_MAX_ADDR))
+				priv->phy_addr = *prop;
+		of_node_put(phy_node);
 	}
 
 	/* Hardware init */
@@ -982,6 +1019,20 @@
 	if (rv < 0)
 		goto probe_error;
 
+	/* Now report the link setup */
+	switch (priv->phy_addr) {
+	 case FEC5200_PHYADDR_NONE:
+		dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n",
+			 priv->speed, priv->duplex ? 'F' : 'H');
+		break;
+	 case FEC5200_PHYADDR_7WIRE:
+		dev_info(&ndev->dev, "using 7-wire PHY mode\n");
+		break;
+	 default:
+		dev_info(&ndev->dev, "Using PHY at MDIO address %i\n",
+			 priv->phy_addr);
+	}
+
 	/* We're done ! */
 	dev_set_drvdata(&op->dev, ndev);
 
diff --git a/drivers/net/fec_mpc52xx.h b/drivers/net/fec_mpc52xx.h
index 8b1f753..a227a52 100644
--- a/drivers/net/fec_mpc52xx.h
+++ b/drivers/net/fec_mpc52xx.h
@@ -26,25 +26,6 @@
 
 #define FEC_WATCHDOG_TIMEOUT	((400*HZ)/1000)
 
-struct mpc52xx_fec_priv {
-	int duplex;
-	int r_irq;
-	int t_irq;
-	struct mpc52xx_fec __iomem *fec;
-	struct bcom_task *rx_dmatsk;
-	struct bcom_task *tx_dmatsk;
-	spinlock_t lock;
-	int msg_enable;
-
-	int has_phy;
-	unsigned int phy_speed;
-	unsigned int phy_addr;
-	struct phy_device *phydev;
-	enum phy_state link;
-	int speed;
-};
-
-
 /* ======================================================================== */
 /* Hardware register sets & bits                                            */
 /* ======================================================================== */
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 7a3625f..efc971d 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -783,7 +783,9 @@
 		}
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(tty);
+	spin_lock(&port->lock);
 
 	return psc_ops->raw_rx_rdy(port);
 }