Commit 0a012ae7 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

pathched xilinx_emacps.c for Atheros AR8035 PHY, aded some debug output

parent e399661d
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@ S = "${WORKDIR}/git"


FILESEXTRAPATHS_append := "${THISDIR}/linux-xlnx:"
FILESEXTRAPATHS_append := "${THISDIR}/linux-xlnx:"
SRC_URI_append += " file://xilinx_nandps_elphel393.patch"
SRC_URI_append += " file://xilinx_nandps_elphel393.patch"
#SRC_URI_append += " file://xilinx_emacps_elphel393.patch"
SRC_URI_append += " file://xilinx_emacps.patch"


inherit kernel
inherit kernel
require linux-dtb.inc
require linux-dtb.inc
+115 −0
Original line number Original line Diff line number Diff line
Index: git/drivers/net/ethernet/xilinx/xilinx_emacps.c
===================================================================
--- git.orig/drivers/net/ethernet/xilinx/xilinx_emacps.c	2013-11-23 16:44:54.262025863 -0700
+++ git/drivers/net/ethernet/xilinx/xilinx_emacps.c	2013-11-23 00:04:25.000000000 -0700
@@ -468,6 +468,11 @@
 							second */
 #endif
 
+/* Elphel */
+#define AT803X_PHY_ID		0x004dd072 /*Particular one, AR8035 but we'll use a broad mask */
+#define AT803X_PHY_ID_MASK	0xffffffe0
+
+
 #define xemacps_read(base, reg)						\
 	__raw_readl(((void __iomem *)(base)) + (reg))
 #define xemacps_write(base, reg, val)					\
@@ -566,9 +571,18 @@
 static int xemacps_mdio_read(struct mii_bus *bus, int mii_id, int phyreg)
 {
 	struct net_local *lp = bus->priv;
-	u32 regval;
+	u32 regval,oldregval;
 	int value;
 	volatile u32 ipisr;
+	/* check/wait for idle */
+	if ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) &
+	  XEMACPS_NWSR_MDIOIDLE_MASK)==0){
+	    oldregval = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET);
+	  	       dev_warn(&lp->pdev->dev," ********* %s:%d Should not happen (add spinlock if it does) - MDIO is NOT IDLE, shift register value=0x%08x\n",
+	  	    		   __func__,__LINE__,(int) value);
+	  	       while ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) &
+	  	    		  XEMACPS_NWSR_MDIOIDLE_MASK)==0); /* just wait */
+	}
 
 	regval  = XEMACPS_PHYMNTNC_OP_MASK;
 	regval |= XEMACPS_PHYMNTNC_OP_R_MASK;
@@ -606,8 +620,17 @@
 	u16 value)
 {
 	struct net_local *lp = bus->priv;
-	u32 regval;
+	u32 regval,oldregval;
 	volatile u32 ipisr;
+	/* check/wait for idle */
+	if ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) &
+	  XEMACPS_NWSR_MDIOIDLE_MASK)==0){
+	    oldregval = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET);
+	  	       dev_warn(&lp->pdev->dev," ********* %s:%d Should not happen (add spinlock if it does) - MDIO is NOT IDLE, shift register value=0x%08x\n",
+	  	    		   __func__,__LINE__,(int) value);
+	  	       while ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) &
+	  	    		  XEMACPS_NWSR_MDIOIDLE_MASK)==0); /* just wait */
+	}
 
 	regval  = XEMACPS_PHYMNTNC_OP_MASK;
 	regval |= XEMACPS_PHYMNTNC_OP_W_MASK;
@@ -738,6 +761,50 @@
 	}
 }
 
