U-Boot: no MAC driver is built — enable the GMAC to unlock TFTP boot #39
Labels
No labels
blocked-physical
cleanup
hardware
infra
kernel
P1-critical
P2-high
P3-normal
P4-later
reliability
security
upstream
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
tiagoagueda/a80#39
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
U-Boot has the entire network stack compiled in and no ethernet driver, which is why
there is no
Net:line in the banner.Measured
Consistent with the banner in 13-first-mainline-boot.md,
which goes straight from
MMC:to the prompt, and with the olderNet: No ethernet found.in 16-ethernet-broken.md.The hard half
This is the config-level statement of the finding in
34-ethernet-cold-boot.md: U-Boot omits
AXP*_POWER, soaxp_init()never runs and every AXP rail sits at its OTP default until Linux bindsaxp20xat ~5.24 s. The PHY's two supplies are AXP rails (axp15_sw0,axp15_aldo3). The PHY is unpowered for U-Boot's entire lifetime.So enabling the driver symbols is necessary and not sufficient. PMIC support in U-Boot
is the real work, and the A80's AXP806 + AXP809 pair over RSB is not covered by
mainline sunxi's existing AXP support.
Why it is worth it
writes and zero unbootable-kernel risk — a bad kernel is one
resetaway ratherthan a rescue-SD trip. That is what makes the A15 cluster work (Phase 4) cheap.
boot, the PHY is ready long before the kernel's one-shot MDIO scan, and the settle
loop in
linux-stmmac-mdio-settlebecomes unnecessary rather than needing to bereshaped for upstream (see issue #19).
network-attached serial, since it cannot see SPL and is unauthenticated UDP.
Suggested order
ETH_DESIGNWARE+SUN7I_GMAC+PHY_REALTEK, confirm the failure mode is"PHY not responding" rather than "no driver".
axp15_sw0andaxp15_aldo3.dhcp/tftpbootfrom the U-Boot prompt.Acceptance
Net:line present in the banner with a MAC address.dhcpgets a lease from 192.168.27.1.Progress 2026-08-29: the GMAC half is done; the PMIC half has a different blocker
Full write-up in 56-uboot-gmac-and-pmic.md. Three commits on
draco-aw80. The board is back on its known-good bootloaders.Two corrections to this issue
There is no AXP809 on this board.
31-power-topology.mdestablished that electrically — RSB slave NACK at0x3a3. It is an AXP806 alone at0x745, so "the AXP806 + AXP809 pair" overstates the problem.Mainline U-Boot already covers the AXP806.
pmic/axp.cmatchesx-powers,axp806,axp_regulator.ccarries a fullaxp806_regulators[]includingaldo3andsw, andsun8i_rsb.cis aUCLASS_I2Cdriver so the PMIC binds as an ordinary I2C child.DM_I2Cwas already on. There is no PMIC driver to write — which also supersedes note 09's "main U-Boot porting task", since that reasoned only about the legacyAXP*_POWERpath.⚠️ Step 1 of the suggested order is wrong: do not enable
CONFIG_SUN7I_GMAC.board/sunxi/gmac.cwritesccm->gmac_clk_cfgatCCM + 0x164, the sun4i register layout. On sun9i that register is standalone at0x00800030.Done and committed
CLK_BUS_GMAC=GATE(0x584, BIT(17))andRST_BUS_GMAC=RESET(0x5a4, BIT(17))inclk_a80.c— without these the designware probe aborts in itsclk_enable()loopethernet0alias, without whichsetup_environment()never generates the SID-derived MACgmacnode refreshed — it still carried afixed-linkand a "no PHY answers" comment from before the MDIO settle fixETH_DESIGNWARE,PHY_REALTEKdrivers/clk/sunxi/clk_a80_r.c, the sun9i CPUS-domain gates and resetsNo work is needed on the MDIO divider:
designware.chardcodesMII_CLKRANGE_150_250M, the same range the kernel picks withsnps,clk-csr = <4>.The hang, and the fix, validated on hardware
The first attempt hung between
DRAM: 3.5 GiBandCore: NN devices— i.e. insidedm_init_and_scan(), wherealways-onregulators are force-probed and drag up the RSB.r_rsbtakesclocks = <&apbs_gates 3>/resets = <&apbs_rst 3>— providers at0x08001428and0x080014b0that U-Boot had for no sun9i SoC.sun8i_rsb_probe()treats both lookups as best-effort and callssun8i_rsb_init()regardless, so it wrote to a block still gated and in reset, hanging the SoC.CONFIG_SYS_I2C_SUN8I_RSB=yhad been harmless for months only because nothing ever probed the bus.With
clk_a80_r.cin place, confirmed at the U-Boot prompt:and
Core: 79 devices, 19 uclassesagainst the previous build's 55/16.🔴 The actual blocker
Every AXP806 transfer NACKs. The controller is healthy —
ccr = 0x103is exactly whatsun8i_rsb_set_clk()computes,dmcr = 0x007c3e00with START cleared means the mode switch completed,devaddr = 0x003a0000shows the right runtime address. But driven by hand from the prompt:The chip answers on its hardware address and NACKs on its runtime address.
The consequence is what stops the boot: regulators exist but cannot be driven, so
mmcfails onError enabling VMMC supply : -5, U-Boot can read no kernel from either medium, andNet:reportsError enabling phy supply. SoDM_PMIC/PMIC_AXP/REGULATOR_AXPare deliberately not enabled in the defconfig — the tree stays bootable.The lesson worth carrying: the current bootloader works because it never touches the PMIC. Enabling the regulators makes previously-unconditional subsystems depend on RSB transfers, so this is not separable from making those transfers work.
Two leads:
sun8i_rsb_init()writesRSB_CTRL_SOFT_RSTand proceeds without waiting for it to clear, where Linux'ssunxi_rsb_hw_init()polls; and nothing in U-Boot knows aboutx-powers,master-mode, for which Linux writesAXP806_REG_ADDR_EXT.Revised remaining work
0x00800030— needed before a frame can leave the boarddhcp/tftpbootA safe intermediate step is already committed:
ETH_DESIGNWAREwithout the PMIC cannot break booting, sincemmctouches no regulator in that configuration. It should give theNet:line with a real MAC — acceptance criterion 1 — even if the PHY stays silent withoutaldo3at 2500 mV.Progress 2026-08-30: RGMII transmit clock done; the RSB diagnosis was wrong and is now sharper
The transmit clock is programmed
The previous comment said not to enable
CONFIG_SUN7I_GMACbecauseboard/sunxi/gmac.cwrites
ccm->gmac_clk_cfgatCCM + 0x164, the sun4i layout. That is now fixed properly:sun9i keeps the same control in the AHB1 region at
0x00800030- the dtsi'sgmac_tx_clk,carrying the A20's own compatible string, so the fields are identical and only the address
differs.
gmac.cnow selects the right one and the symbol is enabled.The value was read off a running kernel rather than guessed, on a board where the link
negotiates at 1 Gbit:
which is exactly
CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII | CCM_GMAC_CTRL_GPIT_RGMIIwithCONFIG_GMAC_TX_DELAYat its default 0, agreeing with the board DTS carrying noallwinner,tx-delay-ps. Verified in the object code:Commit
1183c9bondraco-aw80.DM_PMICremains off, so this build cannot break booting -mmctouches no regulator without it.Correction: the RSB failure is not a NACK
I previously described the blocker as "the chip acknowledges on its hardware address and NACKs
on its runtime address". That misread the status word:
The observed
0x103has bit 16 clear andTRANS_ERR_DATAreading 1. The AXP806 doesacknowledge; the transfer fails in its data phase, at bit 1. Addressing and authorisation
are not involved.
Clocking is ruled out too, from the tree alone
sun8i_rsb_set_clk()assumes a 24 MHz parent and computesccr = 0x103, which is what theregister holds. That assumption is correct here:
apbs_rsb<-apbs<-ahbs<-cpus_clk, andahbsis a fixed-factor 1:1 clockarch/arm/mach-sunxi/clock_sun9i.cnever references the CPUS domain, so U-Boot does notreprogram it
assigned-clocksanywhere, so Linux does not force it either - it reports what it findsSo U-Boot inherits the same 24 MHz and the divider is right.
Remaining suspects, in order
sun8i_rsb_init()writesRSB_CTRL_SOFT_RSTthen goesstraight to
set_clkandset_device_modewithout waiting for the bit to clear; Linux'ssunxi_rsb_hw_init()polls for it.x-powers,master-mode- nothing in U-Boot's AXP driver knows about it; Linux writesAXP806_REG_ADDR_EXT.0xe89/ runtime0x4eunder Linux.U-Boot's
sun8i_rsb_get_runtime_address()knows only0x3a3and0x745so it neveraddresses it - but the device-mode command is a broadcast, and after a warm reboot the
AC100 still holds the runtime address Linux gave it. This had not been considered before.
Ready to test, and low risk this time
The current build should produce the
Net:line with a SID-derived MAC - acceptance criterion1 of this issue - and cannot leave the board unbootable, because without the PMIC nothing in
the boot path depends on a regulator. Whether the PHY answers MDIO is the open question, since
aldo3is not raised to 2500 mV without the regulator framework.Tested on hardware 2026-08-30:
Net:line achieved; the MAC transmits nothingFlashed to the eMMC with the card out. The board booted normally all the way to Linux -
with
DM_PMICoff nothing in the boot path depends on a regulator, as intended.Net: eth0is acceptance criterion 1 of this issue, replacingNo ethernet found.Working, measured at the U-Boot prompt
ethaddr=02:2c:b6:3a:4d:0c- the SID-derived form, so theethernet0alias worksmii info->OUI = 0x0732, Model = 0x11, Rev = 0x05= RTL8211E (0x001cc915)Waiting for PHY auto negotiation to complete....... doneSpeed: 1000, full duplex0xa4/ reg0x1c=0xBD75- bits 13/12/11, i.e.CTRL_DELAY | TX_DELAY | RX_DELAY, whatrtl8211e_config()writes forrgmii-id0x1140, BMSR0x796D- link up, autoneg completeMDIO works without the PMIC. I predicted the PHY would stay silent until
aldo3reached2500 mV. It does not - it answers and links at gigabit on the power-on defaults. That is a
useful result on its own: the PHY rail is not a prerequisite for MDIO here.
Not working: transmit
pinganddhcpboth fail -ARP Retry count exceeded,BOOTP broadcast 1..7. Captured onthe build host with
tcpdump -i eno1 arpwhile U-Boot pinged:with a control - the same capture on the same interface, with the board running Linux,
caught the same MAC:
Same board, same MAC, same switch. Linux's frames arrive, U-Boot's never leave. The fault is
transmit; receive is untested because nothing gets that far.
Ruled out, with evidence
and out of reset.
0x00800030 = 0x6, byte-identical to a running Linuxcarrying traffic. Linux's
clk-a20-gmac.cconfirms the layout: mask0x3selects the sourcein bits [1:0], and
SUN7I_A20_GMAC_GPIT 2is the gate. U-Boot's..._GPIT_RGMIIname ismisleading, but the bit is right and it is set.
mii_phy_tx_clkandgmac_int_tx_clkare plainfixed-clocknodes; the dtsi states the actual TX rate is not controlled by this clock.
sunxi_mbus.clists only display devices.CONFIG_PHY_GIGE- unset, but used only bycommon/miiphyutil.c, so it explains whymii infoprints10baseT, HDXwhile phylib reports 1000/full. Cosmetic; worth enabling.Next
The remaining surface is the designware transmit DMA path - descriptor ring, the addresses
written into it, and cache maintenance. Worth holding #48 in mind, which records a sun9i block
needing an unexplained
PHYS_OFFSETfixup, though U-Boot has no virtual mapping to confuse.Test-rig note
Spamming a key at the serial port to interrupt autoboot is unreliable and wasted several
boots. The reliable method is
fw_setenv bootdelay 25, reboot, send one newline, thenrestore
bootdelay 2.Board left healthy:
a80-debianon the eMMC running the new build,nproc4, card out.Narrowed further: the MAC completes the frames and reports success
Read the transmit descriptor ring at the prompt after a failed
ping. Ring at0x00831010 = 0xfbf82200, 64-byte stride:des1 = 0x6100003cis FS | LS | TCH with TBS1 = 0x3c = 60 bytes - a real, padded ARPframe.
des0 = 0means the OWN bit is cleared with zero error status. Two of them. DMAstatus
0x44000546also has ETI set, so transmission started.So U-Boot queues complete frames, the DMA consumes them, reports no error, and nothing reaches
the wire. The fault is downstream of the transmit FIFO, in the RGMII output.
Register-by-register against a Linux that carries traffic
gmac_tx_clk0x008000300x000000060x00000006CFG00x272222220x27222222CFG10x272272220x27227222CFG20x000000220x00000022DRV00xdf7fdfff0xdf7fdfffDRV10x0000000f0x0000000fDW_ALTDESCRIPTORunset)Also ruled out this round:
CONFIG_PINCONF=yandPINCTRL_FULL=y, sodrive-strength = <40>really is applied - worth checking because the dtsi warns RGMII DDR needs it and MDIO at
2.35 MHz would tolerate a weak setting that 125 MHz would not. And MAC
conf = 0x00202800confirms full duplex with
MII_PORTSELECTclear, i.e. GMII/1000.Where to look next
Everything software can see matches a working Linux, so more register comparison is not the
way forward. In order:
ping- settles in one measurement whether the 125 MHztransmit clock is present at the pin. Everything above says it should be.
clk_set_rateordering. Linux reaches0x6as two operations -clk_set_ratepicks themux,
clk_prepare_enablesets the gate.eth_init_board()ORs both in a single write. Sameend state, different sequence.
eth_init_board()runs fromboard_init(), long before the designware driver enablesCLK_BUS_GMACand deassertsRST_BUS_GMAC. The write demonstrably sticks, but whether thetransmit clock tree latches it while the block is still in reset is not established. Moving
the call into the driver probe would settle it, and is the cheapest of the three to try.
Note 56 has the detail. Board left healthy on the eMMC,
bootdelayrestored to 2.Both code-side transmit hypotheses tested and dead
Checked at the U-Boot prompt with
mw, after a firstpinghad brought the MAC up and out ofreset - no rebuild and no reflash, which is what made them worth trying before writing code.
mw 0x00800030 0then6,mdconfirms6,pingmw 0x00800030 2(mux, =clk_set_rate) then6(gate, =clk_prepare_enable),pingSo neither the ordering of
eth_init_board()against the driver's clock and reset handling,nor the single-write-versus-two difference from Linux, is the cause. Moving the call into the
driver probe would not have helped and does not need trying - which is the useful part of a
negative result.
#39 now parks for the bench
Everything reachable from software is done and matches a working Linux register for register.
The MAC accepts two complete 60-byte frames, clears OWN with a zero error status, and nothing
arrives. The next useful information is physical:
ping- settles whether the 125 MHz transmit clock ispresent at the pin.
A switch drops a frame with a bad FCS silently, which looks identical from both ends: the MAC
reporting success and
tcpdumpseeing nothing. That would point at RGMII skew despite thePHY's internal delays reading correct.
This puts #39 alongside #53 and #42 as bench work rather than desk work.
What was achieved
Net: eth0: ethernet@830000with a SID-derived MAC - acceptance criterion 1 of this issue1183c9b)DM_PMICstays offdhcpandtftpbootremain out of reach until transmit works.Transmit is not dead. Gigabit transmit is dead.
This is the finding, and it reframes the issue. Forcing the PHY to 100/full at the u-boot
prompt and pinging:
Reproduced twice in the same session. So the MAC, the descriptor rings, the DMA, the pinmux,
the drive strength, the MDIO path and the PHY are all fine, and every negative result recorded
above stands - they were just looking in the wrong place. The fault is confined to the
1000 Mbps RGMII clock domain, i.e. the 125 MHz DDR transmit path, and nothing else.
That also retires the parked next step. A scope on TXCK would have shown a clock present,
because at 100 Mbps the same pin carries 25 MHz and works.
This unblocks the issue's actual goal
The acceptance criteria here are
dhcpand a kernel booted over TFTP. Both are reachableright now by forcing 100 Mbps before the network is used - a
prebootor a line inbootcmddoing the three
mii writes above. 100 Mbps is ~12 MB/s, which for an 8.6 MiB uImage plus a dtbis roughly 1 s of transfer. TFTP boot does not need gigabit.
I would treat that as the fix for #39 and split the gigabit fault into its own issue, rather
than keeping TFTP boot blocked behind a hardware timing problem.
What was eliminated this round
gigabit traffic and u-boot. Linux has several bits u-boot does not (
0x584,0x588,0x590,0x594and the matching reset words). Applying Linux's exact values withmwbefore the pingchanged nothing at gigabit.
SYS_CTRL 0x00800030reads0x00000006in both, confirmed again from kernel context.sole exception of ANAR (
r04: Linux0x0de1, u-boot0x01e1- pause advertisement, which thedriver rewrites at autoneg and which cannot affect transmit).
0xa4,0x1c) reads0xBD75in both.The remaining candidate is RGMII transmit timing at 125 MHz - skew, or the internal delay being
inappropriate for this board at gigabit only. Note the dtsi asks for
rgmii-id, so both delaysare on; a board that needs
rgmii-txidor external skew would look exactly like this.⚠️ I damaged something, and it needs a power cycle
Being explicit because it is my fault and it is visible in the logs.
While testing PHY registers I wrote to the RTL8211E's delay register with the reserved field
(bits 10:0, Realtek test/debug settings) cleared, and at least one write landed on page 0
register
0x1crather than the ext-page one, because the page-select did not take. Since thengigabit autonegotiation flaps - the link comes up at 1 Gbps, drops, and after two or three
attempts settles at 100 Mbps.
The serial log dates it precisely:
Boot 22 is the first boot after my first PHY write. Before that, gigabit was rock solid for
21 consecutive boots, which also disproves a theory I briefly held - that Linux's gigabit was
marginal and u-boot was failing for the same reason. It was not marginal.
Restoring the register to its original
0xBD75did not clear it, and neither did a BMCRsoft reset (
0x8000): a soft reset does not restore the vendor's reserved bits, and there is noPHY reset GPIO in the device tree - only
phy-supply.A power cycle should clear it, since that reloads the PHY straps. Until then the board is
fully usable at 100 Mbps: reachable on
192.168.27.44, 0 failed units, containers running.Lesson worth keeping: on this PHY, read-modify-write the delay bits and never write the whole
register, and verify the page-select took before trusting any paged access.
Recovered, and it confirms the mechanism
Power cycled. Gigabit is clean again on the first attempt:
One link event, no flap, versus three drops and a fallback to 100 Mbps immediately before.
This confirms the diagnosis rather than just clearing the symptom: the RTL8211E's reserved
configuration bits survive a warm reboot and a BMCR soft reset, and are only reloaded from
the straps at power-on. That is why restoring
0xBD75over MDIO did not help - the damage was instate that no software write could reach.
Board otherwise healthy: 0 failed units, docker and healthdog active, wlan0 back, 4 GiB, 4 cores,
bootcount=0, and all scratch u-boot variables cleared withbootdelayback to 2.Practical rule for anyone touching this PHY again: read-modify-write the delay bits only,
never write the whole register, verify the page-select took before trusting a paged access, and
assume any mistake needs physical access to undo. That last part is what makes it worth doing
these experiments while someone can reach the board - or after #5.
Nothing above changes the substantive finding in the previous comment: transmit works at
100 Mbps, the fault is confined to the gigabit RGMII clock domain, and TFTP boot is reachable
now without solving it.
All three acceptance criteria met
Linux came up on it:
7.2.0-14858, the TFTPbootargsin/proc/cmdline, eth0 back at1000 Mbps, 0 failed units, docker active.
iminfo's checksum pass is what makes this abyte-exact transfer rather than a hopeful one.
The 100 Mbps forcing costs nothing
This is the part that makes it a fix rather than a hack. PHY registers do not survive a power
cycle, and Linux re-runs autonegotiation at boot regardless of what u-boot left behind - eth0
reads 1000 after every TFTP boot above. So forcing 100 Mbps for the duration of u-boot has no
runtime cost, and TFTP does not want gigabit anyway: 18.4 MB of kernel, dtb and initrd move in
about 20 seconds.
The gigabit fault is now #76, where it can be worked on without blocking anything.
Two things that cost time, recorded so they do not again
autoload=no. Without it,dhcpinvents a bootfile name from the IP in hex(
C0A81B2C.img) and spends ten timeouts trying to TFTP it from the DHCP server, which has noTFTP. It looks exactly like the network failing.
tftpwindowsize.CONFIG_TFTP_BLOCKSIZEis already 1468 butCONFIG_TFTP_WINDOWSIZEis1 - lockstep, one ACK per block, which is precisely the 490 KiB/s first seen. Setting it to 8
roughly doubled throughput.
The environment, with the reasoning, is in
tools/uboot-netboot-env.txt. Server side istftpd-hpaon ouranos serving/srv/tftp; refresh those files after anydeploy-kernel.shrun.What this unlocks, from the original post
That now holds. It also means a kernel can be tested without
deploy-kernel.shwriting to theeMMC at all, which matters for #65's wear budget.
Note the original post's prediction that PMIC support would be required turned out to be wrong -
MDIO, autonegotiation, DHCP and TFTP all work with
CONFIG_SUNXI_NO_PMIC=y. The PHY's rails attheir OTP defaults are evidently sufficient.
Netconsole: built, not yet flashed
CONFIG_NETCONSOLE=yis committed on the u-boot branch (f6a7cf60921, version-00012) andbuilds clean at 494896 bytes. It is compiled in but not enabled: stdin/stdout/stderr stay on
serial, so a board with no network still prints where it always did, and switching to netconsole
is a deliberate act - which is also the point at which someone accepts that it is unauthenticated
UDP, readable and writable by anyone on the LAN, at the u-boot prompt.
Flashing it needs approval, since writing the eMMC bootloader is the one operation with no
software fallback. Closing this issue on its stated criteria; netconsole is a separate,
optional step.