本帖最后由 UT发布 于 2025-5-16 11:12 编辑
第一步 : 自定义 LWIP 库版本号修改
复制一份你安装的版本的软件最新的库
修改如下文件:
修改 lwip211.mld文件中的版本标识(如将 OPTION VERSION =1 .5 ;改为 2 .0 ), 尽量改大一些,避免 Vitis环境缓存旧库
第二步 : 修改 LWIP 库文件新增以太网芯片的适配
需要修改xemacpsif_physpeed.c或者xaxiemacif_physpeed.c文件 ,分别对应了 ARM 自带的以太网接口使用 MIO 实现以太网功能 LWIP 部分修改和 PL 部分基于 AXI 总线 gig_ethernet_pcs_pma 以太网 IP 扩展以太网使用 LWIP 需要修改的文件。
1: 添加, YT8531 的 PHY标识符
xemacpsif_physpeed.c或者xaxiemacif_physpeed.c文件中增加如下定义
#define PHY_YT8531_IDENTIFIER 0x4f51
2:ARM 自带的以太网接口 xemacpsif_physpeed.c文件修改
第一个修改位置:
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;
else
emacnum = 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));
if (emacnum == 0)
phymapemac0[phy_addr] = TRUE;
else
phymapemac1[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) &&
(phy_reg != PHY_YT8531_IDENTIFIER))
{
xil_printf("WARNING: Not a Marvell or TI or Realtek or YT8531 Ethernet PHY. Please verify the initialization sequence\r\n");
}
}
}
} 复制代码
第二个修改的位置:
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_YT8531_IDENTIFIER) {
RetStatus = get_YT8531_phy_speed(xemacpsp, phy_addr);
} else {
RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
}
return RetStatus;
} 复制代码
第三个修改位置:
复制代码中已经有的get_Realtek_phy_speed函数,修改为,get_YT8531_phy_speed函数,并且对读取的速率寄存器部分修改,读取的值含义对照 YT8531 芯片手册进行速率部分转换为 1000/100/10 三种速度
static u32_t get_YT8531_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;
xil_printf("Start YT8531 PHY autonegotiation \r\n");
XEmacPs_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);
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);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_RESET_MASK;
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
while (1) {
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
if (control & IEEE_CTRL_RESET_MASK)
continue;
else
break;
}
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
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");
//YT8531 REG
XEmacPs_PhyRead(xemacpsp, phy_addr,0X11,&status_speed);
status_speed = status_speed>>8;
if (status_speed & 0x04) {
temp_speed = status_speed & 0xc0;
if (temp_speed == 0x80)
return 1000;
else if(temp_speed == 0x40)
return 100;
else
return 10;
}
return XST_FAILURE;
} 复制代码
3:PL 扩展 xaxiemacif_physpeed.c文件的修改
第一个修改位置:
detect_phy函数中增加对该PHY的识别
static int detect_phy(XAxiEthernet *xaxiemacp)
{
u16 phy_reg;
u16 phy_id;
u32 phy_addr;
for (phy_addr = 31; phy_addr > 0; phy_addr--)
{
if(PHY_ADDR_CNT_UP)
phy_addr = 32 - phy_addr;
XAxiEthernet_PhyRead(xaxiemacp, 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, ("XAxiEthernet detect_phy: PHY detected at address %d.\r\n", phy_addr));
LWIP_DEBUGF(NETIF_DEBUG, ("XAxiEthernet detect_phy: PHY detected.\r\n"));
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_1_REG,
&phy_reg);
if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&
(phy_reg != TI_PHY_IDENTIFIER) &&
(phy_reg != PHY_REALTEK_IDENTIFIER)&&
(phy_reg != PHY_YT8531_IDENTIFIER)
){
xil_printf("WARNING: Not a Marvell or TI Ethernet PHY. Please verify the initialization sequence\r\n");
}
phyaddrforemac = phy_addr;
return phy_addr;
}
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_1_REG,
&phy_id);
if (phy_id == PHY_XILINX_PCS_PMA_ID1) {
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_2_REG,
&phy_id);
if (phy_id == PHY_XILINX_PCS_PMA_ID2) {
/* Found a valid PHY address */
LWIP_DEBUGF(NETIF_DEBUG, ("XAxiEthernet detect_phy: PHY detected at address %d.\r\n",
phy_addr));
phyaddrforemac = phy_addr;
return phy_addr;
}
}
}
LWIP_DEBUGF(NETIF_DEBUG, ("XAxiEthernet detect_phy: No PHY detected. Assuming a PHY at address 0\r\n"));
/* default to zero */
return 0;
} 复制代码
第二个修改位置 :
get_IEEE_phy_speed函数中,增加对以太网芯片速率识别的调用
unsigned get_IEEE_phy_speed(XAxiEthernet *xaxiemacp)
{
u16 phy_identifier;
u16 phy_model;
u8 phytype;
#ifdef XPAR_AXIETHERNET_0_BASEADDR
u32 phy_addr = detect_phy(xaxiemacp);
/* Get the PHY Identifier and Model number */
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_1_REG, &phy_identifier);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_2_REG, &phy_model);
/* Depending upon what manufacturer PHY is connected, a different mask is
* needed to determine the specific model number of the PHY. */
if (phy_identifier == MARVEL_PHY_IDENTIFIER) {
phy_model = phy_model & MARVEL_PHY_MODEL_NUM_MASK;
if (phy_model == MARVEL_PHY_88E1116R_MODEL) {
return get_phy_speed_88E1116R(xaxiemacp, phy_addr);
} else if (phy_model == MARVEL_PHY_88E1111_MODEL) {
return get_phy_speed_88E1111(xaxiemacp, phy_addr);
}
}
else if (phy_identifier == TI_PHY_IDENTIFIER) {
phy_model = phy_model & TI_PHY_DP83867_MODEL;
phytype = XAxiEthernet_GetPhysicalInterface(xaxiemacp);
if (phy_model == TI_PHY_DP83867_MODEL && phytype == XAE_PHY_TYPE_SGMII) {
return get_phy_speed_TI_DP83867_SGMII(xaxiemacp, phy_addr);
}
if (phy_model == TI_PHY_DP83867_MODEL) {
return get_phy_speed_TI_DP83867(xaxiemacp, phy_addr);
}
}
else if(phy_identifier == PHY_YT8531_IDENTIFIER)
{
return get_YT8531_phy_speed(xaxiemacp, phy_addr);
}
else if(phy_identifier == PHY_REALTEK_IDENTIFIER)
{
return get_Realtek_phy_speed(xaxiemacp, phy_addr);
}
else {
LWIP_DEBUGF(NETIF_DEBUG, ("XAxiEthernet get_IEEE_phy_speed: Detected PHY with unknown identifier/model.\r\n"));
}
#endif
#ifdef PCM_PMA_CORE_PRESENT
return get_phy_negotiated_speed(xaxiemacp, phy_addr);
#endif
} 复制代码
第三个修改位置:
该代码需要复制xemacpsif_physpeed.c代码中已经有的get_Realtek_phy_speed函数,修改为,get_YT8531_phy_speed函数,并且基于 AXI 接口读取寄存器的函数进行修改,最后对读取的速率寄存器部分修改,读取的值含义对照 YT8531 芯片手册进行速率部分转换为 1000/100/10 三种速度
static u32_t get_YT8531_phy_speed(XAxiEthernet *xaxiemacp, u32_t phy_addr)
{
u16_t control;
u16_t status;
u16_t status_speed;
u32_t timeout_counter = 0;
u32_t temp_speed;
xil_printf("Start YT8531 PHY autonegotiation \r\n");
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
control |= IEEE_PAUSE_MASK;
control |= ADVERTISE_100;
control |= ADVERTISE_10;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
&control);
control |= ADVERTISE_1000;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
control);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_RESET_MASK;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
while (1) {
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
if (control & IEEE_CTRL_RESET_MASK)
continue;
else
break;
}
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
sleep(1);
timeout_counter++;
if (timeout_counter == 30) {
xil_printf("Auto negotiation error \r\n");
return XST_FAILURE;
}
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
}
xil_printf("autonegotiation complete \r\n");
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,0X11,&status_speed);
status_speed = status_speed>>8;
if (status_speed & 0x04) {
temp_speed = status_speed & 0xc0;
if (temp_speed == 0x80)
return 1000;
else if(temp_speed == 0x40)
return 100;
else
return 10;
}
return XST_FAILURE;
} 复制代码