PHY控制寄存器(CR):你第一个要掌握的寄存器

控制寄存器,英文叫 Control Register,也就是我们常说的 CR 寄存器。它的地址是 0x0,PHY 上电后的第一件事,往往就是读写它。

说实话,我做过不少 PHY 驱动,每次拿到新芯片,最先翻的就是 CR 寄存器。为什么?因为它管着 PHY 的“开关”和“模式”。你想想看,如果连这个都配不对,后边的眼图优化根本无从谈起。

CR 寄存器到底长什么样?

CR 寄存器是 16 位的,标准定义在 IEEE 802.3 第 22 条里。每个比特都有自己的使命。我整理了一张表,你直接看:

比特位 名称 说明
15 Reset 软件复位,写 1 复位 PHY,完成后硬件自动清 0
14 Loopback 环回模式,写 1 使能,用于诊断或调试
13 Speed Select (LSB) 与位 6 配合:00=10M, 01=100M, 10=1000M
12 Auto-Negotiation Enable 自动协商使能,写 1 启动
11 Power Down 节电模式,写 1 进入休眠
10 Isolate 隔离模式,写 1 断开 MAC 与 PHY 的数据通路
9 Restart Auto-Negotiation 写 1 重新开始协商
8 Duplex Mode 0=半双工, 1=全双工
7 Collision Test 碰撞测试使能,用于测试 MII 接口
6 Speed Select (MSB) 与位 13 配合使用
5:0 Reserved 保留位,一般读回来为 0

你别被这 16 个比特吓到。实际上,日常配置只用其中几个。我个人习惯先记住三个关键位:复位(位 15)、自动协商使能(位 12)和速度双工选择(位 13、6、8)。其他位多数是调试时才碰。

软件复位:你必须等它完成

写 CR 位 15 为 1,就能让 PHY 软复位。但有个坑——我记得第一次做项目时,复位完立马去读另一个寄存器,结果读回来全是 0xFF。查了半天才发现,PHY 复位需要时间。

注意: 写复位位之后,必须轮询该位,直到它自动清 0。否则后续操作可能失败。不同 PHY 的复位时间不一样,从几百微秒到几十毫秒都有。

正确的做法是:

// 伪代码示例:安全软复位
phy_write(addr, 0x8000);  // 写 CR 位 15=1
while (phy_read(addr) & 0x8000) {
    // 等待位 15 清 0
    delay_us(10);
}

嗯,这里要注意,有些 PHY 在复位期间不响应读操作。我曾遇到过一个芯片,复位后第一次读超时,加了重试才搞定。你写驱动时最好留个超时退出,别死等。

自动协商:开还是关?

这是个经典选择题。位 12 控制自动协商,位 9 是重启协商。我遇到的大多数项目,都要求开自动协商。但也不是的。

举个例子。我做某个交换机项目时,上位机要求必须强制 100M 全双工。我一开始开了自动协商,结果 PHY 和对方一直协商不成功,链路反复 UP/DOWN。后来关了自动协商,强制配死,问题就解决了。

我的建议: 默认开自动协商,除非你明确知道对方不支持协商,或者你需要固定速率。关掉自动协商时,必须同时配好速度和双工,否则链路可能不通。

配置自动协商,一般需要配合 AN 广告寄存器(寄存器 4)一起设。单独开位 12 不够,你得告诉 PHY 它支持哪些能力。这部分我后面会细讲。

速度与双工:两个比特决定一切

速度由位 13(LSB)和位 6(MSB)编码。双工由位 8 单独控制。组合起来就是:

位 13 位 6 速度
0 0 10 Mbps
1 0 100 Mbps
0 1 1000 Mbps
1 1 保留

说白了,位 13 是速度的低位,位 6 是高位。你看到这个编码方式,可能会问:为什么不直接用一个 2 位字段?只能说,IEEE 标准就是这么定的,咱们只能照做。

我一般写驱动时,会用宏定义把常用组合预置好:

#define PHY_CR_10M_HALF     0x0000
#define PHY_CR_10M_FULL     0x0100
#define PHY_CR_100M_HALF    0x2000
#define PHY_CR_100M_FULL    0x2100
#define PHY_CR_1000M_FULL   0x4140  // 千兆必须全双工

环回与隔离:调试的利器

位 14 是环回。使能后,发送的数据直接 loop 回接收端,不经过网线。这是我最常用的调试手段。眼图不好时,先做个本地环回,能快速判断问题是出在 PHY 内部还是外部链路。

位 10 是隔离。打开后,PHY 和 MAC 之间的数据通路断开。这个模式一般用于多 PHY 系统,或者在测试时想单独看 PHY 的状态。

经验: 环回模式下,PHY 仍然可以响应 MDIO 读写。你可以用它来验证寄存器配置是否正确,而不需要实际接网线。

一张图理清 CR 寄存器配置流程

下面我把 CR 寄存器的核心操作画成一张流程图。你跟着它走一遍,基本就能搞定绝大多数场景了。

PHY 控制寄存器配置流程图 控制寄存器(CR)操作流程 读取 CR 寄存器 需要软件复位? (上电/异常恢复) 是 写位 15=1 等待位 15 清零 否 使用自动协商? (常见场景) 是 位 12=1 配置 AN 广告 否 手动配速度 位13/6/8 环回/隔离模式配置 调试时开启 写回 CR 寄存器 验证写回值 读回检查是否一致 注意 自动协商开启时,速度双工位被忽略,由 AN 结果覆盖。手动模式需要位 12=0。

这张图基本覆盖了我平时配置 CR 的所有路径。你照着走,不太容易出错。

几个常见的坑

最后,我把我踩过的坑总结一下。你记住这些,能少走弯路:

  • 复位后不要马上写。 我遇到过复位后立即写其他寄存器,结果 PHY 根本不响应。等复位位清 0 了再操作。
  • 自动协商和手动模式不能混用。 开了 AN 却还去设速度双工位,有些 PHY 可以,有些会冲突。我建议你二选一。
  • 读回检查很重要。 写完 CR 后,读回来确认一下。尤其是一些 PHY 的保留位会返回非 0 值,你写的时候要小心。
  • 环回模式不能一直开着。 调试完了记得关掉。我曾有一次忘了关环回,上线后一直收不到对端数据,查了半天才发现。
个人技巧: 我每次初始化 PHY 时,都会先写 0x8000 软复位,然后等待,再读回 CR 确认复位成功。这步虽然简单,但能避免后面 90% 的奇怪问题。