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: 
Explorer
Explorer
174 Views
Registered: ‎10-14-2017

Failure to initialize Microchip PHY in lwIp echo server example

Jump to solution

I am using the MYIR Z-turn with z7020 chip and trying to get the lwIP working in FreeRTOS based design. I've taken the FreeRTOS lwIP echo server example as basis. I understand that the Xilinx port examples only support Marvell, TI or Realtek PHY chips, but looking at my boards documentation I can see that I'm using the Microchip KSZ9031RNX PHY. 

I read from this and this thread, and also form this AR and from this github repo how to implement the Microchip PHY support. So in essence I added support for doing the auto-negotiation with the Microchip PHY in the xemacpsif_physpeed.c file. However I still can't get the Ethernet example working. Stepping through the code with a debugger I can see that the network_thread actually hangs when calling the xemac_add function. More precicesly it hangs where it tries to perform auto-negotiation by resetting the PHY and waiting the PHY to come out of the reset (while(1) loop) which it never seems to do.

However, I think the main problem is the communication with the PHY chip as all calls to the XEmacPs_PhyRead functions seem to return with a value of 0xFFFF.  I think this is also the reason why PHY address is not correctly identified in call to detect_phy function - from board documentation I see that PHY address should be 3, but it does not get detected as the XEmacPs_PhyRead function always returns 0xFFFF value when looping down to 0 from 31. 

In the other hand I know that the hardware is okay and works because I've run linux on the board which is able to use the ethernet interface. So it has to be something in the software or configuration. I've also tried the standalone version of the echo server, but no difference, it still does not work. 

Is there something else that I should configure or change in the lwIP source files to make it work with the Microchip PHY? 

I'm using the Vivado/SDK 2018.3 release and FreeRTOS10 v1.2 and lwIp202 v1.2 versions. 

0 Kudos
1 Solution

Accepted Solutions
Explorer
Explorer
88 Views
Registered: ‎10-14-2017

Re: Failure to initialize Microchip PHY in lwIp echo server example

Jump to solution

Okay,

So I got it to work now with the echo exmaple. Below are the modifcations I had to do in the xemacpsif_physpeed.c file. I'll list them here hoping that this might help someone in the future who wants to use Microchip PHY (KSZ9031RNX) with emac. This, however, is the standalone version, I haven't tried yet with the FreeRTOS.

Firstly add the Microchip PHY identifier as a macro definition:

#define PHY_MICROCHIP_IDENTIFIER			0x0022

 

In function detect_phy:

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;
	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)) {
			/* Found a valid PHY address */
			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) &&
				(phy_reg != PHY_REALTEK_IDENTIFIER) &&
				(phy_reg != PHY_MICROCHIP_IDENTIFIER)) {
				xil_printf("WARNING: Not a Marvell, TI, Realtek or Microchip Ethernet PHY. Please verify the initialization sequence\r\n");
			}
		}
	}
}

In function get_IEEE_phy_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_REALTEK_IDENTIFIER) {
		RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr);
	} else if (phy_identity == PHY_MICROCHIP_IDENTIFIER) {
		RetStatus = get_Microchip_phy_speed(xemacpsp, phy_addr);
	} else {
		RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
	}

	return RetStatus;
}

And finaly I added a new function called get_Microchip_phy_speed before the get_IEEE_phy_speed:

static u32_t get_Microchip_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 PHY autonegotiation for Microchip PHY\r\n");

	// initially we do not concern us with TX and RX path timing
//	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);

	// following is Marvell PHY specific
//	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... ");

	while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
		sleep(1);
		// this is MArvell PHY specific and does not seem to actually do anything
//		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,31,
					&status_speed);
	// check that link status is "Not failing"
	if ((status_speed & 0x1) == 0) {
		temp_speed = status_speed & 0x70;  // mask out the speed indication bits

		if (temp_speed == 0x40)
			return 1000;
		else if(temp_speed == 0x20)
			return 100;
		else if(temp_speed == 0x10)
			return 10;
		else
			xil_printf("Could not get the negotiated speed from the PHY \r\n");
	}

	xil_printf("PHY indicated link failure, could not get the negotiated speed \r\n");

	return XST_SUCCESS;
}

