The short answer to your question is: you can’t determine the PHY address from phy_id. They’re two unrelated things.
What 0x2000a231 actually is
That value is the concatenation of MDIO registers 2 and 3 (PHYIDR1 / PHYIDR2), which hold the device identity, not its location on the bus:
Field
Value
Meaning
PHYIDR1
0x2000
OUI bits 3–18
PHYIDR2[15:10]
0x28
OUI bits 19–24
→ OUI
0x080028
Texas Instruments
PHYIDR2[9:4]
0x23
Vendor model number (DP83867)
PHYIDR2[3:0]
0x1
Model revision
This value would be exactly the same whether the DP83867 were strapped to address 0, 7, or 31. The phy_id tells you what answered; it says nothing about where you asked.
Where you can check the address 0
Through sysfs:/sys/class/net/ethernet0/phydev is a symlink into the MDIO bus device — the target ends in :00, and that two-digit suffix is the MDIO address. Try:
readlink -f /sys/class/net/ethernet0/phydev
ls /sys/bus/mdio_bus/devices/
ethtool’s PHYAD field, which the driver reports directly from phydev->mdio.addr — i.e. the address the driver bound to.
Mechanically: at boot the MDIO bus is scanned, something responded at address 0, the kernel read registers 2/3 from it and got 0x2000a231. The address came from the scan; the ID came from the response.
The safe recommendation for your design is: strap your external PHY to a non-zero address (and make sure the strap resistors hold the value stably through reset). The DP83867 latches these pins at power-up and then drives them as outputs, and the same applies to external PHY.