lwip: axiethernet: Support to get autoneg speed for different PHYs

Currently, the AXI Ethernet adapter is configured to support only
Marvel PHYs which exist on all Xilinx boards.  This patch allows
to get the auto-negotiation speed of any PHY using IEEE specification.

Signed-off-by: Srikanth Thokala <sthokal@xilinx.com>
Acked-by: Anirudha Sarangi <anirudh@xilinx.com>
This commit is contained in:
Srikanth Thokala 2014-06-06 14:43:53 +05:30 committed by Jagannadha Sutradharudu Teki
parent 2ba225fa69
commit a503a3dd66
2 changed files with 149 additions and 139 deletions

View file

@ -1,5 +1,8 @@
Change Log for lwip
=================================
2014-06-06
* Fix for CR 800240 - Removed the limitation of
supporting only Marvel PHY in AXI Ethernet adapter.
2014-1-30
* Fix for CRs 771112 and 766087. The sys_arch.c
last made (related to freertos) are reverted back.

View file

@ -147,6 +147,85 @@ static int detect_phy(XAxiEthernet *xaxiemacp)
return 0;
}
unsigned get_phy_speed_88E1116R_model(XAxiEthernet *xaxiemacp, u32 phy_addr)
{
u16 phy_val;
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;
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 atphy_valts */
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,
&phy_val);
if (phy_val & 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;
}
unsigned get_IEEE_phy_speed(XAxiEthernet *xaxiemacp)
{
u32 phy_addr = detect_phy(xaxiemacp);
@ -165,6 +244,12 @@ unsigned get_IEEE_phy_speed(XAxiEthernet *xaxiemacp)
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 3, &phy_model);
phy_model = phy_model & PHY_MODEL_NUM_MASK;
if ((phy_identifier == MARVEL_PHY_IDENTIFIER) &&
(phy_model == MARVEL_PHY_88E1116R_MODEL)) {
return get_phy_speed_88E1116R_model(xaxiemacp, phy_addr);
}
if ((phy_identifier == MARVEL_PHY_IDENTIFIER) &&
(phy_model == MARVEL_PHY_88E1111_MODEL)) {
if (XAxiEthernet_GetPhysicalInterface(xaxiemacp) ==
@ -190,171 +275,93 @@ unsigned get_IEEE_phy_speed(XAxiEthernet *xaxiemacp)
xil_printf("%s: Phy Reset failed\n\r", __FUNCTION__);
return 0;
}
}
}
}
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr,
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr,
IEEE_1000_ADVERTISE_REG_OFFSET,
ADVERTISE_1000);
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr,
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr,
IEEE_AUTONEGO_ADVERTISE_REG,
ADVERTISE_100_AND_10);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
&control);
control |= (IEEE_CTRL_AUTONEGOTIATE_ENABLE |
IEEE_STAT_AUTONEGOTIATE_RESTART);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
&control);
control |= (IEEE_CTRL_AUTONEGOTIATE_ENABLE |
IEEE_STAT_AUTONEGOTIATE_RESTART);
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr,
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
control);
/* Read PHY control and status registers is successful. */
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
&control);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
/* Read PHY control and status registers is successful. */
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
&control);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_STATUS_REG_OFFSET,
&status);
if ((control & IEEE_CTRL_AUTONEGOTIATE_ENABLE) && (status &
IEEE_STAT_AUTONEGOTIATE_CAPABLE)) {
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_STATUS_REG_OFFSET,
&status);
}
if ((control & IEEE_CTRL_AUTONEGOTIATE_ENABLE) && (status &
IEEE_STAT_AUTONEGOTIATE_CAPABLE)) {
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_STATUS_REG_OFFSET,
&status);
}
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_PARTNER_ABILITIES_1_REG_OFFSET,
&partner_capabilities);
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
XAxiEthernet_PhyRead(xaxiemacp, phy_addr,
IEEE_PARTNER_ABILITIES_3_REG_OFFSET,
&partner_capabilities_1000);
if (partner_capabilities_1000 &
IEEE_AN3_ABILITY_MASK_1GBPS)
return 1000;
}
if (partner_capabilities_1000 &
IEEE_AN3_ABILITY_MASK_1GBPS)
return 1000;
}
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_100MBPS)
return 100;
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS)
return 10;
xil_printf("%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\r\n",
__FUNCTION__);
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_100MBPS)
return 100;
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS)
return 10;
xil_printf("%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\r\n",
__FUNCTION__);
return 10;
} else {
/* Update TEMAC speed accordingly */
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
/* Get commanded link speed */
phylinkspeed = control &
IEEE_CTRL_1GBPS_LINKSPEED_MASK;
switch (phylinkspeed) {
case (IEEE_CTRL_LINKSPEED_1000M):
return 1000;
case (IEEE_CTRL_LINKSPEED_100M):
return 100;
case (IEEE_CTRL_LINKSPEED_10M):
return 10;
default:
xil_printf("%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\r\n",
__FUNCTION__, phylinkspeed);
return 10;
}
} else {
/* Update TEMAC speed accordingly */
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
/* Get commanded link speed */
phylinkspeed = control &
IEEE_CTRL_1GBPS_LINKSPEED_MASK;
switch (phylinkspeed) {
case (IEEE_CTRL_LINKSPEED_1000M):
return 1000;
case (IEEE_CTRL_LINKSPEED_100M):
return 100;
case (IEEE_CTRL_LINKSPEED_10M):
return 10;
default:
xil_printf("%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\r\n",
__FUNCTION__, phylinkspeed);
return 10;
}
} else {
return (control & IEEE_CTRL_LINKSPEED_MASK) ? 100 : 10;
}
}
} else if ((phy_identifier == MARVEL_PHY_IDENTIFIER) &&
(phy_model == MARVEL_PHY_88E1116R_MODEL)) {
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;
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 atphy_valts */
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;
return (control & IEEE_CTRL_LINKSPEED_MASK) ? 100 : 10;
}
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,
&phy_val);
if (phy_val & 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;
} else {
xil_printf("%s: unknown PHY link speed\r\n", __FUNCTION__);
return 0;
}
}