+/* http://www.spinics.net/lists/devicetree/msg06322.html */
+static int ar8035_phy_fixup(struct phy_device *dev)
+{
+	u16 val;
+	struct net_local *lp = dev->bus->priv;
+	dev_dbg(&lp->pdev->dev,"fixup start");
+
+	/* Ar803x phy SmartEEE feature cause link status generates glitch,
+	 * which cause ethernet link down/up issue, so disable SmartEEE
+	 */
+	phy_write(dev, 0xd, 0x3);
+	phy_write(dev, 0xe, 0x805d);
+	phy_write(dev, 0xd, 0x4003);
+
+	val = phy_read(dev, 0xe);
+	phy_write(dev, 0xe, val & ~(1 << 8));
+	/*Enable if needed */
+#if 0
+	/* To enable AR8031 output a 125MHz clk from CLK_25M */
+	phy_write(dev, 0xd, 0x7);
+	phy_write(dev, 0xe, 0x8016);
+	phy_write(dev, 0xd, 0x4007);
+
+	val = phy_read(dev, 0xe);
+	val &= 0xffe3;
+	val |= 0x18;
+	phy_write(dev, 0xe, val);
+#endif
+/* Next one what is really needed for Elphel 393 */
+	/* introduce tx clock delay */
+	phy_write(dev, 0x1d, 0x5);
+	val = phy_read(dev, 0x1e);
+	val |= 0x0100;
+	phy_write(dev, 0x1e, val);
+
+	/*check phy power*/
+	val = phy_read(dev, 0x0);
+	if (val & BMCR_PDOWN)
+		phy_write(dev, 0x0, val & ~BMCR_PDOWN);
+	dev_dbg(&lp->pdev->dev,"fixup end");
+	return 0;
+}
+
+
 static int xemacps_clk_notifier_cb(struct notifier_block *nb, unsigned long
 		event, void *data)
 {
@@ -840,7 +907,7 @@
 	struct resource res;
 	struct device_node *np = of_get_parent(lp->phy_node);
 	struct device_node *npp;
-
+    phy_register_fixup_for_uid(AT803X_PHY_ID,  AT803X_PHY_ID_MASK,  ar8035_phy_fixup);
 	lp->mii_bus = mdiobus_alloc();
 	if (lp->mii_bus == NULL) {
 		rc = -ENOMEM;
+0 −458
Original line number Original line Diff line number Diff line
diff --git a/drivers/net/ethernet/xilinx/xilinx_emacps.c b/drivers/net/ethernet/xilinx/xilinx_emacps.c
index 1a0db68..01e4f16 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emacps.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emacps.c
@@ -484,7 +484,14 @@ MDC_DIV_64, MDC_DIV_96, MDC_DIV_128, MDC_DIV_224 };
 #define xemacps_write(base, reg, val)					\
 	__raw_writel((val), (void __iomem *)((base) + (reg)))
 
-
+/* Elphel */
+/* Assuming Xilinx made fixup that is valid for all Marvell PHYs we'll move it into a separate fixup
+   as it is not applicable to Atheros AR8035 used in Elphel393 */
+/*#define MARVELL_PHY_ID_88E1510		0x01410dd0*/
+#define MARVELL_PHY_ID		0x01410dd0 /*Particular one, but we'll use a broad mask */
+#define MARVELL_PHY_ID_MASK	0xfffff000
+#define AT803X_PHY_ID		0x004dd072 /*Particular one, AR8035 but we'll use a broad mask */
+#define AT803X_PHY_ID_MASK	0xffffffe0
 
 struct ring_info {
 	struct sk_buff *skb;
@@ -524,6 +531,8 @@ struct net_local {
 
 	spinlock_t tx_lock;
 	spinlock_t rx_lock;
+	
+	spinlock_t phy_rw_lock; /* to prevent multiple operations on the bus */ 
 
 	struct platform_device *pdev;
 	struct net_device *ndev; /* this device */
@@ -578,15 +587,32 @@ static struct net_device_ops netdev_ops;
 static int xemacps_mdio_read(struct mii_bus *bus, int mii_id, int phyreg)
 {
 	struct net_local *lp = bus->priv;
-	u32 regval;
+	u32 regval,oldregval;
 	int value;
 	volatile u32 ipisr;
-
+	unsigned long flags;
+	int collisions=0;
 	regval  = XEMACPS_PHYMNTNC_OP_MASK;
 	regval |= XEMACPS_PHYMNTNC_OP_R_MASK;
 	regval |= (mii_id << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK);
 	regval |= (phyreg << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK);
+	/* wait for idle */
+	if ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) & 
+	  XEMACPS_NWSR_MDIOIDLE_MASK)==0){
+	    oldregval = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET);
+	  	       dev_warn(&lp->pdev->dev," ********* %s:%d Should not happen - MDIO is NOT IDLE, shift register value=0x%08x\n",__func__,__LINE__,(int) value);
+	/* No waiting now, spinlock should take care */	      
+	}
 
