2. PHY 寄存器概述
说实话,搞懂 PHY 寄存器,是玩转 MDIO 的第一步。你想想看,MDIO 协议本身不复杂,它就是一根时钟线加一根数据线。真正复杂的,是 PHY 芯片内部那一大堆寄存器。我刚开始接触这玩意时,看着数据手册里几百页的寄存器描述,头都大了。
不过别慌。PHY 寄存器虽然多,但结构是有规律的。咱们先捋清楚它的骨架,后面填肉就轻松了。
2.1 PHY 寄存器的基本概念
PHY 芯片内部有一组寄存器,每个寄存器 16 位宽。MDIO 协议就是用来读写这些寄存器的。你可以把它想象成 PHY 的“控制面板”和“状态显示屏”。
写入某个寄存器,就是给 PHY 下达指令。比如强制设置成百兆全双工模式。读取某个寄存器,就是查看 PHY 当前的运行状态。比如链接有没有建立,有没有收到错误帧。
那地址怎么分配?每个 PHY 都有一个 5 位的器件地址,范围 0-31。最多可以挂 32 个 PHY 器件在同一对 MDIO 总线上。每个 PHY 内部,寄存器地址是 5 位或者更宽(取决于是否支持扩展地址)。
核心要点: MDIO 帧结构里,目标器件地址(PHYAD)和寄存器地址(REGAD)决定了你访问的是哪个 PHY 的哪个寄存器。
我记得有一次项目调试,板子上同时挂了 4 个不同的 PHY。地址分配没规划好,结果有两个 PHY 地址冲突了。那真是查了半天,最后用 MDIO-Tool 一个个扫描才发现的。所以,硬件设计阶段就最好把地址定死,多用电阻上拉下拉配置好。
2.2 寄存器的主要分类
PHY 寄存器可以分成几大类。不同厂家的定义会有些差异,但基本骨架都在 IEEE 802.3 规范里框死了。我个人习惯按功能把它们分成三块:
- 基本寄存器(0-15): IEEE 802.3 强制定义的,所有标准 PHY 都必须支持。这部分是通用基础。
- 扩展寄存器(16-31): 规范里预留了地址空间,但具体功能由厂家自己定义。很多通用功能也在这里。
- 厂商特定寄存器(32+): 如果你用 Clause 45 协议,地址空间更大。这些通常用于芯片的私有功能、调试模式和高级特性。
说白了,基本寄存器就像是一套通用的工具箱。你拿任何一家 PHY,0 号寄存器的控制和 1 号寄存器的状态,功能上基本一致。但扩展和厂商寄存器,就是每家厂商自己的独门兵器了。换 PHY 芯片时,这部分代码经常要重写。
2.3 标准寄存器详解(0-15)
咱们重点看一下最关键的那几个基本寄存器。我挑几个必须掌握的讲讲。
| 寄存器地址 | 寄存器名称 | 主要功能 |
|---|---|---|
| 0 | BMCR (Basic Mode Control Register) | 控制复位、回环、速度选择、自动协商使能、重启自动协商 |
| 1 | BMSR (Basic Mode Status Register) | 指示链接状态、自动协商完成、能力、扩展能力 |
| 2 | PHY Identifier Register #1 (OUI 低位) | 厂商 OUI 的低 16 位 |
| 3 | PHY Identifier Register #2 (OUI 高位 + 型号 + 版本) | 厂商 OUI 的高 4 位、器件型号、版本号 |
| 4 | ANAR (Auto-Negotiation Advertisement Register) | 向对端广播自己支持的能力(速度、双工、流控) |
| 5 | ANLPAR (Auto-Negotiation Link Partner Ability Register) | 读取对端 PHY 广播的能力 |
| 6 | ANER (Auto-Negotiation Expansion Register) | 自动协商扩展状态,比如下一个页面等待 |
你可能会问,这么多寄存器,从哪里开始读?我的经验是:第一步先读 0 号和 1 号寄存器。读 0 号确认芯片没有处于复位或掉电状态。读 1 号看链接有没有建立。链接都没起来,后面的自动协商结果全是白搭。
小技巧: 读 PHY ID 寄存器(地址 2 和 3),可以快速确认你读到的 PHY 是不是板子上焊的那一颗。我曾经用这招抓出过硬件焊接虚焊的问题,电流表都测不出来,但 MDIO 一读 ID,全 0xFFFF,马上定位到了。
2.4 扩展寄存器与厂商特殊寄存器
地址 16 往后的寄存器,虽然地址空间有限,但各家厂商用得五花八门。比较常见的有:
- 中断源/屏蔽寄存器: PHY 有变化时主动通知你,比如链接断开。不用你一直轮询。
- 数字调试寄存器: 查看内部数字信号的状态,比如时钟好不好、复位完成没。
- 模拟调试寄存器: 查看眼图、信噪比、均衡器状态等模拟域数据。这个对信号完整性分析很有用。
- EEE(节能以太网)相关寄存器: 控制低功耗模式。
- MDI/MDIX 控制: 自动翻转/手动切换网口线序。
这些寄存器每家 PHY 的数据手册都会给一张表。你不需要背,但要知道它们在哪里。真要用到的时候,拿着手册对着寄存器地址翻就行了。
避坑指南: 我曾经在项目里用 Clause 22 的 MDIO 去读一个 Clause 45 的 PHY 的扩展寄存器,结果读出来的数据完全是错的。MDIO 协议有两个主要标准:Clause 22 和 Clause 45。前者地址空间小,后者支持更大的寻址范围。用之前一定要确认你的 PHY 和 MDIO 控制器工作在哪个协议模式下。
2.5 PHY 寄存器架构总览
下面这张图是我画的 PHY 寄存器架构总览,帮你把刚才说的内容串起来。你可以把它当作查手册时的索引地图。
你看这张图,左边是基本寄存器,中间是扩展寄存器,右边是厂商特定寄存器。它们之间的线表示地址空间的递进关系。基本寄存器是所有 PHY 的“通用语言”。扩展寄存器是“方言”。厂商特定寄存器就是“黑话”了。
嗯,这里要注意一下。虽然基本寄存器是通用的,但具体到每个位,不同厂商的实现可能会有微小差异。比如复位完成标志位,有的 PHY 放在 0 号寄存器的某一位,有的放在 1 号寄存器的某一位。所以,最稳妥的做法还是看数据手册。
2.6 寄存器访问的核心原则
说了这么多,最后总结几条我自己写 MDIO 驱动时一直遵循的原则:
- 先读 ID,确认存在。 读地址 2 和 3,如果全是 0xFFFF 或 0x0000,说明链路有问题或者地址不对。
- 写前必须读。 很多寄存器是读-改-写结构的。你直接写整个 16 位值,会把其他位的配置覆盖掉。我建议先读回当前值,改掉你想要的位,再写回去。
- 复位后不要立刻操作。 PHY 复位后需要一段时间稳定下来。不同芯片时间不同,从几毫秒到几十毫秒都有。加个延时再操作。
- 自动协商期间,不要乱改速度。 如果你已经使能了自动协商,又手动写死了速度和双工模式,PHY 会进入混乱状态。要么全部交给自动协商,要么完全手动配置。
我的习惯: 我喜欢在调试初期写一个简单的循环,轮训 1 号 BMSR 寄存器的链接位。看它从 0 变 1 的过程,能直观感受到自动协商的节奏。如果半天没变,还能及时判断是硬件问题还是配置问题。
好了,寄存器的基础骨架就是这些。后面章节我们会拿着 MDIO-Tool 一个坑一个坑地踩过去。你先把这张架构图印在脑子里,后面写代码时,调头查手册的速度会快很多。