以太网初始化设计(MDIO 控制器)

发布时间:2023年12月18日


前言

PHY芯片根据不同的需求,会有不同的工作模式,例如需要设置其以太网通信速率为千兆、百兆、十兆或自动协商,而处理器也需要知道其连接状态,例如需要知道网络是否已经连接通,以及当前的链接速率是多少。为了实现这些功能,IEEE 在以太网标准 IEEE 802.3 中使用若干条款定义了用处理器用来管理PHY 芯片的标准控制接口——MDIO。
本章,我们将学习 MDIO 接口相关知识,并设计相应的驱动模块,通过 MDIO接口带领大家学习如何配置 PHY 芯片。

提示:以下是本篇文章正文内容,下面案例可供参考

一、PHY 管理接口 MDIO 介绍

MDIO 是一种简单的双线串行接口,将管理器件(如 MAC 控制器、微处理器)与具备管理功能的 PHY芯片相连接,从而控制收发器并从收发器收集状态信息。可收集的信息包括链接状态、传输速度与选择、断电、低功率休眠状态、TX/RX 模式选择、自动协商控制、环回模式控制等。除了拥有 IEEE 要求的功能之外,收发器厂商还可添加更多的信息收集功能。MDIO 总线包含两个信号:MDC 和 MDIO。MDC 是管理数据的时钟信号,由管理器(如处理器或 MAC)输出给 PHY 芯片,最高速率可超过 5MHz。MDIO 则是管理数据的输入输出双向接口,其中的数据与 MDC 时钟同步。和大家熟悉的 I2C 接口相似,MDIO 总线也支持多设备模式,即一个 MDIO总线上最多可连接 32 个 PHY 芯片的 MDIO 接口,通过在传输过程中的 PHY 器件地址字段传输不同的器件地址值来指定具体操作哪个 PHY 芯片。
在这里插入图片描述
每个 PHY 芯片都有一个硬件地址,该地址为 5 位,由固定部分和可变部分组成,可变部分可以通过物理上拉或者接地设置。若多个 PHY 芯片同时连接在同一个 MDIO 总线上,需要设置不同的 PHY 器件地址以示区分。每个 PHY 芯片中都有最多 32 个寄存器可供读写(32 个寄存器,需要 5 位寄存器地址),包括由 IEEE 802.3 规范定义的前 16 个标准功能寄存器和后续最多 16 个由 PHY 芯片厂家自定义的功能寄存器。所有 PHY 芯片的前 16 个寄存器功能定义都必须相同,后续 0~16 个寄存器的功能由 PHY 芯片厂家根据实际需求自定义。
我使用的 开发板上使用的 PHY 芯片型号为Realtek 的 RTL8211 ,通过查询手册可以知道其器件地址由固定的 00+由引脚控制的 PHYAD[2:0]组成,为00001。

二、MDIO 时序介绍

介绍了 MDIO 接口之后,要想正确的使用 MDIO 接口来管理 PHY 芯片,还需要了解 MDIO 接口的时序流程。MDIO 的工作流程为:

  1. 空闲:MDIO 接口在没有传输数据的空闲状态(IDLE)数据线 MDIO处于高阻态。
  2. 开始:MAC 或处理器驱动 MDIO 产生一个 2bit 的开始标识码(01),标志着一次读、写传输的开始。
  3. 读写标记:MAC 或处理器驱动 MDIO 产生一个 2bit 数据来标识本次操作是读操作(10)还是写操作(01)。
  4. PHY 器件地址:MAC 或处理器驱动 MDIO 产生 5 位的 PHY 器件地址数据,用来指明此次操作是针对的具体那一个 PHY 芯片。
  5. PHY 寄存器地址:MAC 或处理器驱动 MDIO 产生 5 位的 PHY 寄存器地址数据,用来指明此次操作是针对的 PHY 中具体哪一个寄存器。
  6. MDIO 控制权切换:在读操作中,由于在 PHY 移出寄存器中的数据时MDIO 信号将由 PHY 芯片接管驱动,既 MDIO 信号存在一个驱动切换的情形,为了避免切换过程中 MAC 或处理器驱动和 PHY 芯片同时驱动 MDIO 信号以出现冲突干扰,在传输完 PHY 寄存器地址后,需要传输 2bit 的 TA(Turnaround)信号,传输该信号时,MAC 或处理器MDIO 信号为高阻状态,即不驱动 MDIO 信号至低电平,对于读操作,PHY 芯片将在这 2bit 信号的第 2 个 bit 时将 MDIO 信号拉低以标记读出数据传输。同时,这第 2 个 bit 还将作为类似于 I2C 总线中的应答位,如果在读操作中,该 bit 没有被拉低,则表明读 PHY 芯片操作失败。对于写操作,第一个 bit 时 MAC 或处理器和 PHY 芯片都保持为高阻状态,MDIO 被上拉电阻拉为高电平,在第 2 个 bit 时由 MAC 或处理器将该位
    拉低。
  7. 读写数据:MDIO 串行读出/写入 16bit 的寄存器数据。
  8. IDLE 状态: MDIO 再次进入高阻状态,对于部分 PHY 芯片,MDC 将
    继续产生至少 7 个时钟周期之后方可停止。
    【注意】在空闲和开始状态之间,MDIO 需要保持高阻态至少 32 个 MDC 时钟周期,该段称为前导信号(preamble)。
    下表为一次读写操作的数据帧格式:
    在这里插入图片描述
    其中各段的意义和功能如下表所示:
    在这里插入图片描述
    MDIO 会在 MDC 的下降沿变化,变化后的数据会在 MDC 上升沿被采样,进而组成上述所说的数据帧。
    在这里插入图片描述
    基于该时序图,我们便能很方便的写出对应的驱动模块,对 PHY 芯片进行读写操作。至于具体在什么模式下需要对什么寄存器进行操作,则需要读者查询 PHY 芯片手册中对应寄存器的说明。

