Re: [PATCH net v1] net: phy: motorcomm: yt8821: disable MDIO broadcast address 0
From: Russell King (Oracle)
Date: Sat Feb 21 2026 - 19:19:28 EST
On Sun, Feb 22, 2026 at 12:46:53AM +0100, Jakub Vaněk wrote:
> The YT8821 PHY responds on two MDIO addresses by default: the address
> selected by its strapping pins and the broadcast address 0.
>
> On platforms where another PHY is hardwired to respond only on address 0
> (e.g. the internal Gigabit PHY in the MediaTek MT7981B SoC), this can lead
> to MDIO bus conflicts. The YT8821 may incorrectly respond to transactions
> intended for the other PHY, leaving it in an inconsistent state. The
> following issues were observed on a Cudy M3000 router:
>
> - Achieving just 100 Mbps speeds on gigabit links. Dmesg would show
> messages like
>
> [ 133.997177] YT8821 2.5Gbps PHY mdio-bus:01: Downshift occurred from negotiated speed 1Gbps to actual speed 100Mbps, check cabling!
> [ 134.009400] mtk_soc_eth 15100000.ethernet eth0: Link is Up - 100Mbps/Full - flow control off
>
> - Having the PHY report that the link is up, yet no data would flow.
> - The YT8821 would be affected by an "ip link set dev eth1 down"
> command aimed at the other PHY.
>
> Avoid this conflict by disabling the broadcast address 0 early in
> the PHY configuration process. The .probe callback is called early
> enough to stop the issues from occurring. The .config_init callback
> re-establishes the workaround after the PHY undergoes a hardware
> reset.
>
> This change makes the YT8821 work reliably on the Cudy M3000 router
> when running the current OpenWrt main branch with a small device tree
> patch.
>
> Link: https://github.com/openwrt/openwrt/pull/21584
> Fixes: b671105b88c3 ("net: phy: Add driver for Motorcomm yt8821 2.5G ethernet phy")
> Signed-off-by: Jakub Vaněk <linuxtardis@xxxxxxxxx>
> ---
> drivers/net/phy/motorcomm.c | 48 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 48 insertions(+)
>
> diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
> index 42d46b5758fc..bcb60d0bcab5 100644
> --- a/drivers/net/phy/motorcomm.c
> +++ b/drivers/net/phy/motorcomm.c
> @@ -227,6 +227,9 @@
> #define YT8521_LED_100_ON_EN BIT(5)
> #define YT8521_LED_10_ON_EN BIT(4)
>
> +#define YTPHY_MDIO_ADDRESS_CONTROL_REG 0xA005
> +#define YTPHY_MACR_EN_PHY_ADDR_0 BIT(6)
> +
> #define YTPHY_MISC_CONFIG_REG 0xA006
> #define YTPHY_MCR_FIBER_SPEED_MASK BIT(0)
> #define YTPHY_MCR_FIBER_1000BX (0x1 << 0)
> @@ -2760,6 +2763,30 @@ static int yt8821_soft_reset(struct phy_device *phydev)
> YT8521_CCR_SW_RST, 0);
> }
>
> +/**
> + * yt8821_disable_mdio_address_zero() - disable MDIO broadcast address 0
> + * @phydev: a pointer to a &struct phy_device
> + *
> + * The YT8821 responds on two MDIO addresses by default:
> + * - the address selected by its strapping pins
> + * - the broadcast address 0
> + *
> + * Some other PHYs (e.g. the MT7981B internal Gigabit PHY) are hardwired to
> + * respond only on MDIO address 0. If the YT8821 also listens on address 0,
> + * it may incorrectly react to transactions intended for those PHYs.
> + *
> + * Disabling address 0 on the YT8821 early avoids such MDIO bus conflicts.
> + *
> + * Returns: 0 or negative errno code
> + */
> +static int yt8821_disable_mdio_address_zero(struct phy_device *phydev)
> +{
> + return ytphy_modify_ext(phydev,
> + YTPHY_MDIO_ADDRESS_CONTROL_REG,
> + YTPHY_MACR_EN_PHY_ADDR_0,
> + 0);
> +}
> +
> /**
> * yt8821_config_init() - phy initializatioin
> * @phydev: a pointer to a &struct phy_device
> @@ -2795,6 +2822,10 @@ static int yt8821_config_init(struct phy_device *phydev)
> phydev->rate_matching = RATE_MATCH_PAUSE;
> }
>
> + ret = yt8821_disable_mdio_address_zero(phydev);
> + if (ret < 0)
> + return ret;
> +
> ret = yt8821_serdes_init(phydev);
> if (ret < 0)
> return ret;
> @@ -2812,6 +2843,22 @@ static int yt8821_config_init(struct phy_device *phydev)
> return yt8821_soft_reset(phydev);
> }
>
> +/**
> + * yt8821_probe() - early PHY initialization
> + * @phydev: a pointer to a &struct phy_device
> + *
> + * Returns: 0 or negative errno code
> + */
> +static int yt8821_probe(struct phy_device *phydev)
> +{
> + /*
> + * Disable the MDIO broadcast address (0) as early as possible.
> + * This prevents the YT8821 from responding to transactions
> + * intended for a different PHY that is fixed at address 0.
> + */
> + return yt8821_disable_mdio_address_zero(phydev);
This is too late (chicken and egg problem exists) - phylib will already
have scanned the bus, and found a PHY at address 0 (whether it read the
IDs correctly because of the conflict is a separate matter. If there's
a conflict between two devices, the PHY IDs read will be a mess.)
However, if this PHY is the only PHY on the bus, and some driver uses
phy_find_first(), it will find the PHY at address 0, but it won't
respond anymore.
Failing the probe for address 0 doesn't solve the problem either - there
will still be a struct phy_device created for address 0, and if this
driver doesn't bind to it, the generic PHY driver will be bound manually
by phylib.
I can't see a simple way to handle this in the kernel. So, I'm going
to say this instead: boot loaders / board firmware need to sort this
mess out and program this PHY not to respond at address 0.
To put it another way, this isn't a problem to be solved in the kernel.
It's a board design/firmware issue, and that's where it needs to be
solved.
One of the responsibilities of board firmware is to ensure that the
devices on the board are configured sensibly for the operating system.
What you've said above, where two PHYs conflict on address zero is
a failure to configure the devices on the board sensibly.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!