UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Observer pstootman
Observer
11,917 Views
Registered: ‎03-29-2015

2015.4 + lwip + KSZ9031 link issues

SDK 2015.4, Zynq XC7Z020, baremetal application on PS0, lwip 1.4.1 and FreeRTOS 8.2.3 enabled in the BSP, Micrel KSZ9031RNX PHY

Various link auto-negotiation/speed/detection issues; details below.

Custom board, but hardware is fine because if we run linux (petalinux 2015.4) instead of baremetal, the ethernet works perfectly. And same observations on many different hardware units.

So I guess there is some issue in the lwip code or the xemacps code in the BSP, for this particular PHY, related to link up/down/negotiation activities. Has anyone made (lwip/xemacps for 2015.4 BSP) plus ksz9031 phy work reliably, and if so what are the required steps ? Many thanks.

 

More details;

a) lwip API function 'netif_is_link_up' doesn't work, always returns false

b) Link speed auto-negotiation doesn't work; link light will come up but then no traffic gets through; if my board is connected direct to PC, this can be 'worked around' by disabling auto-negotiation in the partner (my PC), and then in lwip BSP settings in SDK GUI, also set a fixed link speed. Then traffic will pass OK after link established.

c) I am suspicious problem is in xemacps driver (maybe some PHY register definitions different from the Marvell PHY that Xilinx uses... or maybe Micrel PHY needs some extra kicks or steps in its configuration/bringup...) because if I substitute FreeRTOS+TCP stack instead of lwip, I also have wrong link speed value reported back up into FreeRTOS+TCP stack, and also have to disable auto-negotiation to get any traffic through. Figuring out the functional differences between linux driver code and lwip/xemacps code for this PHY is way beyond me...

d) In my baremetal software I pulse the MIO pin I use for the ethernet PHY hardware reset, before calling lwip stack initialisation... so I guess PHY should be in the same/fresh state every time I try to start up the stack.

 

I've seen this thread;

Test-the-ethernet-KSZ9031-with-lwip-code-created-by-the-EDK

but it doesn't mention tool versions and original post is a year ago and no solutions offered, so I start new one... but I get the feeling I might not be alone in my KSZ9031/Zynq link struggles. I guess a lot of people replaced the Marvell PHY in the reference designs with KSZ9031 PHY.

 

The 2 most recent changes to KSZ9031 linux driver described here;

http://code.metager.de/source/history/linux/stable/drivers/net/phy/micrel.c

seem very relevant indeed to my issues described above ... but I've no idea how to integrate the same functional steps/fixes into the lwip/xemacps code.

 

Many thanks.

 

0 Kudos
7 Replies
Visitor patrick.knox
Visitor
11,442 Views
Registered: ‎02-28-2014

Re: 2015.4 + lwip + KSZ9031 link issues

I've used this PHY, but only with the lwip version from SDK 2014.3 (we did build the vivado project with 2015.3 though since we needed VHDL2008 support, and added the 2014.3 repository to our workspace to make use of 2014.3 lwip since we verified it worked with that version).  We had to disable auto negotiation in the BSP, setting the link speed to 1Gbps.  Also, if you are making use of interrupts we had to change sys_arch_protect/unprotect to disable/enable only the emac interrupt and not all interrupts using the assembly calls (dafault). the Hopefully this works the same in SDK 2015.4. 

0 Kudos
Newbie rarteche
Newbie
7,331 Views
Registered: ‎11-08-2016

Re: 2015.4 + lwip + KSZ9031 link issues

