4. PHY寄存器地址映射
PHY芯片的寄存器空间,说白了就是一张地址表。你通过 mdio-tool 写入地址,然后读出或写入数据。这个地址怎么映射?里面有什么坑?我来聊聊我的经验。
我们知道,PHY寄存器地址通常分为三类:
- 基本寄存器(MII寄存器,地址0~31)
- 扩展寄存器(如Clause 45的MMD空间,地址可到更大范围)
- 厂商特定寄存器(各个芯片厂自己定义的)
这三类在调试时都很常见,但用法和技巧完全不同。
4.1 基本寄存器:MII寄存器0~31
最早的标准是IEEE 802.3定义的MII管理接口。每个PHY有32个16位寄存器,地址0到31。我用 mdio-tool 直接访问,比如 mdio-tool -p eth0 read 0x01 0x00 可以读出PHY ID。
常用寄存器地址和功能,我整理了一张表,方便你对照:
| 地址 | 名称 | 读/写 | 说明 |
|---|---|---|---|
| 0x00 | BMCR | R/W | 基本控制寄存器(复位、速度、双工、自协商等) |
| 0x01 | BMSR | R | 基本状态寄存器(链接状态、能力等) |
| 0x02 | PHYIDR1 | R | PHY标识符高16位 |
| 0x03 | PHYIDR2 | R | PHY标识符低16位 |
| 0x04 | ANAR | R/W | 自协商通告寄存器 |
| 0x05 | ANLPAR | R | 自协商链路伙伴能力寄存器 |
| 0x06 | ANER | R | 自协商扩展状态寄存器 |
| 0x10~0x1F | 厂家专用 | R/W | 部分标准预留,实际多被厂商扩展使用 |
0x02 和 0x03 确认PHY型号。如果读出全是0或0xFFFF,那大概率通信有问题。
注意,如果你用的PHY只支持Clause 22(MII管理),那地址空间就只有这32个。但很多新PHY已经支持Clause 45了,地址空间就大了好几倍。
4.2 扩展寄存器:Clause 45 与 MMD
Clause 45引入了MMD(Management Data Model)概念。每个PHY可以有多达32个MMD(地址0~31),每个MMD内部又有64K个16位寄存器。总空间接近2M位,当然实际芯片不会全用。
对于Clause 45访问,mdio-tool 需要指定端口、设备地址、MMD地址和寄存器地址。比如:
# 读MMD 7(AN状态机)的寄存器0x0001
mdio-tool -p eth0 -v45 read 0x00 0x07 0x0001
这时你写错了地址,读回来可能就是零或者乱码。我曾经在调试Marvell PHY时,把MMD和寄存器地址搞反了,折腾了半小时才发现……后面记住了:mdio-tool -v45 的第一个地址是PHY设备地址,第二个是MMD,最后是寄存器偏移。
常见MMD编号和用途:
- MMD 0: 保留
- MMD 1: PMA/PMD(物理介质连接层)
- MMD 2: WIS(广域接口子层)
- MMD 3: PCS(物理编码子层)
- MMD 7: 自协商状态机
- MMD 31: 厂商特定
为什么要分这么多MMD?说白了就是为了支持更复杂的高速以太网标准(10GBASE-T、25GBASE-T等)。每个子层都独立管理自己的寄存器。
4.3 厂商特定寄存器
基本寄存器和扩展寄存器都是标准定义的,但每家PHY厂商都会把自己的扩展功能塞进“厂商特定寄存器”。这些地址一般位于MMD的特定范围(比如MMD 31),或者Clause 22的0x10~0x1F,或者Clause 45的MMD 3中自己定义的偏移。
调试这些寄存器,你首先得去翻PHY的datasheet或者寄存器手册。比如Marvell 88E1510的“LED控制寄存器”就在地址0x10(MMD 0下)。
另外,有些厂商会采用“页切换”机制:在同一地址写不同的“页号”来访问不同的寄存器组。比如RTL8211系列的“扩展寄存器”就需要先写页寄存器(0x1F),再写目标地址。这个技巧如果不看手册,光靠猜会抓狂。
我画了一张图,把三类寄存器地址映射的关系展示出来。你可以看出基本寄存器在Clause 22的0~31,Clause 45的MMD把空间延展了,而厂商特定寄存器则像“彩蛋”一样散落在各处。
4.4 什么时候用哪种映射?
你可能会问:我怎么知道这个PHY支不支持Clause 45?最简单的方法是读基本寄存器0x02和0x03,如果读到的是标准厂商ID(比如0x0141对应Marvell),然后尝试用Clause 45方式读MMD 0的寄存器0x0000,如果返回非0值,那就是支持的。
我个人的习惯是:
- 老PHY(百兆/千兆基础型): 只用Clause 22基本寄存器调试就够了。
- 新PHY(2.5G/5G/10G): 必须用Clause 45,甚至厂商特定页切换。
4.5 避坑:地址冲突与调试陷阱
调试时,我遇到过几个典型问题,分享给你。
- 读回全0或0xFFFF: 一般是地址写错了,或者PHY没有响应。检查PLL(电源)和复位引脚。
- 写0x10寄存器没反应: 可能这个寄存器属于MMD 3下的子空间,需要在写之前先设置MMD地址。有些PHY要求先写MMD地址到特定寄存器(如0x1D/0x1E),再通过标准地址读写。
- 寄存器值不变: 可能该位是只读的,或者需要先解除锁定。我曾经被一个“影子寄存器”坑过——写入后需要再读一次才会生效。
核心经验: 调试任何PHY寄存器前,先花10分钟读datasheet的“Register Map”章节。哪怕只看一下地址范围,也能省去至少30分钟的猜测试错时间。我自己的笔记本里,专门为常用PHY(88E1510、RTL8211、BCM5461)画了简易地址简表。调试时直接对照,效率翻倍。