【AMD Xilinx】ZUBoard(5):移植KSZ9131千兆phy驱动

2024-01-05 09:20

本文主要是介绍【AMD Xilinx】ZUBoard(5):移植KSZ9131千兆phy驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【AMD Xilinx】ZUBoard(5):移植KSZ9131千兆phy驱动

  • 一、需求
  • 二、软件搭建
    • 1. 在bsp中添加lwip库
    • 2. 创建lwip的例子
  • 三、 Phy驱动调试
    • 1. 问题查找
    • 2. 修改驱动
      • 1) 查找芯片手册
      • 2)增加宏PHY_MICROCHIP_IDENTIFIER
      • 3)修改函数detect_phy
      • 3)修改函数get_IEEE_phy_speed
      • 4)增加get_Microchip_phy_speed的具体实现
    • 3. 重新测试
  • 四、网口灯工作状况说明
    • 1.正常网口灯说明
    • 2. 排查过程记录

一、需求

在hackster.io上看到有人问板上的phy在裸机模式下怎么驱动。

https://www.hackster.io/whitney-knitter/getting-started-with-avnet-s-zuboard-1cg-f1d793

在这里插入图片描述

嗨,我刚买了这块板来尝试一些在同一设备上混合软件和hdl的项目。我试图在A53-0上建立并运行一些UDP通信(在独立/裸机应用程序中),并尝试了UDP模板应用程序。不幸的是,Avnet在板上安装了一个不支持的以太网PHY芯片(Microchip
KSZ9131RNXC ),模板无法初始化它。 你知道有没有这种芯片的初始化代码的独立版本的例子吗? 提前感谢。

这个phy在linux下识别是没问题的,而官方demo都是在linux下跑的,因此不需要考虑这个问题。

但是裸机模式下默认的驱动确实不支持,所以需要我们手动修改。

二、软件搭建

1. 在bsp中添加lwip库

首先在bsp包中添加lwip库,否则在软件模板中没法生成带lwip的例程。

选中platform.spr,选A53对应的Board Support Package,点Modify BSP Settings
在这里插入图片描述

选中lwip211,点ok重新编译bsp
在这里插入图片描述

注意在standalone界面,可以修改stdin和stdout的串口。一般现成的开发板串口都是固定uart0或者uart1,其实是可以自定义修改的。

在这里插入图片描述

2. 创建lwip的例子

bsp编译完成后,创建新程序,选lwIP Echo Server模板

在这里插入图片描述
创建完成后,打开main.c,根据你自己的网络环境,修改ip地址、掩码、网关,然后运行
在这里插入图片描述

运行起来一直卡在这里
在这里插入图片描述

三、 Phy驱动调试

1. 问题查找

单步跟踪发现进入到init_emacps后,问题出在函数XEmacPs_SetOperatingSpeed

源代码路径psu_cortexa53_0/standalone_psu_cortexa53_0/bsp/psu_cortexa53_0/libsrc/lwip211_v1_7/src/contrib/ports/xilinx/netif/xemacpsif_hw.c

在这里插入图片描述
因为speed只能为10,100,1000,而实际值识别到的speed为0,所以导致错误。




再回头看刚才的打印信息

在这里插入图片描述
原因很明显了,驱动默认只支持Marvell、TI、Realtek这三个品牌的phy,其他品牌的phy需要我们自己根据手册来写驱动

2. 修改驱动

在这里插入图片描述

可以看到

		XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,&phy_reg);if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&(phy_reg != PHY_TI_IDENTIFIER) &&(phy_reg != PHY_REALTEK_IDENTIFIER)) {xil_printf("WARNING: Not a Marvell or TI or Realtek Ethernet PHY. Please verify the initialization sequence\r\n");}

关键是XEmacPs_PhyRead读PHY_IDENTIFIER_1_REG寄存器的值,根据这个值判断厂家型号

#define PHY_IDENTIFIER_1_REG					2#define PHY_MARVELL_IDENTIFIER				0x0141
#define PHY_TI_IDENTIFIER					0x2000
#define PHY_REALTEK_IDENTIFIER				0x001c

所以要做的第一步就是查芯片手册,找到寄存器2对应的值,增加一个品牌分支

1) 查找芯片手册