三、MDIO 接口注意事项

  1. 部分 PHY芯片(如 RTL8211)要求在一次读写操作完成,转为 IDLE状态之后,还需要 MDC 信号持续至少 7 个时钟周期以确保 PHY 芯片正常完成该操作。
  2. PHY 芯片的 MDIO 引脚需要连接至少 1.5K Ohm 的上拉电阻。
  3. 在 PHY 芯片成功 Link 之前,不得向 PHY 芯片提供发送使能信号,即TX_EN信号在 PHY芯片没有成功 Link之前不得出现高电平,否则可能会影响 PHY 芯片的自动协商和工作模式设置。
  4. PHY 芯片一般都有一个硬件复位引脚 reset,一般 PHY 芯片都会做出说明,在该复位信号释放后需要等待至少多久的时间(例如,对于RTL8211,这个值为 30ms)才能开始使用 MDIO 接口对 PHY 芯片进行读写操作。

四、mdio_bit_shift 模块设计

4.1、mdio_bit_shift 模块设计

根据协议帧的格式和上面的读写时序图,我们发现这个协议帧里面的变化内容有 OP、PYHAD、REGAD、以及传输的数据(DATA)等字段,在这里我们可以把这些作为端口,同时加入传输开始 start 和传输完成 done 等握手信号来指示当前的模块工作状态,因此设计出图所示模块单元:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
模块使用状态机来描述 MDIO 接口的读写时序,对于时序图中的每个字段都采样独热码定义了一个状态,如下:

localparam IDLE = 8'h01,
PRE = 8'h02,
ST = 8'h04,
OP = 8'h08,
PHYAD = 8'h10,
REGAD = 8'h20,
TA = 8'h40,
DATA = 8'h80;

在不同状态下,让状态机按照时序图对差异部分进行描述,从而实现对phy寄存器的配置和读取,该部分代码如下:

always @ (negedge mdc or negedge rst_n)
	if (!rst_n) begin
		rddata <= 'd0;
		mdio_oe <= 1'b0;
		mdio_o <= 1'b1;
		cnt <= 'd0;
		done <= 1'b0;
		state <= IDLE;
	end else begin
    case (state)
        IDLE:
            begin
                mdio_o <= 1'b1;
                mdio_oe <= 1'b0;
                done <= 1'b0;
                rddata <= 'd0;
                if (start)
                begin
                    cnt <= 'd0;
                    state <= PRE;
					mdio_oe <= 1'b1;
                end
            end
        PRE://PRE 32'hffff_ffff  32bit
            begin
                mdio_oe <= 1'b1;    
                mdio_o <= 1'b1;
                cnt <= cnt + 1'b1;
                if (cnt > 'd30)
                begin
                    cnt <= 'd0;
                    state <= ST;
                    mdio_o <= 1'b0;
                end
            end
        ST: //ST 01  2bit
            begin
                mdio_o <= 1'b1;
                cnt <= cnt + 1'b1;
                if (cnt >= 'd1)
                begin
                    cnt <= 'd0;
                    state <= OP;
                    mdio_o <= if_read;
                end
            end
        OP
文章来源:https://blog.csdn.net/wd12306/article/details/135066683
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。