Skip to content

Commit 2eaa162

Browse files
committed
Add Micrel PHY support to xilinx_ultrascale port
Authored-by: Pete Bone <[email protected] >
1 parent 1f71d69 commit 2eaa162

File tree

1 file changed

+243
-0
lines changed

1 file changed

+243
-0
lines changed

source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_physpeed.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ uint32_t phy_detected[ 4 ];
157157
#define PHY_MARVELL_IDENTIFIER 0x0141
158158
#define PHY_TI_IDENTIFIER 0x2000
159159
#define PHY_REALTEK_IDENTIFIER 0x001c
160+
#define PHY_MICREL_IDENTIFIER 0x0022
160161
#define PHY_AR8035_IDENTIFIER 0x004D
161162
#define PHY_XILINX_PCS_PMA_ID1 0x0174
162163
#define PHY_XILINX_PCS_PMA_ID2 0x0C00
@@ -659,6 +660,240 @@ static uint32_t get_Realtek_phy_speed( XEmacPs * xemacpsp,
659660
return XST_FAILURE;
660661
}
661662

663+
#define LPA_IEEE_1000FD 0x0800
664+
#define LP5_IEEE_100BTXFD 0x0100
665+
#define LP5_IEEE_10BTFD 0x0040
666+
#define MICREL_ID_KSZ9021 0x0161
667+
#define MICREL_ID_KSZ9031 0x0162
668+
#define MICREL_ID_KSZ9131 0x0164
669+
670+
671+
static int set_Micrel_phy_delays( XEmacPs * EmacPsInstancePtr,
672+
uint32_t PhyAddr )
673+
{
674+
int Status;
675+
uint16_t PhyType, PhyData;
676+
677+
XEmacPs_PhyRead( EmacPsInstancePtr, PhyAddr, 0x3, ( u16 * ) &PhyData ); /* read value */
678+
PhyType = ( PhyData >> 4 );
679+
680+
/* enabling RGMII delays */
681+
if( PhyType == MICREL_ID_KSZ9131 ) /* KSZ9131 */
682+
{
683+
FreeRTOS_printf( ( "Detected KSZ9131 Ethernet PHY\n\r" ) );
684+
/*Ctrl Delay */
685+
u16 RxCtrlDelay = 7; /* 0..15, default 7 */
686+
u16 TxCtrlDelay = 7; /* 0..15, default 7 */
687+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
688+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0004 ); /* Reg 0x4 */
689+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
690+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxCtrlDelay | ( RxCtrlDelay << 4 ) ) );
691+
/*Data Delay */
692+
u16 RxDataDelay = 7; /* 0..15, default 7 */
693+
u16 TxDataDelay = 7; /* 0..15, default 7 */
694+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
695+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0005 ); /* Reg 0x5 */
696+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
697+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxDataDelay | ( RxDataDelay << 4 ) | ( RxDataDelay << 8 ) | ( RxDataDelay << 12 ) ) );
698+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
699+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0006 ); /* Reg 0x6 */
700+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
701+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxDataDelay | ( TxDataDelay << 4 ) | ( TxDataDelay << 8 ) | ( TxDataDelay << 12 ) ) );
702+
/*Clock Delay */
703+
u16 RxClockDelay = 31; /* 0..31, default 15 */
704+
u16 TxClockDelay = 31; /* 0..31, default 15 */
705+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
706+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0008 ); /* Reg 0x8 RGMII Clock Pad Skew */
707+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
708+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxClockDelay | ( TxClockDelay << 5 ) ) );
709+
}
710+
else if( PhyType == MICREL_ID_KSZ9031 ) /* KSZ9031 */
711+
{
712+
FreeRTOS_printf( ( "Detected KSZ9031 Ethernet PHY\n\r" ) );
713+
/*Ctrl Delay */
714+
u16 RxCtrlDelay = 7; /* 0..15, default 7 */
715+
u16 TxCtrlDelay = 7; /* 0..15, default 7 */
716+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
717+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0004 ); /* Reg 0x4 */
718+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
719+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxCtrlDelay | ( RxCtrlDelay << 4 ) ) );
720+
/*Data Delay */
721+
u16 RxDataDelay = 7; /* 0..15, default 7 */
722+
u16 TxDataDelay = 7; /* 0..15, default 7 */
723+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
724+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0005 ); /* Reg 0x5 */
725+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
726+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxDataDelay | ( RxDataDelay << 4 ) | ( RxDataDelay << 8 ) | ( RxDataDelay << 12 ) ) );
727+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
728+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0006 ); /* Reg 0x6 */
729+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
730+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxDataDelay | ( TxDataDelay << 4 ) | ( TxDataDelay << 8 ) | ( TxDataDelay << 12 ) ) );
731+
/*Clock Delay */
732+
u16 RxClockDelay = 31; /* 0..31, default 15 */
733+
u16 TxClockDelay = 31; /* 0..31, default 15 */
734+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 );
735+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0008 ); /* Reg 0x8 RGMII Clock Pad Skew */
736+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 );
737+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxClockDelay | ( TxClockDelay << 5 ) ) );
738+
}
739+
else if( PhyType == MICREL_ID_KSZ9021 ) /* KSZ9021 */
740+
{
741+
FreeRTOS_printf( ( "Detected KSZ9021 Ethernet PHY\n\r" ) );
742+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xB, 0x8104 ); /* write Reg 0x104 */
743+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xC, 0xF0F0 ); /* set write data */
744+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xB, 0x8105 ); /* write Reg 0x105 */
745+
XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xC, 0x0000 ); /* set write data */
746+
}
747+
748+
/* Issue a reset to phy */
749+
Status = XEmacPs_PhyRead( EmacPsInstancePtr, PhyAddr, 0x0, &PhyData );
750+
PhyData |= 0x8000;
751+
Status = XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0x0, PhyData );
752+
vTaskDelay( 1 );
753+
Status |= XEmacPs_PhyRead( EmacPsInstancePtr, PhyAddr, 0x0, &PhyData );
754+
755+
if( Status != XST_SUCCESS )
756+
{
757+
return Status;
758+
}
759+
760+
return PhyType;
761+
}
762+
763+
static uint32_t get_Micrel_phy_speed( XEmacPs * xemacpsp,
764+
uint32_t phy_addr )
765+
{
766+
const char * name_ptr;
767+
uint16_t temp, phy_type;
768+
uint16_t control;
769+
uint16_t status;
770+
uint16_t status_speed;
771+
uint32_t timeout_counter = 0;
772+
773+
/* Just to prevent compiler warnings about unused variables. */
774+
( void ) name_ptr;
775+
776+
777+
FreeRTOS_printf( ( "Start Micrel PHY program delay\r\n" ) );
778+
779+
if( ( phy_type = set_Micrel_phy_delays( xemacpsp, phy_addr ) ) != XST_FAILURE )
780+
{
781+
FreeRTOS_printf( ( "Delay Set Okay!\r\n" ) );
782+
}
783+
else
784+
{
785+
FreeRTOS_printf( ( "Delay Set Error!\r\n" ) );
786+
}
787+
788+
switch( phy_type )
789+
{
790+
case MICREL_ID_KSZ9021:
791+
name_ptr = "KSZ9021";
792+
break;
793+
794+
case MICREL_ID_KSZ9031:
795+
name_ptr = "KSZ9031";
796+
break;
797+
798+
case MICREL_ID_KSZ9131:
799+
name_ptr = "KSZ9131";
800+
break;
801+
802+
default:
803+
name_ptr = "!UNKNOWN!";
804+
break;
805+
}
806+
807+
FreeRTOS_printf( ( "Start %s auto-negotiation\r\n", name_ptr ) );
808+
809+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control );
810+
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
811+
control |= IEEE_PAUSE_MASK;
812+
control |= ADVERTISE_100;
813+
control |= ADVERTISE_10;
814+
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control );
815+
816+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &control );
817+
control |= ADVERTISE_1000;
818+
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, control );
819+
820+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, &control );
821+
control |= ( 7 << 12 );
822+
control |= ( 1 << 11 );
823+
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, control );
824+
825+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control );
826+
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
827+
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
828+
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control );
829+
830+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control );
831+
control |= IEEE_CTRL_RESET_MASK;
832+
XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control );
833+
834+
while( 1 )
835+
{
836+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control );
837+
838+
if( control & IEEE_CTRL_RESET_MASK )
839+
{
840+
continue;
841+
}
842+
else
843+
{
844+
break;
845+
}
846+
}
847+
848+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status );
849+
850+
FreeRTOS_printf( ( "Waiting for %s to complete Auto-negotiation.\r\n", name_ptr ) );
851+
852+
while( !( status & IEEE_STAT_AUTONEGOTIATE_COMPLETE ) )
853+
{
854+
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
855+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp );
856+
timeout_counter++;
857+
858+
if( timeout_counter == 30 )
859+
{
860+
FreeRTOS_printf( ( "Auto negotiation error \r\n" ) );
861+
return XST_FAILURE;
862+
}
863+
864+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status );
865+
}
866+
867+
FreeRTOS_printf( ( "%s Completed Auto-negotiation\r\n", name_ptr ) );
868+
869+
/* Check for high speed connection first */
870+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_3_REG_OFFSET, &status_speed );
871+
872+
if( status_speed & LPA_IEEE_1000FD )
873+
{
874+
FreeRTOS_printf( ( "Micrel PHY %s speed 1000Mbps\r\n", name_ptr ) );
875+
return 1000;
876+
}
877+
else /* No high speed so check lows... */
878+
{
879+
XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &status_speed );
880+
881+
if( status_speed & LP5_IEEE_100BTXFD )
882+
{
883+
FreeRTOS_printf( ( "Micrel PHY %s speed 100Mbps\r\n", name_ptr ) );
884+
return 100;
885+
}
886+
887+
if( status_speed & LP5_IEEE_10BTFD )
888+
{
889+
FreeRTOS_printf( ( "Micrel PHY %s speed 10Mbps\r\n", name_ptr ) );
890+
return 10;
891+
}
892+
}
893+
894+
return XST_FAILURE;
895+
}
896+
662897
/* Here is a XEmacPs_PhyRead() that returns the value of a register. */
663898
static uint16_t XEmacPs_PhyRead2( XEmacPs * InstancePtr,
664899
u32 PhyAddress,
@@ -898,6 +1133,10 @@ static const char * pcGetPHIName( uint16_t usID )
8981133
pcReturn = "Realtek RTL8212";
8991134
break;
9001135

1136+
case PHY_MICREL_IDENTIFIER:
1137+
pcReturn = "MICREL PHY";
1138+
break;
1139+
9011140
case PHY_AR8035_IDENTIFIER:
9021141
pcReturn = "Atheros_ar8035";
9031142
break;
@@ -945,6 +1184,10 @@ static uint32_t get_IEEE_phy_speed_US( XEmacPs * xemacpsp,
9451184
RetStatus = get_Marvell_phy_speed( xemacpsp, phy_addr );
9461185
break;
9471186

1187+
case PHY_MICREL_IDENTIFIER:
1188+
RetStatus = get_Micrel_phy_speed( xemacpsp, phy_addr );
1189+
break;
1190+
9481191
case PHY_AR8035_IDENTIFIER:
9491192
RetStatus = get_AR8035_phy_speed( xemacpsp, phy_addr );
9501193
prvSET_AR803x_TX_Timing( xemacpsp, phy_addr );

0 commit comments

Comments
 (0)