Example design for the Ethernet FMC on the ZedBoard using 4 AXI Ethernet blocks
C Tcl CartoCSS Makefile Batchfile
Permalink
Failed to load latest commit information.
SDK updated for Vivado 2016.1 Apr 28, 2016
Vivado corrected script names Jun 19, 2016
README.md added "repo moved" message Jun 19, 2016

README.md

zedboard-qgige-axieth

This repo has moved

This repo has been merged into the Ethernet FMC AXI Ethernet repo in an effort to group similar example designs into a common repository and simplify code maintenance. Please use the linked repository for the latest sources.

Example design for the Quad Gigabit Ethernet FMC on the ZedBoard using AXI Ethernet

Description

This project demonstrates the use of the Opsero Quad Gigabit Ethernet FMC. The design contains 4 AXI Ethernet blocks configured with DMAs.

All AXI Ethernet

Requirements

Single port limit

This example supports lwIP running on only one port of the Ethernet FMC. You can configure the port on which to run lwIP by setting the ETH_FMC_PORT define in the main.c file of the SDK application. Valid values for ETH_FMC_PORT are 0,1,2 or 3.

Library modifications for Vivado 2016.1

To use this project, some modifications must be made to the lwIP libraries provided by the Xilinx SDK. These modifications can be made either to the BSP code of your SDK workspace, or to the SDK sources. I personally recommend modifying the SDK sources as every rebuild of the BSP results in the BSP sources being overwritten with the SDK sources.

Modification to xaxiemacif_dma.c

Open the following file:

C:\Xilinx\SDK\2016.1\data\embeddedsw\ThirdParty\sw_services\lwip141_v1_4\src\contrib\ports\xilinx\netif\xaxiemacif_dma.c

Replace this line of code:

dmaconfig = XAxiDma_LookupConfig(XPAR_AXIDMA_0_DEVICE_ID);

With this one:

dmaconfig = XAxiDma_LookupConfig(xemac->topology_index);

Modification to xaxiemacif_physpeed.c

Open the following file:

C:\Xilinx\SDK\2016.1\data\embeddedsw\ThirdParty\sw_services\lwip141_v1_4\src\contrib\ports\xilinx\netif\xaxiemacif_physpeed.c

Add the following define statement to the code:

#define MARVEL_PHY_88E1510_MODEL 0x1D0

That defines the PHY model identifier for the Marvell 88E1510 PHYs that are found on the Ethernet FMC.

Add the following function code just above the function called get_IEEE_phy_speed:

unsigned int get_phy_speed_88E1510(XAxiEthernet *xaxiemacp, u32 phy_addr)
{
    u16 temp;
    u16 control;
    u16 status;
    u16 partner_capabilities;

    xil_printf("Start PHY autonegotiation \r\n");

    XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
    XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
    //control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
    control &= ~(0x10);
    XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, control);

    XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);

    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_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
    XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
                                                                &control);
    control |= (7 << 12);   /* max number of gigabit attempts */
    control |= (1 << 11);   /* enable downshift */
    XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
                                                                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;
    }
    xil_printf("Waiting for PHY to complete autonegotiation.\r\n");

    XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
    while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
        AxiEthernetUtilPhyDelay(1);
        XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2,
                                                                    &temp);
        if (temp & IEEE_AUTONEG_ERROR_MASK) {
            xil_printf("Auto negotiation error \r\n");
        }
        XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET,
                                                                &status);
        }

    xil_printf("autonegotiation complete \r\n");

    XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &partner_capabilities);

    if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */
        return 1000;
    else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */
        return 100;
    else                    /* 10Mbps */
        return 10;
}

That is a custom function that communicates with the 88E1510 PHY to determine the autonegotiated link speed.

Now find this block of code:

    if (phy_identifier == MARVEL_PHY_IDENTIFIER) {
        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);
        }
    }

and replace it with this block of code:

    if (phy_identifier == MARVEL_PHY_IDENTIFIER) {
        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_model == MARVEL_PHY_88E1510_MODEL) {
            return get_phy_speed_88E1510(xaxiemacp, phy_addr);
        }
    }

We have just added an extra else-if statement to call our custom PHY speed function added earlier.

License

Feel free to modify the code for your specific application.

Fork and share

If you port this project to another hardware platform, please send me the code or push it onto GitHub and send me the link so I can post it on my website. The more people that benefit, the better.

About the author

I'm an FPGA consultant and I provide FPGA design services to innovative companies around the world. I believe in sharing knowledge and I regularly contribute to the open source community.

Jeff Johnson FPGA Developer