FreeRTOC TCP multi

wonger wrote on Tuesday, October 15, 2019:

I’m trying to run FreeRTOS TCP multi on a Zynq-7000 given in this post by Hein Tibosch:
https://sourceforge.net/p/freertos/discussion/382005/thread/bceca0f6/#484b

It is working on ps_eth0, but not on ps_eth1. If I understand correctly, on the Zynq-7000, ps_eth1 is not identical to ps_eth0; it requires GMII-to-RGMII IP in the Zynq PL to work properly. Do I need a different driver for ps_eth1? It appears to use the same xemacps driver as ps_eth0, but I don’t understand how that can be if the hardware is slightly different. Or is there some standard way to configure the PL to allow ps_eth1 to work properly with xemacps driver?

Thank you for any help.

wonger wrote on Tuesday, October 15, 2019:

In FreeRTOS TCP multi, directory …/portable/NetworkInterface/Zynq/NetworkInferface.c, there is this function:

static inline unsigned long ulReadMDIO( BaseType_t xEMACIndex, unsigned ulRegister )
{
    uint16_t usValue;

    // Always ETH0 because both PHYs are connected to ETH0 MDIO
    XEmacPs_PhyRead( &( xEMACpsifs[ 0 ].emacps ), phy_detected[xEMACIndex], ulRegister, &usValue );
    return usValue;
}

Is this board specific that both PHYs are connected to ETH0 MDIO? For which board was this the case?

heinbali01 wrote on Wednesday, October 16, 2019:

Hello Ewing,

There has been a lot of development recently on the /multi /IPv6 branch of FreeRTOS+TCP. The new sources are not yet in aws:master, but in a separate branch called aws:hein/tcpipv6

Please use the +TCP sources from freertos_plus_tcp_multi along with the latest kernel and other libraries from aws:master

I tend to define ipconfigMULTI_INTERFACE globally, to let main.c know that /multi must be used.

The /multi version of Xilinx’ NetworkInterface.c has been successfully used for 2 EMAC’s. I’m asking the person who did that if he can give you a hint. I know very little about the details of ps_eth0 / ps_eth1.

You can ask any further questions here in this post.

kenchang1 wrote on Wednesday, October 16, 2019:

I have been using eth0 + eth1 + freertos (custom board) for some time now. If I remember correctly it is common to let ETH0 talk to both PHYs with 1 MDIO interface (to save pins?). They just need to have a different address (hardwired).
If you are not sure, you can play with XEmacPs_PhyRead() in debug mode to see if you can talk to the PHY differently. If possible, let us know which board you are using.

https://forums.xilinx.com/t5/Embedded-Linux/Marvell-Phy-and-switch-share-MDIO-bus/td-p/844523
https://forums.xilinx.com/t5/Embedded-Linux/Secondary-eth1-ethernet-port-not-working/td-p/861499

wonger wrote on Wednesday, October 16, 2019:

I’m also using a custom Zynq board. But it has separate MDIO buses for ETH0 and ETH1. And for ETH1, it goes gem1 --> gmii-to-rgmii IP --> PHY. The MDIO bus goes into the gmii-to-rgmii IP and then out to the PHY chip. The gmii-to-rgmii IP has its own PHY address.

Do you know if the Xilinx drivers and FreeRTOS TCP multi assume one MDIO bus for both ETH0 and ETH1? It seems like FreeRTOS TCP multi does, at least according to the ulReadMDIO() function I posted above.

Do you use the gmii-to-rmii IP in the PL for ETH1 in your custom board? If you do use this IP, can you tell me the clock frequencies you use for clk_in and gmii_clk? And did you #define XPAR_GMII2RGMIICON_0N_ETH1_ADDR in x_emacpsif_physpeed.c with the PHY address of the gmii-to-rgmii IP? In the Phy_Setup() function, it uses the #define to do an extra write to set the link speed on the gmii-to-rgmii IP:

unsigned Phy_Setup (XEmacPs *xemacpsp)
{
	unsigned long conv_present = 0;
	unsigned long convspeeddupsetting = 0;
	unsigned long convphyaddr = 0;

#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR
	convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR;
	conv_present = 1;
#else
#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR
	convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR;
	conv_present = 1;
#endif
#endif

#ifdef  ipconfigNIC_LINKSPEED_AUTODETECT
	link_speed = get_IEEE_phy_speed(xemacpsp);
	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;
	}
#elif	defined(ipconfigNIC_LINKSPEED1000)
	SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
	link_speed = 1000;
	configure_IEEE_phy_speed(xemacpsp, link_speed);
	convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
	sleep(1);
#elif	defined(ipconfigNIC_LINKSPEED100)
	SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
	link_speed = 100;
	configure_IEEE_phy_speed(xemacpsp, link_speed);
	convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
	sleep(1);
#elif	defined(ipconfigNIC_LINKSPEED10)
	SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
	link_speed = 10;
	configure_IEEE_phy_speed(xemacpsp, link_speed);
	convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
	sleep(1);
#endif
	if (conv_present) {
		XEmacPs_PhyWrite(xemacpsp, convphyaddr,
		XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
	}

	return link_speed;
}

Thanks for your help!

kenchang1 wrote on Wednesday, October 16, 2019:

We did use the GMII2RGMII interface for gem1, but I don’t know the HW design details, because I was not the HW designer.
The PHY address should be set at the PHY side, not at the GMII2RGMII side. It is usually hardwired on the board.
If you have connected the second PHY to MDIO of gem1, try changing the code to this:
XEmacPs_PhyRead( &( xEMACpsifs[ 1 ].emacps ), phy_detected[xEMACIndex], ulRegister, &usValue );
Use the debugger to verify the PHY address.