查下原理图,用的phy芯片是Microchip KSZ9131RNXC
在这里插入图片描述

在这里插入图片描述

https://www.microchip.com/en-us/product/KSZ9131#document-table

2)增加宏PHY_MICROCHIP_IDENTIFIER

根据手册查找对应的寄存器描述,phy的id应该为0x0022

因此增加宏PHY_MICROCHIP_IDENTIFIER,值为0x0022

#define PHY_MICROCHIP_IDENTIFIER            0x0022

3)修改函数detect_phy

修改函数
void detect_phy(XEmacPs *xemacpsp)

void detect_phy(XEmacPs *xemacpsp)
{u16_t phy_reg;u32_t phy_addr;u32_t emacnum;if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR)emacnum = 0;elseemacnum = 1;for (phy_addr = 31; phy_addr > 0; phy_addr--) {XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,&phy_reg);if ((phy_reg != 0xFFFF) &&((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {/* Found a valid PHY address */LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",phy_addr));xil_printf(("XEmacPs detect_phy: PHY detected at address %d.\r\n", phy_addr));if (emacnum == 0)phymapemac0[phy_addr] = TRUE;elsephymapemac1[phy_addr] = TRUE;XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,&phy_reg);if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&(phy_reg != PHY_TI_IDENTIFIER) &&(phy_reg != PHY_REALTEK_IDENTIFIER)) {xil_printf("WARNING: Not a Marvell or TI or Realtek Ethernet PHY. Please verify the initialization sequence\r\n");if(PHY_MICROCHIP_IDENTIFIER == phy_reg){xil_printf("Phy: MICROCHIP --Add by Leo 2023.12\r\n");}}}}
}

3)修改函数get_IEEE_phy_speed

修改速度函数,增加对Microchip的判断分支

static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{u16_t phy_identity;u32_t RetStatus;XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,&phy_identity);if (phy_identity == PHY_TI_IDENTIFIER) {RetStatus = get_TI_phy_speed(xemacpsp, phy_addr);} else if (phy_identity == PHY_REALTEK_IDENTIFIER) {RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr);} else if (phy_identity == PHY_MICROCHIP_IDENTIFIER) { //增加了对Microchip的判断分支RetStatus = get_Microchip_phy_speed(xemacpsp, phy_addr); } else {RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);}return RetStatus;
}

4)增加get_Microchip_phy_speed的具体实现

然后再增加get_Microchip_phy_speed的具体实现,
仔细对比了寄存器的差别,主要是速度寄存器的地址和解析与ieee不一样

