基本寄存器0(BMCR):控制寄存器的位定义

BMCR 是 PHY 的“总开关”。你想想看,一个芯片上电后总得有个地方告诉它:你要不要自检?跑多快?跟谁握手?这些决定都写进这个 16 位寄存器里。

我刚开始调 PHY 时总觉得这寄存器太简单——不就是置位嘛。直到有一次量产回来的板子死活协商不上,最后发现是某个软件工程师把复位位多清了 0.5ms。嗯,从那以后我再也不小看这个寄存器了。

BMCR 的位定义总览

先给张速查表,让你一眼知道每个位是干嘛的。后面我会挨个说坑在哪。

位号名称默认值关键说明
15软复位0自清位,写1触发复位,完成后自动归0
14环回模式01=内部环回,用于调试数据通路
13速度选择(LSB)依物理层配合位6(速度MSB),10=1000M,01=100M,00=10M
12自动协商使能11=开启自动协商,0=手动模式
11掉电模式01=进入低功耗,链路断开
10隔离01=电隔离GMII/MII接口,调试用
9重启自动协商0写1触发重新协商,完成后自清
8双工模式11=全双工,0=半双工
7碰撞测试0仅用于测试设备
6速度选择(MSB)依物理层与位13组合成2bit速度值
5:0保留/厂家自定义0一般只读或用于厂测,不要乱写

几个关键位的实战理解

位15:软复位 —— 千万别只写一次就以为完了

写1触发复位,芯片内部逻辑会立即开始重新初始化。但它是个自清位——你写入1后,必须轮询直到它变回0才算复位完成。

我曾经踩过的坑: 某次在产品代码里写完寄存器后直接去配其他 PHY 寄存器,结果前几笔配置被复位过程覆盖了。后来我习惯在复位后加一个超时循环,确认软复位位为0了再往下走。

// 建议的软复位流程(伪代码)
write_phy(REG_BMCR, 0x8000);  // 写位15=1
timeout = 1000;
while ( (read_phy(REG_BMCR) & 0x8000) && timeout-- ) {
    delay_us(10);
}
if (timeout == 0) {
    // 处理复位超时异常
}

位14:环回模式 —— 隔离问题的利器

把这个位置1后,PHY 的发送数据输出会被环回到接收端。说白了就是自我对话,不依赖外部链路。

我一般在调试板卡硬件问题时会优先用这个:先开环回看 MAC→PHY 的数据回路是否正常。如果环回通信正常,那问题大概率在变压器、连接器或对端设备上。

小技巧: 环回模式下链路状态寄存器里的 Link Status 可能依然显示 Down,别慌——这是正常的,因为物理层根本没接外部介质。

位12与位13+位6:自动协商与速度选择 —— 二选一的关系

自动协商使能位(位12)等于1时,速度选择位(位13和位6)会被硬件忽略,芯片完全靠协商结果决定速度。只有自动协商关闭时,手动指定的速度才生效。

我记得调试一个交换机的级联端口时遇到一个问题:明明强制了1000M全双工,但 peer 端就是协商成100M。后来发现是对方开启了自动协商,我这边位12被意外置1了。你看,一个小位搞垮整条链路。

速度编码对照:

  • 00(Z) —— 10BASE-T 半双工(实际很少这么设)
  • 01(LSB) —— 100BASE-TX 半双工
  • 10(MSB) —— 1000BASE-T 半双工
  • 11 —— 1000BASE-T 全双工(最常见)

位11掉电 & 位10隔离 —— 调试阶段的“隐形杀手”

这两个位容易被忽视。调试时如果 PHY 链路老是 down,可以检查一下是不是误写了掉电位。我遇到过因为驱动框架调用了某个 suspend 函数导致位11被意外置1的案例,查了三天才定位到。

位10隔离在带外管理或者多 PHY 共享 MDIO 时比较有用,但普通应用一般保持0。如果不小心置1,MII 接口会变成高阻,读出来全是错数据。

BMCR 控制寄存器位域结构 15 14 13 12 11 10 9 8 7 6 位5~0(保留/厂商自定义) 软复位 环回 速度LSB 自协商使能 掉电 隔离 重启自协商 双工 碰撞测试 速度MSB 常见组合说明 ▪ 自动协商开启(位12=1):速度位(13,6)被忽略,PHY自动与对端协商最佳速率与双工 ▪ 自动协商关闭(位12=0):必须手动设置速度位(13,6)和双工位(8),否则链路不稳定 ▪ 环回模式(位14=1):优先使用,用于隔离MAC→PHY或PCB走线问题 写入 PHY 进入对应工作模式 自动协商模式 位12=1 强制速度/双工 位12=0 环回/掉电/隔离 调试或低功耗

几个面试中高频的问题实战

  1. 为什么软复位后读 BMCR 还是 0x1000?
    很多 PHY 在上电后会自动协商使能默认为1(位12=1),而复位不会改变这个默认值。如果你期望手动模式,必须在复位完成后再次写入位12=0。
  2. 环回模式下能抓到 link up 中断吗?
    通常不能。因为链路检测逻辑被旁路了。不要指望环回能触发链路状态变化。
  3. 不小心把掉电位写成1,卡死了怎么办?
    重新用软复位位15复位一次可以恢复。但前提是 MDIO 时钟还没丢。如果掉电后 MDIO 也被停掉……那就只能断电重启了。

调试总结(我个人的排查顺序):

  • 第一步:读 BMCR 看当前配置(特别是位12、位15和掉电位)
  • 第二步:写个干净的初值 —— 先复位,再关闭自动协商,手动设好速度和双工
  • 第三步:确认链路状态寄存器(BMSR)里的 link 位,排除外部问题
  • 第四步:还不行就开环回,验证 PHY 核心通路是否正常

BMCR 虽小,但它是整个 PHY 行为的总指挥。你花半小时吃透这一页,后面调试任何 PHY 寄存器都会顺手很多。