☰
RK3588 GMAC调试实战:国产PHY替换从踩坑到修通全记录
2026/10/5 6:08:50 网站建设 项目流程

RK3588的GMAC调试说难不难,说简单也真不简单。我这块核心板原本用的是参考设计的RTL8211F千兆PHY,原厂SDK适配得比较完善,网络都是“一次点亮”。结果中途因为供货和成本原因,我把默认的RTL8211F换成了一颗国产PHY芯片,接下来就是连续几天的“水逆”期——PHY ID读不到、link起来了ping不通、千兆变百兆、速率一高就疯狂掉包……这篇文章就把我在RK3588网络调试过程中换PHY踩到的坑,以及最终怎么一一排查、修通的完整记录分享出来,希望对正在做国产化替换或者调试RK3588 GMAC的朋友有所帮助。

1. 内容整体设计与思路拆解

1.1 RK3588 GMAC硬件架构回顾

RK3588这颗SoC上集成了两路GMAC控制器,兼容RGMII和RMII两种MAC-PHY接口模式。我这边用的是GMAC1,走的是标准RGMII接口,通过MDIO总线管理PHY芯片。默认参考设计里挂的就是RTL8211F,属于Realtek的千兆PHY,支持10/100/1000Mbps自适应,RGMII接口,内置了完整的物理层收发功能。原厂SDK里针对这颗PHY做了完整的适配,包括驱动支持、设备树参数、时钟配置、延迟补偿等等。所以如果你不动这个方案,网络部分基本是0调试成本的。

但问题在于,RTL8211F这颗PHY在当前市场环境下,供货周期和价格都不太理想。我这次因为项目批量生产需求,决定把它替换成一颗国产PHY——裕太微的YT8531,同样是千兆PHY,同样支持RGMII,理论上是可以做到pin-to-pin兼容替换的。当然,实际做起来远没有“理论”那么顺利。

提醒一下:如果你也在做RK3588网络调试,先确认你用的是哪一路GMAC,GMAC0和GMAC1在设备树中的节点名不一样,管脚也不一样。别改了半天发现自己调的节点根本不是板子上走的那一路。

1.2 替换PHY需要考虑哪些维度

换PHY不是把芯片焊上去就能用,至少要过一遍以下几个维度:

电气兼容性:供电电压是否一致(常见3.3V或1.8V),RGMII信号电平是否匹配,时钟引脚是输入还是输出模式。RTL8211F和YT8531在这点上基本兼容,但还是要看具体封装和外围电路。

MDIO地址:PHY芯片的MDIO地址由芯片引脚上下拉决定。RTL8211F常见地址是0x01,而YT8531的默认地址可能不同。如果两者不一致,MDIO总线扫描时就读不到PHY ID,驱动加载会失败。

RGMII内部延迟(Delay):这是换PHY最容易翻车的地方。RGMII接口标准要求TX和RX方向各加约2ns的延迟,用来补偿时钟和数据的相位差。问题是,这颗延迟可以在PCB上走线实现,也可以在PHY芯片内部实现,由寄存器或strap引脚配置。RTL8211F的内部延迟默认开启,所以原厂SDK往往不额外配置MAC侧的延迟。而很多国产PHY的延迟默认配置不一样,如果两者没有对齐,就会出现“link能up但数据全错”的诡异现象。

参考时钟方向:RGMII模式下,125MHz(千兆)/25MHz(百兆)参考时钟可以由MAC提供也可以由PHY提供,取决于CLK方向配置。RK3588的设备树里有对应配置项,换PHY后需要重新确认。

硬件复位与供电时序:PHY芯片的复位引脚、供电时序、时钟稳定时间都要和MAC驱动匹配。如果复位时间太短,PHY内部还没准备好,驱动扫描MDIO就会失败。

