MDIO协议标准:IEEE 802.3 Clause 22 vs Clause 45

如果你做过以太网PHY调试,肯定绕不开MDIO。但你可能遇到过这种情况:按照Clause 22的时序去读一个10G PHY的寄存器,结果读回来的数据全是0xFF。我刚开始也犯过这个错——直到我仔细翻了芯片手册,才发现那家伙用的是Clause 45。

这两个版本的MDIO,说白了就是一个旧协议、一个新协议。Clause 22是1998年的老标准,只支持32个PHY,每个PHY有32个16位寄存器。而Clause 45是2002年推出的,专为10G/40G/100G这类复杂器件设计,地址空间大了很多。我们做调试,首先得搞清楚手上用的是哪个版本,不然连读写都做不对。

1. 为什么会有两个版本?

早期的以太网PHY功能简单,IEEE 802.3 Clause 22定义的MDIO接口足够用。后来随着10GBASE-T、光模块、背板以太网的出现,器件内部需要管理的寄存器越来越多,Clause 22的32个寄存器地址显然不够用。

于是IEEE推出了Clause 45,引入了“设备地址(DEVAD)”和“端口地址(PORTAD)”两级寻址,理论上能支持32个端口,每个端口最多32个设备,每个设备又有65536个16位寄存器。这下地址空间几乎无限了。不过要注意,Clause 45的时序和帧格式跟Clause 22完全不同,不能混用。

2. 核心差异速览表

先把最关键的几个区别列出来,后面再一个个细讲。这张表我建议你打印出来贴在工作台上,调试时一眼就能对照。

对比项 Clause 22 Clause 45
帧开始码(ST) 01 (2-bit) 00 (2-bit)
操作码(OP) 读:10, 写:01 地址:00, 读:11, 写:01, 读后增地址:10
目标地址字段 PHY地址(5bit) + 寄存器地址(5bit) 端口地址(5bit) + 设备地址(5bit)
数据字段 16位数据 16位数据,但地址写入/读取时数据含义不同
最大PHY/器件数 最多32个PHY 32端口 × 32设备(共1024个目标)
寄存器地址空间 每个PHY 32个寄存器(0~31) 每个设备 65536个寄存器(0~65535)
MDC时钟频率 通常2.5MHz,最快可达25MHz 同样,取决于器件规格
帧间距(Inter-Frame Gap) 2个MDC周期(空闲) 2个MDC周期(要求更严格)
预充电(Idle/Preamble) 32个MDC周期的1 32个MDC周期的1(有时可省略)

3. 帧格式:最直观的区别

Clause 22的帧格式很传统:先发32个1做预充电,然后2位ST码(01),2位OP码,5位PHY地址,5位寄存器地址,2位转向(TA),16位数据。总共64个MDC周期(不含预充电)。

Clause 45的帧格式分两种:

  • 地址帧(Address Frame):OP码=00,后面跟端口地址、设备地址,再跟16位寄存器地址。用于告诉器件接下来要读或者写哪个寄存器。
  • 数据帧(Data Frame):OP码=11(读)、01(写)、10(读后增地址),后面跟同样的端口/设备地址,然后TA,再跟16位数据。

我个人习惯先看ST码。如果抓到的ST是01,妥妥的Clause 22;如果是00,就是Clause 45。这个判断最快,不用管后面的OP码。

提示:有些PHY芯片同时支持两种模式(如通过strap pin或寄存器切换)。我用过一个10G PHY,上电时默认Clause 45,但可以用一个特定寄存器切回Clause 22兼容模式。一定要确认当前工作在哪个模式,否则通信对不上。

4. 关键细节:地址 vs 数据分离

Clause 45最核心的改变是地址和数据分离。Clause 22是一次性把PHY地址和寄存器地址都放进帧里,然后直接读写数据。Clause 45需要先发一个地址帧告诉器件“我要操作哪个寄存器”,然后再发数据帧读写实际数据。

为什么会这样设计?因为Clause 45的器件内部寄存器太多,用5位根本不够。通过地址帧可以指定16位的寄存器地址,这样就能寻址65536个寄存器。我当时调试一个40G背板PHY,里面光控制PCS的寄存器就有两百多个,用Clause 22根本没法搞。

注意:Clause 45的地址帧写完寄存器地址后,数据帧的端口地址和设备地址必须与地址帧一致。我曾经在代码里把端口地址搞反了,结果读出来的一直是0x0000,排查了半天才发现地址帧和后续数据帧的DEVAD不一致。