+	spin_lock_irqsave(&lp->phy_rw_lock, flags);
+	if ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) & 
+	  XEMACPS_NWSR_MDIOIDLE_MASK)==0){
+	    do {
+		collisions++;
+	        ipisr = xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET);
+	    } while ((ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0);
+	    oldregval = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET);
+	}
 	xemacps_write(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET, regval);
 
 	/* wait for end of transfer */
@@ -597,7 +623,9 @@ static int xemacps_mdio_read(struct mii_bus *bus, int mii_id, int phyreg)
 
 	value = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET) &
 			XEMACPS_PHYMNTNC_DATA_MASK;
-
+	spin_unlock_irqrestore(&lp->phy_rw_lock, flags);
+	if (collisions>0)  dev_warn(&lp->pdev->dev, "Previous value of the mii register after shift = 0x%08x, waited %d cycles\n",(int) oldregval, collisions);
+	dev_dbg(&lp->pdev->dev,"mii_id=%x phyreg=%x value=%04x",mii_id,phyreg,(int)value);
 	return value;
 }
 
@@ -618,15 +646,32 @@ static int xemacps_mdio_write(struct mii_bus *bus, int mii_id, int phyreg,
 	u16 value)
 {
 	struct net_local *lp = bus->priv;
-	u32 regval;
+	u32 regval,oldregval;
 	volatile u32 ipisr;
-
+	unsigned long flags;
+	int collisions=0;
 	regval  = XEMACPS_PHYMNTNC_OP_MASK;
 	regval |= XEMACPS_PHYMNTNC_OP_W_MASK;
 	regval |= (mii_id << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK);
 	regval |= (phyreg << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK);
 	regval |= value;
+	/* wait for idle */
+	if ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) & 
+	  XEMACPS_NWSR_MDIOIDLE_MASK)==0){
+	    oldregval = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET);
+	        dev_warn(&lp->pdev->dev," ********* %s:%d Should not happen - MDIO is NOT IDLE, shift register value=0x%08x\n",__func__,__LINE__,(int) value);
+	/* No waiting now, spinlock should take care */	      
+	}
 
+	spin_lock_irqsave(&lp->phy_rw_lock, flags);
+	if ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) & 
+	  XEMACPS_NWSR_MDIOIDLE_MASK)==0){
+	    do {
+		collisions++;
+	        ipisr = xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET);
+	    } while ((ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0);
+	    oldregval = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET);
+	}
 	xemacps_write(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET, regval);
 
 	/* wait for end of transfer */
@@ -634,7 +679,9 @@ static int xemacps_mdio_write(struct mii_bus *bus, int mii_id, int phyreg,
 		cpu_relax();
 		ipisr = xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET);
 	} while ((ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0);
-
+	spin_unlock_irqrestore(&lp->phy_rw_lock, flags);
+	if (collisions>0)  dev_warn(&lp->pdev->dev,"Previous value of the mii register after shift = 0x%08x, waited %d cycles\n",(int) oldregval, collisions);
+	dev_dbg(&lp->pdev->dev,"mii_id=%x phyreg=%x value=%04x",mii_id,phyreg,(int)value);
 	return 0;
 }
 
@@ -655,6 +702,8 @@ static void xemacps_phy_init(struct net_device *ndev)
 	struct net_local *lp = netdev_priv(ndev);
 	u16 regval;
 	int i = 0;