注意要禁用RX delay和TX delay。开始我没有设置,在100M下工作正常,在1000M下怎么都ping不通,反复查了好久还以为是网络拓扑有问题,最后才发现是这个问题。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//Add by Leo Wang
#define MICROCHIP_CONTROL_REG  0x1F#define MICROCHIP_SPEED_MASK  0x0070
#define MICROCHIP_SPEED_1000  0x0040
#define MICROCHIP_SPEED_100   0x0020
#define MICROCHIP_SPEED_10    0x0010#define MMD_FUNCTION_DATA           0x4000static u32_t read_mmd_register(XEmacPs *InstancePtr, u32 PhyAddress, u32 devadd,u32 RegisterNum, u16 *PhyDataPtr)
{u32_t phyregtemp;u32_t RetStatus;XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd);XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_ADDAR, RegisterNum);XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd | MMD_FUNCTION_DATA);RetStatus = XEmacPs_PhyRead(InstancePtr, PhyAddress, PHY_ADDAR, (u16_t *)&phyregtemp);if (RetStatus != XST_SUCCESS) {return XST_FAILURE;}*PhyDataPtr= phyregtemp;return XST_SUCCESS;
}static u32_t write_mmd_register(XEmacPs *InstancePtr, u32 PhyAddress, u32 devadd,u32 RegisterNum, u16 PhyData)
{XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd);XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_ADDAR, RegisterNum);XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_REGCR, devadd | MMD_FUNCTION_DATA);XEmacPs_PhyWrite(InstancePtr, PhyAddress, PHY_ADDAR, PhyData);return XST_SUCCESS;
}#define KSZ9131RN_MMD_COMMON_CTRL_REG	2
#define KSZ9131RN_RXC_DLL_CTRL		0x4c   //2.76
#define KSZ9131RN_TXC_DLL_CTRL		0x4d   //2.77
#define MICROCHIP_DLL_DELAY_NOT_USED	0x1000  //bit12 bypass rxdll/txdllstatic u32_t get_Microchip_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{u16_t control;u16_t status;u16_t status_speed;u32_t timeout_counter = 0;u32_t temp_speed;u32_t RetStatus;xil_printf("Start PHY autonegotiation \r\n");XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control | IEEE_CTRL_RESET_MASK);sleep(1);RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);if (RetStatus != XST_SUCCESS) {xil_printf("Error during reset \n\r");return XST_FAILURE;}//RGMII_ID SETUP#if 0// --> RXRetStatus = read_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_RXC_DLL_CTRL, &control);if (RetStatus != XST_SUCCESS) {xil_printf("Error setting RX delay\n\r");return XST_FAILURE;}control &= ~MICROCHIP_DLL_DELAY_NOT_USED;write_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_RXC_DLL_CTRL, control);
#endif
#if 1//  --> TXRetStatus = read_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_TXC_DLL_CTRL, &control);if (RetStatus != XST_SUCCESS) {xil_printf("Error setting TX delay\n\r");return XST_FAILURE;}control &= ~MICROCHIP_DLL_DELAY_NOT_USED;write_mmd_register(xemacpsp, phy_addr, KSZ9131RN_MMD_COMMON_CTRL_REG, KSZ9131RN_TXC_DLL_CTRL, control);
#endif//REG4 10/100/1000MXEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);control |= IEEE_ASYMMETRIC_PAUSE_MASK;control |= IEEE_PAUSE_MASK;control |= ADVERTISE_100;control |= ADVERTISE_10;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,&control);control |= ADVERTISE_1000;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,control);//REG0 1.自动协商使能 2.自动协商复位XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;control |= IEEE_STAT_AUTONEGOTIATE_RESTART;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);//读REG1状态寄存器XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);xil_printf("Waiting for PHY to complete autonegotiation.\r\n");//根据bit5判断协商是否完成,没完成就一直等待,直到30秒超时while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {sleep(1);timeout_counter++;if (timeout_counter == 30) {xil_printf("Auto negotiation error \r\n");return XST_FAILURE;}XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);}xil_printf("autonegotiation complete \r\n");//主要是修改这个速度寄存器的解析XEmacPs_PhyRead(xemacpsp, phy_addr, MICROCHIP_CONTROL_REG,&status_speed);xil_printf("MICROCHIP_CONTROL_REG = 0x%.4x \r\n", status_speed);if (0 == (status_speed & 0x0001)) {temp_speed = status_speed & MICROCHIP_SPEED_MASK;if (temp_speed == MICROCHIP_SPEED_1000)return 1000;else if(temp_speed == MICROCHIP_SPEED_100)return 100;elsereturn 10;}return XST_FAILURE;
}

寄存器0x1F说明如下:
在这里插入图片描述

3. 重新测试

运行结果:
正常识别到phy速度,我在电脑端用的是usb转百兆网卡,点对点方式连接的开发板,因此识别出来的速度是100M。

如果连到路由器这个值有可能是100或者1000。

现在10M网卡基本见不到了,如果显示是10大概率还是工作不正常,需要另行分析。

如果有多个网卡,windows下用-S(srcaddr的意思)来指定源网卡ip,linux下改成-I(interface)
192.168.1.100是电脑ip
192.168.1.10是开发板的ip

ping -S 192.168.1.100 192.168.1.10 -t

命令后的-t是一直ping,没有这个参数ping 4次就会停下来
在这里插入图片描述

在电脑端ping这个ip,正常ping通,说明phy确实已经正常工作。
在这里插入图片描述

四、网口灯工作状况说明

这个phy的led有点特殊,我开始以为寄存器没配置对,仔细查了手册,发现正常工作就是这样。

1.正常网口灯说明

我们正常的网口会有两个灯:
连接指示灯(绿色):连接指示灯亮就代表线路连接正常。

信号指示灯(黄色)
在连接指示灯亮的情况下,信号指示灯的含义如下:
a) 如果信号指示灯闪烁,代表信号正常,正在通信;
b) 如果信号指示灯灭,代表没有通信;
c) 如果信号指示灯长亮,代表网线短路。

