第1章 MDIO总线协议概述:发展历史、应用场景、与PHY的关系

1.1 从一次调试点说起

记得我刚做嵌入式那会儿,调一块千兆网卡,板子死活link不上。示波器上了,电平量了,电阻也重新焊了一遍,就是不行。老工程师过来看了一眼,说了一句:「你读一下PHY的寄存器。」

我当时就愣住了——读寄存器?怎么读?

他指了指板子上那两根线:MDC和MDIO。这就是我第一次见到MDIO总线。

说白了,MDIO就是一种专门用来读写PHY芯片内部寄存器的串行总线。你想想看,PHY芯片就像个小黑盒子。速率协商到多少了?链路有没有建立?有没有检测到远端故障?这些信息全藏在它的寄存器里。MDIO就是打开这个盒子的钥匙。

核心理解:MDIO(Management Data Input/Output)是IEEE 802.3标准定义的管理接口,用于MAC层与PHY层之间的控制通信。一共就两根线——MDC时钟线和MDIO数据线,却能完成整个PHY的配置和状态监控。

后来我才明白,其实MDIO的应用远不止调试。产品量产时,每个PHY的初始化配置、工作模式设定、链路监控,全得靠它。没有MDIO,PHY就像个没法调音的音响——能响,但好不了。

1.2 发展历史:从Clause 22到Clause 45

MDIO最早出现在1995年的IEEE 802.3u标准里。那时候叫Clause 22。支持5 MHz时钟,一次传16位数据,地址空间只有5位,最多管32个PHY。

我记得当时做设计,32个地址感觉还挺宽裕。后来设备越来越密,端口越来越多,发现不够用了。32个?一个交换机几十个口,再加上CPU本地PHY,很容易就占满了。

于是在2002年的IEEE 802.3ae(万兆以太网)标准里,推出了Clause 45。地址空间扩展到32位,时钟也提到了12.5 MHz。而且Clause 45向下兼容Clause 22——同一个控制器可以同时接两种类型的PHY。

避坑提示:我曾经在一个项目里混用Clause 22和Clause 45的PHY,结果发现有些寄存器读出来全是0。查了半天才知道,帧格式不一样,控制器得先区分当前操作的是哪种类型的PHY。后面我们会详细拆解这个问题。

两种标准的差异,我用一个表格总结:

特性 Clause 22 Clause 45
推出时间 1995年(802.3u) 2002年(802.3ae)
最大时钟 5 MHz 12.5 MHz
PHY地址宽度 5 bit(0~31) 32 bit
寄存器地址宽度 5 bit(0~31) 16 bit(0~65535)
数据宽度 16 bit 16 bit
帧格式 固定5位地址 可扩展地址 + 类型字段
向下兼容 — 支持

嗯,这里有个关键点:Clause 45并不是简单地把地址变宽了,它的帧结构完全重新设计了。读操作和写操作的编码方式也不一样。不少工程师用Clause 22的时序去读Clause 45的PHY,结果读回来的数据完全不对。

1.3 MDIO的应用场景

MDIO几乎出现在所有带以太网的设备里。我列几个典型的:

  • 交换机/路由器:批量管理数十个千兆/万兆PHY,初始化配置 + 链路监控
  • 嵌入式主板:U-Boot阶段初始化PHY,内核驱动中轮询链路状态
  • FPGA设计:通过软核MDIO控制器驱动外部PHY芯片
  • 车载以太网:管理BroadR-Reach等车载专用PHY
  • 基站/服务器:监控高速链路的信号质量、FEC纠错统计
  • 测试仪器:网络测试仪、协议分析仪通过MDIO注入错误或读取诊断信息

说句实话,只要你做以太网硬件或者底层驱动,就绕不开MDIO。我个人习惯是在每个项目的硬件设计阶段就确认MDIO的上拉电阻和时钟布线——这两样出问题,后面调试能让你怀疑人生。

注意:MDIO总线上需要外接上拉电阻(通常是1.5 kΩ~10 kΩ),否则数据线无法正常输出高电平。我遇到过一块板子,MDIO怎么都读不到数据,最后发现是上拉电阻虚焊了。

1.4 MDIO与PHY的关系

这个关系其实很好理解。PHY负责物理层信号转换,但它有很多参数需要配置——速率、双工模式、自动协商使能、流控使能、交叉/直连检测等等。这些配置都存放在PHY内部的寄存器里。

MDIO就是用来读写这些寄存器的总线。它连接在MAC和PHY之间,作为控制面存在。

你可以这么看:

  • 数据面:走RGMII / SGMII / SerDes,传输网络数据包
  • 控制面:走MDIO,配置和监控PHY状态

一个管数据,一个管配置。两者互不干扰,但又缺一不可。

下面这张图展示了MDIO总线系统的完整架构:

MDIO 总线系统架构图 主控设备 (CPU/MAC) MDIO 控制器 MDIO 总线 (MDC + MDIO) 时钟线 + 双向数据线 PHY #0 寄存器空间