check this link (http://www.elogics.net/bbs/board.php?bo_table=manual03&wr_id=58&page=). I already check the modification it work using the lwip 1.4.1 and FreeRTOS 8.2.3 echo server example . You need only to compare the files xemacpsif_hw.c, xemacpsif_hw.c and xemacpsif_speed.c in the BSP project with the partial code in the link, pay attention basically to the functions get_Micrel_phy_speed()  and get_IEEE_phy_speed().

 

code in the web page

 

// 파일명: xemacpsif.c

static err_t low_level_init(struct netif *netif){
init_emacps(xemacpsif, netif);
 
}
 
// 여기 호출 
// 파일명: xemacpsif_hw.c
void init_emacps(xemacpsif_s *xemacps, struct netif *netif)
{
u32_t mac_address = (u32_t)(netif->state);
XEmacPs *xemacpsp;
XEmacPs_Config *mac_config;
s32_t status = XST_SUCCESS;
u32_t i;
u32_t phyfoundforemac0 = FALSE;
u32_t phyfoundforemac1 = FALSE;
 
 
mac_config = (XEmacPs_Config *)xemacps_lookup_config(mac_address);
 
xemacpsp = &xemacps->emacps;
 
 
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
if (status != XST_SUCCESS) {
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
}
 
XEmacPs_SetMdioDivisor(xemacpsp, MDC_DIV_224);
 
 
#ifdef PCM_PMA_CORE_PRESENT
#ifdef  XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT
link_speed = phy_setup(xemacpsp, XPAR_PCSPMA_1000BASEX_PHYADDR);
#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT
link_speed = phy_setup(xemacpsp, XPAR_PCSPMA_SGMII_PHYADDR);
#endif
#else
 
detect_phy(xemacpsp);
 
for (i = 31; i > 0; i--) {
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
if (phymapemac0[i] == TRUE) {
link_speed = phy_setup(xemacpsp, i);               /// initialize maker phy vendor
phyfoundforemac0 = TRUE;
}
} else {
if (phymapemac1[i] == TRUE) {
link_speed = phy_setup(xemacpsp, i);
phyfoundforemac1 = TRUE;
}
}
}
 
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
if (phyfoundforemac0 == FALSE)
link_speed = phy_setup(xemacpsp, 0);
} else {
if (phyfoundforemac1 == FALSE)
link_speed = phy_setup(xemacpsp, 0);
}
#endif
 
XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
 
{
volatile s32_t wait;
for (wait=0; wait < 20000; wait++);
}
}
 
void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
{
u32_t mac_address = (u32_t)(netif->state);
XEmacPs *xemacpsp;
XEmacPs_Config *mac_config;
s32_t status = XST_SUCCESS;
 
 
mac_config = (XEmacPs_Config *)xemacps_lookup_config(mac_address);
 
xemacpsp = &xemacps->emacps;
 
 
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
if (status != XST_SUCCESS) {
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
}
 
XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
 
 
{
volatile s32_t wait;
for (wait=0; wait < 20000; wait++);
}
}
 
void setup_isr (struct xemac_s *xemac)
{
xemacpsif_s   *xemacpsif;
 
xemacpsif = (xemacpsif_s *)(xemac->state);
 
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
    (void *) emacps_send_handler,
    (void *) xemac);
 
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
   (void *) emacps_recv_handler,
   (void *) xemac);
 
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
   (void *) emacps_error_handler,
   (void *) xemac);
}
 
// 여기호출
// 파일명: xemacpsif_speed.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;
//while(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)) {
 
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)) {
xil_printf("WARNING: Not a Marvell or TI Ethernet PHY. Please verify the initialization sequence\r\n");
}
}
}
 
//}
}
 
u32_t phy_setup (XEmacPs *xemacpsp, u32_t phy_addr)
{
u32_t link_speed;
u16_t regval;
u32_t conv_present = 0;
u32_t convspeeddupsetting = 0;
u32_t convphyaddr = 0;
 
link_speed = get_IEEE_phy_speed(xemacpsp, phy_addr);   //  micron phy set
if (link_speed == 1000) {
 
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
} else if (link_speed == 100) {
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
} else {
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
}
 
if (conv_present) {
XEmacPs_PhyWrite(xemacpsp, convphyaddr,
XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
}
 
xil_printf("link speed for phy address %d: %d\r\n", phy_addr, link_speed);
return link_speed;
}
 
 
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_MIC_IDENTIFIER){
RetStatus = get_Micrel_phy_speed(xemacpsp, phy_addr);
} else {
RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
}
if (RetStatus != XST_SUCCESS) {
return RetStatus;
}
 