而在这个板子
直接与电脑相连(100M):左边灯不亮,右边黄色闪烁。
连路由器(1000M):左边绿灯亮,隔几秒闪一下。右边灯不亮

2. 排查过程记录

先查RJ-45座的型号,ARJM11C7-502-KB-EW2,根据手册确定两个led各对应哪个io

https://abracon.com/Magnetics/ARJM11.pdf

根据手册和原理图,可以看出左边的灯对应的是Phy芯片的LED_LINK(LED2),右边的黄灯对应LED_Y(LED_ACT, LED1)

在phy手册里面有说明,在1000M情况下,LED2亮和闪烁。在100M的情况下,LED1常亮和闪烁。所以正常情况下,不会出现两个灯同时亮,只有1个灯会亮

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

再查Phy芯片手册
在这里插入图片描述
在这里插入图片描述

这篇关于【AMD Xilinx】ZUBoard(5):移植KSZ9131千兆phy驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/572398

相关文章

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

驱动(RK3588S)第七课时:单节点设备树

目录 需求一、设备树的概念1、设备树的后缀名:2、设备树的语法格式3、设备树的属性(重要)4、设备树格式举例 二、设备树所用函数1、如何在内核层种获取设备树节点:2、从设备树上获取 gpio 口的属性3、获取节点上的属性只针对于字符串属性的4、函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的

驱动安装注册表指令

HKCR: HKEY_CLASSES_ROOT HKCU: HKEY_CURRENT_USER HKLM: HKEY_LOCAL_MACHINE HKU: HEKY_USER HER: 相对根键

UMDF驱动安装

VS2013 + WDF8.1,UMDF驱动选择User Mode Driver,不要选User Mode Driver 2.0,否则Win7安装有问题,如图 另外,在驱动安装时不要忘记WUDFUpdate_<主版本号><次版本号>.dll文件,具体文件名在INF中查找。此文件可在WDF的安装目录中找到。注意:在WDF的安装目录中会有3个WUDFUpdate_xxx.dll文件,x86,x6

电脑驱动分类

电脑驱动程序(驱动程序)是操作系统与硬件设备之间的桥梁,用于使操作系统能够识别并与硬件设备进行通信。以下是常见的驱动分类: 1. 设备驱动程序 显示驱动程序:控制显卡和显示器的显示功能,负责图形渲染和屏幕显示。 示例:NVIDIA、AMD 显示驱动程序。打印机驱动程序:允许操作系统与打印机通信,控制打印任务。 示例:HP、Canon 打印机驱动程序。声卡驱动程序:管理音频输入和输出,与声卡硬件

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本  1.2 认识Nano版本 2 STM32F446U上移植RT-Thread  2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet  2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码  2.2.3.

麒麟系统安装GPU驱动

1.nvidia 1.1显卡驱动 本机显卡型号:nvidia rtx 3090 1.1.1下载驱动 打开 https://www.nvidia.cn/geforce/drivers/ 也可以直接使用下面这个地址下载 https://www.nvidia.com/download/driverResults.aspx/205464/en-us/ 1.1.3安装驱动 右击,

windows10 卸载网络驱动以及重新安装

右键桌面此电脑的图标,点击管理,设备管理器—网络适配器,找到下图中的驱动(不同的系统或者显卡会导致网卡驱动名称与下图不一样,多为Realtek开头),右键选择卸载设备,然后重启电脑,系统会自动重新安装驱动 新电脑首次安装驱动: 根据主板厂家,比如华硕,进入华硕官网,点击服务支持,点击下载中心,选择型号,点击右侧驱动程序和工具软件,选择windows版本,下载相应的驱动,下载完之后在对应文件中找

笔记整理—内核!启动!—kernel部分(1)驱动与内核的关系

首先,恭喜完成了uboot部分的内容整理,其次补充一点,uboot第一部分和第二部分的工作不是一定的,在不同的版本中,可能这个初始化早一点,那个的又放在了第二部分,版本不同,造成的工作顺序不同,但终归是要完成基本内容初始化并传参给kernel的。         那么至于驱动与内核的关系,用一张图来说明最适合不过:         驱动位于OS层的中下层与硬件相接。驱动是内