4. RK平台以太网驱动调试:GMAC/RGMII接口配置、PHY芯片驱动调试、MDIO总线通信验证
好,咱们进入第四章。这一章是实打实的硬骨头——以太网驱动调试。说白了,就是让RK芯片的网口能正常工作,能ping通,能跑满带宽。
我个人习惯把以太网调试分成三层:MAC层(GMAC)、PHY层、以及连接它们的MDIO总线。这三层任何一个出问题,网口都起不来。咱们一个一个拆解。
4.1 GMAC/RGMII接口配置
GMAC是芯片内部的以太网控制器,RGMII是它和外部PHY芯片之间的接口标准。RK平台的GMAC驱动在drivers/net/ethernet/stmicro/stmmac/目录下,核心是dwmac-rk.c这个文件。
配置GMAC,主要看设备树。我见过太多人一上来就改驱动代码,其实90%的问题出在设备树配置上。
4.1.1 设备树关键节点
以RK3568为例,GMAC的设备树节点长这样:
&gmac1 {
status = "okay";
phy-mode = "rgmii";
clock_in_out = "input";
snps,reset-gpio = &gpio3 RK_PB1 GPIO_ACTIVE_LOW;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 50000>;
pinctrl-names = "default";
pinctrl-0 = &gmac1_miim
&gmac1_rx_bus2
&gmac1_tx_bus2
&gmac1_rgmii_clk
&gmac1_rgmii_bus;
tx_delay = <0x4e>;
rx_delay = <0x26>;
phy-handle = &phy0;
phy0: ethernet-phy@0 {
reg = <0x0>;
compatible = "ethernet-phy-ieee802.3-c22";
};
};
这里有几个关键点,我挨个说:
- phy-mode:必须和硬件设计一致。RGMII就写"rgmii",如果是RMII就写"rmii"。写错了,PHY根本不通。
- tx_delay / rx_delay:这是RGMII接口的时序补偿。RK芯片内部有可编程延迟链,用来对齐数据和时钟。这两个值需要根据PCB走线长度来调,我遇到过好几次因为走线不等长导致千兆不通,调一下delay值就好了。
- snps,reset-gpio:PHY芯片的复位引脚。复位时序很重要,delay-us的三个值分别是:复位前等待、复位低电平持续时间、复位后等待。有些PHY芯片对复位时序很敏感,比如RTL8211F,复位时间不够它就不工作。
4.1.2 RGMII时序调试
RGMII接口有四种时序模式:内部延迟和外部延迟,分别对应TX和RX。RK芯片默认使用内部延迟模式,也就是在芯片内部加延迟。
调试时序,我一般用这个方法:
- 先用默认值(比如tx_delay=0x30, rx_delay=0x30)试一下,看能不能link up。
- 如果能link up但ping不通,或者丢包严重,说明时序不对。
- 用
ethtool -s eth0 speed 100 duplex full降到百兆试试。如果百兆正常千兆不正常,基本就是时序问题。 - 调整tx_delay和rx_delay,每次增减0x10,反复测试。
我曾经在一个项目上,PCB走线长了3厘米,千兆死活不通。调了整整一天的delay值,最后发现tx_delay要设到0x6e才能稳定工作。嗯,这种问题最磨人。
4.2 PHY芯片驱动调试
PHY芯片是物理层器件,负责把数字信号转换成模拟信号。RK平台常用的PHY芯片有:RTL8211F、YT8512C、AR8035等。
PHY驱动调试,核心是确认PHY芯片是否被正确识别和初始化。
4.2.1 PHY ID读取
系统启动时,内核会通过MDIO总线读取PHY芯片的ID寄存器(寄存器2和3)。如果读不到正确的ID,说明MDIO通信有问题,或者PHY芯片没工作。
查看PHY ID的方法:
# 查看系统识别的PHY
cat /sys/bus/mdio_bus/devices/stmmac-0:00/phy_id
# 或者用mdio工具直接读
mdio eth0 phy_addr 2
mdio eth0 phy_addr 3
常见的PHY ID:
| PHY芯片 | PHY ID (32位) | 厂商 |
|---|---|---|
| RTL8211F | 0x001cc916 | Realtek |
| YT8512C | 0x000001c8 | Motorcomm |
| AR8035 | 0x004dd072 | Atheros |
| BCM89811 | 0x600d8490 | Broadcom |
4.2.2 PHY状态检查
PHY初始化完成后,可以用ethtool查看状态:
ethtool eth0
# 输出示例
Settings for eth0:
Supported ports: [ TP MII ]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supported pause frame use: No
Supports auto-negotiation: Yes
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised pause frame use: No
Advertised auto-negotiation: Yes
Speed: 1000Mb/s
Duplex: Full
Port: Twisted Pair
PHYAD: 0
Transceiver: internal
Auto-negotiation: on
Link detected: yes
重点关注Link detected和Speed。如果Link detected为no,说明物理层没通。先查网线、查对端设备、查PHY芯片供电。
如果Speed显示为10Mb/s或100Mb/s,但硬件支持千兆,可能是:
- 网线质量差(千兆需要4对线,百兆只需要2对)
- PHY芯片的千兆模式被关闭了
- RGMII时序不对,导致千兆协商失败
4.2.3 自定义PHY驱动
有些PHY芯片内核没有现成驱动,需要自己写。其实大部分PHY芯片都兼容通用PHY驱动Generic PHY,但有些特殊功能(比如EEE、WOL)需要单独实现。
我写过一次YT8512C的驱动,核心就是实现phy_driver结构体:
static struct phy_driver yt8512_driver = {
.phy_id = 0x000001c8,
.name = "Motorcomm YT8512C",
.phy_id_mask = 0xfffffff0,
.features = PHY_GBIT_FEATURES,
.soft_reset = yt8512_soft_reset,
.config_init = yt8512_config_init,
.config_aneg = yt8512_config_aneg,
.read_status = yt8512_read_status,
.suspend = yt8512_suspend,
.resume = yt8512_resume,
};
注册驱动后,内核就能自动匹配并初始化这个PHY芯片了。
4.3 MDIO总线通信验证
MDIO总线是管理接口,用来读写PHY芯片的寄存器。它只有两根线:MDC(时钟)和MDIO(数据)。
MDIO通信验证,说白了就是确认CPU能不能正常读写PHY寄存器。
4.3.1 硬件层面验证
先用示波器抓MDC和MDIO的波形。MDC的频率一般是2.5MHz(标准模式)或12.5MHz(高速模式)。如果MDC没有波形,说明GMAC没正常工作,或者设备树里的pinctrl配置错了。
我遇到过最奇葩的问题:MDC有波形,MDIO也有数据,但PHY就是不响应。最后发现是PHY芯片的地址引脚没拉对,PHY地址是0x01,但设备树里配的是0x00。这种问题,用示波器一看就明白了。
4.3.2 软件层面验证
内核启动时,MDIO总线会扫描所有可能的PHY地址(0x00~0x1F)。如果扫描不到PHY,会有这样的日志:
stmmac - user: MDIO bus: error
mdio_bus: stmmac-0:00: PHY ID 0xffffffff at 0, ignored
看到这个日志,说明MDIO通信失败。排查步骤:
- 检查PHY芯片供电(1.8V或3.3V,看芯片手册)
- 检查PHY芯片复位引脚是否拉高
- 检查MDC和MDIO的上下拉电阻(一般需要4.7kΩ上拉)
- 检查设备树中的PHY地址是否正确
如果扫描成功,日志会显示:
mdio_bus: stmmac-0:00: PHY ID 0x001cc916 at 0, driver: RTL8211F Gigabit Ethernet
看到这个,说明MDIO通信正常,PHY芯片被正确识别了。
4.3.3 手动读写PHY寄存器
调试时,我经常手动读写PHY寄存器来验证功能。用mdio工具:
# 读PHY地址0的寄存器0(控制寄存器)
mdio eth0 0 0
# 写PHY地址0的寄存器0
mdio eth0 0 0x1140
# 读PHY地址0的寄存器1(状态寄存器)
mdio eth0 0 1
常用的PHY寄存器:
| 寄存器地址 | 名称 | 说明 |
|---|---|---|
| 0x00 | BMCR | 控制寄存器,可以复位、设置速度/双工 |
| 0x01 | BMSR | 状态寄存器,查看link状态、协商结果 |
| 0x02 | PHY ID High | PHY ID高16位 |
| 0x03 | PHY ID Low | PHY ID低16位 |
| 0x04 | ANAR | 自动协商通告寄存器 |
| 0x05 | ANLPAR | 自动协商对端能力寄存器 |
4.4 本章知识体系
下面这张图总结了以太网驱动调试的整体流程和关键节点:
这张图把调试流程分成了三条主线:时序调试、PHY驱动调试、MDIO通信验证。实际调试时,我建议先走MDIO验证,确认物理层通信正常后,再调时序和驱动。这样能快速定位问题,避免浪费时间。