I tried to understand what's happening in U-Boot regarding the PHY.

What I see is that the PHY in the Raspberry Pi 4 needs to be reset when U-Boot is run after the firmware loaded it via netboot.

As far as I can tell, the bcmgenet driver will use the generic pyh driver in drivers/net/phy/phy.c and this one is not resetting the PHY. Some other broadcom phy drivers in drivers/net/phy/broadcom.c use a config op that adds a phy_reset() call (bcm5461_config).

Is there a reason the generic driver does not reset the phy?
It seems the best way would be to add a new phy driver to broadcom.c that targets the Raspberry Pi 4 and overrides the config op with one that does the reset.

I don't have access to other Raspberry Pi models, but this might also be necessary for others.


Am 20.08.26 um 16:35 schrieb André Althaus:
I'm trying to netboot a Raspberry Pi 4 B and use the U-Boot pxe bootflow to bring up a NixOS system (using the extlinux.conf file created by NixOS). When I do that the U-Boot DHCP process retries multiple times to get an IP and sometimes running out of retries. The TFTP transfers afterwards show many timeouts (T). I tried to boot the same firmware files and U-Boot binary from the SD card and then the pxe bootflow works without problems. Every time the dhcp fails or the tftp timeout occurs, I can see the crc error counter on the switch port increase.

I suspect, that the firmware leaves the network peripherals in some state that is not completely reset/initialized by u-boot.

I tried to debug it with Qwen AI 3.8 and actually got a seemingly working patch. Obviously I'm not confident this is the correct fix.

/proc/cpuinfo:
Revision    : c03114
Serial        : 1000000057c90c1d
Model        : Raspberry Pi 4 Model B Rev 1.4

vcgencmd version:
May 21 2026 11:20:25
Copyright (c) 2012 Broadcom
version 288930ab4712b99596f32732664aaaeb881ef1e0 (clean) (release) (start)

rpi-eeprom-update:
BOOTLOADER: up to date
   CURRENT: So 17. Mai 19:13:18 UTC 2026 (1779045198)
    LATEST: Fr 9. Jan 16:12:13 UTC 2026 (1767975133)
   RELEASE: default (/nix/store/0a6v8w38pn6gfagyc5f0czz0jhhqpz40-raspberrypi-eeprom-2026.05.11-2712/lib/firmware/raspberrypi/bootloader-2711/default)
            Use raspi-config to change the release.

  VL805_FW: Using bootloader EEPROM
     VL805: up to date
   CURRENT: 000138c0
    LATEST: 000138c0

rpi-eeprom-config:
[all]
BOOT_UART=0
WAKE_ON_GPIO=1
ENABLE_SELF_UPDATE=1
BOOT_ORDER=0xf21
NET_INSTALL_AT_POWER_ON=1

u-boot master (ece349ade2973e220f524ce59e59711cc919263f):
make rpi_arm64_defconfig

Additional configs:
CONFIG_CMD_MII=y
CONFIG_BOOTSTD_FULL=y

CONFIG_USE_BOOTCOMMAND=y
CONFIG_BOOTCOMMAND="bootflow scan -lb pxe"

CONFIG_LOG=y
CONFIG_LOG_MAX_LEVEL=7
CONFIG_LOG_CONSOLE=y


During the debugging, Qwen told me to try the following manual reset of the PHY after the firmware started u-boot and before running the bootflow:
mii write 1 0 0x8000        # PHY soft reset
mii read  1 0                      # repeat until bit15 clears (PHY reset done)
1140
mii write 1 4 0x01E1        # advertise 10/100 F+H, pause (known-good value)
mii write 1 9 0x0300        # 1000T cap
mii write 1 0 0x1200        # AN enable + AN restart
mii read  1 1                      # expect 0x796D (link up) after ~2 s
7949

Afterwards the bootflow worked without problems.

It added the following patch which seems to fix the problems:
diff --git a/drivers/net/bcmgenet.c b/drivers/net/bcmgenet.c
index a0264dc386d..1c867e61dd2 100644
--- a/drivers/net/bcmgenet.c
+++ b/drivers/net/bcmgenet.c
@@ -601,6 +601,30 @@ static int bcmgenet_mdio_init(const char *name, struct udevice *priv)
     return mdio_register(bus);
 }

+static int bcmgenet_phy_soft_reset(struct bcmgenet_eth_priv *priv)
+{
+    int val;
+    int timeout = 100; /* ms */
+
+    /* Firmware may leave the internal GPHY in a state where MDIO
+     * auto-negotiation works but the RGMII data path corrupts frames,
+     * so force the PHY back to its defaults before attaching to it. */
+    if (bcmgenet_mdio_write(priv->bus, priv->phyaddr, 0, MII_BMCR, BIT(15)))
+        return -EIO;
+
+    do {
+        udelay(1000);
+        val = bcmgenet_mdio_read(priv->bus, priv->phyaddr, 0, MII_BMCR);
+        if (val < 0)
+            return val;
+    } while ((val & BIT(15)) && --timeout);
+
+    if (!timeout)
+        return -ETIMEDOUT;
+
+    return 0;
+}
+
 /* We only support RGMII (as used on the RPi4). */
 static int bcmgenet_interface_set(struct bcmgenet_eth_priv *priv)
 {
@@ -665,6 +689,12 @@ static int bcmgenet_eth_probe(struct udevice *dev)
         return ret;

     priv->bus = miiphy_get_dev_by_name(name);
+    if (!priv->bus)
+        return -ENODEV;
+
+    ret = bcmgenet_phy_soft_reset(priv);
+    if (ret)
+        return ret;

     return bcmgenet_phy_init(priv, dev);
 }

Its explanation:
The Broadcom legacy firmware performs its own DHCP/TFTP over the same GENET before loading U-Boot, then shuts the MAC/PD down and hands off without re-initialising the embedded GPHY. At hand-off the GPHY's MDIO register file and IEEE auto-negotiation still function, so U-Boot's generic PHY machinery brings the link up cleanly — but the RGMII/PMA data path is left in a firmware-era state that corrupts frames on the wire (bad FCS, visible only as the switch's receive CRC errors under load).

Two facts support this being an initialisation-missing problem rather than a driver bug in the normal path:

- The identical binary is stable when booting from SD, i.e. when the firmware never used the network (a clean, default-like GPHY state reaches U-Boot). - A single PHY soft-reset at first use fully cures it; there is no other state difference between the two paths that was found (speed/duplex/advertise settings are identical once link is up).



If you need more information or some register values, I can provide them.

Attachment: smime.p7s
Description: Kryptografische S/MIME-Signatur

Reply via email to