1. PHY 寄存器基础:概述、地址空间与 MII 基本寄存器组
各位好,我是老周。做硬件调试这些年,我最怕的就是 PHY 芯片死活不通,抓个 MDIO 波形一看,寄存器读回来的值全是 0xFF 或者 0x0000。说真的,这种问题十有八九是对 PHY 寄存器的基础结构没吃透。今天咱们就把这块骨头啃下来。
1.1 什么是 PHY 寄存器?
说白了,PHY 芯片内部的寄存器就是它的大脑。CPU 或 MAC 通过 MDIO/MDC 接口去读写这些寄存器,从而控制 PHY 的链路状态、速率、双工模式、协商结果,甚至拿到诊断信息。
我习惯把 PHY 寄存器比作一个“配置面板”。每个地址对应一个旋钮或指示灯。你读它,知道当前状态;你写它,改变 PHY 行为。这个面板长得什么样?IEEE 802.3 规定了基本框架,但每家芯片厂商还会自己加料。
1.2 寄存器地址空间:别乱闯
PHY 寄存器的地址宽度通常为 5 位,也就是 0~31,共 32 个地址。
为啥是 32 个?因为 MDIO 帧结构里地址字段只给了 5 位(实际上支持 Clause 22 的规范)。当然,后来有了 Clause 45,地址扩展到 16 位,那是后话。我们做以太网调试最常见的还是 Clause 22 的 5 位地址。
那么这 32 个地址怎么分配?我整理了一张表,大家存着:
| 地址范围 | 寄存器类型 | 说明 |
|---|---|---|
| 0x00~0x0F | 基本寄存器组 | IEEE 802.3 强制要求,标准功能 |
| 0x10~0x1F | 扩展寄存器组 | 芯片厂商自定义,或扩展标准功能 |
注意,0x10~0x1F 这部分每个厂家的定义都不一样。你在调试时如果发现某个地址读回来是 0,别急着认为芯片坏了——很可能是这个地址在你这颗 PHY 上没有实现,或者实现的功能与数据手册不一致。
1.3 MII 基本寄存器组(0x00~0x0F)
这 16 个寄存器是所有 Clause 22 兼容 PHY 必须支持的。它们定义了 PHY 的“身份证”和行为。我按照地址顺序,把他们分成了几个功能组:
- 控制与状态(0x00~0x01):主控。0x00 写复位、自协商使能、速率双工设置;0x01 读链路状态、协商完成、远端错误等。
- PHY 标识(0x02~0x03):生产商 ID 和设备型号。这两个寄存器是 OUI 的后 24 位,用来区分不同 PHY。我习惯在读通基本寄存器后先看一下 0x02、0x03,确认芯片型号对不对。
- 自协商通告与能力(0x04~0x05):4 通告自己的能力,5 对端的能力。抓协商问题就看这两个。
- 自动协商扩展 & 下一页(0x06~0x07):用于 1000BASE-T 等高速协商。
- 扩展状态 & 保留(0x08~0x0F):其中 0x0F 常用来做扩展页选择。
下面这张图概括了整个寄存器地址空间和基本寄存器的角色。你看,基本寄存器就像一个标准工具箱,扩展寄存器是厂商自定义工具包。
1.4 控制寄存器 0x00——你第一个要掌握的寄存器
地址 0x00(BMCR) 是 PHY 的遥控器。写这个寄存器可以复位、自协商、强制速率/双工。我建议你调试时第一个动作就是读 0x00,看看是不是处于复位状态(bit 15 = 1)。
它的比特位含义(以常见的 RTL8211 为例):
- Bit 15:软件复位(写 1 复位,自清除)
- Bit 14:环回模式
- Bit 13:速率选择高位(1000M)
- Bit 12:自协商使能
- Bit 11:掉电
- Bit 10:隔离
- Bit 9:重启自协商
- Bit 8:双工模式
- Bit 6/5/2:协同决定速率
// 举例:读当前配置
uint16_t bmcr = phy_read(phy_addr, 0x00);
if(bmcr & (1<<15)) {
printf("警告:PHY 正在复位中\n");
}
if(bmcr & (1<<12)) {
printf("自协商已使能\n");
} else {
printf("强制模式,检查 bit13, bit8, bit6 等\n");
}
1.5 状态寄存器 0x01——看 PHY 好不好
地址 0x01(BMSR) 是只读寄存器,告诉你 PHY 的基础能力和当前状态。
我每次读状态寄存器时,会特别关注下面几个比特:
- Bit 5:自协商完成(1 = 完成)——这是最重要的标志位。如果一直不置位,说明协商失败。
- Bit 2:链路状态(1 = 已建立)。
- Bit 0~3:扩展能力(支持 100BASE-T4、100BASE-X、10BASE-T 等)。
我的调试口诀:“一读 0x00 看控制,二读 0x01 看状态,三读 0x02 查 ID,四读 0x04 对能力。”这个习惯跟了我十多年,极少失手。
1.6 PHY 标识符寄存器(0x02、0x03)
这两个寄存器合起来组成 32 位的 PHY 标识。其中 0x02 是高 16 位(OUI 后 16 位 + 厂商型号 6 位),0x03 是低 16 位(型号 + 修订版本)。
我做过一个工具,启动后自动读 0x02 和 0x03,然后查表匹配芯片型号。如果匹配不上,直接报错“未知 PHY,请检查硬件”。这个方法帮我挡掉了很多因贴错芯片导致的故障。
1.7 自协商相关寄存器(0x04~0x07)
0x04(ANAR)通告自己的能力,0x05(ANLPAR)显示对端能力。通过比较这两个,就能知道为什么协商结果是 100M 半双工而不是 1000M 全双工——很可能有一端没支持。
0x06(ANER)和 0x07(ANNPTR)用于扩展页,1000BASE-T 的协商需要这些寄存器做下一页交换。这块比较深,我们后面章节再细聊。
1.8 回顾与实用建议
这一章的内容其实很基础,但基础的东西最容易被忽视。很多工程师遇到 PHY 不通就量产去换芯片,结果换了还不行——最后发现是寄存器地址配错了。
我建议你在调试 PHY 之前,先准备好一张标准寄存器表(0x00~0x0F),并把你用的 PHY 的 datasheet 扩展寄存器表也打印出来贴墙上。每次读回值后,对照着看,异常值很快就能圈定。
嗯,这一章就到这里。你把这些概念吃透了,后面讲异常值定位方法时才不会发懵。