In the AM35xx TRM, Table 22-43 on page 2564 documents the field descriptions for the USERACCESS0
register, which is used to kick off a MDIO access operation. For clarity, the table is reproduced as follows:
Bit | Field | Value | Description |
---|---|---|---|
31 | GO | 0-1 | Go bit. Writing a 1 to this bit causes the MDIO state machine to perform an MDIO access when it is convenient for it to do so; this is not an instantaneous process. Writing a 0 to this bit has no effect. This bit is writeable only if the MDIO state machine is enabled. This bit will self clear when the requested access has been completed. Any writes to USERACCESS0 are blocked when the GO bit is 1. |
30 | WRITE | 0-1 | Write enable bit. Setting this bit to 1 causes the MDIO transaction to be a register write; otherwise, it is a register read. |
29 | ACK | 0-1 | Acknowledge bit. This bit is set if the PHY acknowledged the read transaction. |
28-26 | Reserved | 0 | Reserved |
25-21 | REGADR | 0-1Fh | Register address bits. This field specifies the PHY register to be accessed for this transaction. |
20-16 | PHYADR | 0-1Fh | PHY address bits. This field specifies the PHY to be accessed for this transaction. |
15-0 | DATA | 0-FFFFh | User data bits. These bits specify the data value read from or to be written to the specified PHY register. |
USERACCESS0
is a 32-bit MMIO register. In U-Boot, it is accessed as follows:
static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
int dev_addr, int phy_reg)
{
struct cpsw_mdio *mdio = MII_TO_CPSW_MDIO(bus);
int data, ret;
u32 reg;
if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
return -EINVAL;
ret = cpsw_mdio_wait_for_user_access(mdio);
if (ret)
return ret;
reg = (USERACCESS_GO | USERACCESS_READ |
(phy_reg << USERACCESS_PHY_REG_SHIFT) |
(phy_id << USERACCESS_PHY_ADDR_SHIFT));
writel(reg, &mdio->regs->user[0].access);
ret = cpsw_mdio_wait_for_user_access(mdio);
if (ret)
return ret;
reg = readl(&mdio->regs->user[0].access);
data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1;
return data;
}
You might be wondering what happens in cpsw_mdio_wait_for_user_access
. Well, it spinwaits for the GO
bit to be cleared by the CPSW hardware for up to CPSW_MDIO_TIMEOUT
(100) milliseconds. And what happens if that timeout is hit?
Chaos. The CPSW hardware is sensitive to the MDIO pin muxing, so if the pins are not muxed for MDIO by the board file in U-Boot, the GO
bit will never be cleared. This will cause to a string of seemingly random errors from the mii
and mdio
commands. There is no command to soft interrupt the CPSW hardware while a PHY access is pending, either, so the driver enters an invalid state where it is waiting for the GO bit to clear on every user access command.
To get out of this state, the entire switch block has to be turned off and back on again. This could be implemented in the driver, but it is probably not worth it in the context of what the driver is used for.