驱动适配:SDK默认可能只编译了RTL8211F的驱动,或者把PHY识别为Generic PHY。你需要确认新PHY的驱动是否编译进内核,必要时需要修改内核配置,甚至添加自研PHY驱动。

我把需要确认的项目整理成了一个表格,替换前建议逐项打勾:

检查项RTL8211F(原方案)YT8531(替换方案)是否需改动
MDIO地址0x01(由strap决定)0x00/0x01(由strap决定)可能需改设备树
RGMII内部TX Delay默认开启默认关闭设备树或寄存器需调整
RGMII内部RX Delay默认开启默认开启一般无需改动
参考时钟方向PHY提供(Slave模式)PHY提供(Slave模式)一般无需改动
复位电平/时序低有效,复位脉宽>10ms低有效,复位脉宽>10ms检查实际电路
内核PHY驱动Realtek专用驱动裕太微专用/Generic需确认编译配置

1.3 为什么原厂默认配置“一把就亮”

很多搞RK3588的朋友刚拿到开发板时,网络都得很顺利:接线、插电、配IP,ping通,收工。这其实是原厂SDK和参考设计共同作用的结果。RK3588的SDK里,设备树针对RTL8211F做了专门的适配,比如gmac1节点里的phy-mode = "rgmii"、tx_delay和rx_delay参数都调到了合适值。同时Realtek PHY的驱动在Linux内核里已经很成熟,phy_id匹配后自动加载正确驱动。

但这恰恰是风险所在:默认配置的“专一性”太强了。一旦你换了PHY,这些参数全部变成“错误预设”。而且这些问题很隐蔽——硬件能上电,MDIO偶尔能读到ID,但网络始终不通。你甚至会怀疑是不是PCB坏了,而不是配置问题。我这次就是在这个环节耗了不少时间。

2. 核心细节解析与实操要点

2.1 设备树里到底哪些参数管PHY

RK3588的GMAC节点在设备树里长这样(默认RTL8211F配置):

&gmac1 { status = "okay"; phy-mode = "rgmii"; clock_in_out = "input"; snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 10000 50000>; tx_delay = <0x3b>; rx_delay = <0x2a>; pinctrl-names = "default"; pinctrl-0 = <&gmac1_miim &gmac1_tx_bus2 &gmac1_rx_bus2 &gmac1_rgmii_clk &gmac1_rgmii_bus>; phy-handle = <&phy0>; }; &mdio1 { status = "okay"; phy0: ethernet-phy@1 { reg = <0x1>; compatible = "ethernet-phy-id001c.c916"; clocks = <&cru CLK_GMAC1_RMII_125M>; ... }; };

其中compatible = "ethernet-phy-id001c.c916"是RTL8211F的PHY ID,reg = <0x1>是MDIO地址。tx_delay和rx_delay的单位是纳秒,这两个值专门用来调整RK3588 MAC侧RGMII信号的延迟。

换PHY之后,最需要动的就是这三处。YT8531的PHY ID是4f51.e91a,如果驱动按ID匹配失败,还可以直接留空让内核按Generic PHY处理,或者去掉compatible字段。

注意:设备树里clock_in_out = "input"表示125MHz参考时钟由外部PHY提供给MAC,也就是PHY做主时钟。如果你的板子在设计时改成了MAC提供时钟给PHY,这里要改成"output",同时检查对应的时钟配置。这个参数搞错,PHY大概率起不来,或者link状态反复跳。

2.2 RGMII延迟补偿机制解读

这是全文最值得细看的部分。RGMII接口之所以难调,核心就在这个2ns延迟上。

我们知道,RGMII在千兆模式下用125MHz的DDR时钟沿同时采样数据和控制信号。PCB走线长度不同、PHY芯片不同,时钟和数据到达MAC的时间就会有偏差。如果偏差太大,采样点就不稳定,数据就会出错。为了统一解决这个问题,RGMII标准规定发送端要把时钟或数据延迟约2ns,接收端再根据实际情况做补偿。

