一次 MDIO 配置 switch 的调试过程
1、什么是 MDIO
- 物理层时序
总线的电平协议类似 IIC 的协议。有两线通讯,一条时钟 MDC,一条数据 MDIO。但是数据的表示和 IIC 有些许差异。 - 使用场景
用于读写每个PHY的控制寄存器和状态寄存器,以达到控制PHY行为和监控PHY状态的目的。这是一个总线,可以挂32个不同地址的器件,通过不同的地址和对应的器件进行通讯。 - 使用方法
一般的GMAC控制器带有MIDO接口,通过配置GMAC的对应寄存器来进行发送读写。也可以使用普通 IO 模拟的方式来读写。
2、使用 MAC 对应的寄存器来读写
我这里使用 xilinx 的 MAC 为例,其他的 GAMC 也是类似的配置方法。
该寄存器的字段解释:
【15 - 0】:写入的data
【22 - 18】:phy 的寄存器的地址
【27 - 23】:phy 的 ID
【29 - 28】:读或者写操作的选择
按照上面的规则配置好该寄存器,硬件会自动产生 MDIO 时序和 PHY 通讯。
3、读写 PHY
- 一般通过读取 PHY 的器件 ID 来测试与 PHY 通讯是否正常。首先需要确定 PHY 的 ID,一般是由硬件配置的。从手册中找到 器件ID 的寄存器地址,然后使用 MDIO 读写即可。下面代码为读取 88e1512 的 ID 的示例.
#define MARVELL_PHY_ID_88E1512 0x01410dd1
#define MII_MARVELL_PHY_PAGE 22
#define GMII_PHYID1 2 /* PHY Idendifier Register 1 */
#define GMII_PHYID2 3 /* PHY Idendifier Register 2 */
#define PHY_ID1_SHIFT (16)
UINT uiAddr = 0;
UINT16 usValue;
UINT32 uiID;
// mv88e1512
pfuncPhyWrite(uiAddr, MII_MARVELL_PHY_PAGE, 0);//切换 phy 的 page 0
pfuncPhyRead(uiAddr, GMII_PHYID1, &usValue); // 读 ID
uiID = usValue << PHY_ID1_SHIFT;
pfuncPhyRead(uiAddr, GMII_PHYID2, &usValue);
uiID |= usValue;
uiID &= 0xFFFFFFFF;
4、switch 的配置
- 某些 switch 芯片也可以挂在 MDIO 总线上来进行配置(需要注意某些 MCU 的 MAC 不支持超过 32 个寄存器地址的配置方式),也有使用 SPI 的方式进行配置。
由于 switch 的寄存器过多,所以发明了新的配置方式(不同于上面的 phy 的直接写地址+数据),新的方式是一次写数据需要进行2次操作,类似 eeprom 的读写,需要地址和数据分开两次写入,进行2次操作。下面代码示例展示了 2 个 write 调用写入一个 val 的过程。
读接口类似,但是先要写入读取的地址,然后再读数据,本例没有在代码中展示。
#define MV88E6XXX_SMI_DATA 0x01
#define MV88E6XXX_SMI_CMD 0x00
#define MV88E6XXX_SMI_CMD_BUSY 0x8000
#define MV88E6XXX_SMI_CMD_MODE_22 0x1000
#define MV88E6XXX_SMI_CMD_OP_22_WRITE 0x0400
pfuncPhyWrite(phyid, MV88E6XXX_SMI_DATA, data);
pfuncPhyWrite(phyid,
MV88E6XXX_SMI_CMD,
MV88E6XXX_SMI_CMD_BUSY |
MV88E6XXX_SMI_CMD_MODE_22 |
MV88E6XXX_SMI_CMD_OP_22_WRITE |
(dev << 5) | reg);