I will now try to understand why this did not work with my first project where I didn't have the fsbl and try to get it working with FreeRTOS as well.

 

View solution in original post

4 Replies
Moderator
Moderator
116 Views
Registered: ‎08-25-2009

Re: Failure to initialize Microchip PHY in lwIp echo server example

Jump to solution

 Hi @ronnu ,

The AR that you pointed out (https://www.xilinx.com/support/answers/63495.html) should be enough to get LWIP to work with a different PHY.

We've had customers doing this successfully by following the steps.

Have you debugged further in the function that why the PHY address is not properly detected?

 

"Don't forget to reply, kudo and accept as solution."
0 Kudos
Explorer
Explorer
100 Views
Registered: ‎10-14-2017

Re: Failure to initialize Microchip PHY in lwIp echo server example

Jump to solution

Hi @nanz , thanks for the reply!

Yeah, I tried again with clean start following this tutorial by the fpgadeveloper and this time it can correctly read from the PHY (the read values returned are not 0xFF anymore). I do not understand why this is as I did nothing more than added fsbl when compared to my previous project, but I'm still using the jtag-mode to boot. Is it possible that fsbl enables or configures something that makes it work? I haven't tried removing fsbl from my project as I would like to try getting the auto-negotiation work before that.

 

 

0 Kudos
Explorer
Explorer
89 Views
Registered: ‎10-14-2017

Re: Failure to initialize Microchip PHY in lwIp echo server example

Jump to solution

Okay,

So I got it to work now with the echo exmaple. Below are the modifcations I had to do in the xemacpsif_physpeed.c file. I'll list them here hoping that this might help someone in the future who wants to use Microchip PHY (KSZ9031RNX) with emac. This, however, is the standalone version, I haven't tried yet with the FreeRTOS.

Firstly add the Microchip PHY identifier as a macro definition:

#define PHY_MICROCHIP_IDENTIFIER			0x0022

 

In function detect_phy:

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;
	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)) {
			/* Found a valid PHY address */
			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) &&
				(phy_reg != PHY_REALTEK_IDENTIFIER) &&
				(phy_reg != PHY_MICROCHIP_IDENTIFIER)) {
				xil_printf("WARNING: Not a Marvell, TI, Realtek or Microchip Ethernet PHY. Please verify the initialization sequence\r\n");
			}
		}
	}
}

In function get_IEEE_phy_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_REALTEK_IDENTIFIER) {
		RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr);
	} else if (phy_identity == PHY_MICROCHIP_IDENTIFIER) {
		RetStatus = get_Microchip_phy_speed(xemacpsp, phy_addr);
	} else {
		RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
	}

	return RetStatus;
}

And finaly I added a new function called get_Microchip_phy_speed before the get_IEEE_phy_speed:

static u32_t get_Microchip_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 PHY autonegotiation for Microchip PHY\r\n");

	// initially we do not concern us with TX and RX path timing
//	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);

	// following is Marvell PHY specific
//	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... ");

	while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
		sleep(1);
		// this is MArvell PHY specific and does not seem to actually do anything
//		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,31,
					&status_speed);
	// check that link status is "Not failing"
	if ((status_speed & 0x1) == 0) {
		temp_speed = status_speed & 0x70;  // mask out the speed indication bits

		if (temp_speed == 0x40)
			return 1000;
		else if(temp_speed == 0x20)
			return 100;
		else if(temp_speed == 0x10)
			return 10;
		else
			xil_printf("Could not get the negotiated speed from the PHY \r\n");
	}

	xil_printf("PHY indicated link failure, could not get the negotiated speed \r\n");

	return XST_SUCCESS;
}

I will now try to understand why this did not work with my first project where I didn't have the fsbl and try to get it working with FreeRTOS as well.

 

View solution in original post

Moderator
Moderator
57 Views
Registered: ‎08-25-2009

Re: Failure to initialize Microchip PHY in lwIp echo server example

Jump to solution

Hi @ronnu ,

Great to see you've got this resolved.

Please mark your own solution thread as "Accepted Solution" so it will benifit other forum users.

 

"Don't forget to reply, kudo and accept as solution."
0 Kudos