具体到RK3588,MAC侧可以调tx_delay和rx_delay;PHY侧也可以通过寄存器或者外部电阻配置内部延迟。麻烦在于:MAC侧调了,PHY侧也调了,到底是谁加谁、谁减谁,不同芯片的组合结果完全不一样。

RTL8211F的做法是:内部已经默认开启了TX和RX的延迟,所以原厂SDK里就把MAC侧的tx_delay调得比较大(0x3b=59个单位,约2ns左右)。而YT8531默认的延迟配置和RTL8211F不同,特别是TX方向延迟默认是关闭的。如果你沿用RTL8211F的参数,MAC和PHY两边的延迟叠加起来,信号就错了。

这个延迟问题在现象上非常有迷惑性:链路能协商成功,速率也是1000Mbps,但ping包大量丢包或完全不通。如果只是偶尔丢包,大概率就是延迟边界问题。

排查时可以这样操作:先用ethtool eth0看link和速率,如果link正常但ping不通,优先把设备树里的tx_delay/rx_delay降到较小值或设为0,让PHY侧负责延迟。以YT8531为例,我最终的配置是:

tx_delay = <0x1f>; rx_delay = <0x1f>;

这个值把延迟主要交给PHY内部处理,MAC侧只做微调。当然具体值每个板子的PCB走线不一样,建议用二分法逐步尝试,每次修改后重启网络并做压力测试。

2.3 MDIO地址不对会怎样

MDIO地址没对上,现象特别干脆:dmesg里报PHY ID not found at address 1,或者干脆MDIO扫描不到任何设备,/sys/bus/mdio_bus/devices/目录下空无一物。

RTL8211F的地址由PHYADD0引脚决定,常见参考设计接地,地址是0x01。YT8531也有类似引脚,但我这块模块上,YT8531的地址被我误以为是0x01,其实是0x00。结果驱动在地址1上扫描,始终找不到PHY,网络节点直接failed to find PHY.

定位这一步最简单:在板子启动后用mdio-tools(需要CONFIG_MDIO_BUS相关工具)扫描总线,或者直接看kernel启动日志里MDIO总线枚举到了哪些设备。比如:

root@rk3588:~# cat /sys/bus/mdio_bus/devices/*/phy_id 0x4f51e91a

如果总线地址是对的,这里就能直接看到PHY ID。如果看不到,先自查复位引脚是否拉高、MDIO上拉电阻是否正常、PHY供电是否稳定。

实操心得:MDIO总线很多时候是因为PHY还在复位状态才读不到ID。RK3588的设备树里有snps,reset-delays-us = <0 10000 50000>,含义是复位后延迟10ms释放,释放后再等50ms才去扫描MDIO。如果PHY上电初始化时间比较长(有些国产PHY要100ms),需要把这个50ms调大。

3. 实操过程与核心环节实现

3.1 从换芯片到故障复现

我这个项目在替换PHY之前,原RTL8211F方案是稳定运行的。替换成YT8531后,第一次上电,dmesg里已经有异常苗头:

rk_gmac-dwmac fe1c0000.ethernet eth0: no phy at mdio address 1 rk_gmac-dwmac fe1c0000.ethernet eth0: __stmmac_open: Cannot attach to PHY (error: -19)

这里两个关键信息:一是MDIO地址1上没找到PHY,二是网卡没能挂载PHY驱动。我把设备树的reg = <0x1>改成了reg = <0x0>之后,MDIO能读到PHY ID了,网络节点也能正常附着。但紧接着又出现第二个问题:

rk_gmac-dwmac fe1c0000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx

link是1Gbps全双工,看起来一切正常,但ping 192.168.1.1直接100%丢包。如果你也遇到“link up但ping不通”,请把注意力优先放到RGMII延迟上,而不是怀疑PHY芯片坏了。

3.2 DTS设备树改造实录

最终我改完的gmac1节点关键参数如下:

&gmac1 { status = "okay"; phy-mode = "rgmii"; clock_in_out = "input"; snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 10000 100000>; // 复位后多等100ms tx_delay = <0x1f>; rx_delay = <0x1f>; pinctrl-names = "default"; pinctrl-0 = <&gmac1_miim &gmac1_tx_bus2 &gmac1_rx_bus2 &gmac1_rgmii_clk &gmac1_rgmii_bus>; phy-handle = <&phy0>; }; &mdio1 { status = "okay"; phy0: ethernet-phy@0 { reg = <0x0>; compatible = "ethernet-phy-id4f51.e91a"; // YT8531的PHY ID clocks = <&cru CLK_GMAC1_RMII_125M>; reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; reset-assert-us = <10000>; reset-deassert-us = <50000>; }; };

这里有几个点值得展开。

第一,compatible字段我显式填了ethernet-phy-id4f51.e91a,让内核能直接匹配到裕太微的PHY驱动。如果SDK里没有对应驱动,可以去掉这个字段,内核会把它当作Generic PHY处理,基本功能也能用,但可能有些厂商特有寄存器没法配置,比如厂商自定义的延迟调节、LED闪烁模式等。

第二,reset-delays-us和PHY节点里的reset-assert-us/reset-deassert-us有些重复,但建议都保留。实践中发现,snps,reset-delays-us是MAC驱动框架去控制复位,而PHY节点里的reset-gpios则是PHY驱动自己控制复位。某些SDK版本下,只写其中一处可能不生效。双保险更稳妥。

第三,tx_delay = <0x1f>如果换算成纳秒大约是1ns左右,实际上等于把MAC侧的TX延迟减半,让PHY内部补齐剩下的。这是通过反复试出来的最优值。你可以从0x0开始往上加,每一档ping 100个包看丢包率,找到丢包率最低的那个档位。

3.3 内核配置与驱动匹配确认

除了设备树,内核里的PHY驱动也要确认。进入内核目录:

cd kernel make menuconfig

在Device Drivers -> PHY Device support and infrastructure下确认以下几项:

  • Realtek PHY drivers对应RTL8211F,如果你已经彻底不用它,可以不勾选,但建议保留,方便后续回退对比。
  • Motorcomm PHY drivers或者Broadcom PHY drivers等,看你的SDK支持哪些。如果SDK里没有裕太微的驱动,先确认Generic PHY类型是开启的,一般位于PHY Device support and infrastructure -> Generic PHY driver。

这里有个容易踩的坑:如果SDK自带的PHY驱动文件里没有YT8531具体型号,但drivers/net/phy/motorcomm.c已经存在,那么大概率通过PHY ID匹配还是能找到。但如果完全没有对应驱动,即使MDIO能读到ID,也会报unrecognized PHY错误。这种情况不要慌,Generic PHY通常也能让网络跑起来,只是延迟调节等功能可能要手动通过mdio-tools命令去操作PHY寄存器。

注意:内核配置改完一定要重新编译并烧录boot.img或kernel镜像,只改设备树不够。我见过有人只改了DTS并重新打包resource.img,结果内核还是老版本,PHY驱动完全不生效,白白排查了大半天。

3.4 第一次完整ping通后的验证

设备树和内核改完,重新烧录,启动后先确认基本状态:

root@rk3588:~# dmesg | grep -i phy [ 1.896491] mdio_bus fe1c0000.ethernet: MDIO device at address 0 is: 4f51 e91a [ 2.531282] motorcomm-mdio 4f51.e91a: probe successful root@rk3588:~# ethtool eth0 Settings for eth0: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Speed: 1000Mb/s Duplex: Full Port: Twisted Pair PHYAD: 0 Transceiver: internal Auto-negotiation: on

看到4f51 e91a被正确识别,Speed: 1000Mb/s,链路全双工,说明PHY基本已经工作。这时候再ping:

root@rk3588:~# ping -c 100 -i 0.2 192.168.1.1 PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data. 64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.428 ms 64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.398 ms ... --- 192.168.1.1 ping statistics --- 100 packets transmitted, 100 received, 0% packet loss, time 19902ms rtt min/avg/max/mdev = 0.365/0.402/0.485/0.028 ms

0%丢包且平均延迟0.4ms,说明延迟配置已基本到位。

3.5 UDP传输和网络调试助手验证

做嵌入式网络调试,很多时候不只是ping通那么简单。比如我在调一个视频推流方案,需要验证UDP链路的稳定性。这里推荐命令行环境下直接用网络调试助手或者iperf3做UDP测试。

我个人的习惯是先在PC端开一个软件形式的网络调试助手(Windows下的UDP调试工具都行),设置本地端口为5000,然后在RK3588板子上往PC的IP和端口发UDP数据:

root@rk3588:~# echo "rk3588 udp test packet" | nc -u -w1 192.168.1.100 5000

PC端如果收到了字符串,说明UDP通路完全正常。如果只是ping通但UDP丢包严重,多半还是PHY的延迟配置在边界上,要微调tx_delay/rx_delay。

如果要测吞吐量,建议用iperf3:

# 在PC端开启服务 iperf3 -s -u -p 5001 # 在RK3588端打流 iperf3 -c 192.168.1.100 -u -b 100M -t 30 -p 5001

测出来的UDP丢包率如果长时间为0,说明链路已经足够稳定。我改完延迟参数后,持续用500Mbps速率打流30分钟,丢包率为0,这才算真正修通。

4. 常见问题与排查技巧实录

4.1 踩坑速查表

先把我经历过的、以及周围同行常见的问题整理成一张表:

现象可能原因排查方向
MDIO扫描不到PHYMDIO地址不对;复位未释放;供电异常确认strap引脚;确认复位时序;量PHY供电
PHY ID读到了但驱动不加载内核无对应PHY驱动用Generic PHY或编译对应驱动
link up了但ping不通RGMII延迟配置不对调整tx_delay/rx_delay,优先降低TX侧延迟
千兆速率上不去,只有百兆网络变压器/线缆问题;PHY自动协商问题换网线;查变压器中心抽头配置;检查PHY寄存器协商结果
丢包率随速率升高而增大RGMII延迟边界不稳用二分法微调延迟,跑UDP压力测试
拔插网线后link恢复不了复位/中断脚配置问题检查PHY interrupt是否接入MAC,确认二次协商逻辑
两个网口同时用冲突GMAC1/GMAC0管脚复用冲突检查pinctrl,同一组IO不能同时配给两个MAC

这些现象如果放在一起看,会发现大部分问题都出在“配置”而不是“硬件”。这也提醒我们:换PHY芯片时,硬件改版固然要紧,但软件适配必须同步推进,否则就是给自己挖坑。

4.2 RGMII延迟微调的实操手法

延迟参数没有“绝对正确”的值,它依赖PCB走线、PHY型号、MAC芯片内部结构。建议按以下步骤系统化调:

第一步,把设备树里tx_delay和rx_delay都设为0x1f左右,让PHY内部默认延迟承担大部分任务。

第二步,iperf3打流,观察丢包率。如果丢包率高,把tx_delay往大调(比如0x3b),重新打流。记录每个值对应的丢包率。

第三步,如果tx_delay调到最大依然丢包,再调整rx_delay。通常TX和RX延迟一个负责上行一个负责下行,通过打UDP双向流可以区分是哪一方向出了问题。

这里有一个小技巧:RK3588设备树里tx_delay单位是picoseconds还是nanoseconds在不同SDK版本里不一致。有的是直接写纳秒<0x3b>,有的版本里写的是延迟单位数量。最好先读一下当前内核的stmmac驱动源码,确认这个值最终是怎么被换算的,再决定怎么写。

提示:不要同时把MAC侧和PHY侧的延迟都拉满。RGMII标准里TX方向总的延迟要接近2ns,如果MAC加了2ns、PHY内部又加了2ns,总延迟变成了4ns,反而会采到错误的数据边沿。这就是为什么RTL8211F的默认配置下,设备树里tx_delay不能加太多。

4.3 硬件层面的排查小技巧

软件配置查到头了还不行,就要回到硬件。我常用的排查顺序是:

  1. 万用表量PHY供电:确认3.3V和1.8V(如有)是否稳定,纹波是否过大。PHY这类模拟混合芯片对电源纹波比较敏感,纹波太大时可能link状态会反复跳变。
  2. 示波器看MDIO波形:MDIO是双向总线,调试时用示波器抓MDC时钟周期和MDIO数据线上的响应。如果PHY在MDC上升沿之后没有正确驱动MDIO,很可能是PHY没真正进入正常工作状态。
  3. 量125MHz参考时钟:如果PHY做主时钟给MAC,用示波器确认PHY的CLK_OUT引脚真的有125MHz输出,且相位抖动不大。如果时钟输出异常,MAC侧大概率收不到有效数据,即使link起来了也跑不通。
  4. 检查网络变压器:很多国产PHY对网络变压器的中心抽头电压有不同的要求。RTL8211F常用的是中心抽头接2.5V或3.3V,YT8531可能类似但也有差异。如果变压器抽头电压不对,会导致信号幅度偏低或偏压不对,link不稳定或者根本协商不上。

我在这次调试中遇到过百兆正常但千兆不通的情况,最终排查发现是变压器中心抽头电容虚焊,导致千兆模式下信号质量不达标。这种硬件问题在软件配置全部正确时尤其让人抓狂,但好在通过回环测试和信号量测最终定位了。

4.4 一劳永逸的PHY驱动注册技巧

如果你要经常换不同PHY做测试,强烈建议在设备树里不要写死compatible,而是让它走PHY ID自动匹配。比如这样:

&mdio1 { status = "okay"; phy0: ethernet-phy@0 { reg = <0x0>; compatible = "ethernet-phy-id4f51.e91a"; ... }; };

这个写法问题和解决思路其实在于:如果SDK内核里对应的PHY驱动确实存在并注册了PHY_ID_MATCH_EXACT(0x4f51e91a)这类宏,它就能自动匹配。如果没有驱动,又显式填了compatible,某些内核版本反而会报“unsupported PHY ID”然后拒绝绑定。

更稳妥的做法是:先用compatible = "ethernet-phy-id4f51.e91a"让内核自主识别,如果不起作用,直接去掉这一行,只保留reg和reset相关属性,让内核用Generic PHY驱动兜底。等网络能通之后,再慢慢细化驱动配置。

我自己一般会准备两套DTS,一套用原厂参考配置(RTL8211F),一套是新PHY的配置(YT8531),烧录前用U-Boot环境变量切换设备树。这样出问题可以快速对比,排查效率高很多。

结语

这次把RK3588默认的RTL8211F换成国产YT8531,整个过程折腾了大约三天。回头看,核心问题其实就集中在MDIO地址和RGMII延迟这两处,但牵扯出来的知识链条非常长:从设备树的PHY参数,到内核的驱动匹配,再到硬件层面的信号完整性。如果你也在做类似的PHY替换,或者正在开发基于RK3588的网络方案,希望这篇笔记能帮你少走点弯路。

最后再分享一个习惯:换任何PHY芯片,我都会先把新芯片的数据手册翻一遍,特别关注延迟配置、MDIO地址、参考时钟这三个章节。这些信息通常在数据手册里写得很清楚,只是容易被忽略。别看网上说“某某芯片和某某芯片可以pin-to-pin兼容”,电气上兼容不代表软件上兼容。提前把软件配置准备好,再动手改硬件,效率会高很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询