+	
+	dev_dbg(&lp->pdev->dev, "Seems to be for Marvell again ..."); /* Used for non-Zynq */
 
 	/* set RX delay */
 	regval = xemacps_mdio_read(lp->mii_bus, lp->phy_dev->addr, 20);
@@ -711,13 +760,18 @@ static void xemacps_adjust_link(struct net_device *ndev)
 {
 	struct net_local *lp = netdev_priv(ndev);
 	struct phy_device *phydev = lp->phy_dev;
-	struct phy_device *gmii2rgmii_phydev = lp->gmii2rgmii_phy_dev;
 	int status_change = 0;
 	u32 regval;
-
+	long rate;
+	unsigned long flags;
+	dev_dbg(&lp->pdev->dev,"xemacps_adjust_link()\n"); /* Too noisy -each second */
 	if (phydev->link) {
 		if ((lp->speed != phydev->speed) ||
 			(lp->duplex != phydev->duplex)) {
+			
+			spin_lock_irqsave(&lp->tx_lock, flags);
+			spin_lock(&lp->rx_lock);
+		
 			regval = xemacps_read(lp->baseaddr,
 				XEMACPS_NWCFG_OFFSET);
 			if (phydev->duplex)
@@ -727,48 +781,32 @@ static void xemacps_adjust_link(struct net_device *ndev)
 
 			if (phydev->speed == SPEED_1000) {
 				regval |= XEMACPS_NWCFG_1000_MASK;
-				xemacps_set_freq(lp->devclk, 125000000,
-						&lp->pdev->dev);
+				rate= 125000000;
 			} else {
 				regval &= ~XEMACPS_NWCFG_1000_MASK;
 			}
 
 			if (phydev->speed == SPEED_100) {
 				regval |= XEMACPS_NWCFG_100_MASK;
-				xemacps_set_freq(lp->devclk, 25000000,
-						&lp->pdev->dev);
+				rate= 25000000;
 			} else {
 				regval &= ~XEMACPS_NWCFG_100_MASK;
 			}
 
 			if (phydev->speed == SPEED_10) {
-				xemacps_set_freq(lp->devclk, 2500000,
-						&lp->pdev->dev);
+				rate= 2500000;
 			}
 
 			xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET,
-			regval);
-
-			if (regval & XEMACPS_NWCFG_1000_MASK) {
-				xemacps_mdio_write(lp->mii_bus,
-				gmii2rgmii_phydev->addr,
-				XEMACPS_GMII2RGMII_REG_NUM,
-				XEMACPS_GMII2RGMII_SPEED1000_FD);
-			} else if (regval & XEMACPS_NWCFG_100_MASK) {
-				xemacps_mdio_write(lp->mii_bus,
-				gmii2rgmii_phydev->addr,
-				XEMACPS_GMII2RGMII_REG_NUM,
-				XEMACPS_GMII2RGMII_SPEED100_FD);
-			} else {
-				xemacps_mdio_write(lp->mii_bus,
-				gmii2rgmii_phydev->addr,
-				XEMACPS_GMII2RGMII_REG_NUM,
-				XEMACPS_GMII2RGMII_SPEED10_FD);
-			}
-
+				regval);
+			xemacps_set_freq(lp->devclk,rate,&lp->pdev->dev);
 			lp->speed = phydev->speed;
 			lp->duplex = phydev->duplex;
 			status_change = 1;
+			
+			spin_unlock(&lp->rx_lock);
+			spin_unlock_irqrestore(&lp->tx_lock, flags);
+			dev_dbg(&lp->pdev->dev,"[XEMACPS_NWCFG_OFFSET] -> %08x",(int) xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET));
 		}
 	}
 
@@ -788,6 +826,83 @@ static void xemacps_adjust_link(struct net_device *ndev)
 	}
 }
 
+static int marvell_phy_fixup(struct phy_device *dev)
+{
+	struct net_local *lp = dev->bus->priv;
+//	struct net_local *lp = netdev_priv(ndev);
+	struct phy_device *phydev = lp->phy_dev;
+	struct phy_device *gmii2rgmii_phydev = lp->gmii2rgmii_phy_dev;
+	u32 regval;
+	dev_dbg(&lp->pdev->dev,"fixup start");
+	if (phydev->link) {
+		xemacps_adjust_link(lp->ndev); /* will set clock speed, duplex for SoC - then use those values for PHY*/
+/* Do always as parameters are already updated?*/
+		regval = xemacps_read(lp->baseaddr,
+			XEMACPS_NWCFG_OFFSET);
+		if (regval & XEMACPS_NWCFG_1000_MASK) {
+			xemacps_mdio_write(lp->mii_bus,
+			gmii2rgmii_phydev->addr,
+			XEMACPS_GMII2RGMII_REG_NUM,
+			XEMACPS_GMII2RGMII_SPEED1000_FD);
+		} else if (regval & XEMACPS_NWCFG_100_MASK) {
+			xemacps_mdio_write(lp->mii_bus,
+			gmii2rgmii_phydev->addr,
+			XEMACPS_GMII2RGMII_REG_NUM,
+			XEMACPS_GMII2RGMII_SPEED100_FD);
+		} else {
+			xemacps_mdio_write(lp->mii_bus,
+			gmii2rgmii_phydev->addr,
+			XEMACPS_GMII2RGMII_REG_NUM,
+			XEMACPS_GMII2RGMII_SPEED10_FD);
+		}
+	}
+	dev_dbg(&lp->pdev->dev,"fixup end");
+	return 0;
+}
+
+/* http://www.spinics.net/lists/devicetree/msg06322.html */
+static int ar8035_phy_fixup(struct phy_device *dev)
+{
+	u16 val;
+	struct net_local *lp = dev->bus->priv;
+	dev_dbg(&lp->pdev->dev,"fixup start");
+
+	/* Ar803x phy SmartEEE feature cause link status generates glitch,
+	 * which cause ethernet link down/up issue, so disable SmartEEE
+	 */
+	phy_write(dev, 0xd, 0x3);
+	phy_write(dev, 0xe, 0x805d);
+	phy_write(dev, 0xd, 0x4003);
+
+	val = phy_read(dev, 0xe);
+	phy_write(dev, 0xe, val & ~(1 << 8));
+	/*Enable if needed */
+#if 0
+	/* To enable AR8031 output a 125MHz clk from CLK_25M */
+	phy_write(dev, 0xd, 0x7);
+	phy_write(dev, 0xe, 0x8016);
+	phy_write(dev, 0xd, 0x4007);
+
+	val = phy_read(dev, 0xe);
+	val &= 0xffe3;
+	val |= 0x18;
+	phy_write(dev, 0xe, val);
+#endif
+/* Next one what is really needed for Elphel 393 */
+	/* introduce tx clock delay */
+	phy_write(dev, 0x1d, 0x5);
+	val = phy_read(dev, 0x1e);
+	val |= 0x0100;
+	phy_write(dev, 0x1e, val);
+
+	/*check phy power*/
+	val = phy_read(dev, 0x0);
+	if (val & BMCR_PDOWN)
+		phy_write(dev, 0x0, val & ~BMCR_PDOWN);
+	dev_dbg(&lp->pdev->dev,"fixup end");
+	return 0;
+}
+
 static int xemacps_clk_notifier_cb(struct notifier_block *nb, unsigned long
 		event, void *data)
 {
@@ -865,6 +980,8 @@ static int xemacps_mii_probe(struct net_device *ndev)
 
 	dev_dbg(&lp->pdev->dev, "attach [%s] phy driver\n",
 			lp->phy_dev->drv->name);
+	dev_info(&lp->pdev->dev, "attach [%s] phy driver, phy_addr 0x%x, phy_id 0x%08x\n",
+			lp->phy_dev->drv->name,lp->phy_dev->addr, lp->phy_dev->phy_id);
 
 	if (lp->gmii2rgmii_phy_node) {
 		phydev = of_phy_connect(lp->ndev,
@@ -894,6 +1011,8 @@ static int xemacps_mii_init(struct net_local *lp)
 	struct resource res;
 	struct device_node *np = of_get_parent(lp->phy_node);
 	struct device_node *npp;
+//        phy_register_fixup_for_uid(MARVELL_PHY_ID, MARVELL_PHY_ID_MASK, marvell_phy_fixup);
+        phy_register_fixup_for_uid(AT803X_PHY_ID,  AT803X_PHY_ID_MASK,  ar8035_phy_fixup);
 
 	lp->mii_bus = mdiobus_alloc();
 	if (lp->mii_bus == NULL) {
@@ -1007,9 +1126,20 @@ static void xemacps_set_hwaddr(struct net_local *lp)
 static void xemacps_reset_hw(struct net_local *lp)
 {
 	u32 regisr;
+	unsigned long flags;
+	int dbg_cycles=-1;
 	/* make sure we have the buffer for ourselves */
 	wmb();
 
+	/* Do not interrupt MDIO PHY communication in the middle */
+	spin_lock_irqsave(&lp->phy_rw_lock, flags);
+	
+	/* Only wait if MDIO is enabled */
+	if (xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET) & XEMACPS_NWCTRL_MDEN_MASK) {
+		dbg_cycles=0;
+		while ((xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET) & XEMACPS_NWSR_MDIOIDLE_MASK) == 0) dbg_cycles++;;
+	}
+	
 	/* Have a clean start */
 	xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, 0);
 
@@ -1025,6 +1155,17 @@ static void xemacps_reset_hw(struct net_local *lp)
 	xemacps_write(lp->baseaddr, XEMACPS_IDR_OFFSET, ~0UL);
 	regisr = xemacps_read(lp->baseaddr, XEMACPS_ISR_OFFSET);
 	xemacps_write(lp->baseaddr, XEMACPS_ISR_OFFSET, regisr);
+	
+	spin_unlock_irqrestore(&lp->phy_rw_lock, flags);
+	if (dbg_cycles<0) {
+		dev_dbg(&lp->pdev->dev,"MDIO was disabled\n");
+		
+	} else if (dbg_cycles==0) {
+		dev_dbg(&lp->pdev->dev,"MDIO was idle\n");
+	} else {
+		dev_dbg(&lp->pdev->dev,"Waited %d cycles until MDIO became idle\n",dbg_cycles);
+	}
+	
 }
 
 #ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
@@ -1640,13 +1781,35 @@ static void xemacps_init_tsu(struct net_local *lp)
 #endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */
 
 /**
+ *  Temporary fix for some bug - losing access to I/O registers (dmatest suspected)
+ *  @lp: local device instance pointer
+ */
+static int wait_register_access(struct net_local *lp)
+{
+	int timeout=1000;
+	int tries=0;
+	u32 regval_dbg=xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET);
+	
+	if ((xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET) | xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET)) == 0 ) {
+		for (tries=1;tries<timeout;tries++){
+			if ((xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET) | xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET)) != 0 ) break;
+			printk("-");
+		}
+		dev_warn(&lp->pdev->dev,"Seems I/O register access was lost. Waited %d (of %d), Now [XEMACPS_NWCFG_OFFSET]=0x%08x,  [XEMACPS_NWSR_OFFSET]=0x%08x, old [XEMACPS_PHYMNTNC_OFFSET]=0x%08x\n",tries,timeout, (int) xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET), (int) xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET),(int) regval_dbg);
+		if (tries<timeout) return 0;
+		return 1;
+	}
+	return 0;
+}	
+/**
  * xemacps_init_hw - Initialize hardware to known good state
  * @lp: local device instance pointer
  **/
 static void xemacps_init_hw(struct net_local *lp)
 {
 	u32 regval;
-
+	wait_register_access(lp); /* temporary bug fix */
+	
 	xemacps_reset_hw(lp);
 	xemacps_set_hwaddr(lp);
 
@@ -1659,7 +1822,7 @@ static void xemacps_init_hw(struct net_local *lp)
 	regval |= XEMACPS_NWCFG_PAUSEEN_MASK;
 	regval |= XEMACPS_NWCFG_100_MASK;
 	regval |= XEMACPS_NWCFG_HDRXEN_MASK;
-
+/* Zynq bug semi-fix - MDC is above specs even with 667 MHz */
 	if (lp->board_type == BOARD_TYPE_ZYNQ)
 		regval |= (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK);
 	if (lp->ndev->flags & IFF_PROMISC)	/* copy all */
@@ -2601,7 +2764,10 @@ static int xemacps_probe(struct platform_device *pdev)
 	struct device_node *np;
 	const void *prop;
 	u32 regval = 0;
+	u32 regval_redadback;
 	int rc = -ENXIO;
+	unsigned long flags;
+	
 
 	r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -2626,6 +2792,7 @@ static int xemacps_probe(struct platform_device *pdev)
 
 	spin_lock_init(&lp->tx_lock);
 	spin_lock_init(&lp->rx_lock);
+	spin_lock_init(&lp->phy_rw_lock);
 
 	lp->baseaddr = ioremap(r_mem->start, (r_mem->end - r_mem->start + 1));
 	if (!lp->baseaddr) {
@@ -2634,8 +2801,8 @@ static int xemacps_probe(struct platform_device *pdev)
 		goto err_out_free_netdev;
 	}
 
-	dev_dbg(&lp->pdev->dev, "BASEADDRESS hw: %p virt: %p\n",
-			(void *)r_mem->start, lp->baseaddr);
+	dev_info(&lp->pdev->dev, "BASEADDRESS hw: %p (up to %p) virt: %p\n",
+			(void *)r_mem->start, (void *)r_mem->end, lp->baseaddr);
 
 	ndev->irq = platform_get_irq(pdev, 0);
 
@@ -2656,6 +2823,7 @@ static int xemacps_probe(struct platform_device *pdev)
 
 	lp->ip_summed = CHECKSUM_UNNECESSARY;
 	lp->board_type = BOARD_TYPE_ZYNQ;
+	wait_register_access(lp); /* temporary bug fix */
 
 	rc = register_netdev(ndev);
 	if (rc) {
@@ -2745,8 +2913,22 @@ static int xemacps_probe(struct platform_device *pdev)
 
 	if (lp->board_type == BOARD_TYPE_ZYNQ) {
 		/* Set MDIO clock divider */
-		regval = (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK);
+		/* Always divide by 224 ???  Does not match UG585 - likely Zynq hardware bug. MDC is already too high */
+		/* it also overwrites other bits, not OR-es, that causes intermittent network failures depending on device
+		 *  acrivation sequence */
+		spin_lock_irqsave(&lp->tx_lock, flags);
+		spin_lock(&lp->rx_lock);
+		regval=	xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET) & ~XEMACPS_NWCFG_MDCCLKDIV_MASK;
+		regval |= (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK);
 		xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval);
+		spin_unlock(&lp->rx_lock);
+		spin_unlock_irqrestore(&lp->tx_lock, flags);
+		regval_redadback=xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET);
+		dev_dbg(&lp->pdev->dev,"%08x -> [XEMACPS_NWCFG_OFFSET] -> 0x%08x, baseaddr=0x%08x(0x%08x)",(int)regval,(int)regval_redadback, (int)lp->baseaddr, (int)lp->ndev->base_addr);
+		if (regval_redadback != regval){
+		dev_warn(&lp->pdev->dev,"%s:%d failed to write to XEMACPS_NWCFG_OFFSET: wrote 0x%08x, read 0x%08x\n",__func__,__LINE__,(int) regval, (int) regval_redadback);
+			
+		}
 	}
 
 	regval = XEMACPS_NWCTRL_MDEN_MASK;