return XST_SUCCESS;
}
 
static u32_t get_Micrel_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;
u32_t phyregtemp;
 
xil_printf("Start Micrel PHY autonegotiation  \r\n");
 
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);  //reg 0x04
control |= IEEE_ASYMMETRIC_PAUSE_MASK;   //0x0800
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_COPPER_SPECIFIC_CONTROL_REG, &control);  //reg 0x0f
control |= (7 << 12);
control |= (1 << 11);
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, control);
 
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);        //reg 0x00
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;
}
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
}
xil_printf("autonegotiation complete \r\n");
 
#define IEEE_1000BASE_STATUS_REG 0x0a
 
//XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_SPECIFIC_STATUS_REG, &status_speed);
XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_1000BASE_STATUS_REG, &status_speed);
if (status_speed & 0x0800) {
 
xil_printf("micrel phy ksz9031 speed %x \r\n",status_speed);
return 1000;
}
 
return XST_SUCCESS;
}

 

 

0 Kudos
6,324 Views
Registered: ‎01-20-2014

Re: 2015.4 + lwip + KSZ9031 link issues

I also used the same PHY in my custom board and after lot of study I have solved this problem.

create the new application LWiP Echo server from template.

replace the below file with the file attached with this post.

"/YOURAPPLICATION_bsp/ps7_cortexa9_0/libsrc/lwip141_v1_3/src/contrib/ports/xilinx/netif/xemacpsif_physpeed.c"

 

use the packet sender to send and receive the packets from LWIP echo server application

 

NOTE: the actual board address 192.168.1.10 Port:7

 

cheers

Manjunath BK

0 Kudos
Xilinx Employee
Xilinx Employee
6,307 Views
Registered: ‎08-02-2007

Re: 2015.4 + lwip + KSZ9031 link issues

hi,

 

to support a different phy other than marvell, you should be following this AR.

https://www.xilinx.com/support/answers/63495.html

 

--hs

----------------------------------------------------------------------------------------------
Kindly note- Please mark the Answer as "Accept as solution" if information provided is helpful.

Give Kudos to a post which you think is helpful and reply oriented.
----------------------------------------------------------------------------------------------
Visitor blue_xxy
Visitor
803 Views
Registered: ‎04-03-2018

Re: 2015.4 + lwip + KSZ9031 link issues

Hi,

 

I run the LWIP echo template after replaced the file.

 

it's also not work correctly。

 

uart print:

TCP packets sent to port 6001 will be echoed back

Start Micrel PHY autonegotiation  
Waiting for PHY to complete autonegotiation.
autonegotiation complete
link speed for phy address 3: 0

 

it always break here .

 

0 Kudos
Newbie jaana_jia
Newbie
58 Views
Registered: ‎02-11-2019

2017.4 /2015.4+ lwip + KSZ9031 (100mbps, or automatic negotiation)link issues

1000M can be achieved according to the instructions, but how to achieve 100mbps, or automatic negotiation。

0 Kudos
Visitor ajk
Visitor
12 Views
Registered: ‎12-22-2016

Re: 2017.4 /2015.4+ lwip + KSZ9031 (100mbps, or automatic negotiation)link issues

Hi,

i have boards with KZ9031. The patch mentioned previously by another user to add Micrel's OEM and DEV ID speed detect routines are required. I added those patches.

For me Auto negotiation works only the PHY for which the MDIO is configured. There are some links in the web which discuss about the problem with MDIO config and the auto negotiation. Sorry, did not book mark them.

But, in Board Support Package Settings, under lwip.., you can select the Speed 1000 or 100 or 10. I fixed it at 1000 and do not require auto nego.

Hope that is of some help.

 

0 Kudos