5. 操作码的含义变化

Clause 22只有两种操作:读(10)和写(01)。Clause 45增加了“地址帧(00)”和“读后增地址(10)”。这个“读后增地址”非常有用,特别是在连续读取队列或统计寄存器时。

我用过一次,读一个10G PHY的误码计数寄存器,需要连续读32个地址。每次读完后地址自动加1,省掉中间发地址帧的时间,速度能快好几倍。不过要注意,不是所有Clause 45器件都支持读后增地址,调试前先查手册确认。

6. 转向时间(TA)的差异

两个版本都有2位转向时间(Turn Around),但Clause 22要求写操作时主机在第1个TA位输出Z(高阻),第2个TA位输出0;读操作时主机在第1个TA位输出Z,然后器件在第2个TA位输出0。Clause 45的TA时序类似,但多了地址帧场景——地址帧里没有TA位,而是紧跟着16位寄存器地址。

嗯,这里要注意:用逻辑分析仪抓波形时,看到TA位是“ZZ”说明是读操作,主机在等器件应答;看到“Z0”是写操作。如果波形里根本没有TA位,那基本就是Clause 45的地址帧了。

7. 预充电和帧间距

两版都要求空闲时MDIO保持高阻抗(通过上拉电阻拉到高),并且每个帧前有32个MDC周期的预充电(全部为1)。但Clause 45的某些器件允许省略这32个1,只要满足片选确认条件就行。我个人建议不要省,兼容性最好。

帧间距方面,Clause 22要求至少2个MDC周期的空闲(MDIO高阻),Clause 45要求一样。但我遇到过一个Marvell的PHY,Clause 45模式下要求至少4个周期的间隔,否则会丢帧。所以实际调试时,我习惯用8个周期的间距,安全第一。

实战经验:我调试过一款100G QSFP28光模块,内部是Clause 45 MDIO。第一次读取模块温度时,一直读到0xFFFF。用示波器一抓,发现地址帧的DEVAD写对了,但PORTAD写成了0(默认端口),而模块实际挂在端口1上。改过来后一切正常。所以调试Clause 45时,先确认端口地址和设备地址,别急着怀疑时序。

8. 用一张图看清区别

下面这张SVG对比了Clause 22和Clause 45的完整帧结构。注意看ST码的颜色、地址字段的拆分方式,以及Clause 45如何用地址帧+数据帧分两步完成一次寄存器操作。

Clause 22 vs Clause 45 帧结构对比 Clause 22 帧(读写共用格式) PRE ST:01 OP PHYAD REGAD TA DATA 32b (1) 2b 5b 5b 2b 16b Clause 45 地址帧(先写寄存器地址) PRE ST:00 OP:00 PORTAD DEVAD REG_ADDR (16b) 32b 2b 2b 5b 5b + 16b Clause 45 数据帧(读取/写入实际数据) PRE ST:00 OP:11/01/10 PORTAD DEVAD TA DATA 32b 2b 2b 5b 5b 2b + 16b 关键区别:Clause 22 将PHY地址+寄存器地址放在同一帧;Clause 45 将端口地址+设备地址放在帧头, 通过单独的地址帧写入16位寄存器地址,再通过数据帧读写数据(OP码区分读写类型)。

9. 调试中的避坑指南

  • ST码读错:有些逻辑分析仪默认把ST码显示为“01”,但实际上是Clause 45的“00”。我遇到过这种情况,必须看二进制原始数据,别相信显示出来的“ST=0x1”这种简写。
  • TA位驱动冲突:Clause 45读操作时,主机在TA的第1位必须释放MDIO,让器件在第2位拉低。如果主机没释放,两强驱动会打架,波形中间出现毛刺。我曾经因为这个烧坏过一个PHY的MDIO引脚——还好只是IO损坏,芯片没挂。
  • 帧间距不够:有些SoC的MDIO控制器写死了Clause 22的帧间距(2周期),但Clause 45器件要求更宽松。如果读回的数据错位,试着在代码里插入几个空闲周期。
  • 设备地址混淆:Clause 45中“设备”不是物理PHY,而是PHY内部的逻辑功能块(如PCS、PMA、PMD)。比如一个10G PHY,端口0的设备0可能是铜介质PMA,设备1可能是FEC。读错设备地址,数据自然不对。

好了,Clause 22和Clause 45的核心区别就这些。记住最关键的判断方法:先看ST码,再看帧里有没有地址帧。下次你抓MDIO波形时,应该一眼就能认出用的哪个版本了。