mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-29 08:01:08 +00:00
net: memac_phy: add a timeout to MDIO operations
We have encountered circumstances when a board design does not include pull-up resistors on the external MDIO buses which are not used. This leads to the MDIO data line not being pulled-up, thus the MDIO controller will always see the line as busy. Without a timeout in the MDIO bus driver, the execution is stuck in an infinite loop when any access is initiated on that external bus. Add a timeout in the driver so that we are protected in this circumstance. This is similar to what is being done in the Linux xgmac_mdio driver. Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com> Reviewed-by: Madalin Bucur <madalin.bucur@oss.nxp.com> [Rebased] Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
This commit is contained in:
parent
46fdf763b8
commit
64a0fb4cc3
1 changed files with 58 additions and 18 deletions
|
@ -28,6 +28,8 @@ struct fm_mdio_priv {
|
|||
};
|
||||
#endif
|
||||
|
||||
#define MAX_NUM_RETRIES 1000
|
||||
|
||||
static u32 memac_in_32(u32 *reg)
|
||||
{
|
||||
#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN
|
||||
|
@ -37,6 +39,42 @@ static u32 memac_in_32(u32 *reg)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until the MDIO bus is free
|
||||
*/
|
||||
static int memac_wait_until_free(struct memac_mdio_controller *regs)
|
||||
{
|
||||
unsigned int timeout = MAX_NUM_RETRIES;
|
||||
|
||||
while ((memac_in_32(®s->mdio_stat) & MDIO_STAT_BSY) && timeout--)
|
||||
;
|
||||
|
||||
if (!timeout) {
|
||||
printf("timeout waiting for MDIO bus to be free\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait till the MDIO read or write operation is complete
|
||||
*/
|
||||
static int memac_wait_until_done(struct memac_mdio_controller *regs)
|
||||
{
|
||||
unsigned int timeout = MAX_NUM_RETRIES;
|
||||
|
||||
while ((memac_in_32(®s->mdio_data) & MDIO_DATA_BSY) && timeout--)
|
||||
;
|
||||
|
||||
if (!timeout) {
|
||||
printf("timeout waiting for MDIO operation to complete\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write value to the PHY for this device to the register at regnum, waiting
|
||||
* until the write is done before it returns. All PHY configuration has to be
|
||||
|
@ -48,6 +86,7 @@ int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
|
|||
struct memac_mdio_controller *regs;
|
||||
u32 mdio_ctl;
|
||||
u32 c45 = 1; /* Default to 10G interface */
|
||||
int err;
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
regs = bus->priv;
|
||||
|
@ -69,9 +108,9 @@ int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
|
|||
} else
|
||||
memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
err = memac_wait_until_free(regs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set the port and dev addr */
|
||||
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
|
||||
|
@ -81,16 +120,16 @@ int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
|
|||
if (c45)
|
||||
memac_out_32(®s->mdio_addr, regnum & 0xffff);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
err = memac_wait_until_free(regs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Write the value to the register */
|
||||
memac_out_32(®s->mdio_data, MDIO_DATA(value));
|
||||
|
||||
/* Wait till the MDIO write is complete */
|
||||
while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY)
|
||||
;
|
||||
err = memac_wait_until_done(regs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -106,6 +145,7 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
|
|||
struct memac_mdio_controller *regs;
|
||||
u32 mdio_ctl;
|
||||
u32 c45 = 1;
|
||||
int err;
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
regs = bus->priv;
|
||||
|
@ -129,9 +169,9 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
|
|||
} else
|
||||
memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
err = memac_wait_until_free(regs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set the Port and Device Addrs */
|
||||
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
|
||||
|
@ -141,17 +181,17 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
|
|||
if (c45)
|
||||
memac_out_32(®s->mdio_addr, regnum & 0xffff);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
err = memac_wait_until_free(regs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Initiate the read */
|
||||
mdio_ctl |= MDIO_CTL_READ;
|
||||
memac_out_32(®s->mdio_ctl, mdio_ctl);
|
||||
|
||||
/* Wait till the MDIO write is complete */
|
||||
while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY)
|
||||
;
|
||||
err = memac_wait_until_done(regs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Return all Fs if nothing was there */
|
||||
if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER)
|
||||
|
|
Loading…
Reference in a new issue