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

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

parent e399661d
...@@ -16,7 +16,7 @@ S = "${WORKDIR}/git" ...@@ -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
......
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;
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;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment