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 寄存器架构总览 标准基本寄存器 (0-15) IEEE 802.3 强制定义 0: BMCR - 控制复位、速度、自动协商 1: BMSR - 链接状态、自动协商完成 2-3: PHY ID - 厂商/型号/版本 4-6: AN 寄存器 - 自动协商能力交换 标准扩展寄存器 (16-31) 地址预留,功能由厂商定义 16-17: 扩展状态与控制 18-19: 中断源 / 中断屏蔽 20-23: 测试与调试功能 24-31: 厂商自定义 厂商特定寄存器 (32+ / 可扩展地址) Clause 45 协议支持更大寻址空间 数字调试(时钟/复位) 模拟调试(眼图/均衡) EEE/节能控制 关键说明 • 基本寄存器是通用的,跨厂商可移植。扩展寄存器和厂商寄存器换 PHY 必须重写。 • 用 MDIO-Tool 时,建议先从 0-3 号寄存器读起,确认芯片 ID 和基础状态。

你看这张图,左边是基本寄存器,中间是扩展寄存器,右边是厂商特定寄存器。它们之间的线表示地址空间的递进关系。基本寄存器是所有 PHY 的“通用语言”。扩展寄存器是“方言”。厂商特定寄存器就是“黑话”了。

嗯,这里要注意一下。虽然基本寄存器是通用的,但具体到每个位,不同厂商的实现可能会有微小差异。比如复位完成标志位,有的 PHY 放在 0 号寄存器的某一位,有的放在 1 号寄存器的某一位。所以,最稳妥的做法还是看数据手册。

2.6 寄存器访问的核心原则

说了这么多,最后总结几条我自己写 MDIO 驱动时一直遵循的原则:

  1. 先读 ID,确认存在。 读地址 2 和 3,如果全是 0xFFFF 或 0x0000,说明链路有问题或者地址不对。
  2. 写前必须读。 很多寄存器是读-改-写结构的。你直接写整个 16 位值,会把其他位的配置覆盖掉。我建议先读回当前值,改掉你想要的位,再写回去。
  3. 复位后不要立刻操作。 PHY 复位后需要一段时间稳定下来。不同芯片时间不同,从几毫秒到几十毫秒都有。加个延时再操作。
  4. 自动协商期间,不要乱改速度。 如果你已经使能了自动协商,又手动写死了速度和双工模式,PHY 会进入混乱状态。要么全部交给自动协商,要么完全手动配置。

我的习惯: 我喜欢在调试初期写一个简单的循环,轮训 1 号 BMSR 寄存器的链接位。看它从 0 变 1 的过程,能直观感受到自动协商的节奏。如果半天没变,还能及时判断是硬件问题还是配置问题。

好了,寄存器的基础骨架就是这些。后面章节我们会拿着 MDIO-Tool 一个坑一个坑地踩过去。你先把这张架构图印在脑子里,后面写代码时,调头查手册的速度会快很多。