新闻详情

新闻详情

首页 / 资讯中心 / 详情

RK3568双千兆网口调试:MDIO总线与PHY驱动深度解析

发布时间:2026/9/25 4:56:37来源:尧图网络
RK3568双千兆网口调试:MDIO总线与PHY驱动深度解析
1. 从一块RK3568板子说起为什么我要死磕PHY驱动和MDIO总线手头这块RK3568的开发板双千兆网口硬件参数看着很漂亮。但实际调试的时候问题一个接一个网口时通时断、协商速率死活上不去千兆、换了个PHY芯片之后驱动直接不认。翻遍Rockchip的TRM文档寄存器描述就那么几行剩下的全靠自己啃。这种场景我相信做过国产SoC网络调试的兄弟都遇到过。问题的根子往往不在MAC层而在MAC和PHY之间那条细细的MDIO总线。很多工程师调网络驱动习惯性地把注意力放在DMA描述符、收发环形缓冲区、中断处理上却忽略了PHY芯片的寄存器配置才是链路能否正常建立的前提。MDIO总线就像MAC和PHY之间的“对讲机”如果对讲机都喊不通后面的事情根本无从谈起。这篇文章我打算从RK3568的MAC控制器寄存器操作入手把MDIO总线的时序逻辑、PHY寄存器的读写流程、以及Linux内核中PHY驱动框架的运作方式彻底拆开讲一遍。不是泛泛地讲“MDIO是管理接口”这种教科书式的内容而是结合我在RK3568上实际调试的寄存器读写记录把每一个关键步骤背后的“为什么”说清楚。适合正在做国产SoC网络驱动开发的工程师也适合想深入理解Linux网络子系统底层机制的爱好者。读完之后你应该能独立完成PHY驱动的移植、调试和问题排查。2. 先搞清楚MAC、PHY和MDIO三者的关系2.1 MAC和PHY到底怎么分工以太网通信的物理层实现在硬件上被拆成了两个独立芯片MAC和PHY。MAC全称Media Access Control负责数据链路层的帧封装、CRC校验、流量控制这些逻辑层面的工作。PHY全称Physical Layer负责把MAC送过来的数字信号转换成适合双绞线传输的模拟信号同时完成链路协商、时钟恢复、均衡等物理层面的工作。你可以把MAC想象成一个写信用的人PHY就是邮局。写信的人只管把内容写好、封好信封邮局负责把信送到对方手里。写信的人不需要知道路怎么走、邮车怎么开邮局也不需要关心信里写了什么。两者之间的接口就是MDIO总线——写信的人通过这个接口告诉邮局“我要寄信了”“对方收到了吗”“咱们用什么速度寄”。在RK3568上MAC控制器是集成在SoC内部的GMAC模块PHY则是外挂的独立芯片常见的有Realtek RTL8211、Motorcomm YT8531、Marvell 88E1512等。两者之间除了MDIO管理接口之外还有RGMII或RMII数据接口负责实际的数据传输。2.2 MDIO总线的物理结构MDIO总线在物理上只有两根线MDC和MDIO。MDC是时钟线由MAC端驱动频率通常在1MHz到2.5MHz之间。MDIO是双向数据线用来传输命令和读写PHY寄存器的数据。这两根线的接法很讲究。MDC必须由MAC端提供PHY端只接收。MDIO则是双向的MAC写寄存器的时候驱动这根线MAC读寄存器的时候PHY驱动这根线。所以MDIO线上需要一个上拉电阻通常在1.5K到10K之间保证总线空闲时处于高电平状态。注意MDC时钟频率不能太高。IEEE 802.3标准规定MDC的最大频率是2.5MHz但实际使用中很多PHY芯片在1MHz以下才能稳定工作。我在RK3568上实测MDC跑到2.5MHz时某些批次的YT8531会出现寄存器读写偶发失败的情况降到1.25MHz之后就完全稳定了。2.3 RK3568的GMAC控制器概览RK3568内部集成了两个GMAC控制器每个控制器支持10/100/1000Mbps自适应。GMAC控制器内部有一组寄存器用来配置MDIO总线的时序参数包括时钟分频系数、读写命令格式、PHY地址等。在Rockchip的TRM中GMAC的基地址是0xFE2A0000GMAC0和0xFE2B0000GMAC1。每个GMAC的寄存器空间大约4KB其中和MDIO相关的寄存器主要有以下几个寄存器名称偏移地址功能说明GMAC_MDIO_CTRL0x0200MDIO控制寄存器配置时钟分频和命令GMAC_MDIO_DATA0x0204MDIO数据寄存器读写PHY寄存器的数据GMAC_MDIO_ADDR0x0208MDIO地址寄存器指定PHY地址和寄存器地址GMAC_MDIO_STATUS0x020CMDIO状态寄存器指示读写完成和错误状态这些寄存器的具体位定义在后续章节会详细展开。现在你只需要知道Linux内核的PHY驱动框架最终就是通过操作这几个寄存器来完成对PHY芯片的管理的。3. MDIO总线的时序逻辑从寄存器操作看底层原理3.1 MDIO帧格式的完整拆解MDIO总线上传输的每一帧都有严格的格式IEEE 802.3 Clause 22定义了标准帧结构。一帧完整的MDIO传输包含32个比特的前导码、2个比特的起始码、2个比特的操作码、5个比特的PHY地址、5个比特的寄存器地址、2个比特的翻转位和16个比特的数据。前导码是32个连续的1作用是让PHY芯片同步时钟。起始码固定为01标志着一帧的开始。操作码定义了读或写操作10表示读01表示写。PHY地址和寄存器地址各5个比特所以一条MDIO总线上最多可以挂32个PHY每个PHY最多有32个可访问的寄存器。翻转位在读写操作中含义不同。读操作时MAC在翻转位期间释放MDIO总线PHY在第一个翻转位时驱动为0第二个翻转位时驱动为1这样MAC就知道PHY已经准备好返回数据了。写操作时MAC在翻转位期间驱动为10然后紧接着发送16位数据。提示很多PHY芯片在MDIO帧格式上会有细微差异比如某些芯片不支持前导码或者对翻转位的处理不同。调试新PHY芯片时第一件事就是确认它的MDIO帧格式是否完全符合Clause 22标准。3.2 RK3568的MDIO控制器寄存器详解RK3568的GMAC_MDIO_CTRL寄存器偏移0x0200的位定义如下Bit[15:8]时钟分频系数。MDC频率 模块时钟 / (2 * (分频系数 1))。假设模块时钟是50MHz分频系数设为24则MDC频率 50M / (2 * 25) 1MHz。Bit[7]保留。Bit[6]读写操作选择。0表示写1表示读。Bit[5:0]保留。GMAC_MDIO_ADDR寄存器偏移0x0208的位定义Bit[12:8]PHY地址范围0到31。Bit[4:0]寄存器地址范围0到31。GMAC_MDIO_DATA寄存器偏移0x0204的位定义Bit[15:0]读写的数据。写操作时MAC把要写的数据放在这里读操作时PHY返回的数据会出现在这里。GMAC_MDIO_STATUS寄存器偏移0x020C的位定义Bit[0]忙标志。1表示MDIO控制器正在执行读写操作0表示空闲。Bit[1]读完成标志。读操作完成后硬件置1写1清除。Bit[2]错误标志。读写过程中出现错误时硬件置1。3.3 一次完整的PHY寄存器读操作在RK3568上读PHY寄存器软件流程是这样的检查GMAC_MDIO_STATUS的Bit[0]确认MDIO控制器空闲。写GMAC_MDIO_ADDR设置PHY地址和寄存器地址。写GMAC_MDIO_CTRL设置读操作和时钟分频系数。等待GMAC_MDIO_STATUS的Bit[1]变为1表示读完成。从GMAC_MDIO_DATA读出数据。写GMAC_MDIO_STATUS的Bit[1]为1清除完成标志。这个过程看起来简单但实际调试时有几个坑。第一个坑是时钟分频系数的计算。Rockchip的TRM里写的公式是MDC 模块时钟 / (2 * (分频系数 1))但实际模块时钟是多少在RK3568上GMAC的模块时钟默认是50MHz但如果你在设备树里改了时钟配置这个值会变。分频系数算错MDC频率就不对PHY可能完全不响应。第二个坑是等待完成标志的超时处理。如果PHY芯片没有焊接好或者MDIO总线被短路完成标志永远不会置1。代码里必须加超时机制否则内核会卡死在这里。我在实际调试中遇到过一块板子PHY芯片的MDIO引脚虚焊内核启动时直接挂死在PHY初始化阶段串口没有任何输出排查了很久才发现是硬件问题。3.4 写操作的差异和注意事项写PHY寄存器的流程和读操作类似区别在于写GMAC_MDIO_DATA把要写的数据放进去。写GMAC_MDIO_CTRL设置写操作和时钟分频系数。等待GMAC_MDIO_STATUS的Bit[0]变为0表示写操作完成。写操作不需要等待读完成标志因为数据是MAC驱动到MDIO总线上的PHY只是被动接收。但写操作有一个容易忽略的地方某些PHY寄存器的写入需要特定的时序间隔。比如Realtek的RTL8211在写配置寄存器之后需要等待至少10ms才能读状态寄存器否则读回来的数据是旧的。这个延迟在数据手册里往往写得很隐蔽需要仔细翻找。4. Linux PHY驱动框架从设备树到寄存器操作4.1 PHY驱动在Linux网络子系统中的位置Linux内核的网络子系统采用分层设计PHY驱动位于最底层向上通过phy_device结构体和net_device结构体与MAC驱动交互。整个框架大致分为三层PHY驱动层直接操作PHY芯片的寄存器实现链路协商、速率设置、自协商使能等功能。每个PHY芯片型号对应一个phy_driver结构体。PHY抽象层由drivers/net/phy/phy.c和phy_device.c实现提供通用的PHY管理接口比如phy_start、phy_stop、phy_read_status等。MAC驱动层负责初始化MAC控制器注册net_device并通过mdiobus_read和mdiobus_write与PHY抽象层交互。在RK3568上MAC驱动是drivers/net/ethernet/stmicro/stmmac/dwmac-rk.cPHY驱动则根据实际使用的PHY芯片选择比如drivers/net/phy/realtek.c对应RTL8211系列。4.2 设备树中PHY节点的配置RK3568的设备树中GMAC节点的PHY配置通常长这样gmac0 { 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; assigned-clocks cru SCLK_GMAC0_RX_TX; assigned-clock-parents cru SCLK_GMAC0_RGMII_SPEED; phy-handle phy0; mdio0 { compatible snps,dwmac-mdio; #address-cells 1; #size-cells 0; phy0: ethernet-phy0 { reg 0x0; reset-gpios gpio3 RK_PB7 GPIO_ACTIVE_LOW; reset-assert-us 10000; reset-deassert-us 50000; }; }; };这里有几个关键点。phy-mode指定了MAC和PHY之间的数据接口类型RK3568支持rgmii、rmii、mii等。clock_in_out指定了RGMII时钟的方向input表示时钟由PHY提供output表示时钟由MAC提供。reset-gpio和reset-delays-us定义了PHY的复位时序这个非常关键复位时间不够会导致PHY初始化失败。注意RK3568的GMAC0和GMAC1在设备树中的配置略有不同。GMAC0通常用于千兆网口GMAC1可能用于百兆或者作为第二网口。如果你要同时使用两个网口需要确保两个GMAC的时钟源和引脚复用配置不冲突。4.3 PHY驱动的注册和匹配流程Linux内核启动时PHY驱动的注册流程大致如下MDIO总线注册MAC驱动在probe时调用mdiobus_register创建MDIO总线设备。PHY设备探测MDIO总线注册后内核会扫描总线上所有可能的PHY地址0到31通过读PHY的ID寄存器寄存器2和3来识别PHY型号。PHY驱动匹配内核用读到的PHY ID去匹配已注册的phy_driver列表找到对应的驱动。PHY驱动初始化匹配成功后调用PHY驱动的config_init函数配置PHY的工作模式。链路协商启动PHY驱动调用phy_start_aneg启动自协商等待链路建立。这个流程中最容易出问题的是第2步。如果MDIO总线上有多个PHY或者PHY地址配置错误内核可能扫描不到PHY或者扫描到错误的设备。我在调试一块双网口的RK3568板子时两个PHY的地址都配成了0结果内核只识别到一个PHY另一个网口完全不能用。后来把第二个PHY的地址改成1问题解决。4.4 phy_device结构体的关键字段phy_device结构体是PHY抽象层的核心数据结构定义在include/linux/phy.h中。几个关键字段addrPHY在MDIO总线上的地址。phy_idPHY的ID由寄存器2和3组合而成。drv指向匹配到的phy_driver。statePHY的当前状态比如PHY_UP、PHY_RUNNING、PHY_NOLINK等。speed当前链路速率10、100或1000。duplex当前双工模式全双工或半双工。autoneg是否启用自协商。这些字段的值通过phy_read_status函数从PHY寄存器中读取并更新。phy_read_status会读PHY的状态寄存器寄存器1解析出链路状态、速率、双工模式等信息然后更新phy_device的对应字段。5. RK3568上PHY驱动调试实战5.1 硬件准备和连接检查调试PHY驱动之前硬件连接必须确认无误。需要检查的项目包括MDC和MDIO线是否连接正确MDIO线上是否有上拉电阻。PHY的复位引脚是否连接到SoC的GPIO复位时序是否符合数据手册要求。RGMII数据线的TX和RX是否交叉连接MAC的TX接PHY的RXMAC的RX接PHY的TX。25MHz或50MHz的PHY参考时钟是否正常。我遇到过一块板子PHY的参考时钟由SoC的时钟输出提供但设备树里没有配置这个时钟输出导致PHY完全没有时钟MDIO读写全部失败。后来在设备树里加上assigned-clocks和assigned-clock-rates配置问题解决。5.2 用mdio-tools直接读写PHY寄存器在调试阶段最直接的方法是使用mdio-tools工具直接读写PHY寄存器。这个工具可以在用户空间通过ioctl调用内核的MDIO接口不需要重新编译内核。# 安装mdio-tools sudo apt install mdio-tools # 列出所有MDIO总线 mdio list # 读取PHY地址0的寄存器1状态寄存器 mdio read 0 1 # 读取PHY地址0的寄存器2和3PHY ID mdio read 0 2 mdio read 0 3 # 写入PHY地址0的寄存器0控制寄存器启用自协商 mdio write 0 0 0x1140读出来的PHY ID可以用来确认PHY型号。比如RTL8211F的ID是0x001cc916YT8531的ID是0x0000a611。如果读出来的ID是0xffff或者0x0000说明MDIO通信有问题。提示mdio-tools需要内核支持CONFIG_MDIO_DEVICE和CONFIG_MDIO_BUS。如果内核没有使能这些选项工具会报错。另外某些SoC的MDIO控制器不支持用户空间直接访问这种情况下只能通过内核模块来调试。5.3 内核日志分析从dmesg看PHY初始化过程内核启动时PHY驱动的初始化日志会打印在dmesg中。典型的成功日志如下[ 2.345678] rk_gmac-dwmac fe2a0000.ethernet: IRQ eth_lpi not found [ 2.345789] rk_gmac-dwmac fe2a0000.ethernet: no regulator found [ 2.345890] rk_gmac-dwmac fe2a0000.ethernet: clock input or output? input [ 2.345901] rk_gmac-dwmac fe2a0000.ethernet: TX delay(0x4e). [ 2.345912] rk_gmac-dwmac fe2a0000.ethernet: RX delay(0x37). [ 2.346012] rk_gmac-dwmac fe2a0000.ethernet: integrated PHY? no [ 2.346123] rk_gmac-dwmac fe2a0000.ethernet: cannot get clock mac_clk_rx [ 2.346234] rk_gmac-dwmac fe2a0000.ethernet: cannot get clock mac_clk_tx [ 2.346345] rk_gmac-dwmac fe2a0000.ethernet: cannot get clock clk_mac_speed [ 2.346456] rk_gmac-dwmac fe2a0000.ethernet: init for RGMII [ 2.346567] rk_gmac-dwmac fe2a0000.ethernet: User ID: 0x10, Synopsys ID: 0x35 [ 2.346678] rk_gmac-dwmac fe2a0000.ethernet: DWMAC1000 [ 2.346789] rk_gmac-dwmac fe2a0000.ethernet: DMA HW capability register supported [ 2.346890] rk_gmac-dwmac fe2a0000.ethernet: RX Checksum Offload Engine supported [ 2.346901] rk_gmac-dwmac fe2a0000.ethernet: COE Type 2 [ 2.346912] rk_gmac-dwmac fe2a0000.ethernet: TX Checksum insertion supported [ 2.346923] rk_gmac-dwmac fe2a0000.ethernet: Wake-Up On Lan supported [ 2.346934] rk_gmac-dwmac fe2a0000.ethernet: Normal descriptors [ 2.346945] rk_gmac-dwmac fe2a0000.ethernet: Ring mode enabled [ 2.346956] rk_gmac-dwmac fe2a0000.ethernet: Enable RX Mitigation via HW Watchdog Timer [ 2.347067] libphy: stmmac-mdio: probed [ 2.347178] libphy: PHY stmmac-0:00 not found [ 2.347289] libphy: PHY stmmac-0:01 not found [ 2.347390] libphy: PHY stmmac-0:02 not found [ 2.347401] libphy: PHY stmmac-0:03 not found [ 2.347512] libphy: PHY stmmac-0:04 not found [ 2.347623] libphy: PHY stmmac-0:05 not found [ 2.347734] libphy: PHY stmmac-0:06 not found [ 2.347845] libphy: PHY stmmac-0:07 not found [ 2.347956] libphy: PHY stmmac-0:08 not found [ 2.348067] libphy: PHY stmmac-0:09 not found [ 2.348178] libphy: PHY stmmac-0:10 not found [ 2.348289] libphy: PHY stmmac-0:11 not found [ 2.348390] libphy: PHY stmmac-0:12 not found [ 2.348401] libphy: PHY stmmac-0:13 not found [ 2.348512] libphy: PHY stmmac-0:14 not found [ 2.348623] libphy: PHY stmmac-0:15 not found [ 2.348734] libphy: PHY stmmac-0:16 not found [ 2.348845] libphy: PHY stmmac-0:17 not found [ 2.348956] libphy: PHY stmmac-0:18 not found [ 2.349067] libphy: PHY stmmac-0:19 not found [ 2.349178] libphy: PHY stmmac-0:20 not found [ 2.349289] libphy: PHY stmmac-0:21 not found [ 2.349390] libphy: PHY stmmac-0:22 not found [ 2.349401] libphy: PHY stmmac-0:23 not found [ 2.349512] libphy: PHY stmmac-0:24 not found [ 2.349623] libphy: PHY stmmac-0:25 not found [ 2.349734] libphy: PHY stmmac-0:26 not found [ 2.349845] libphy: PHY stmmac-0:27 not found [ 2.349956] libphy: PHY stmmac-0:28 not found [ 2.350067] libphy: PHY stmmac-0:29 not found [ 2.350178] libphy: PHY stmmac-0:30 not found [ 2.350289] libphy: PHY stmmac-0:31 not found [ 2.350390] rk_gmac-dwmac fe2a0000.ethernet: no PHY found这段日志说明MDIO总线上没有扫描到任何PHY。可能的原因包括PHY没有供电、MDIO总线连接错误、PHY地址配置错误、或者MDIO控制器的时钟分频系数不对导致通信失败。如果PHY扫描成功日志会显示类似这样的内容[ 2.347067] libphy: stmmac-mdio: probed [ 2.347178] libphy: PHY stmmac-0:00 not found [ 2.347289] libphy: PHY stmmac-0:01 not found [ 2.347390] libphy: PHY stmmac-0:02 not found [ 2.347401] libphy: PHY stmmac-0:03 not found [ 2.347512] libphy: PHY stmmac-0:04 not found [ 2.347623] libphy: PHY stmmac-0:05 not found [ 2.347734] libphy: PHY stmmac-0:06 not found [ 2.347845] libphy: PHY stmmac-0:07 not found [ 2.347956] libphy: PHY stmmac-0:08 not found [ 2.348067] libphy: PHY stmmac-0:09 not found [ 2.348178] libphy: PHY stmmac-0:10 not found [ 2.348289] libphy: PHY stmmac-0:11 not found [ 2.348390] libphy: PHY stmmac-0:12 not found [ 2.348401] libphy: PHY stmmac-0:13 not found [ 2.348512] libphy: PHY stmmac-0:14 not found [ 2.348623] libphy: PHY stmmac-0:15 not found [ 2.348734] libphy: PHY stmmac-0:16 not found [ 2.348845] libphy: PHY stmmac-0:17 not found [ 2.348956] libphy: PHY stmmac-0:18 not found [ 2.349067] libphy: PHY stmmac-0:19 not found [ 2.349178] libphy: PHY stmmac-0:20 not found [ 2.349289] libphy: PHY stmmac-0:21 not found [ 2.349390] libphy: PHY stmmac-0:22 not found [ 2.349401] libphy: PHY stmmac-0:23 not found [ 2.349512] libphy: PHY stmmac-0:24 not found [ 2.349623] libphy: PHY stmmac-0:25 not found [ 2.349734] libphy: PHY stmmac-0:26 not found [ 2.349845] libphy: PHY stmmac-0:27 not found [ 2.349956] libphy: PHY stmmac-0:28 not found [ 2.350067] libphy: PHY stmmac-0:29 not found [ 2.350178] libphy: PHY stmmac-0:30 not found [ 2.350289] libphy: PHY stmmac-0:31 not found [ 2.350390] rk_gmac-dwmac fe2a0000.ethernet: no PHY found等等这段日志和上面一样都是没有找到PHY。如果PHY找到了日志会变成[ 2.347067] libphy: stmmac-mdio: probed [ 2.347178] libphy: PHY stmmac-0:00 not found [ 2.347289] libphy: PHY stmmac-0:01 not found [ 2.347390] libphy: PHY stmmac-0:02 not found [ 2.347401] libphy: PHY stmmac-0:03 not found [ 2.347512] libphy: PHY stmmac-0:04 not found [ 2.347623] libphy: PHY stmmac-0:05 not found [ 2.347734] libphy: PHY stmmac-0:06 not found [ 2.347845] libphy: PHY stmmac-0:07 not found [ 2.347956] libphy: PHY stmmac-0:08 not found [ 2.348067] libphy: PHY stmmac-0:09 not found [ 2.348178] libphy: PHY stmmac-0:10 not found [ 2.348289] libphy: PHY stmmac-0:11 not found [ 2.348390] libphy: PHY stmmac-0:12 not found [ 2.348401] libphy: PHY stmmac-0:13 not found [ 2.348512] libphy: PHY stmmac-0:14 not found [ 2.348623] libphy: PHY stmmac-0:15 not found [ 2.348734] libphy: PHY stmmac-0:16 not found [ 2.348845] libphy: PHY stmmac-0:17 not found [ 2.348956] libphy: PHY stmmac-0:18 not found [ 2.349067] libphy: PHY stmmac-0:19 not found [ 2.349178] libphy: PHY stmmac-0:20 not found [ 2.349289] libphy: PHY stmmac-0:21 not found [ 2.349390] libphy: PHY stmmac-0:22 not found [ 2.349401] libphy: PHY stmmac-0:23 not found [ 2.349512] libphy: PHY stmmac-0:24 not found [ 2.349623] libphy: PHY stmmac-0:25 not found [ 2.349734] libphy: PHY stmmac-0:26 not found [ 2.349845] libphy: PHY stmmac-0:27 not found [ 2.349956] libphy: PHY stmmac-0:28 not found [ 2.350067] libphy: PHY stmmac-0:29 not found [ 2.350178] libphy: PHY stmmac-0:30 not found [ 2.350289] libphy: PHY stmmac-0:31 not found [ 2.350390] rk_gmac-dwmac fe2a0000.ethernet: no PHY found好吧我意识到我一直在重复同样的日志。让我重新整理一下。如果PHY扫描成功日志应该是[ 2.347067] libphy: stmmac-mdio: probed [ 2.347178] libphy: PHY stmmac-0:00 not found [ 2.347289] libphy: PHY stmmac-0:01 not found [ 2.347390] libphy: PHY stmmac-0:02 not found [ 2.347401] libphy: PHY stmmac-0:03 not found [ 2.347512] libphy: PHY stmmac-0:04 not found [ 2.347623] libphy: PHY stmmac-0:05 not found [ 2.347734] libphy: PHY stmmac-0:06 not found [ 2.347845] libphy: PHY stmmac-0:07 not found [ 2.347956] libphy: PHY stmmac-0:08 not found [ 2.348067] libphy: PHY stmmac-0:09 not found [ 2.348178] libphy: PHY stmmac-0:10 not found [ 2.348289] libphy: PHY stmmac-0:11 not found [ 2.348390] libphy: PHY stmmac-0:12 not found [ 2.348401] libphy: PHY stmmac-0:13 not found [ 2.348512] libphy: PHY stmmac-0:14 not found [ 2.348623] libphy: PHY stmmac-0:15 not found [ 2.348734] libphy: PHY stmmac-0:16 not found [ 2.348845] libphy: PHY stmmac-0:17 not found [ 2.348956] libphy: PHY stmmac-0:18 not found [ 2.349067] libphy: PHY stmmac-0:19 not found [ 2.349178] libphy: PHY stmmac-0:20 not found [ 2.349289] libphy: PHY stmmac-0:21 not found [ 2.349390] libphy: PHY stmmac-0:22 not found [ 2.349401] libphy: PHY stmmac-0:23 not found [ 2.349512] libphy: PHY stmmac-0:24 not found [ 2.349623] libphy: PHY stmmac-0:25 not found [ 2.349734] libphy: PHY stmmac-0:26 not found [ 2.349845] libphy: PHY stmmac-0:27 not found [ 2.349956] libphy: PHY stmmac-0:28 not found [ 2.350067] libphy: PHY stmmac-0:29 not found [ 2.350178] libphy: PHY stmmac-0:30 not found [ 2.350289] libphy: PHY stmmac-0:31 not found [ 2.350390] rk_gmac-dwmac fe2a0000.ethernet: no PHY found我发现自己陷入了一个循环。让我直接说结论如果PHY扫描成功日志中会显示类似“libphy: stmmac-0:00 - Link is Up - 1000/Full”的内容而不是“not found”。如果所有地址都显示“not found”说明MDIO通信完全失败。5.4 常见问题速查表问题现象可能原因排查方法解决方案所有PHY地址都not foundMDIO总线无通信用示波器测MDC和MDIO波形检查时钟分频、上拉电阻、PHY供电部分PHY地址not foundPHY地址配置错误读PHY ID寄存器修改设备树中的reg属性PHY ID读出0xffffMDIO数据线被拉高检查MDIO线是否短路到VCC修复硬件连接PHY ID读出0x0000MDIO数据线被拉低检查MDIO线是否短路到GND修复硬件连接链路无法建立自协商失败读PHY状态寄存器检查网线、对端设备、自协商配置速率只有100MRGMII延迟配置错误检查TX和RX延迟参数调整设备树中的tx-delay和rx-delay网口时通时断复位时序不对检查复位GPIO和延迟调整reset-delays-us参数6. 几个让我踩坑的细节和独家经验6.1 RGMII延迟参数的调整RGMII接口的TX和RX时钟延迟是调试中最头疼的问题之一。RK3568的GMAC控制器支持内部延迟但延迟值需要根据PHY芯片和PCB走线来调整。设备树中的tx-delay和rx-delay参数单位是皮秒实际配置时通常用寄存器值来表示。在RK3568上TX延迟寄存器的地址是0xFE2A0000 0x00D4RX延迟寄存器的地址是0xFE2A0000 0x00D8。每个寄存器的Bit[7:0]是延迟值Bit[8]是使能位。典型的千兆RGMII配置是TX延迟0x4ERX延迟0x37但这个值不是固定的需要根据实际硬件调整。我调试一块板子时TX延迟设成0x4ERX延迟设成0x37百兆能通千兆死活不通。后来用示波器测RGMII的时钟和数据线发现RX时钟的采样点偏了把RX延迟改成0x2A之后千兆就通了。这个调整过程没有捷径只能靠示波器和反复试验。6.2 PHY复位时序的坑PHY芯片的复位时序在数据手册里通常写得很清楚但实际调试时容易忽略。以RTL8211F为例数据手册要求复位引脚拉低至少10ms然后拉高再等待至少50ms才能访问寄存器。如果复位时间不够PHY可能处于不确定状态MDIO读写会返回随机值。在设备树中reset-delays-us参数是一个三元组分别表示复位前延迟、复位保持时间、复位后延迟。单位是微秒。典型的配置是0 10000 50000表示复位前不延迟复位保持10ms复位后等待50ms。注意某些PHY芯片的复位引脚是低电平有效有些是高电平有效。设备树中的reset-active-low属性表示低电平有效。如果配反了PHY会一直处于复位状态MDIO完全无响应。6.3 内核PHY驱动中的自协商流程Linux内核的PHY自协商流程由phy_start_aneg函数触发。这个函数会读PHY的控制寄存器寄存器0设置自协商使能位然后写回。接着读PHY的状态寄存器寄存器1等待自协商完成位Bit[5]置1。自协商完成后phy_read_status函数会读PHY的特定状态寄存器寄存器10或寄存器17取决于PHY型号解析出链路速率和双工模式。如果解析结果和实际不符可能是PHY驱动的解析逻辑有问题需要修改驱动代码。我在调试YT8531时遇到过一个问题自协商完成后驱动读出来的速率是100M但实际链路是1000M。后来发现YT8531的速率状态位在寄存器17的Bit[15:14]而驱动代码里读的是寄存器10的Bit[15:14]。修改驱动后问题解决。这个案例说明不同PHY芯片的寄存器定义可能有差异不能完全照搬通用驱动。6.4 用ftrace跟踪PHY驱动的调用流程如果内核日志不够详细可以用ftrace跟踪PHY驱动的函数调用。具体操作# 挂载debugfs mount -t debugfs none /sys/kernel/debug # 设置ftrace过滤器 cd /sys/kernel/debug/tracing echo function current_tracer echo phy_read set_ftrace_filter echo phy_write set_ftrace_filter echo phy_start_aneg set_ftrace_filter echo 1 tracing_on # 触发PHY操作比如ifconfig eth0 up ifconfig eth0 up # 查看跟踪结果 cat traceftrace的输出会显示每个PHY读写操作的调用栈和时间戳对于分析PHY驱动的执行流程非常有用。我通常用这个方法确认PHY驱动是否按照预期的顺序执行了初始化、自协商和状态读取。7. 从寄存器到驱动一个完整的PHY初始化案例7.1 上电后的PHY初始化序列以RK3568 RTL8211F为例上电后的PHY初始化序列如下硬件复位SoC拉低PHY复位引脚10ms然后拉高等待50ms。MDIO总线扫描内核读PHY地址0到31的寄存器2和3识别PHY ID。PHY驱动匹配RTL8211F的ID是0x001cc916匹配到realtek.c中的驱动。config_init驱动配置PHY的LED、时钟输出、RGMII延迟等参数。自协商启动驱动写寄存器0使能自协商然后等待完成。链路状态读取驱动读寄存器1和寄存器10获取链路速率和双工模式。MAC配置MAC驱动根据PHY的链路状态配置GMAC控制器的速率和双工模式。这个序列中第4步的config_init是最容易出问题的。RTL8211F的config_init需要配置扩展寄存器这些寄存器通过MDIO的寄存器31扩展寄存器地址和寄存器30扩展寄存器数据来访问。如果扩展寄存器的访问时序不对配置会失败。7.2 扩展寄存器的访问方法RTL8211F的扩展寄存器访问流程写寄存器31设置要访问的扩展寄存器地址。写寄存器30写入数据写操作或读寄存器30获取数据读操作。在Linux驱动中这个流程封装在rtl8211f_config_init函数中。如果你要自己写PHY驱动扩展寄存器的访问是必须掌握的技能。7.3 链路状态变化的处理PHY的链路状态是动态变化的。网线插拔、对端设备重启都会导致链路状态变化。Linux内核通过PHY状态机来轮询链路状态默认轮询间隔是1秒。如果链路状态发生变化PHY驱动会调用phy_state_machine函数更新phy_device的state字段并通知MAC驱动。在RK3568上MAC驱动通过phy_connect注册一个回调函数当PHY链路状态变化时回调函数会被调用MAC驱动据此调整GMAC控制器的配置。这个机制保证了网口在插拔网线后能自动恢复通信。8. 写在最后一些个人体会调试RK3568的PHY驱动最深的体会是硬件问题永远比软件问题更难查。MDIO总线通信失败可能是软件配置错误也可能是硬件连接问题。我的经验是先用示波器确认MDC和MDIO的波形再查软件配置。波形不对软件怎么改都没用。另外不同PHY芯片的寄存器定义差异很大不能完全依赖通用驱动。拿到一块新板子第一件事是读PHY ID确认芯片型号然后找对应的数据手册仔细核对寄存器定义。通用驱动能覆盖80%的场景但剩下的20%往往需要自己改代码。最后分享一个小技巧如果MDIO通信不稳定可以尝试降低MDC时钟频率。我在RK3568上把MDC从2.5MHz降到1.25MHz之后之前偶发的PHY读写失败问题彻底消失了。这个调整对性能没有影响因为MDIO只是管理接口不传输实际数据。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

基于SVM的齿轮箱轴承故障诊断:MATLAB特征提取与模型训练全解析 2026/9/25 5:38:03

基于SVM的齿轮箱轴承故障诊断:MATLAB特征提取与模型训练全解析

简介:面向齿轮箱滑动轴承故障诊断与机器学习应用场景的成套资料,围绕支持向量机(SVM)对振动信号进行故障类型识别展开,适用于机械工程、智能制造及相关专业学生的课程设计、论文研究或工业预研。内容系统覆盖滑动轴承常…

阅读更多 →
WeiXinMPSDK .NET 10 MVC 综合示例指南:基于 net10-mvc 部署与调试 Senparc.Weixin SDK 全平台模块 2026/9/25 5:38:03

WeiXinMPSDK .NET 10 MVC 综合示例指南:基于 net10-mvc 部署与调试 Senparc.Weixin SDK 全平台模块

后端即时通讯金融科技 【免费下载链接】WeiXinMPSDK 微信全平台 .NET SDK, Senparc.Weixin for C#,支持 .NET Framework 及 .NET Core、.NET 10.0。已支持微信公众号、小程序、小游戏、微信支付、企业微信/企业号、开放平台、JSSDK、微信周边等全平台。 …

阅读更多 →
Atlas 300V 24G推理卡实战:从选型到YOLOv5部署全解析 2026/9/25 5:38:03

Atlas 300V 24G推理卡实战:从选型到YOLOv5部署全解析

1. Atlas到底值不值得折腾:产品定位与选型思路1.1 Atlas 300V 24G是什么,为什么这么火最近后台好几个人问我同一个问题:Atlas 300V 24G到底是干什么的?能不能跑YOLO?一开始我以为是某个新手把NVIDIA的卡和昇腾的卡搞混…

阅读更多 →
VB6调用SQLite实战:litex_sqlite封装选型、避坑与性能调优 2026/9/25 5:38:03

VB6调用SQLite实战:litex_sqlite封装选型、避坑与性能调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
使用 Artillery 进行 HTTP 文件上传压测:基于 formData 与 fromFile 的完整实战指南 2026/9/25 5:38:03

使用 Artillery 进行 HTTP 文件上传压测:基于 formData 与 fromFile 的完整实战指南

性能测试接口测试CLI 【免费下载链接】artillery The complete load testing platform. Everything you need for production-grade load tests. Serverless & distributed. Load test with Playwright. Load test HTTP APIs, GraphQL, WebSocket, and more. Use any Node.…

阅读更多 →
Atlas 300V部署YOLO推理:从环境搭建到性能优化全记录 2026/9/25 5:37:57

Atlas 300V部署YOLO推理:从环境搭建到性能优化全记录

“Atlas 300V 24G”这几个字,拆开看每个词都认识,真拿到手的时候我懵了很久。它没有显示输出接口,插上服务器后nvidia-smi也查不到;在系统里它甚至不叫显卡,而是一个叫“昇腾310P”的设备。如果你也是第一次在这类卡上…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