ZYNQ使用88E1510 PHY芯片的驱动程序
阅读原文时间:2023年07月09日阅读:2

SDK V2014.4

PHY 88E1510

PL端以太网,自协商

standalone应用程序

PL端设计,略。

根据PL端生成的hdf,新建项目,采用官方lwip echo server例程。发现运行结果为

-----lwIP TCP echo server ------

TCP packets sent to port 6001 will be echoed back

auto-negotiated link speed: 69073

很明显不对。

1、调试发现运行到 xaxiemacif_physpeed.c文件中的get_IEEE_phy_speed()函数时,phy_model = 464 = 0x1D0,不属于例程自带的以下两个型号:

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);
    }
}

2、所以加入该型号的驱动函数:

#define MARVEL_PHY_88E1510_MODEL                  0x1D0

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

    xil_printf("in get_phy_speed_88E1510.\r\n");//FOR DEBUG
    /* Get the PHY Identifier and Model number */
    XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 2, &phy_identifier);
    XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 3, &phy_model);
    phy_model = phy_model & PHY_MODEL_NUM_MASK;

    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) )
    {
        sleep(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;
}

3、然后将 get_IEEE_phy_speed()函数改为:

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);
    }
}

4、编译运行结果正确:

-----lwIP TCP echo server ------

TCP packets sent to port 7 will be echoed back

in get_phy_speed_88E1510.

Waiting for PHY to complete autonegotiation.

autonegotiation complete

auto-negotiated link speed: 1000

Board IP: 192.168.1.10

Netmask : 255.255.255.0

Gateway : 192.168.1.1

TCP echo server started @ port 7

5、官方例程是回显网口数据,即在网口输入什么就输出什么,如果想在串口也输出,可以改下recv_callback()函数:

if (tcp_sndbuf(tpcb) > p->len) {
    err = tcp_write(tpcb, p->payload, p->len, 1);
    xil_printf("%s\n\r",(char*)( p->payload)); //加上这句话即可在串口也回显网口数据
} else
    xil_printf("no space in tcp_sndbuf\n\r");