1. 为什么需要PL端以太网?
在Zynq和ZynqMP系列芯片中,PS端(Processing System)通常自带1-2个千兆以太网控制器,但实际项目中经常会遇到以下情况:PS端以太网资源不够用、需要特殊PHY芯片支持、或者要在PL端(Programmable Logic)实现定制化网络协议。这时候就需要在PL端实现以太网功能。
我最近在一个工业网关项目中就遇到了这种情况:PS端两个以太网口已经分别用于上下行通信,但客户临时要求增加第三个网口用于设备调试。这时候PL端以太网就成了救命稻草。不过从硬件配置到驱动移植的完整过程,确实踩了不少坑。
2. EMIO配置实战
2.1 Vivado中的关键设置
在Vivado中通过EMIO引出PL端以太网时,有几个参数特别容易出错:
PHY Address:这个地址不是实际PHY芯片的地址!官方文档说得比较模糊,实测发现这里应该填一个虚拟地址(比如默认的8),必须与实际PHY地址不同才能正常工作。我在项目中用的KSZ9031 PHY地址是1,这里就填了8。
时钟偏斜(Skew):RGMII协议要求TX_CLK要有2ns的延迟。在"Provide 2ns skew on RGMII TXC"选项中:
- 如果PHY芯片自带延迟功能(如KSZ9031),选"Skew added by PHY"
- 如果PHY不支持延迟,选"Add 2ns skew in the IP"
共享逻辑(Shared Logic):单路GMII2RGMII转换选"Include Shared Logic in Core"最省事。但如果是多路设计,可能需要选"External"模式统一管理时钟和复位。
2.2 硬件连接注意事项
复位信号:GMII2RGMII IP的tx_reset和rx_reset是高电平有效,而Zynq的PS复位通常是低电平,记得加个反相器。可以直接用Verilog实现:
assign gmii_rst_n = ~ps_reset;时钟输入:
- Zynq-7000系列需要200MHz时钟
- ZynqMP系列需要375MHz时钟 这个时钟必须来自PS端的FPGA时钟输出(通过CLK_WIZ生成),不能直接用外部晶振!
3. 裸机调试技巧
3.1 修改lwIP驱动支持自定义PHY
Xilinx提供的lwIP驱动默认只支持少数PHY芯片,遇到非常规PHY(比如Microchip的KSZ系列)就需要自己动手改代码。关键修改点在xemacpsif_physpeed.c文件:
添加PHY识别码:
#define MICREL_PHY_IDENTIFIER 0x00221620 // KSZ9031的ID实现专用的速度获取函数:
static u32_t get_phy_speed_ksz9031(XEmacPs *xemacpsp, u32_t phy_addr) { // 详细实现参考原厂手册的寄存器配置 // 特别注意RGMII时钟延迟的配置 XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control); control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK; // 开启延迟 XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control); // ...其他配置 }在
get_IEEE_phy_speed()函数中添加分支判断:if(phy_identity == MICREL_PHY_IDENTIFIER){ RetStatus = get_phy_speed_ksz9031(xemacpsp, phy_addr); }
3.2 GMII2RGMII的宏定义陷阱
很多人调试不通是因为漏掉了关键宏定义。在xparameters.h中必须添加:
#define XPAR_GMII2RGMIICON_0N_ETH0_ADDR 8 // 与Vivado中设置的虚拟地址一致这个地址会被phy_setup_emacps()函数用来配置速度模式(10/100/1000Mbps)。
4. Linux驱动移植详解
4.1 内核配置与设备树编写
使用PetaLinux定制系统时,需要确保:
内核配置开启GMII2RGMII驱动:
CONFIG_XILINX_GMII2RGMII=y设备树配置(以Gem1为例):
&gem1 { gmii2rgmii-phy-handle = <&gmii_to_rgmii_0>; phy-handle = <&phy1>; ps7_ethernet_1_mdio: mdio { #address-cells = <1>; #size-cells = <0>; phy1: phy@1 { device_type = "ethernet-phy"; // PHY特有配置 }; gmii_to_rgmii_0: phy@8 { compatible = "xlnx,gmii-to-rgmii-1.0"; reg = <8>; // 必须与Vivado虚拟地址一致 phy-handle = <&phy1>; }; }; };
4.2 常见版本兼容性问题
不同版本的Linux内核驱动可能有细微差异:
4.19版本:需要手动添加时钟绑定,否则会报错:
clocks = <&clk_core>; // 添加时钟引用 clock-names = "idelay_ctrl";5.10版本:驱动改用了新的框架,设备树需要增加:
xlnx,phy-type = <1>; // 1表示RGMII时钟警告:常见提示"gmii_to_rgmii: missing clock",实测不影响功能,可以通过修改驱动代码屏蔽相关打印。
5. 调试经验分享
5.1 硬件信号测量
当网络不通时,建议按以下顺序排查:
- 用示波器检查RGMII的TXC时钟是否稳定(125MHz@1000Mbps)
- 测量TXD[3:0]信号是否有数据活动
- 确认PHY芯片的复位信号和供电正常
5.2 软件调试技巧
查看PHY寄存器:
ethtool -d eth1 # 查看PHY寄存器值强制设置速率(排除自动协商问题):
ethtool -s eth1 speed 100 duplex full autoneg off驱动调试信息:
dmesg | grep gmii # 过滤驱动加载日志
我在最近的项目中发现,某些PHY芯片(如RTL8211)需要在上电后延迟至少500ms再进行MDIO访问,否则会配置失败。这种情况可以在设备树中添加reset-delay-us参数:
phy1: phy@1 { reset-delay-us = <500000>; };