第一次拿到 YT8521SH 这颗 PHY 的时候,说实话我是有点犯嘀咕的。以太网物理层芯片这块,以前要么用瑞昱、美满这些老牌货,要么就得接受一颗芯片伺候半天。YT8521SH 作为国产方案里出货量很猛的千兆 PHY,看着“好像没啥问题”,真正自己画原理图、调 uboot 的时候才会发现,网上资料大多是拿参考设计一笔带过,最要命的复位时序、LED 行为、电源纹波这些细节,全得自己踩一遍才知道坑在哪。
这篇文章就不绕弯子了,直接从电路设计讲到 uboot 驱动适配,重点把 YT8521SH 的复位、LED、电源三个容易翻车的部分单独拆出来说,最后补上调试实录和故障排查表。做网络产品、路由网关、工控板,或者只是想把手头板子的网口调通的工程师,这篇应该能帮你省下至少一个通宵。
1. 项目整体设计与选型思路
1.1 YT8521SH 是什么,为什么选它
YT8521SH 是裕太微电子推出的一款单端口 10/100/1000M 自适应以太网物理层收发器,接口侧支持 RGMII,也兼容一部分 SoC 的 RMII 模式(具体要看封装和手册里的 strapping 配置)。片上集成了均衡、CDR、自适应均衡这些模拟前端电路,外部除了晶振、变压器、阻容,基本不需要额外器件。
我选它主要出于三点考虑。第一是国产化率要求,很多新项目从立项就有国产器件比例要求,YT8521SH 属于正经量产多年、大批量铺货的型号,不是那种拿 demo 板吹牛的芯片;第二是价格和供货,相比同规格进口 PHY,它的 BOM 成本优势明显,而且渠道比较稳定,不太会出现“有价无市”的情况;第三是功耗和发热控制不错,千兆满速跑起来壳温比较友好,对无风扇设备比较重要。
不过选它也有代价。最直接的代价是软件生态里 hmm……不能直接套用老牌 PHY 的驱动配置,很多寄存器是厂家自定义的。尤其刚上手时,你会发现 uboot 自带的 PHY 驱动列表里未必有这颗芯片,需要自己配 ID、自己补初始化。这是后面要重点讲的。
1.2 整体方案架构:从 MAC 到网口的链路
在讲细节之前,先把整条链路理清楚。一颗以太网 PHY 在系统里所处的位置,可以简化成下面这条通路:
CPU/SoC 的 MAC 控制器(如 RGMII 接口)-> MDIO/MDC 管理接口 -> YT8521SH PHY -> 网口变压器 -> RJ45 座
MAC 负责协议栈、封包解析,PHY 负责把数字信号变成能在网线上传输的模拟差分信号。MAC 和 PHY 之间,除了 RGMII 数据总线,还有一条 MDIO 管理总线,用来读写 PHY 内部寄存器,完成协商、状态查询、速率配置这些操作。
我这次用的平台是一颗带 RGMII 接口的 Cortex-A 系列 SoC,跑 uboot 做引导,Linux 系统后面再起来。硬件上给 YT8521SH 分配了独立的 MDIO 地址,复位引脚接到 SoC 的 GPIO,LED 引脚直接驱动两颗指示灯。
这个架构典型到不能再典型,但恰恰是这种“典型”方案,最容易被忽略的恰恰是细节。你可以把 PHY 想象成一个外设,SoC 通过 MDIO 来控制它,但 PHY 自己也有“脾气”——上电时序错了它不工作,时钟偏了它协商不上,LED 极性反了它给你瞎闪。下面我就按硬件设计到软件适配的顺序,一个一个说。
2. 硬件设计细节:电源、复位、LED 与时钟
2.1 电源设计:别让 PHY 输在纹波上
YT8521SH 的电源设计不算复杂,但绝不能图省事直接一坨 3.3V 糊上去。它内部同时有数字逻辑和模拟前端(SerDes、ADC、PLL),这两部分对电源噪声的敏感度完全不一样。常规做法是分成模拟电源和数字电源,或者至少用磁珠/π型滤波把模拟区域单独隔离出来。
具体到我这块板子,用的是单 3.3V 供电方案,核心电压由芯片内部 LDO 产生。原理图部分我给每个电源引脚都加了“一大一小”去耦电容,也就是 1uF 陶瓷电容并联 0.1uF 高频电容,位置尽量靠近 IC 引脚。模拟电源 AVDD 这边,额外串联了一颗磁珠,再加大容值钽电容做低频滤波。硬件调试时我拿示波器看过,不接磁珠时 AVDD 上的噪声峰峰值在 50mV 左右,接了磁珠能压到 20mV 以内,这个对千兆链路的稳定性确实有影响,尤其长时间高负载传输时,电源噪声大的板子更容易出现 CRC 错误。
很多工程师容易忽略 VDDIO 这一路。YT8521SH 的 VDDIO 决定了 IO 口电平,如果 SoC 侧 RGMII 是 1.8V,而 PHY 的 VDDIO 给了 3.3V,那轻则信号采不到,重则烧引脚。我的板子 SoC 和 PHY 都在 3.3V 域,所以 VDDIO 直接接 3.3V,这个没那么纠结。但如果你用的是支持 1.8V RGMII 的高性能 SoC,一定要先确认两端电平匹配,别指望电平转换电路能救回来。
电源这部分最后提一句“复位电流”这个概念。有些工程师在设计复位电路时只关注电压时序,忽视了复位引脚的驱动能力。YT8521SH 的 RESET_N 是内部上拉的,外部如果只接 RC 复位,电容充电瞬间会产生很大的灌电流,复位芯片或者 GPIO 必须能承受这个瞬态电流,否则复位信号会被拉斜,导致芯片复位的阈值点不稳定。
2.2 复位电路:最容易被“差不多”毁掉的时序
复位这一节我单独拉出来讲,是因为它踩过的坑最多。YT8521SH 的 RESET_N 引脚是低电平有效,内部有上拉,硬件上你需要保证三点:上电后复位信号维持低电平的时间足够长;复位释放时电源电压已经稳定;复位释放后,时钟信号已经稳定。
先说 RC 复位。很多参考设计里直接画一个 10k 电阻加 0.1uF 电容,看起来“能复位”,实际上在温度变化、电源爬坡斜率不同时,RC 延时的重复性很差。你用示波器能测到它确实复位了,但量产 100 块板子可能有 5 块就是起不来,查了半天发现是复位释放时电源纹波还在抖。工业级产品不建议用纯 RC,至少也要加一个带滞回的比较器或者专用的复位芯片。
如果实在要用 RC,时间常数要按最坏情况算。假设复位阈值是 0.7×VDD,上电复位低电平时间至少需要 10ms(具体查手册),那么 RC 的放电时间必须覆盖这段。我见过有人用 10k+0.1uF,计算时间是 1ms,很明显不够。建议直接用复位芯片,比如常见的 MAX809 或者国产的 SGM809,输出低电平复位,精度和可靠性都会好很多。
这里还得提一下“异步复位同步释放”,这个词常出现在 FPGA 设计里,但放到 PHY 复位上也是同一个道理。如果你用 SoC 的 GPIO 控制 RESET_N,GPIO 是异步信号,当 SoC 内部时钟还没稳定的时候,GPIO 输出的复位时序可能是乱的。稳妥的做法是:SoC 的 GPIO 在初始化阶段先保持复位有效,等系统时钟稳定、电源稳定之后再释放复位,释放之后不要立刻去读 PHY 寄存器,等至少几十毫秒再操作。换句话说,复位的“释放”动作要由软件来同步,而不是纯靠硬件自生自灭。
我在 uboot 里的处理方式是:板级初始化时把复位 GPIO 拉低,延时 50ms,再拉高,再延时 100ms,之后才允许 MDIO 总线访问 PHY。这套时序我实测下来非常稳,基本没有出现“MDIO 超时”或者“PHY ID 读不出来”的情况。
2.3 LED 接口电路与配置思路
YT8521SH 的 LED 引脚数量不多,通常就是 LED0 和 LED1(部分封装可能有更多扩展)。硬件上非常简单,每个 LED 引脚串联一个限流电阻到 LED 正极,LED 负极接地。关键在于这个 LED 是“灌电流”还是“推电流”驱动,以及 PHY 引脚默认输出的极性。
我遇到的现象是这样的:按参考设计接好 LED,上电后灯完全不亮。查了手册才发现,这颗 PHY 的 LED 引脚默认极性是高有效还是低有效,取决于芯片的 strapping 引脚和寄存器配置,参考设计里的接法可能是给另一种极性用的。后来我在 uboot 初始化里把 LED 模式寄存器改成了“推电流驱动、低电平点亮”,硬件上 LED 正极接 3.3V、负极经电阻接 LED 引脚,才正常亮起来。
所以画原理图之前,强烈建议先去手册里查到 LED 驱动方式的默认配置,再决定 LED 接线方向。很多国产 PHY 为了兼容多个方案,默认状态不一定是你想要的。软件能改是一回事,但硬件上如果接反了,虽然能用软件补偿,总归多一道风险;最好一开始就按你最终要实现的寄存器配置来设计硬件。
至于 LED 的功能映射,常见需求是两颗灯:一颗绿色常亮表示 Link 千兆,一颗黄色闪烁表示 Activity。但你需要在 PHY 的扩展寄存器里选择 LED 的复用功能,默认可能是一个灯表示速递,另一个表示双工,并不是你想要的 Link/Act。这个不同型号差异很大,我这边整理了一份常用映射思路,后面驱动适配部分会再说。
2.4 时钟设计:25MHz 晶振的微妙之处
YT8521SH 需要一路 25MHz 时钟,常见用法是无源晶振配两个负载电容,也可以直接由 SoC 提供 25MHz 时钟输入。无源晶振方案成本低,但 PCB 布局要求高。晶振离 PHY 的 XI/XO 引脚越近越好,两根走线尽量等长,底下铺地铜,周围不要走高频数字信号。我用四层板,晶振放在 PHY 同一面,第二层完整铺地,这样基本不会因为时钟辐射引发信号完整性问题。
负载电容的取值要匹配晶振本身的 CL 值。我的晶振规格是 CL=20pF,PCB 上两条走线寄生电容大约 3pF 左右,所以每个引脚接 18pF 对地电容,实测频率偏差在 10ppm 以内。如果你用的晶振 CL 不太一样,别照抄这个值,先用频率计测一下,或者直接按晶振手册推荐值起步。
时钟这块有一个很典型的故障:晶振起振了,但是幅度不够。PHY 内部的时钟检测电路有阈值,幅度不够会认为时钟无效,芯片就停在复位状态。排查办法是用示波器测 XI 引脚的波形,正常应该是 1.8V 到 3.3V 满摆幅的正弦或方波;如果只有几百毫伏,大概率是负载电容选大了、驱动不足,或者晶振本身质量问题。
2.5 MDI 差分线对与变压器选型注意
这部分严格说不算 YT8521SH 特有,但既然聊到电路设计,还是得提。PHY 的 MDI 引脚(通常 4 对差分线)需要连接到网络变压器,再接到 RJ45。变压器有两个作用:一是电气隔离,二是共模噪声抑制。
选变压器时注意三点:支持千兆(1GBase-T),搭配的 RJ45 是否集成变压器,以及中心抽头的接法。YT8521SH 的 MDI 中心抽头需要接电源或者对地接电容,具体看手册里的内部结构。我之前图省事直接按某厂参考设计接,结果发现他们用的变压器和我不一样,导致中心抽头悬空,链路协商是正常的,但插上网线后偶尔会断流。后来按手册要求接了电源和退耦电容,问题才消失。
PCB 走线方面,4 对差分线要等长、同层、少打孔,差分阻抗控制在 100Ω 左右。如果板子空间紧张必须换层,一定要加回流地孔。还有网口变压器下方不要铺实铜,挖空隔离能有效减少共模干扰,这对长网线传输尤其重要。
3. uboot 驱动适配与初始化实现
硬件画完、板子打样回来,接下来就是最激动的环节——让 PHY 在 uboot 里被正确识别并完成协商。很多人以为 uboot 里只要把设备树地址写对就完事了,实际上 YT8521SH 需要你手动补不少初始化动作,尤其是 LED 模式、RGMII 延时和软复位这些东西。
3.1 从 uboot 源码到驱动使能
先说一下从哪里拿到带 YT8521SH 驱动的 uboot。不要随便下载一个 uboot 主线包,主线 U-Boot 对国产 PHY 的支持是陆续合入的,如果你的版本比较老,可能压根不认识这颗 PHY。我这边用的方法,是直接看板卡厂商提供的 SDK 里有没有drivers/net/phy/motorcomm.c这个文件。有的话,说明厂商已经做了适配,省事;没有的话,先从网上下一个较新的 uboot 源码,把 motorcomm.c 拷贝过来,并确认 Kconfig 和 Makefile 里打开了CONFIG_PHY_MOTORCOMM。
驱动文件里通常会定义这颗 PHY 的 ID,类似:
#define PHY_ID_YT8521 0x00000133注意不同版本芯片 ID 可能有细微差别。我在调试时遇到过一个问题:读出来的 PHY ID 和驱动里不一致,导致驱动 probe 失败。这种情况要先确认芯片是不是同一个型号、不同批次,然后以实际读出来的 ID 为准,修改宏定义。怎么读 ID?uboot 命令行下就能读,后面调试部分会说。
3.2 设备树配置:复位 GPIO 和 PHY 地址
设备树里要配置 MDIO 总线下的 PHY 节点。以我用的平台为例,设备树片段大致如下:
&mdio0 { status = "okay"; ethernet_phy0: ethernet-phy@1 { reg = <1>; compatible = "ethernet-phy-id0013.3100"; reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; reset-assert-us = <10000>; reset-deassert-us = <50000>; }; };这里reg = <1>就是 PHY 的 MDIO 地址,地址取决于原理图上 PHYAD[0] 引脚的上拉/下拉配置。一般 PHY 默认地址是 0,但如果板子上挂了多个 PHY,就要通过引脚 strap 把地址改掉。这里的 compatible 字符串对应 PHY ID,0013.3100是举例,实际要以你驱动里的宏转换成xxx.xxxx格式来填。
reset-gpios是 uboot 驱动复位 PHY 用的。reset-assert-us表示复位拉低持续时间,reset-deassert-us表示释放后等待时间。这两个时间一定要给够。我这边给的 10ms 和 50ms 是实测比较稳的组合,如果你的 PHY 上电后要更长时间才能准备好,可以继续加大。注意千万不要在系统起来后立刻访问 PHY 寄存器,这是新手最容易踩的坑。
3.3 驱动初始化流程:复位、读 ID、配置 LED
uboot 中 PHY 驱动的 probe 流程通常是:MDIO 总线扫描 -> 读 PHY ID -> 匹配驱动 -> 调用 config_init -> 启动 autoneg。YT8521SH 在 config_init 里需要做的几件事,我按优先级排一下:
第一,确保 PHY 已从复位中恢复。如果设备树里配了 reset-gpios,这一步驱动会帮你做。如果没有配,就必须保证硬件上电时复位已经释放,否则后续 MDIO 读 ID 全是 0xffff。
第二,读 PHY ID 确认访问正常。可以用标准 MII 寄存器 0x02/0x03 读取:
u32 phy_id; phy_id = (mii_read(dev, addr, MII_PHYSID1) << 16) | mii_read(dev, addr, MII_PHYSID2); printf("PHY ID: 0x%08x\n", phy_id);如果读出来不是预期值,先查硬件连接,不要急着改驱动。MDIO 是慢速管理接口,用示波器看 MDC/MDIO 波形是最直接的判断方法。
第三,配置 RGMII 延时。千兆 RGMII 接口对 RX 时钟延时非常敏感,YT8521SH 一般有两种方案:在 SoC 侧打延时,或者在 PHY 内部打延时。到底是哪种,要结合 SoC 的 RGMII 配置。如果两端都没打延时,千兆可能 ping 不通或者协商速率很高但数据全错。我在 uboot 初始化里会显式设置 PHY 的 RX 延时寄存器,确保 MAC 侧不用额外加延时。这个值因平台而异,但大方向是:优先在 PHY 侧配置延时,减少 SoC 侧负担。
第四,配置 LED 模式。这一步直接关系到你板子上的灯能不能按预期亮。YT8521SH 的 LED 行为寄存器在扩展寄存器空间,需要通过 MDIO 读写。配置目标一般是:
- LED0:千兆 Link,常亮
- LED1:数据传输 Activity,闪烁
- 极性设置为低电平点亮
具体寄存器地址我这边就不写了,以手册为准。但调试思路是通用的:先让 PHY 工作在默认点亮模式,确认硬件没问题,再改成你想要的闪烁逻辑。
3.4 autoneg 协商与速率回退
配置完初始化,还要确认协商策略。YT8521SH 支持 10/100/1000M 自适应,默认应该是全部通告。但有些产品为了 EMC 或者功耗考虑,会限制最高速率只协商到 100M。这个可以在 uboot 环境变量或驱动代码里做。
我的做法是在 config_init 之后,调用标准 genphy 的 autoneg 流程,让 PHY 自动协商。注意的是,YT8521SH 在千兆协商时对 Master/Slave 配置比较敏感,如果对端设备强制成 Slave,而这边又强制成 Slave,可能协商不出千兆。遇到这种情况,可以在驱动里把BMCR_ANENABLE和速度位重新写一遍,强制本端为 Master。这是个小众问题,但我确实遇到过,属于大概率“换一台交换机就好,换另一台就千兆起不来”的经典故障。
4. 调试方法与常见问题排查实录
4.1 快速定位 PHY 是否正常工作
拿到一块新板子,如果网口 ping 不通,先别急着怀疑驱动,按下面的顺序排查:
先看硬件。上电后用万用表量 PHY 的电源引脚是否都有电,地是否连好;再示波器看晶振是否有 25MHz 时钟;然后看 RESET_N 引脚波形,确认复位释放后是高电平。
再看 MDIO 是否能正常访问。在 uboot 命令行输入:
mdio read 0 2 mdio read 0 3如果0xffff,说明没读到 PHY 或地址不对。如果读到了 ID,说明 PHY 已经响应。
再看协商状态:
mdio read 0 1这个寄存器是 BMSR,bit5 表示 autoneg complete,如果为 0,说明协商没完成,需要查对端设备、网线、PHY 配置。
最后看 RGMII 数据通路。这个要配合 SoC 侧的网络自环命令,分别从 MAC 侧和 PHY 侧打流,定位是 MAC 问题还是 PHY 问题。PHY 内部一般提供 loopback 模式,uboot 下可以设置 MII BMCR 的 loopback 位,把数据从 PHY 发出去再收回来,测试数字通路是否正常。
4.2 常见故障与对策速查表
我把调试过程中遇到的典型问题整理成一张表,方便对照排查。
| 故障现象 | 可能原因 | 对策 |
|---|---|---|
| MDIO 读 PHY ID 为 0xffff | 复位未释放、MDIO 引脚接错、PHY 地址不对 | 查复位时序和 GPIO,示波器看 MDC 是否有波形 |
| PHY ID 能读到,但协商不上 | 网口变压器中心抽头接错、对端设备问题、RGMII 延时未配置 | 检查变压器接法,换网线,配置 PHY 延时 |
| 协商上千兆,但数据丢包严重 | RGMII RX 延时缺失、电源纹波过大、差分线质量差 | 开 PHY 侧 RX 延时,检查电源滤波,检查差分走线 |
| LED 不亮 | LED 极性配反、驱动电流不足、LED 模式寄存器不对 | 查硬件极性,调整寄存器配置 |
| LED 常亮不闪烁 | 配置成了 Link 指示而非 Activity 指示 | 改 LED 功能映射寄存器 |
| 复位后偶尔起不来 | 复位释放时间不够、复位信号有毛刺 | 用复位芯片或加长软件延时,确保复位干净 |
| 千兆协商偶尔回退百兆 | 对端 Master/Slave 不一致、线缆质量差 | 强制本端为 Master,检查网线 |
这里尤其强调一下“RGMII 延时缺失”这个问题,它非常隐蔽。RGMII 标准里 Data 信号和时钟是同步发送的,接收端要靠延迟来正确采样,如果发送端不带延时,接收端也不带,信号在建立/保持时间边缘采集,就会出现“链路通但数据乱飞”的诡异现象。YT8521SH 手册里会明确告诉你怎么开内部延时,uboot 配置时一定要落实到位。
4.3 一个让我印象深刻的现场问题
最后分享一个实际遇到的疑难杂症。有个项目在低温测试时,网口偶尔会 ping 不通,常温下完全正常。一开始我怀疑是晶振低温起振不良,换了好几个品牌晶振,问题仍在。后来用示波器长时间抓复位引脚,才发现低温下 SoC GPIO 输出高电平的上升沿变慢,复位释放时间被拉长,导致 PHY 部分寄存器复位不完整。解决办法不是在硬件上猛堆电容,而是在 uboot 驱动初始化里,先给 PHY 做一次软复位再读 ID,软复位后增加延时。从那以后,我就养成了习惯:任何 PHY 在 config_init 阶段都先执行一次软复位,再往下走初始化,兼容性会好很多。
5. 经验总结与给后来者的建议
这块内容本来可以到此结束,但我还是想多说几句实操层面的东西。
YT8521SH 这芯片本身并不复杂,它真正考验人的地方在于“默认状态”和“最终需求”之间的差距。硬件上所有 strap 引脚、复位时序、电源去耦,都决定了芯片上电一瞬间处于什么状态;而 uboot 里写的那几行寄存器配置,是在把芯片往你想要的状态上掰。所以设计阶段就要想着软件怎么写,软件调试阶段又要回头检查硬件设计是不是给自己挖了坑。
如果是从零开始做板子,我的建议是:原理图阶段就把 PHY 的电源、时钟、复位、LED、MDI 这几部分单独画一页,标注清楚每个引脚的默认状态和连接去向;PCB 阶段把差分对、晶振去耦、复位信号完整性当成重点评审;软件阶段先不要贪多,先让 uboot 能稳定读到 PHY ID,再逐步加配置。这个顺序看着慢,其实是最快的。
最后再分享一个小技巧:调试 PHY 时,在 uboot 里多封装几个命令,比如一次性 dump 所有寄存器、修改某个寄存器、执行软复位,能让你在调试过程中效率翻倍。我后来把这几个命令做成了板级命令,遇到新板子先跑一遍寄存器 dump,基本 10 分钟内能判断出硬件有没有问题,而不是靠猜。“硬件好调就是一层窗户纸,硬件有问题就是无底洞”这句话,用在 PHY 调试上再合适不过。