ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RK3568下YT8531/YT8521 PHY移植避坑指南:RGMII与设备树详解

RK3568下YT8531/YT8521 PHY移植避坑指南:RGMII与设备树详解 最近在做一块基于瑞芯微RK3568的板子网络这块用的是裕太微的YT8531千兆PHY。本来以为内核自带的驱动一开就能通结果从设备树到驱动配置前前后后折腾了好几天。这里头坑确实多尤其是RGMII的延时配置、PHY地址、复位时序这些不踩一遍真的很难记住。这篇文章就把我这次移植YT8531/YT8521的完整过程、设备树写法和遇到的坑都整理出来希望能帮到正在搞嵌入式Linux网络调试的朋友。先说清楚这篇文章适合谁看正在做嵌入式Linux平台网络适配的、被PHY芯片驱动和设备树折磨过的、以及想把RGMII/SGMII这些接口概念弄明白的开发者。我会把原理、设备树写法、内核配置、实测调试过程都串在一起讲尽量做到看完能直接上板操作。1. 项目背景与选型思路1.1 YT8531/YT8521到底是什么YT8531和YT8521都是裕太微电子Motorcomm出品的单口千兆以太网PHY芯片。YT8531一般是电口千兆YT8521则更常见于光口或者电口千兆的应用场景两者都支持RGMII和SGMII两种与MAC相连的接口模式。在嵌入式Linux里MAC控制器比如RK3568的GMAC、i.MX的FEC、NXP的TSEC等负责上层协议的处理和帧的封装解析而PHY芯片负责物理层信号的收发、编解码、协商速率等工作。MAC和PHY之间的数据通道常用的就是RGMII和SGMII这也决定了设备树里phy-mode这个属性要怎么写。这次项目用的主控是RK3568内置两个千兆GMAC一个接YT8531走RGMII另一个接YT8521走SGMII。两个PHY同门同宗但配置起来却各有各的讲究后面我会专门对比。1.2 为什么选裕太微而不选Marvell/Realtek国内做嵌入式产品这两年选裕太微的PHY越来越多原因很简单性价比高、供货稳定、驱动逐渐被主流内核主线支持。以前大家习惯用RTL8211F、AR8031/8035这些但缺货涨价让人苦不堪言。YT8531/YT8521在功能上和AR8031高度相似寄存器布局也有不少共通之处所以很多老方案可以直接平移过来改一改。不过这里要提醒一句选型时别只看硬件兼容一定要确认你的内核版本里有没有对应驱动。我这次用的是Linux 6.1内核里已经带了motrcomm_phy驱动直接开CONFIG_MOTORCOMM_PHY就能用。如果你用的是老旧内核比如4.19或更早大概率需要自己移植厂商提供的驱动源码那就又是另一番折腾了。1.3 本次项目的硬件拓扑先交代一下硬件环境方便后面讲问题时大家能对上号主控RK3568MAC0接YT8531RGMII接口PHY地址0MAC1接YT8521SGMII接口PHY地址3时钟方案MAC0使用外部25M晶振给PHY提供参考时钟PHY再输出125M给MAC也就是clock_in_out input这种模式MAC1的SGMII参考时钟由主控侧提供硬件上还有个关键点YT8531的PHY地址不是随便定的它是由芯片的strap管脚一般是PHYAD[4:0]在复位时采样的电平决定的。我板子上把地址配置成了0所以mdio总线扫描时它应该在地址0上回应。这个一定要和硬件工程师确认不然设备树里reg写错后面的所有工作都白做。2. 设备树配置的关键细节2.1 一个能跑通的RGMII设备树模板先把设备树模板贴出来后面再讲解每个字段的含义。以RK3568的GMAC1对应mac1节点接YT8531为例gmac1 { status okay; phy-mode rgmii-id; clock_in_out input; snps,reset-gpio gpio3 RK_PB2 GPIO_ACTIVE_LOW; snps,reset-active-low; snps,reset-delays-us 0 20000 80000; assigned-clocks cru SCLK_GMAC1_RX_TX, cru SCLK_GMAC1; assigned-clock-parents cru SCLK_GMAC1_RGMII_SPEED, cru CLK_GMAC1_125M; pinctrl-names default; pinctrl-0 gmac1_rgmii_clk, gmac1_rgmii_bus; phy-handle phy_yt8531; mdio { compatible snps,dwmac-mdio; #address-cells 1; #size-cells 0; phy_yt8531: ethernet-phy0 { reg 0; reset-gpios gpio3 RK_PB2 GPIO_ACTIVE_LOW; reset-assert-us 20000; reset-deassert-us 80000; compatible ethernet-phy-id4f51.e11a, ethernet-phy-ieee802.3-c22; }; }; };注意几个重点phy-mode rgmii-id这是最容易出错的地方我后面单独用一小节讲。phy-handle指向mdio子节点里的PHY节点。复位GPIO可以在MAC节点下用snps,reset-gpio也可以在PHY子节点里用标准的reset-gpios。我个人推荐在PHY子节点里写因为这样驱动框架能更好地控制复位时序特别是配合reset-assert-us和reset-deassert-us这两个属性。2.2 phy-mode到底该怎么选RGMII接口下phy-mode有几种变体rgmii、rgmii-id、rgmii-rxid、rgmii-txid。它们的区别在于谁来负责给时钟信号加延时delay。RGMII协议本身要求时钟信号在上升沿和下降沿各采一次数据但实际PCB走线长度会导致时钟和数据之间产生相位差所以必须在发送端或者接收端补偿这个延时。简单说rgmiiMAC和PHY都不加延时依赖外部PCB走线或额外器件来补偿。这种模式对Layout要求极高一般不建议用。rgmii-idPHY芯片内部同时给TX和RX时钟加延时MAC侧不加。rgmii-rxid只给RX方向加延时适合MAC发送方向已经自己补偿过的情况。rgmii-txid只给TX方向加延时。对于YT8531最省事的方案就是把MAC侧的延时关闭所有tuning寄存器设为0然后在设备树里直接写rgmii-id让PHY内部处理。这样做的好处是配置简单、一致性高也符合大多数参考设计的做法。但这里有个坑如果你用了rgmii却忘记在MAC侧配置延时寄存器那么大概率会出现“link是up的协商速率也是千兆但ping不通”的诡异现象。因为物理层已经通了但数据采样的时序不对导致链路层数据全是错的。这个问题排查起来非常费劲我建议新板子首次调试直接先用rgmii-id排除掉延时因素。2.3 复位GPIO和上电时序别想当然PHY芯片的复位时序非常关键。YT8531的数据手册里明确写了上电后需要等待时钟稳定然后Reset脚拉低至少一定时间一般是10ms以上再拉高释放之后PHY才能正常响应MDIO访问。设备树里对应的参数是reset-assert-us 20000; /* 复位拉低持续时间20ms */ reset-deassert-us 80000; /* 复位释放后等待稳定80ms */个人习惯把这两个时间都写得稍微充裕一点尤其是reset-deassert-us不要只给几毫秒。如果复位后立刻去读PHY寄存器很容易读到0xffff也就是mdio总线上根本没有设备响应。这个问题我遇到过好几次都是因为复位释放时间太短PHY内部还没准备好。还有一点如果系统里PHY的复位脚和别的外设共用了或者电源时序上有问题PHY可能每次上电状态都不一样。这种硬件层面的问题软件很难绕过去建议调试时先把复位脚独立出来。2.4 那些容易被忽略的设备树属性除了上面几个大项还有几个属性往往被忽略但实际调试时很有用max-speed限制PHY的最大协商速率比如不想让它协商成千兆可以写max-speed 100;。调试链路质量时可以临时加上。ethernet-phy-ieee802.3-c22表示这个PHY支持Clause 22的MDIO访问方式。现在绝大多数PHY都是c22但也有c45的写清楚有助于内核选择正确的访问协议。compatible可以指定具体的PHY ID比如ethernet-phy-id4f51.e11a。这个ID是PHY芯片内部寄存器里的厂商ID和设备ID内核会用它来匹配对应的驱动。如果你不确定ID可以在内核启动后通过mdio工具读取寄存器2和3来计算。另外RK平台的GMAC还有一个特别的地方assigned-clocks和assigned-clock-parents决定了GMAC的时钟来源。如果时钟配错即使PHY工作正常MAC侧也可能因为时钟频率不对而完全不通。这部分在Rockchip的TRM里有详细说明移植时一定要对着原理图确认。3. 内核驱动移植与配置3.1 内核里到底是谁在管PHY拿到一个新的PHY首先要搞清楚Linux网络驱动框架里各层的职责MAC驱动负责收发FIFO、描述符管理、中断处理。在RK平台上就是stmmac/dwmac-rk驱动它只认识phy-handle指向的PHY设备。PHY驱动负责PHY芯片的初始化、协商、寄存器配置。内核的drivers/net/phy/目录下存放着各种PHY驱动motrcomm_phy.c就是裕太微的驱动。PHY核心框架PHYLIB负责MDIO总线管理、PHY设备的枚举、状态机的调度。平时我们说的“移植PHY驱动”实际上大多数情况根本不用自己写驱动只要确保PHY ID能被内核正确识别能匹配到对应的驱动文件就行。YT8531/YT8521的驱动在较新的内核里都有所以任务就简化成了“把内核配置打开把设备树写对”。3.2 menuconfig必须开哪些项这里以Linux 6.1为例执行make menuconfig后需要确认以下几个选项Device Drivers --- Network device support --- PHY Device support and infrastructure --- * Motorcomm PHYs具体路径是CONFIG_MOTORCOMM_PHYy。同时要确认MDIO总线支持也开着一般跟着CONFIG_PHYLIB一起开启。还有个小技巧调试阶段建议把PHY驱动相关的debug打开。方法有两种一种是在内核启动参数里加dyndbgfile drivers/net/phy/motrcomm_phy.c p另一种是直接在驱动文件里改phydev_dbg的打印级别。打开后可以看到PHY的状态切换、协商结果等关键信息比拿示波器量波形快多了。3.3 驱动probe流程观察系统启动后如果一切正常dmesg里应该能看到类似下面的打印mdio_bus 0.1: reset GPIO, active low mdio_bus 0.1: eth0: PHY ID 4f51e11a at 0, driver Motorcomm YT8531 Gigabit Ethernet这说明MDIO总线已经扫到了地址0的PHY并且匹配到了对应的驱动。如果驱动没有匹配你可能会看到Generic PHY或者根本没有相关打印。这时候要回去查设备树里的compatible、PHY ID是否和实际芯片匹配。有一个坑值得专门提醒有些内核版本的motrcomm_phy驱动对YT8531的ID识别是0x4f51e11a但如果你恰好用了带-i后缀的型号或者版本升级了固件ID可能会有变化。遇到识别不了的情况先从寄存器里把实际的ID读出来再决定是改内核驱动还是改设备树。4. 实操过程与核心环节实现4.1 拿到新板子第一步不是改代码很多朋友拿到板子第一件事就是开干改设备树、编内核、烧录折腾一圈发现还是不通。我的建议是先最小化验证硬件。具体做法是接上串口进到uboot或者一个能跑的最简系统比如initramfs先用mdio工具直接读PHY寄存器# 假设mdio总线编号是0可以这样列出总线上的设备 ls /sys/bus/mdio_bus/devices/ # 如果能找到0.0这个设备手动读取PHY ID寄存器 # reg 2 PHY ID high, reg 3 PHY ID low mdio read 0.0 2 mdio read 0.0 3如果读出来的值不是0x4f51和0xe11a而是0xffff那说明MDIO通信有问题可能是PHY地址不对、复位没释放、MDIO上拉电阻没焊接、或者参考时钟没起来。这一步千万不能省它能帮你把问题快速划分到“硬件没通”还是“软件配置不对”。4.2 设备树修改与编译流程设备树改动看起来简单但反复编译烧录很耗时间所以我在修改前会把所有要确认的信息列出来PHY的MDIO地址问硬件或者看原理图strap电阻PHY工作在哪个接口模式RGMII还是SGMII时钟方向input/output也就是谁给谁供时钟复位脚用的是哪个GPIO有效电平是高还是低信息确认完再动手改dts。编译设备树的方式根据平台不同略有差异RK平台一般是用make dtbs或者直接编完整镜像。编译完先反编译一下dtb确认自己写的属性确实编译进去了dtc -I dtb -O dts -o test.dts test.dtb grep -n phy-mode\|ethernet-phy test.dts这一步能避免因为cache或者编译脚本问题导致“我改了但实际没生效”的尴尬。4.3 系统启动后的网络调试命令系统进入Linux后按下面的顺序做基础验证# 1. 查看mdio总线上是否有PHY ls /sys/bus/mdio_bus/devices/ # 2. 查看网络接口状态 ifconfig -a # 3. 拉起网口查看协商结果 ifconfig eth0 up ethtool eth0如果ethtool eth0能看到Speed: 1000Mb/s、Duplex: Full说明物理层已经通了。接下来再用ping测一下实际数据传输能通就说明RGMII/SGMII的时序也没大问题。有些情况下ethtool显示的协商结果不对比如板子明明支持千兆但只协商到百兆。这可能是因为PHY的strap引脚把千兆功能禁用了或者网线/连接器质量不好。这时候先用短网线直连测试排除物理链路因素再说。4.4 SGMII接口的PHY配置差异再来看YT8521走SGMII的情况。SGMII和RGMII不一样它天然有更好的时钟容错能力因为数据和时钟是串行差分传输的所以不太需要像RGMII那样纠结delay。设备树里只需要把phy-mode写成sgmiigmac0 { status okay; phy-mode sgmii; phy-handle phy_yt8521; mdio { compatible snps,dwmac-mdio; #address-cells 1; #size-cells 0; phy_yt8521: ethernet-phy3 { reg 3; reset-gpios gpio3 RK_PB3 GPIO_ACTIVE_LOW; reset-assert-us 20000; reset-deassert-us 80000; }; }; };不过SGMII模式有一个容易忽略的问题MAC侧的SGMII控制器可能会自动协商到一种“SGMII with in-band signaling”的模式PHY芯片如果不支持或者配置不一致就会导致协商失败。YT8521一般没问题但如果你用的是其他厂商的SGMII PHY要留意这一点。实际测试中SGMII链路起来后的表现比RGMII稳定很多ping的延时也更好看。但代价是PCB Layout更复杂差分走线要求更高。5. 常见问题与排查技巧实录5.1 问题速查表下面这个表格是我这次调试过程中最常遇到的几类问题整理成速查形式方便大家对照排查现象可能原因排查方向MDIO扫描不到PHY读寄存器全是0xffffPHY地址不对、复位没释放、MDIO上拉缺失核对strap引脚、检查复位时序、量MDIO波形PHY被识别成Generic PHY内核驱动没有匹配到具体PHY ID更新内核/驱动或检查PHY ID寄存器实际值link up但ping不通RGMII延时配置不一致先用rgmii-id再调整MAC侧tuning寄存器只能协商到百兆上不了千兆千兆能力被strap禁用、网线质量差检查PHY strap配置、换线/换对端设备测试eth0 up后马上downMAC时钟配置错误、PHY供电不稳检查assigned-clocks、量PHY各路电源纹波数据通但吞吐量很低FIFO配置不对、队列中断没配好检查MAC的DMA和中断配置5.2 经典坑一link up但ping不通这是RGMII模式下的经典问题。物理链路协商成功MAC也正确识别了PHY但就是收不到也不发不出数据。我这次就踩了这个坑。因为最初设备树里写的是phy-mode rgmii并且MAC侧的GTXCLK延时寄存器没有做任何配置。理论上这个模式要求PCB走线满足延时要求但我们板子的Layout并没有完全按RGMII的规范来所以数据采样老是差那么一点。解决办法很简单把设备树改成phy-mode rgmii-id让PHY内部自己完成延时补偿。改完之后数据通路立刻恢复正常。不过这里要特别提醒rgmii-id要求PHY驱动支持这个特性。YT8531的驱动是支持的但如果是更老的PHY芯片或者内核驱动版本太旧可能内部没有做延时配置结果rgmii-id写上去也没用。所以在确认PHY驱动能力之前先查一下驱动的源码里对RGMII_ID的处理逻辑。有一些内核版本里stmmac框架会通过phy_interface_mode_is_rgmii()来判断然后把接口模式传给PHY驱动PHY驱动再调用phy_write往指定的寄存器写延时值。如果驱动里没有这段逻辑就需要自己在初始化函数里补。5.3 经典坑二MDIO第一次访问失败复位之后才通另外一个让人抓狂的问题是系统冷启动后PHY偶尔能扫到偶尔扫不到。扫不到的时候读寄存器全是0xffff但只要按一下板子上的复位键PHY再重启一次就正常了。这个问题的根源基本都指向复位时序和上电时序。我用示波器抓过复位脚和PHY供电电压的波形发现Reset拉低释放时PHY的主电源已经稳定了但给PHY提供参考时钟的晶振/振荡器输出还没有完全稳定。PHY在时钟不稳的情况下被复位释放内部初始化就没成功表现出来就是MDIO无响应。设备树里把reset-deassert-us从20ms改到80ms后这个问题就消失了。虽然20ms在手册上看是够的但实际电路里晶振起振时间往往会长一些所以留足余量很有必要。另外有些平台的GPIO驱动在系统启动早期还没准备好导致复位脚在时序上不受控。可以在uboot阶段先做一个GPIO拉低确保PHY在上电后一直处于复位状态直到Linux内核里驱动真正接管复位脚。5.4 排查PHY问题的独家技巧除了上面的套路再分享几个排查网络不通问题时的实用技巧技巧一用ethtool读寄存器。ethtool -d eth0能直接读出PHY内部的寄存器值不需要额外工具。我经常用它来看协商状态寄存器reg 1、PHY ID寄存器reg 2/3、以及一些驱动自定义的寄存器。对照芯片手册就能判断PHY当前的状态。技巧二临时把速率固定到百兆。如果千兆模式下各种诡异问题先试试固定百兆ethtool -s eth0 speed 100 duplex full ip link set eth0 up如果百兆正常但千兆不正常多半是RGMII时序在高速下出了问题或者PCB Layout质量不够。这样可以快速定位问题范围。技巧三抓包配合中断计数。内核里可以通过cat /proc/interrupts看网卡中断是否在增加。如果TX中断在涨但RX中断没反应说明发送方向没问题但接收方向堵了。再用tcpdump -i eth0抓数据包如果能看到对端发来的包但发不出去问题大概率在MAC发送路径。技巧四不要迷信网线。很多“link up但业务不通”的问题最后发现是对端的交换机端口配置了VLAN、或者网线只有百兆的线序。先用一台PC直连板子对ping排除网络环境干扰。5.5 YT8531特有寄存器调试经验YT8531有一个比较有用的特性就是它有一些厂商私有的扩展寄存器可以用来调整RGMII的驱动强度、眼图参数等。在PCB Layout不太理想或者传输距离较长时适当调整这些寄存器可以改善信号质量。设备树里可以通过motorcomm,clk-out-frequency、motorcomm,rx-clk-driver-strength这类厂商自定义属性来配置也可以直接在驱动初始化函数里增加phy_write操作。不过这些寄存器地址和功能在公开的内核驱动里不一定全部实现需要结合芯片手册做二次开发。我的经验是除非信号质量实测有问题否则不建议动这些参数。默认值在绝大多数情况下是能工作的乱改反而容易引入新问题。如果真要调整尽量在实验室用示波器配合实测眼图再定参数不要靠猜。5.6 关于驱动移植的进一步建议如果你用的内核版本比较老内核里连motrcomm_phy.c都没有那怎么办我的建议顺序是先去PHY厂商官网找最新驱动源码或者找代理商要SDK里的PHY驱动补丁。把厂商的motrcomm_phy.c放到drivers/net/phy/目录下同时在Makefile和Kconfig里加上对应的编译项。仔细看驱动里定义的PHY ID确认和设备实际一致。如果ID不一致优先改驱动里的ID匹配列表。编译、测试重点观察启动日志中PHY ID那一行的打印。这种自带的驱动通常会有很多调试开关和平台适配代码比如对RK、NXP等平台的特殊处理移植时不要一股脑全删掉建议先完整编译通过再逐步裁剪。结尾这次把YT8531和YT8521接入RK3568平台前后折腾了差不多一周。回头看真正花时间最多的反而不是代码本身而是各种隐蔽的配置细节。尤其是RGMII的延时配置、PHY地址、复位时序这三个东西只要有一个不对网络就是不通而且现象五花八门很容易把人带偏。我个人最大的体会是调试这类问题一定要先把硬件底子摸清楚再谈软件。哪个引脚做strap、哪个GPIO控复位、时钟从哪边来这些问题最好在画板阶段就跟硬件工程师确认好而不是等板子回来再对着原理图一点点排查。软件上则要善用mdio工具和ethtool它们能帮你把问题范围从“整个网络通路”一步步缩小到寄存器级别。最后再分享一个小技巧如果你手头有多个YT8531/YT8521的板子建议在设备树里把PHY节点的PHY ID注释得详细一点方便后续维护时一眼看出用的是哪个版本。再就是养成每次改完设备树先反编译确认的习惯别让“改了没生效”这种事浪费一整天。希望这篇避坑指南能帮你少走些弯路把更多时间花在真正有挑战的事情上。
返回列表