The board uses the LMK04828 chip to provide clocks for the FPGA's RF-ADC/DAC. For usage methods, please refer to:
The board uses Qualcomm's AR8035-AL1A 10/100/1000M tri-state Ethernet PHY chip. However, this chip cannot be driven by Vitis's built-in LwIP example and needs some modifications to drive this PHY chip.
Generally speaking, there are two methods to modify it: one is to modify the BSP code when creating the project, and the other is to directly modify Vitis's LwIP library code. Here we introduce using the second method, because the first method is more troublesome when frequently modifying BSP settings and regenerating. Moreover, after current testing, the patch method we provide has not brought more side effects.
First, find the file that needs to be modified in the installation folder. Here we take Vitis 2022.2 version as an example:
/tools/Xilinx/Vitis/2022.2/data/embeddedsw/ThirdParty/sw_services/lwip211_v1_8/src/contrib/ports/xilinx/netif/xemacpsif_physpeed.c
At approximately lines 123-128, add the IDENTIFIER macro definition:
#define PHY_MARVELL_IDENTIFIER 0x0141
#define PHY_TI_IDENTIFIER 0x2000
#define PHY_REALTEK_IDENTIFIER 0x001c
#define PHY_ATHEROS_IDENTIFIER 0x004D //<==++++++
#define PHY_XILINX_PCS_PMA_ID1 0x0174
#define PHY_XILINX_PCS_PMA_ID2 0x0C00
At approximately lines 307-311, modify the if statement:
if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&
(phy_reg != PHY_TI_IDENTIFIER) &&
(phy_reg != PHY_REALTEK_IDENTIFIER) &&
(phy_reg != PHY_ATHEROS_IDENTIFIER)) {
xil_printf("WARNING: Not a Marvell or TI or Realtek or Atheros Ethernet PHY. Please verify the initialization sequence\r\n");
}
At approximately line 678, add the register configuration function get_Atheros_phy_speed:
static u32_t get_Atheros_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{
u16_t temp;
u16_t control;
u16_t status;
u16_t status_speed;
u32_t timeout_counter = 0;
u32_t temp_speed;
xil_printf("Start Atheros PHY autonegotiation \r\n");
XEmacPs_PhyRead(xemacpsp, phy_addr, 0xe, &control);
control |= 0x0018;
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0xe, control);
XEmacPs_PhyWrite(xemacpsp,phy_addr, 0x1d, 0x05);
XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1e, &control);
control |= 0x0100;
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1e, control);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1d, 0x0);
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1e, 0x8000);
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);
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
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_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
&control);
control |= (7 << 12); /* max number of gigabit attempts */
control |= (1 << 11); /* enable downshift */
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
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);
XEmacPs_PhyRead(xemacpsp, phy_addr,
IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);
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,IEEE_SPECIFIC_STATUS_REG,
&status_speed);
if (status_speed & 0x400) {
temp_speed = status_speed & IEEE_SPEED_MASK;
if (temp_speed == IEEE_SPEED_1000)
return 1000;
else if(temp_speed == IEEE_SPEED_100)
return 100;
else
return 10;
}
return XST_SUCCESS;
}
At approximately lines 686-692, modify the if statement:
if (phy_identity == PHY_ATHEROS_IDENTIFIER) {
RetStatus = get_Atheros_phy_speed(xemacpsp, phy_addr);
} else 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 {
RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
}
At this point, all patching work is complete, and you can directly use the built-in LwIP routines for the board.
In some cases, we observed that even when the PHY chip is correctly configured, the console still outputs error messages such as "unable to determine type of EMAC with baseaddress". According to debugging, we found that this is caused by defects in the LwIP library file provided by Vitis, which can be patched.
First, find the file that needs to be modified. Here we take Vitis 2022.2 version as an example:
/tools/Xilinx/Vitis/2022.2/data/embeddedsw/ThirdParty/sw_services/lwip211_v1_8/src/contrib/ports/xilinx/netif/xadapter.c
Correct the switch-case statement between lines 136-184, adding break; after each case:
/* initialize based on MAC type */
switch (find_mac_type(mac_baseaddr)) {
case xemac_type_xps_emaclite:
#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
nif = netif_add(netif, ipaddr, netmask, gw,
(void*)(UINTPTR)mac_baseaddr,
xemacliteif_init,
#if NO_SYS
ethernet_input
#else
tcpip_input
#endif
);
#else
nif = NULL;
#endif
break; //<==++++++
case xemac_type_axi_ethernet:
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
nif = netif_add(netif, ipaddr, netmask, gw,
(void*)(UINTPTR)mac_baseaddr,
xaxiemacif_init,
#if NO_SYS
ethernet_input
#else
tcpip_input
#endif
);
#else
nif = NULL;
#endif
break; //<==++++++
#if defined (__arm__) || defined (__aarch64__)
case xemac_type_emacps:
#ifdef XLWIP_CONFIG_INCLUDE_GEM
nif = netif_add(netif, ipaddr, netmask, gw,
(void*)(UINTPTR)mac_baseaddr,
xemacpsif_init,
#if NO_SYS
ethernet_input
#else
tcpip_input
#endif
);
#endif
break; //<==++++++
#endif
default:
xil_printf("unable to determine type of EMAC with baseaddress 0x%08x\r\n",
mac_baseaddr);
}