Hi
I’m trying to setup FREE RTOS + TCP on a custom board using xilinx ultrascale + TI DP83822 PHY.
The PHY as no boot strap as the HW team intended it to be configured by SW.
The PHY wiring on the board is meant to use RGMII interface.
I can't get any traffic on Ethernet but most puzzling is that the PC the board is attached to indicates cable is disconnected.
To my understanding even without any transmit form the MAC the PC should at least recognize a cable is connected if initialization is OK.
I've done the following initialization for the PHY :
#define PHY_TI_BMCCR 0x00 // Basic Control Mode register
#define PHY_TI_BMCCR_RESET_MASK 0x8000
#define PHY_MODEL_TI_DP83822_AUTONEGO_EN 0x1000
#define PHY_MODEL_TI_DP83822_AUTONEGO_RESTART 0x0200
#define PHY_TI_PHYRCR 0x1F // PHY reset control register
#define PHY_TI_PHYRCR_DIGITAL_RESET_MASK 0x8000
#define PHY_TI_PHYRCR_DIGITAL_RESTART_MASK 0x4000
#define PHY_MODEL_TI_DP83822 0x24
#define PHY_MODEL_MASK 0x3F
#define PHY_MODEL_SHIFT 0x4
#define PHY_MODEL_TI_DP83822_LEDCR 0x18
#define PHY_MODEL_TI_DP83822_OVRLED0_EN 0x10
#define PHY_MODEL_TI_DP83822_OVRLED0_ON 0x02
#define PHY_MODEL_TI_DP83822_CR1 0x09
#define PHY_MODEL_TI_DP83822_LINKLOSSREC_EN 0x80
#define PHY_MODEL_TI_DP83822_FASTAUTOMDIX_EN 0x40
#define PHY_MODEL_TI_DP83822_ROBUSTAUTOMDIX_EN 0x20
#define PHY_MODEL_TI_DP83822_FASTAUTONEGO_EN 0x10
#define PHY_MODEL_TI_DP83822_CR2 0x0A
#define PHY_MODEL_TI_DP83822_100BASE_FX_EN 0x4000
#define PHY_MODEL_TI_DP83822_EXT_FULL_DUPLEX_ABILITY_EN 0x0020
#define PHY_MODEL_TI_DP83822_CR3 0x0B
#define PHY_MODEL_TI_DP83822_RCSR 0x17
#define PHY_MODEL_TI_DP83822_RGMII_RX_CLCK_SHIFT_EN 0x1000
#define PHY_MODEL_TI_DP83822_RGMII_TX_CLCK_SHIFT_EN 0x0800
#define PHY_MODEL_TI_DP83822_RGMII_MODE_EN 0x0200
#define PHY_MODEL_TI_DP83822_RGMII_50MHZ_CLCK_SEL 0x0080
#define PHY_MODEL_TI_DP83822_PHYCR 0x19
#define PHY_MODEL_TI_DP83822_AUTOMDIX_EN 0x8000
#define PHY_MODEL_TI_DP83822_LEDCFG_MODE1_EN 0x0020
#define PHY_RESET_MAX_WAIT_TIME 1000000000
#define PHY_RESET_MIN_WAIT_TIME 10000
#define DEBUG_ETHERNET 1
uint32_t configure_IEEE_phy_speed_US( XEmacPs * xemacpsp, unsigned speed, u32 phy_addr )
{
uint16_t phyregtemp, phyregtempcheck;
uint16_t control;
uint16_t phy_identity;
uint16_t phy_model;
uint32_t RetStatus;
volatile uint32_t wait = 0;
/* Perform a reset of the chip equivalent to HW reset */
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_PHYRCR , (uint16_t *) &phyregtemp );
phyregtemp |= PHY_TI_PHYRCR_DIGITAL_RESET_MASK;
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_TI_PHYRCR, phyregtemp );
// RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_PHYRCR, (uint16_t *) &phyregtemp );
//
// if( RetStatus != XST_SUCCESS )
// {
// xil_printf( "Error during digital restart \n\r" );
// return XST_FAILURE;
// }
/* Wait for reset to complete */
wait = 0;
while(wait++ < PHY_RESET_MAX_WAIT_TIME)
{
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_PHYRCR, (uint16_t *) &phyregtemp );
if(((phyregtemp & PHY_TI_PHYRCR_DIGITAL_RESET_MASK) == 0x00) && (wait >= PHY_RESET_MIN_WAIT_TIME))
break;
}
if( wait >= PHY_RESET_MAX_WAIT_TIME )// Reset did not complete on time
{
xil_printf( "Error during reset \n\r" );
return XST_FAILURE;
}
/* Perform PCS registers reset - probably redundant after 1st reset */
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_BMCCR, (uint16_t *) &phyregtemp );
phyregtemp |= 0x8000;
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_TI_BMCCR, phyregtemp );
/* Wait for reset to complete */
wait = 0;
while(wait++ < PHY_RESET_MAX_WAIT_TIME)
{
XEmacPs_PhyRead( xemacpsp, phy_addr, 0, (uint16_t *) &phyregtemp );
if(((phyregtemp & PHY_TI_BMCCR_RESET_MASK) == 0x00) && (wait >= PHY_RESET_MIN_WAIT_TIME))
break;
}
if( wait >= PHY_RESET_MAX_WAIT_TIME )// Reset did not complete on time
{
xil_printf( "Error during PCS registers reset \n\r" );
return XST_FAILURE;
}
// Get device identity
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG, &phy_identity );
//Get device model
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_IDENTIFIER_2_REG, &phy_model );
phy_model = ((phy_model >> PHY_MODEL_SHIFT) & PHY_MODEL_MASK);
if(PHY_TI_IDENTIFIER == phy_identity)
{
switch(phy_model)
{
case PHY_MODEL_TI_DP83822: // MK4 BMU HW PHY
// Setup Basic mode control register to enable Auto negotiation
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_BMCCR, (uint16_t *)&phyregtemp );
phyregtemp |= PHY_MODEL_TI_DP83822_AUTONEGO_EN;
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_TI_BMCCR, phyregtemp );
#if defined(DEBUG_ETHERNET) && (DEBUG_ETHERNET == 1)
// Check init
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_BMCCR, (uint16_t *)&phyregtempcheck );
xil_printf("Reg Adress in PHY %x - setup : %x - value : %x\n", PHY_TI_BMCCR, phyregtemp, phyregtempcheck);
#endif
// Setup control register 1 for link loss recovery enable etc
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR1, (uint16_t *)&phyregtemp );
// phyregtemp |= (PHY_MODEL_TI_DP83822_LINKLOSSREC_EN |
// PHY_MODEL_TI_DP83822_FASTAUTOMDIX_EN |
// PHY_MODEL_TI_DP83822_ROBUSTAUTOMDIX_EN);
phyregtemp |= (PHY_MODEL_TI_DP83822_FASTAUTOMDIX_EN |
PHY_MODEL_TI_DP83822_ROBUSTAUTOMDIX_EN);
phyregtemp &= ~PHY_MODEL_TI_DP83822_FASTAUTONEGO_EN;// Disable fast auto neg
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR1, phyregtemp );
#if defined(DEBUG_ETHERNET) && (DEBUG_ETHERNET == 1)
// Check init
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR1, (uint16_t *)&phyregtempcheck );
xil_printf("Reg Adress in PHY %x - setup : %x - value : %x\n", PHY_MODEL_TI_DP83822_CR1, phyregtemp, phyregtempcheck);
#endif
// Enable 100Mbps capability
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR2, (uint16_t *)&phyregtemp );
phyregtemp |= PHY_MODEL_TI_DP83822_100BASE_FX_EN;
phyregtemp |= PHY_MODEL_TI_DP83822_EXT_FULL_DUPLEX_ABILITY_EN;
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR2, phyregtemp );
#if defined(DEBUG_ETHERNET) && (DEBUG_ETHERNET == 1)
// Check init
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR2, (uint16_t *)&phyregtempcheck );
xil_printf("Reg Adress in PHY %x - setup : %x - value : %x\n", PHY_MODEL_TI_DP83822_CR2, phyregtemp, phyregtempcheck);
#endif
// Disable fast link down options
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR3, 0x0 );
#if defined(DEBUG_ETHERNET) && (DEBUG_ETHERNET == 1)
// Check init
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_CR3, (uint16_t *)&phyregtempcheck );
xil_printf("Reg Adress in PHY %x - setup : %x - value : %x\n", PHY_MODEL_TI_DP83822_CR3, phyregtemp, phyregtempcheck);
#endif
// Setup device in RGMII Mode
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_RCSR, (uint16_t *)&phyregtemp );
phyregtemp &=~PHY_MODEL_TI_DP83822_RGMII_RX_CLCK_SHIFT_EN; // Disable RX clock shift
phyregtemp &=~PHY_MODEL_TI_DP83822_RGMII_TX_CLCK_SHIFT_EN; // Disable TX clock shift
phyregtemp |= PHY_MODEL_TI_DP83822_RGMII_MODE_EN; // HW interface on board is RGMII
phyregtemp &= ~PHY_MODEL_TI_DP83822_RGMII_50MHZ_CLCK_SEL; // make sure clck used is 25MHz
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_RCSR, phyregtemp );
#if defined(DEBUG_ETHERNET) && (DEBUG_ETHERNET == 1)
// Check init
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_RCSR, (uint16_t *)&phyregtempcheck );
xil_printf("Reg Adress in PHY %x - setup : %x - value : %x\n", PHY_MODEL_TI_DP83822_RCSR, phyregtemp, phyregtempcheck);
#endif
// Setup Auto MDI enable and LED to blink in activity
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_PHYCR, (uint16_t *)&phyregtemp );
phyregtemp |= PHY_MODEL_TI_DP83822_AUTOMDIX_EN; // Enable auto MDIX in case we have crossed pairs
phyregtemp &= ~PHY_MODEL_TI_DP83822_LEDCFG_MODE1_EN; // Mode 2 : Have Led0 ON on link and blinking on Tx activity
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_PHYCR, phyregtemp );
#if defined(DEBUG_ETHERNET) && (DEBUG_ETHERNET == 1)
// Check init
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_MODEL_TI_DP83822_PHYCR, (uint16_t *)&phyregtempcheck );
xil_printf("Reg Adress in PHY %x - setup : %x - value : %x\n", PHY_MODEL_TI_DP83822_PHYCR, phyregtemp, phyregtempcheck);
#endif
break;
default:
xil_printf( "Network device not supported \n\r" );
return XST_FAILURE;
break;
}
}
else
{
xil_printf( "Network device not supported \n\r" );
return XST_FAILURE;
}
//
// 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;
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control );
// XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control );
// control &= ~IEEE_CTRL_LINKSPEED_1000M;
// control &= ~IEEE_CTRL_LINKSPEED_100M;
// control &= ~IEEE_CTRL_LINKSPEED_10M;
if( speed == 1000 )
{
//control |= IEEE_CTRL_LINKSPEED_1000M;
xil_printf( "1000Mbps speed not supported \n\r" );
return XST_FAILURE;
}
else if( speed == 100 )
{
//control |= IEEE_CTRL_LINKSPEED_100M;
/* Dont advertise PHY speed of 1000 Mbps */
//XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, 0 );
/* Dont advertise PHY speed of 10 Mbps */
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, ADVERTISE_100 );
}
else if( speed == 10 )
{
//control |= IEEE_CTRL_LINKSPEED_10M;
/* Dont advertise PHY speed of 1000 Mbps */
//XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, 0 );
/* Dont advertise PHY speed of 100 Mbps */
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, ADVERTISE_10 );
}
/* Perform a digital restart */
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_PHYRCR , (uint16_t *) &phyregtemp );
phyregtemp |= PHY_TI_PHYRCR_DIGITAL_RESTART_MASK;
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_TI_PHYRCR, phyregtemp );
// RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_PHYRCR, (uint16_t *) &phyregtemp );
//
// if( RetStatus != XST_SUCCESS )
// {
// xil_printf( "Error during digital restart \n\r" );
// return XST_FAILURE;
// }
/* Wait for reset to complete */
wait = 0;
while(wait++ < PHY_RESET_MAX_WAIT_TIME)
{
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_PHYRCR, (uint16_t *) &phyregtemp );
if(((phyregtemp & PHY_TI_PHYRCR_DIGITAL_RESTART_MASK) == 0x00) && (wait >= PHY_RESET_MIN_WAIT_TIME))
break;
}
if( wait >= PHY_RESET_MAX_WAIT_TIME )// Reset did not complete on time
{
xil_printf( "Error during digital restart \n\r" );
return XST_FAILURE;
}
//XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control | IEEE_CTRL_RESET_MASK );
// Query to restart autonego
XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_BMCCR, (uint16_t *)&phyregtemp );
phyregtemp |= PHY_MODEL_TI_DP83822_AUTONEGO_RESTART;
XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_TI_BMCCR, phyregtemp );
// for( wait = 0; wait < 100000; wait++ );
xil_printf( "\nPHY init sequence done ! \n\r" );
return XST_SUCCESS;
}
Here is a dump of the registers :
Reg 0x0 act value : 0x1100
Reg 0x1 act value : 0x7849
Reg 0x2 act value : 0x2000
Reg 0x3 act value : 0xA240
Reg 0x4 act value : 0x0180
Reg 0x5 act value : 0x0000
Reg 0x6 act value : 0x0004
Reg 0x7 act value : 0x2001
Reg 0x8 act value : 0x0000
Reg 0x9 act value : 0x0060
Reg 0xA act value : 0x4120
Reg 0xB act value : 0x0000
Reg 0xC act value : 0x0000
Reg 0xD act value : 0x401F
Reg 0xE act value : 0x0005
Reg 0xF act value : 0x0000
Reg 0x10 act value : 0x0206
Reg 0x11 act value : 0x0108
Reg 0x12 act value : 0x0000
Reg 0x13 act value : 0x0000
Reg 0x14 act value : 0x0000
Reg 0x15 act value : 0x0000
Reg 0x16 act value : 0x0100
Reg 0x17 act value : 0x0241
Reg 0x18 act value : 0x0400
Reg 0x19 act value : 0x8001
Reg 0x1A act value : 0x0000
Reg 0x1B act value : 0x007D
Reg 0x1C act value : 0x05EE
Reg 0x1D act value : 0x0000
Reg 0x1E act value : 0x0002
Reg 0x1F act value : 0x0000
Reg 0x461 act value : 0x0410
Reg 0x462 act value : 0x0000
Reg 0x467 act value : 0x5FD3
Reg 0x468 act value : 0x0005
I can't see anything wrong my side and can't figure out why at least the PC would not recognize the connection.
For info powering up a ZCU 104 eval board using a DP83867 in JTAG mode without any code running, at least the PC detects the connection on a unidentified network.
Would someone be able to point me in the right direction ?
Thanks
Seb