如何使用gpio模拟mdio通信?
点击左上方蓝色“ 一口Linux ”,选择“ 设为星标 ”
一、前言
实际项目开发中,由于设计原因,会将phy的mdio引脚连接到SoC的2个空闲gpio上,
这样就无法通过Gmac自有的架构实现修改phy,
因此只能通过GPIO模拟的方式实现MDIO,
好在Linux支持MDIO via GPIO功能。
该功能需要用到内核驱动mdio-bitbang.c和mdio-gpio.c。
本例 :
-
平台:
复旦微
-
kernel 版本:
linux 4.14.55-xxxxx
-
phy芯片
yt8521
-
phy连接到
gmac0
-
mdio总线连接到:
gpioc 2
portc 3
二、mdio基础概念
1、SMI接口
SMI是MAC内核访问PHY寄存器接口,它由两根线组成,双工:
-
MDC(Management Data Clock)为时钟,
-
MDIO(Management Data Input/Output)为双向数据通信,
原理上跟I2C总线很类似,也可以通过总线访问多个不同的phy。
MDIO协议是以太网标准IEEE802.3中专门用于MAC和PYH之间管理的串行接口总线,该接口主要用于MAC控制器对PYH层的状态读取和设置(寄存器操作)、获取链路状态,控制物理层协商等操作。
MDC/MDIO基本特性:
-
两线制 :MDC(时钟线)和MDIO(数据线)。分主从设备。
-
时钟频率:2.5MHz
-
通信方式:总线制,可同时接入的PHY数量为32个
-
通过SMI接口,MAC芯片主动的轮询PHY层芯片,获得状态信息,并发出命令信息。
其中主设备称作STA,从设备称作MDI,一个主设备可以对多个从设备进行命令读写操作。
三、mdio协议波形
1、MDIO接口数据帧
在IEEE802.3协议中,把MDIO接口数据帧分为两种,一种是 Clause22 ,另一种是 Clause45 。
前者主要用于百兆千兆以太网,后者用于千兆以上的以太网。
2、Clause22
MDIO 接口的读写通信协议如下图所示:
-
Preamble:
32 位前导码,由 MAC 端发送 32 位逻辑“1”,用于同步 PHY 芯片。
-
ST(Start of Frame):
2 位帧开始信号,用 01 表示。
-
OP(Operation Code):
2 位操作码,读:10 写:01。
-
PHYAD(PHY Address):
5 位 PHY 地址,用于表示与哪个 PHY 芯片通信,因此一个 MAC 上可以连 接多个 PHY 芯片。
-
REGAD(Register Address):
5 位寄存器地址,可以表示共 32 位寄存器。
-
TA(Turnaround):
2 位转向,
在读命令中,MDIO 在此时由 MAC 驱动改为 PHY 驱动,在第一个 TA 位,MDIO 引脚为高阻状态,第二个 TA 位,PHY 将 MDIO 引脚拉低,准备发送数据;
在写命令中,不需 要 MDIO 方向发生变化,MAC 固定输出 2’b10,随后开始写入数据。
-
DATA:
16 位数据,在读命令中,PHY 芯片将读到的对应 PHYAD 的 REGAD 寄存器的数据写到 DATA 中;在写命令中,PHY 芯片将接收到的 DATA 写入 REGAD 寄存器中。需要注意的是,在 DATA 传 输的过程中,高位在前,低位在后。
-
IDLE:
空闲状态,此时 MDIO 为无源驱动,处于高阻状态,但一般用上拉电阻使其上拉至高电平。
波形举例
向phy:3 寄存器0x00 写入 数据0x4140
3、Clause45
四、YT8521
YT8521S是一款高度集成的以太网收发器,符合10BASE-Te、100BASE-TX和1000BASE-T IEEE 802.3标准。
1、引脚
其中与mdio相关引脚:
14 MDC Management Data Clock
15 MDIO Input/Output of Management Data.
Pull up 3.3V/2.5V/1.8V for 3.3V/2.5V/1.8V I/O respectively
2、模块图
3、MDIO协议时序-[重要]
下面YT8521的SMI时序图:
上升沿读数据,下降沿写数据
五、驱动移植
1、驱动文件及移植
mdio-gpio.c
mdio-bitbang.c
勾选 下面几项:
│ │ <*> Bitbanged MDIO buses │ │
│ │ <*> GPIO controlled MDIO bus multiplexers │ │
│ │ <*> MMIO device-controlled MDIO bus multiplexers │ │
2、移植设备树
aliases {
…………
mdio-gpio0 = &mdio0;
};
mdio0: mdio {
compatible = "virtual,mdio-gpio";
gpios = <&portc 2 0 >,<&portc 3 0>;
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@7 {
reg = <0x7>;
yt,phy-delay = <0xfc>;
phy-connection-type = "rgmii-id";
};
};
&gmac0 {
status = "okay";
phy-handle = <&phy0>;
};
由设备树可知,
-
我们创建了1个独立的mdio设备节点,
-
当用命令mdio修改phy时,就会根据gmac0的phy-handle,
-
找到mdio0节点从而调用mdio-gpio驱动模块来配置phy:8521。
下图,是phy直接连接到gmac0的mdio接口,mdio命令执行的通路:
下图是phy连接到gpio口,mdio命令执行的通路:
3、查看log
开机有以下log,说明驱动 移植成功:
# dmesg | grep MDIO
[ 3.257270] libphy: GPIO Bitbanged MDIO: probed
[ 3.274202] libphy: Fixed MDIO Bus: probed
# cd /sys/class/mdio_bus/
# ls
fixed-0 gpio-0 stmmac-0 stmmac-1
# cd gpio-0/
# ls
device gpio-0:03 of_node power subsystem uevent
# cd gpio-0\:03/
# ls
attached_dev phy_has_fixups power
driver phy_id subsystem
of_node phy_interface uevent
4、操作
修改eth0为百兆速率,则设置Speed_Selection位为 01 ,同时自动协商为Autoneg_En要禁用,即设置该寄存器值为0x2140:
# mdio eth0 0x00 0x2140
write phy addr: 0x3 reg: 0x0 value : 0x2140
抓取波形如下:
end
一口Linux
关注,回复【 1024 】海量Linux资料赠送
精彩文章合集
文章推荐