MDIO协议概述
做嵌入式网络设备调试,绕不开PHY芯片。PHY芯片就像网卡的“物理层翻译官”,而MDIO总线,就是我们和这位翻译官对话的唯一通道。很多人一上来就拿着mdio-tool瞎写寄存器,结果PHY没反应,板子还掉线。其实你只要搞懂MDIO协议的本质,调试就变得有章可循了。
1.1 MDIO总线标准
MDIO是Management Data Input/Output的缩写,IEEE 802.3标准里定义得很清楚。简单说,它是一根双向数据线(MDIO)加一根时钟线(MDC),专门用来读写PHY芯片内部的寄存器。嗯,这有点像I2C,但比I2C简单——只有两线,没有设备地址仲裁,读写原子性全靠帧格式保证。
标准分两种:
- Clause 22:最早期版本,支持最多32个PHY(5位PHY地址),每个PHY有32个寄存器(5位寄存器地址)。大部分10/100/1000M PHY还在用这套。
- Clause 45:后来为了10G/40G等高速PHY扩展的,支持4位设备类型(Type)和5位端口地址,寄存器空间大幅扩大到2^16。不过现在大多数消费级PHY还是走Clause 22。
我记得2018年做一个交换机项目,用的Marvell 88E1510,默认是Clause 22。我直接用mdio-tool -v -a 0x10读寄存器,结果怎么都读不到。后来查手册才发现这颗PHY支持两种模式,上电默认走Clause 45。这个坑我踩过一次,希望大家记住:读任何PHY之前,先确认它工作在哪个Clause。
💡 如何快速判断PHY的Clause?读寄存器0(Control Register)的第15位。Clause 22的bit15是复位位,Clause 45的bit15是协议类型选择位。两边读出来行为不一样。
1.2 SMI接口时序
MDIO的物理层叫SMI(Serial Management Interface),由两根线组成:
- MDC:时钟,由MAC/控制器提供,最高频率通常8.33MHz(有些控制器能跑到25MHz,但不推荐)。
- MDIO:双向数据线,必须接上拉电阻(4.7kΩ典型)。
MDIO的读写帧格式一致:先发32个1作为同步前导码,然后是起始码、操作码、PHY地址、寄存器地址、转向位,最后数据。写操作时数据由控制器驱动,读操作时数据由PHY在最后一个时钟沿之后驱动。
很多人以为时序是控制器自动搞定的,自己只需要放心读写就好。其实不然——某些FPGA实现或者自定义MDC生成逻辑,MDC频率太高或占空比不对,PHY直接不理你。
⚠️ 我曾经在一个国产PHY上遇到MDC频率精度问题:控制器跑25MHz,PHY手册写最大8.33MHz,结果PHY间歇性读取错误。把MDC降频到12.5MHz后一切正常。所以,MDC频率宁低勿高。
下面这张图是我项目中常用的MDIO总线连接结构,三个PHY共享MDC和MDIO,通过PHY地址区分:
说回时序细节。一次完整的MDIO读写,控制器要拉高MDC超过1.3μs保持空闲状态,然后发32个1。我习惯用逻辑分析仪抓MDIO波形,如果看到开头没有连续的32个高电平,基本能断定是前导码阶段出问题了。有些控制器可以关闭前导码(通过配置寄存器),但PHY那边也必须是同一模式,否则通讯失败。
1.3 PHY寄存器基本结构
Clause 22标准里,每个PHY有32个寄存器(0x00 ~ 0x1F),每个寄存器16位。IEEE强行规定了前几个寄存器的含义,后面的留给厂商自由发挥。
下面这张表是我每次调试都会先看的“基本功”寄存器:
| 寄存器地址 | 名称 | 关键位 | 我的习惯 |
|---|---|---|---|
| 0x00 | BMCR (Basic Mode Control Register) | Bit15: 软件复位 Bit13: 速度选择 Bit12: 自动协商使能 |
读之前先写0x8000复位一下,避免历史状态干扰 |
| 0x01 | BMSR (Basic Mode Status Register) | Bit5: 自动协商完成 Bit2: 链接状态 |
读完后一定读两次——有些PHY在链接刚变时只会更新一次状态 |
| 0x02 | PHY ID High | OUI高16位 | 用来确认PHY型号,省得查手册 |
| 0x03 | PHY ID Low | OUI低8位 + 型号 + 版本 | 建议跟手册配对,我见过贴错标签的PHY |
| 0x04 | ANAR (Auto-Negotiation Advertiser) | 速度/双工宣告 | 检查两端宣告能力是否匹配 |
你可能注意到了,BMCR的Bit15是复位位。有一次我在调试一个看门狗复位后的PHY,怎么读寄存器都是0xFFFF——那是PHY还在复位过程中,总线还没准备好。后来我在每次读之前等100μs,就稳定了。嗯,这也是个教训。
核心原则:PHY寄存器调试,先读ID(0x02, 0x03)确认设备存在;再读BMSR(0x01)看链接状态;最后才去动BMCR。不要一上来就写自动协商或者强制速度。
至于Clause 45的扩展寄存器,结构更复杂,引入了设备类型(Device Type)和MMD设备地址。很多调试工具(包括mdio-tool)都支持Clause 45,但参数要加 -p 或 --clause45。我个人在用到10G PHY时才会切到Clause 45,普通千兆PHY大部分用Clause 22就够用了。
1.4 为什么说MDIO调试是基本功?
我见过不少同事,遇到网络不通第一反应是换硬件或者飞线改PCB。其实很多时候只是PHY没配置好,或者自动协商失效。用mdio-tool读几个关键寄存器,五分钟就能定位。就比如刚才说的BMSR寄存器,如果Bit2(链接状态)为0,那线缆或者对端肯定有问题;如果为1但自动协商位(Bit5)为0,那就是协商没完成,可以检查MDI/MDIX配置或者对端能力。这些信息,寄存器里写得明明白白。