本章核心要点
- 掌握寄存器0-15的固定含义与访问规则
- 学会通过控制寄存器完成自协商、复位、环回等操作
- 理解状态寄存器如何反馈链路状态与故障
- 学会读取厂商ID与型号,识别芯片身份
// 步骤1: 写入复位命令
write_phy_reg(phy_addr, 0, 0x8000);
// 步骤2: 等待复位完成(关键!)
int timeout = 1000;
while (timeout--) {
uint16_t val = read_phy_reg(phy_addr, 0);
if ((val & 0x8000) == 0) {
printf("Reset complete!\n");
break;
}
delay_us(10); // 至少等10微秒
}
if (timeout == 0) {
printf("ERROR: Reset timeout!\n");
}
经验之谈:复位后,寄存器会回到默认值。但有些PHY在复位期间不响应MDIO读请求,读回来的数据可能是0xFFFF。我一般会在复位后额外延时2ms,确保PHY内部状态机稳定。
## 4.3 寄存器1——基本状态寄存器
这个寄存器告诉你PHY当前的状态。很多调试问题能从这里找到线索。
### 4.3.1 关键位解读
| 位域 | 名称 | 含义 |
|------|------|------|
| 15 | 100BASE-T4支持 | 基本没用,T4早就淘汰了 |
| 14 | 100BASE-TX全双工支持 | 1=支持 |
| 13 | 100BASE-TX半双工支持 | 1=支持 |
| 12 | 10BASE-T全双工支持 | 1=支持 |
| 11 | 10BASE-T半双工支持 | 1=支持 |
| 10:7 | 预留 | 读为0 |
| 6 | MF预充支持 | 一般不用关心 |
| 5 | 自协商完成 | 1=自协商完成(重要!) |
| 4 | 远端错误 | 1=对端报告了错误 |
| 3 | 自协商能力 | 1=支持自协商 |
| 2 | 链路状态 | 1=链路已建立(核心指标) |
| 1 | 页接收能力 | 支持页交换 |
| 0 | 扩展寄存器能力 | 支持寄存器16+ |
**我遇到过一个诡异问题**:板子上电后链路指示灯不亮,但寄存器1的位2(链路状态)却是1。这说明什么?说明MAC侧检测到了信号,但物理层协商出了问题。真相是——对端PHY工作在100M,我这端强制配成了10M。频率不匹配,信号还能被检测到,但数据根本传不了。
### 4.3.2 链路检测实战术
// 检查链路是否建立
uint16_t status = read_phy_reg(phy_addr, 1);
if (status & 0x0004) {
printf("Link is UP\n");
// 检查自协商是否完成
if (status & 0x0020) {
printf("Auto-negotiation complete\n");
// 读伙伴的能力(需要读寄存器5)
uint16_t partner = read_phy_reg(phy_addr, 5);
// ... 进一步分析
}
} else {
printf("Link is DOWN! Check cable/connector\n");
}
## 4.4 寄存器2和3——厂商ID
这两个寄存器构成一个32位的厂商识别码。寄存器2是高16位,寄存器3是低16位。
我记得有一次在实验室里,拿来一块新板子。标签被磨掉了,软件团队不知道里面是什么PHY。我让他们读寄存器2和3,得到0x0141和0x0CC2。查一下标准分配——0x0141是Broadcom的代码。再查0x0CC2对应的具体型号——BCM5461。问题解决了。
### 常见厂商ID简表
| 厂商 | 寄存器2值 | 寄存器3典型值 |
|------|-----------|--------------|
| Broadcom | 0x0141 | 0x0Cx0系列 |
| Marvell | 0x0141 | 0x0Ex0系列 |
| Realtek | 0x001C | 0x81x0系列 |
| Microchip | 0x0050 | 0x6Cx0系列 |
| TI | 0x0800 | 0x28x0系列 |
注意:有些PHY的寄存器2和3在复位后可能是0x0000,需要先执行一次读取或软件复位才能拿到正确ID。别问我怎么知道的——板子刚上电就急着读ID,结果全是0,怀疑人生。
## 4.5 寄存器4和5——自协商伙伴能力
这两个寄存器是调试自协商问题的关键。
寄存器4:广告能力。告诉对端“我能跑哪些模式”。
寄存器5:伙伴能力。告诉本端“对端能跑哪些模式”。
我调试一个1000M项目时,发现链接只能协商到100M。读寄存器5一看,伙伴能力的1000M位根本没置1。换了一台千兆交换机,问题立刻解决。
## 4.6 寄存器6——自协商扩展状态
这个寄存器有4个位特别重要:
| 位域 | 名称 | 含义 |
|------|------|------|
| 15 | 1000BASE-X全双工 | 千兆全双工支持 |
| 14 | 1000BASE-X半双工 | 千兆半双工支持 |
| 13 | 1000BASE-T全双工 | 1000BASE-T全双工 |
| 12 | 1000BASE-T半双工 | 1000BASE-T半双工 |
| 11:0 | 其他 | 一般用不到 |
## 4.7 寄存器0-15知识体系结构图
## 4.8 实战调试方法论
### 4.8.1 上电调试第一步
我每调试一个新板子,都会按这个顺序检查:
1. **读寄存器2和3**:确认PHY型号
2. **读寄存器0**:确认当前配置(复位状态、自协商开关)
3. **读寄存器1**:确认链路是否建立
4. **如果链路down**:检查寄存器4和5,看自协商是否在跑
5. **如果链路up但不通**:检查寄存器0的速率和双工设置
### 4.8.2 常见问题排查
| 现象 | 检查寄存器 | 可能原因 |
|------|-----------|----------|
| 读寄存器全是0xFFFF | 任意 | MDIO不通,检查时钟和数据线 |
| 读寄存器全是0x0000 | 任意 | PHY未上电或复位引脚被拉低 |
| 链路不稳定,频繁up/down | 寄存器1位2 | 线缆质量差或连接器接触不良 |
| 只能协商到最低速率 | 寄存器5 | 对端设备能力不足 |
| 能ping通但丢包 | 寄存器0位14 | 可能误开了环回模式 |
我的一个小技巧:在调试脚本里,我会定期打印寄存器1的值(比如每500ms一次)。连续打印几轮,链路状态、自协商标志的变化模式就能一目了然。很多时候,问题藏在“偶尔闪一下”的异常里。
## 4.9 本章小结
寄存器0-15是PHY调试的起点和基石。掌握了它们,你就能:
- 快速判断硬件通路是否正常
- 读懂链路协商的过程和结果
- 精准定位大部分物理层问题
**我个人经验是**:很多复杂的PHY问题,最后都能追溯到这几个寄存器的某个位上。有时候一个bit就能解释为什么设备不能互通、为什么性能达不到标称值。所以,花时间吃透这16个寄存器,是PHY调试中最值得的投入。