kenchang1 wrote on Wednesday, October 16, 2019:

For further debugging, you can use parts of this code to check all PHY addresses on both MDIO bus (gem0 and gem1).
https://github.com/Xilinx/embeddedsw/blob/master/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_util.c

function: XEmacPsDetectPHY()

wonger wrote on Wednesday, October 16, 2019:

Hi Hein,

I pulled and am using the latest +TCP multi source. I had to make the following modifications:

  1. FreeRTOS_IP.c: line 1100: bIsValidNetworkDescriptor is defined only if ipconfigTCP_IP_SANITY is 1. I added #if ipconfigTCP_IP_SANITY around the call.
  2. FreeRTOS_IP.c: line 1722-1759: if ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0, compiler complains about there being two definitions of prvIsIPv4Multicast(). I set ipconfigETHERNET_DRIVER_FILTERS_PACKETS to 1 for now. If left undefined or 0, the resulting static definition of prvIsIPv4Multicast() causes problems for other files that use this function (e.g., FreeRTOS_Routing.h).

Unfortunately, updating to the latest source broke ETH0 too now. ETH0 was responding to pings before, but now it’s not. Not sure why at this point. Is this how I should initialize the stack with the latest?

pxZynq_FillInterfaceDescriptor( 0, &( xInterfaces[ 0 ] ) );
FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );

pxZynq_FillInterfaceDescriptor( 1, &( xInterfaces[ 1 ] ) );
FreeRTOS_FillEndPoint( &( xInterfaces[ 1 ] ), &( xEndPoints[ 1 ] ), ucIPAddress2, ucNetMask2, ucGatewayAddress2, ucDNSServerAddress2, ucMACAddress2 );

/* You can modify fields: */
xEndPoints[ 0 ].bits.bIsDefault = pdTRUE_UNSIGNED;

FreeRTOS_IPStart();

Before updating to the latest source, I was doing this:

pxZynq_FillInterfaceDescriptor( 0, &( xInterfaces[ 0 ] ) );
FreeRTOS_FillEndPoint( &( xEndPoints[ 0 ] ), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
FreeRTOS_AddEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ) );

pxZynq_FillInterfaceDescriptor( 1, &( xInterfaces[ 1 ] ) );
FreeRTOS_FillEndPoint( &( xEndPoints[ 1 ] ), ucIPAddress2, ucNetMask2, ucGatewayAddress2, ucDNSServerAddress2, ucMACAddress2 );
FreeRTOS_AddEndPoint( &( xInterfaces[ 1 ] ), &( xEndPoints[ 1 ] ) );

/* You can modify fields: */
xEndPoints[ 0 ].bits.bIsDefault = pdTRUE_UNSIGNED;

FreeRTOS_IPStart();

wonger wrote on Wednesday, October 16, 2019:

The GMII2RGMII has its own PHY address. It only has one register at 0x10 though, which should be set to the link speed that the PHY is operating at. That’s what Phy_Setup() seems to be doing with #define XPAR_GMII2RGMIICON_0N_ETH1_ADDR. But ETH1 still doesn’t work for me when doing this. You don’t remember having to set that #define? It is in x_emacpsif_physpeed.c

I’ll try all the debug you mentioned. Thank you for your help.

kenchang1 wrote on Wednesday, October 16, 2019:

Hi ewing, maybe we are not talking about the exact same thing. The PHY address (hardware) is set at the PHY using the CONFIG pin (Marvell PHY for example). The Zynq has a register containing the PHY address (5 bits for values 0 to 31). I am not sure, the GMII2RGMII might have it’s own register containing the PHY address that it uses to communicate with the PHY via MDIO bus. If you haven’t touch the CONFIG pin of both PHYs, they will both have address 0x00 and both are on different MDIO busses (gem0 MDIO and gem1 MDIO).

On my board, both Marvell PHYs are connected to MDIO bus of gem0 and PHY0 has PHY address 0, PHY1 has PHY address 1, configured in hardware via the CONFIG pin of both Marvell PHYs.
I hope this helps.
Best regards,
Ken

wonger wrote on Wednesday, October 16, 2019:

Yes, our hardware appears to be different. I have:
GEM0 --> PHY[0]
GEM1 --> GMII2RGMII[8] --> PHY[0]

Both my PHYs have address 0, but are on different MDIO buses. In addition, the GMII2RGMII IP has PHY address 8. Someone else here on another project hacked the Xilinx emacps driver to death to get ETH1 working. I feel like the emacps driver should work for ETH1/GEM1 with little to no change and is just missing some bit of configuration to work. No one else seems to have trouble with it. So I’m trying to track down that missing bit.

Are you in any position to show me your x_emacpsif_physpeed.c file? Either way, thank you for your help.

heinbali01 wrote on Thursday, October 17, 2019:

Ewing, it’s been a while that I tested /multi on a Xilinx board. I will do so today and show you the initialisation code used. Thanks for your patience.

heinbali01 wrote on Sunday, October 20, 2019:

Hello Ewing,

The problem with Zynq\NetworkInterface.c ( multi version ) was this line:

//		XEmacPs_SetOperatingSpeed( pxEMAC_PS, ulLinkSpeed); /* Duplicate */

I can not remember why it was commented out with the comment “Duplicate”. When I un-commented it, the project worked well again.

If you find the time, can you write me an email? That’s probably quicker than posting every little detail.

My address is hein [at] htibosch [dot] net

Thanks, Hein

wonger wrote on Monday, October 21, 2019:

Hi Hein,

I uncommented that line and latest version of TCP multi still doesn’t work for me. I have emailed you. Thank you.