/* * Copyright (c) 2007-2008, Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Advanced Micro Devices, Inc. nor the names * of its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Some portions copyright (c) 2010-2013 Xilinx, Inc. All rights reserved. * * Xilinx, Inc. * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. * */ /* Standard includes. */ #include #include #include #include "x_emacpsif.h" /*#include "lwipopts.h" */ #include "xparameters_ps.h" #include "xparameters.h" /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" /*/ * FreeRTOS+TCP includes. * / */ /* FreeRTOS+TCP includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" #include "FreeRTOS_IP_Private.h" #include "NetworkBufferManagement.h" #define phyMIN_PHY_ADDRESS 0 #define phyMAX_PHY_ADDRESS 31 #define MINIMUM_SLEEP_TIME ( ( TickType_t ) 1 * configTICK_RATE_HZ ) /*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c *** to run it on a PEEP board ***/ /* Advertisement control register. */ #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ #define ADVERTISE_1000FULL 0x0200 #define ADVERTISE_1000HALF 0x0100 #define ADVERTISE_100_AND_10 \ ( ADVERTISE_10FULL | ADVERTISE_100FULL | \ ADVERTISE_10HALF | ADVERTISE_100HALF ) #define ADVERTISE_100 ( ADVERTISE_100FULL | ADVERTISE_100HALF ) #define ADVERTISE_10 ( ADVERTISE_10FULL | ADVERTISE_10HALF ) #define ADVERTISE_1000 0x0300 /*#define PHY_REG_00_BMCR 0x00 // Basic mode control register */ /*#define PHY_REG_01_BMSR 0x01 // Basic mode status register */ /*#define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1 */ /*#define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2 */ /*#define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg */ #define IEEE_CONTROL_REG_OFFSET 0 #define IEEE_STATUS_REG_OFFSET 1 #define IEEE_AUTONEGO_ADVERTISE_REG 4 #define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5 #define IEEE_PARTNER_ABILITIES_2_REG_OFFSET 8 #define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10 #define IEEE_1000_ADVERTISE_REG_OFFSET 9 #define IEEE_MMD_ACCESS_CONTROL_REG 13 #define IEEE_MMD_ACCESS_ADDRESS_DATA_REG 14 #define IEEE_COPPER_SPECIFIC_CONTROL_REG 16 #define IEEE_SPECIFIC_STATUS_REG 17 #define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19 #define IEEE_EXT_PHY_SPECIFIC_CONTROL_REG 20 #define IEEE_CONTROL_REG_MAC 21 #define IEEE_PAGE_ADDRESS_REGISTER 22 #define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040 #define IEEE_CTRL_LINKSPEED_MASK 0x0040 #define IEEE_CTRL_LINKSPEED_1000M 0x0040 #define IEEE_CTRL_LINKSPEED_100M 0x2000 #define IEEE_CTRL_LINKSPEED_10M 0x0000 #define IEEE_CTRL_FULL_DUPLEX 0x100 #define IEEE_CTRL_RESET_MASK 0x8000 #define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000 #define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008 #define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020 #define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200 #define IEEE_STAT_LINK_STATUS 0x0004 #define IEEE_STAT_1GBPS_EXTENSIONS 0x0100 #define IEEE_AN1_ABILITY_MASK 0x1FE0 #define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00 #define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380 #define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060 #define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030 #define IEEE_SPEED_MASK 0xC000 #define IEEE_SPEED_1000 0x8000 #define IEEE_SPEED_100 0x4000 #define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800 #define IEEE_PAUSE_MASK 0x0400 #define IEEE_AUTONEG_ERROR_MASK 0x8000 #define IEEE_MMD_ACCESS_CTRL_DEVAD_MASK 0x1F #define IEEE_MMD_ACCESS_CTRL_PIDEVAD_MASK 0x801F #define IEEE_MMD_ACCESS_CTRL_NOPIDEVAD_MASK 0x401F #define PHY_DETECT_REG 1 #define PHY_IDENTIFIER_1_REG 2 #define PHY_IDENTIFIER_2_REG 3 #define PHY_DETECT_MASK 0x1808 #define PHY_MARVELL_IDENTIFIER 0x0141 #define PHY_TI_IDENTIFIER 0x2000 #define PHY_REALTEK_IDENTIFIER 0x001c #define PHY_AR8035_IDENTIFIER 0x004D #define PHY_XILINX_PCS_PMA_ID1 0x0174 #define PHY_XILINX_PCS_PMA_ID2 0x0C00 #define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140 #define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100 #define XEMACPS_GMII2RGMII_SPEED10_FD 0x100 #define XEMACPS_GMII2RGMII_REG_NUM 0x10 #define PHY_REGCR 0x0D #define PHY_ADDAR 0x0E #define PHY_RGMIIDCTL 0x86 #define PHY_RGMIICTL 0x32 #define PHY_STS 0x11 #define PHY_TI_CR 0x10 #define PHY_TI_CFG4 0x31 #define PHY_REGCR_ADDR 0x001F #define PHY_REGCR_DATA 0x401F #define PHY_TI_CRVAL 0x5048 #define PHY_TI_CFG4RESVDBIT7 0x80 /* Frequency setting */ #define SLCR_LOCK_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x4 ) #define SLCR_UNLOCK_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x8 ) #define SLCR_GEM0_CLK_CTRL_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x140 ) #define SLCR_GEM1_CLK_CTRL_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x144 ) #ifdef PEEP #define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031 #define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001 #define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011 #endif #define SLCR_GEM_SRCSEL_EMIO 0x40 #define SLCR_LOCK_KEY_VALUE 0x767B #define SLCR_UNLOCK_KEY_VALUE 0xDF0D #define SLCR_ADDR_GEM_RST_CTRL ( XPS_SYS_CTRL_BASEADDR + 0x214 ) #define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF #define ZYNQ_EMACPS_0_BASEADDR 0xE000B000 #define ZYNQ_EMACPS_1_BASEADDR 0xE000C000 #define ZYNQMP_EMACPS_0_BASEADDR 0xFF0B0000 #define ZYNQMP_EMACPS_1_BASEADDR 0xFF0C0000 #define ZYNQMP_EMACPS_2_BASEADDR 0xFF0D0000 #define ZYNQMP_EMACPS_3_BASEADDR 0xFF0E0000 #define CRL_APB_GEM0_REF_CTRL 0xFF5E0050 #define CRL_APB_GEM1_REF_CTRL 0xFF5E0054 #define CRL_APB_GEM2_REF_CTRL 0xFF5E0058 #define CRL_APB_GEM3_REF_CTRL 0xFF5E005C #define CRL_APB_GEM_DIV0_MASK 0x00003F00 #define CRL_APB_GEM_DIV0_SHIFT 8 #define CRL_APB_GEM_DIV1_MASK 0x003F0000 #define CRL_APB_GEM_DIV1_SHIFT 16 #define VERSAL_EMACPS_0_BASEADDR 0xFF0C0000 #define VERSAL_EMACPS_1_BASEADDR 0xFF0D0000 #define VERSAL_CRL_GEM0_REF_CTRL 0xFF5E0118 #define VERSAL_CRL_GEM1_REF_CTRL 0xFF5E011C #define VERSAL_CRL_GEM_DIV_MASK 0x0003FF00 #define VERSAL_CRL_APB_GEM_DIV_SHIFT 8 #define GEM_VERSION_ZYNQMP 7 #define GEM_VERSION_VERSAL 0x107 u32 phymapemac0[ 32 ]; u32 phymapemac1[ 32 ]; static uint16_t prvAR803x_debug_reg_write( XEmacPs * xemacpsp, uint32_t phy_addr, u16 reg, u16 value ); static void prvSET_AR803x_TX_Timing( XEmacPs * xemacpsp, uint32_t phy_addr ); uint32_t ulDetecPHY( XEmacPs * xemacpsp ) { u16 PhyReg1; u16 PhyReg2; u32 phy_addr; u32 Status; for( phy_addr = phyMIN_PHY_ADDRESS; phy_addr <= phyMAX_PHY_ADDRESS; phy_addr++ ) { Status = XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG, &PhyReg1 ); Status |= XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_IDENTIFIER_2_REG, &PhyReg2 ); if( ( Status == XST_SUCCESS ) && ( PhyReg1 > 0x0000 ) && ( PhyReg1 < 0xffff ) && ( PhyReg2 > 0x0000 ) && ( PhyReg2 < 0xffff ) ) { /* Found a valid PHY address */ break; } } return ( phy_addr <= phyMAX_PHY_ADDRESS ) ? phy_addr : ~0U; } unsigned configure_IEEE_phy_speed_US( XEmacPs * xemacpsp, unsigned speed, u32 phy_addr ) { u16 control; 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; } 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 ); } XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control | IEEE_CTRL_RESET_MASK ); { volatile int wait; for( wait = 0; wait < 100000; wait++ ) { } } return 0; } static uint32_t get_TI_phy_speed( XEmacPs * xemacpsp, uint32_t phy_addr ) { uint16_t control; uint16_t status; uint16_t status_speed; uint32_t timeout_counter = 0; uint32_t phyregtemp; int i; uint32_t RetStatus; XEmacPs_PhyRead( xemacpsp, phy_addr, 0x1F, ( uint16_t * ) &phyregtemp ); phyregtemp |= 0x4000; XEmacPs_PhyWrite( xemacpsp, phy_addr, 0x1F, phyregtemp ); RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, 0x1F, ( uint16_t * ) &phyregtemp ); if( RetStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "Error during sw reset \n\r" ) ); return XST_FAILURE; } XEmacPs_PhyRead( xemacpsp, phy_addr, 0, ( uint16_t * ) &phyregtemp ); phyregtemp |= 0x8000; XEmacPs_PhyWrite( xemacpsp, phy_addr, 0, phyregtemp ); /* * Delay */ for( i = 0; i < 1000000000; i++ ) { } RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, 0, ( uint16_t * ) &phyregtemp ); if( RetStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "Error during reset \n\r" ) ); return XST_FAILURE; } /* FIFO depth */ XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_TI_CR, PHY_TI_CRVAL ); RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_TI_CR, ( uint16_t * ) &phyregtemp ); if( RetStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "Error writing to 0x10 \n\r" ) ); return XST_FAILURE; } /* TX/RX tuning */ /* Write to PHY_RGMIIDCTL */ XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA ); RetStatus = XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, 0xA8 ); if( RetStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "Error in tuning" ) ); return XST_FAILURE; } /* Read PHY_RGMIIDCTL */ XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA ); RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_ADDAR, ( uint16_t * ) &phyregtemp ); if( RetStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "Error in tuning" ) ); return XST_FAILURE; } /* Write PHY_RGMIICTL */ XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIICTL ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA ); RetStatus = XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, 0xD3 ); if( RetStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "Error in tuning" ) ); return XST_FAILURE; } /* Read PHY_RGMIICTL */ XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIICTL ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA ); RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_ADDAR, ( uint16_t * ) &phyregtemp ); if( RetStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "Error in tuning" ) ); return XST_FAILURE; } /* SW workaround for unstable link when RX_CTRL is not STRAP MODE 3 or 4 */ XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, PHY_TI_CFG4 ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA ); RetStatus = XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_ADDAR, ( uint16_t * ) &phyregtemp ); phyregtemp &= ~( PHY_TI_CFG4RESVDBIT7 ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, PHY_TI_CFG4 ); XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA ); RetStatus = XEmacPs_PhyWrite( xemacpsp, phy_addr, PHY_ADDAR, phyregtemp ); 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 ); 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 ); XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status ); FreeRTOS_printf( ( "Waiting for PHY to complete autonegotiation.\n" ) ); while( !( status & IEEE_STAT_AUTONEGOTIATE_COMPLETE ) ) { vTaskDelay( MINIMUM_SLEEP_TIME ); timeout_counter++; if( timeout_counter == 30 ) { FreeRTOS_printf( ( "Auto negotiation error \n" ) ); return XST_FAILURE; } XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status ); } FreeRTOS_printf( ( "autonegotiation complete \n" ) ); XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_STS, &status_speed ); if( ( status_speed & 0xC000 ) == 0x8000 ) { return 1000; } else if( ( status_speed & 0xC000 ) == 0x4000 ) { return 100; } else { return 10; } return XST_SUCCESS; } static uint32_t get_Marvell_phy_speed( XEmacPs * xemacpsp, uint32_t phy_addr ) { uint16_t temp; uint16_t control; uint16_t status; uint16_t status_speed; uint32_t timeout_counter = 0; uint32_t temp_speed; 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 ); 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 ); FreeRTOS_printf( ( "Waiting for PHY to complete autonegotiation.\n" ) ); while( !( status & IEEE_STAT_AUTONEGOTIATE_COMPLETE ) ) { vTaskDelay( MINIMUM_SLEEP_TIME ); XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp ); timeout_counter++; if( timeout_counter == 30 ) { FreeRTOS_printf( ( "Auto negotiation error \n" ) ); return XST_FAILURE; } XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status ); } FreeRTOS_printf( ( "autonegotiation complete \n" ) ); XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &status_speed ); if( status_speed & 0x400 ) { temp_speed = status_speed & IEEE_SPEED_MASK; if( temp_speed == IEEE_SPEED_1000 ) { return 1000; } else if( temp_speed == IEEE_SPEED_100 ) { return 100; } else { return 10; } } return XST_SUCCESS; } static uint32_t get_Realtek_phy_speed( XEmacPs * xemacpsp, uint32_t phy_addr ) { uint16_t control; uint16_t status; uint16_t status_speed; uint32_t timeout_counter = 0; uint32_t temp_speed; 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 ); 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 ); FreeRTOS_printf( ( "Waiting for PHY to complete autonegotiation.\n" ) ); while( !( status & IEEE_STAT_AUTONEGOTIATE_COMPLETE ) ) { vTaskDelay( MINIMUM_SLEEP_TIME ); timeout_counter++; if( timeout_counter == 30 ) { FreeRTOS_printf( ( "Auto negotiation error \n" ) ); return XST_FAILURE; } XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status ); } FreeRTOS_printf( ( "autonegotiation complete \n" ) ); XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &status_speed ); if( status_speed & 0x400 ) { temp_speed = status_speed & IEEE_SPEED_MASK; if( temp_speed == IEEE_SPEED_1000 ) { return 1000; } else if( temp_speed == IEEE_SPEED_100 ) { return 100; } else { return 10; } } return XST_FAILURE; } /* Here is a XEmacPs_PhyRead() that returns the value of a register. */ static uint16_t XEmacPs_PhyRead2( XEmacPs * InstancePtr, u32 PhyAddress, u32 RegisterNum ) { LONG lResult; uint16_t usReturn = 0U; lResult = XEmacPs_PhyRead( InstancePtr, PhyAddress, RegisterNum, &( usReturn ) ); if( lResult != ( LONG ) ( XST_SUCCESS ) ) { usReturn = 0U; } return usReturn; } static uint32_t ar8035CheckStatus( XEmacPs * xemacpsp, uint32_t phy_addr ); static void prvSET_AR803x_TX_Timing( XEmacPs * xemacpsp, uint32_t phy_addr ) { /* * rgmii_tx_clk_dly: tx clock delay control bit: * 1 = rgmii tx clock delay enable <<= this option * 0 = rgmii tx clock delay disable. * * Gtx_dly_val: select the delay of gtx_clk. * 00:0.25ns * 01:1.3ns <<= this option * 10:2.4ns * 11:3.4ns */ prvAR803x_debug_reg_write( xemacpsp, phy_addr, 0x5, 0x2d47 ); prvAR803x_debug_reg_write( xemacpsp, phy_addr, 0xb, 0xbc20 ); } static uint32_t get_AR8035_phy_speed( XEmacPs * xemacpsp, uint32_t phy_addr ) { uint32_t timeout_counter = 0; /*Reset PHY transceiver */ XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, IEEE_CTRL_RESET_MASK ); /*Wait for the reset to complete */ while( ( XEmacPs_PhyRead2( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET ) & IEEE_CTRL_RESET_MASK ) != 0U ) { } /*Basic mode control register */ /* IEEE_CTRL_LINKSPEED_100M, also known as 'AR8035_BMCR_SPEED_SEL_LSB' */ /* IEEE_STAT_1GBPS_EXTENSIONS also known as: AR8035_BMCR_DUPLEX_MODE' */ XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, IEEE_CTRL_LINKSPEED_100M | IEEE_CTRL_AUTONEGOTIATE_ENABLE | IEEE_STAT_1GBPS_EXTENSIONS ); #define AR8035_ANAR_SELECTOR_DEFAULT 0x0001 /*Auto-negotiation advertisement register */ XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, IEEE_CTRL_AUTONEGOTIATE_ENABLE | IEEE_ASYMMETRIC_PAUSE_MASK | IEEE_PAUSE_MASK | ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF | AR8035_ANAR_SELECTOR_DEFAULT ); /*1000 BASE-T control register */ XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, ADVERTISE_1000FULL ); #define AR8035_FUNC_CTRL 0x10 #define AR8035_FUNC_CTRL_ASSERT_CRS_ON_TX 0x0800 #define AR8035_FUNC_CTRL_MDIX_MODE 0x0060 #define AR8035_FUNC_CTRL_MDIX_MODE_MANUAL_MDI 0x0000 #define AR8035_FUNC_CTRL_MDIX_MODE_MANUAL_MDIX 0x0020 #define AR8035_FUNC_CTRL_MDIX_MODE_AUTO 0x0060 #define AR8035_FUNC_CTRL_SQE_TEST 0x0004 #define AR8035_FUNC_CTRL_POLARITY_REVERSAL 0x0002 #define AR8035_FUNC_CTRL_JABBER_DIS 0x0001 /*Function control register */ XEmacPs_PhyWrite( xemacpsp, phy_addr, AR8035_FUNC_CTRL, AR8035_FUNC_CTRL_ASSERT_CRS_ON_TX | AR8035_FUNC_CTRL_MDIX_MODE_AUTO | AR8035_FUNC_CTRL_POLARITY_REVERSAL ); /*Dump PHY registers for debugging purpose */ /* ar8035DumpPhyReg(interface); */ #define AR8035_INT_EN 0x12 #define AR8035_INT_STATUS_LINK_FAIL 0x0800 #define AR8035_INT_STATUS_LINK_SUCCESS 0x0400 /*The PHY will generate interrupts when link status changes are detected */ XEmacPs_PhyWrite( xemacpsp, phy_addr, AR8035_INT_EN, AR8035_INT_STATUS_LINK_FAIL | AR8035_INT_STATUS_LINK_SUCCESS ); while( pdTRUE ) { uint32_t status; vTaskDelay( MINIMUM_SLEEP_TIME ); timeout_counter++; if( timeout_counter == 30 ) { FreeRTOS_printf( ( "Auto negotiation error \n" ) ); return XST_FAILURE; } status = ar8035CheckStatus( xemacpsp, phy_addr ); if( status > 10 ) { prvSET_AR803x_TX_Timing( xemacpsp, phy_addr ); return status; } } } #define AR803X_DEBUG_ADDR 0x1D #define AR803X_DEBUG_DATA 0x1E static uint16_t prvAR803x_debug_reg_write( XEmacPs * xemacpsp, uint32_t phy_addr, u16 reg, u16 value ) { XEmacPs_PhyWrite( xemacpsp, phy_addr, AR803X_DEBUG_ADDR, reg ); return XEmacPs_PhyWrite( xemacpsp, phy_addr, AR803X_DEBUG_DATA, value ); } static uint32_t ar8035CheckStatus( XEmacPs * xemacpsp, uint32_t phy_addr ) { uint16_t status; uint32_t linkSpeed = 0U; BaseType_t linkState = pdFALSE; /*Read status register to acknowledge the interrupt */ status = XEmacPs_PhyRead2( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2 ); #define AR8035_INT_STATUS_LINK_FAIL 0x0800 #define AR8035_INT_STATUS_LINK_SUCCESS 0x0400 /*Link status change? */ if( status & ( AR8035_INT_STATUS_LINK_FAIL | AR8035_INT_STATUS_LINK_SUCCESS ) ) { /*Read PHY status register */ status = XEmacPs_PhyRead2( xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG ); #define AR8035_PHY_STATUS_LINK 0x0400 /*Link is up? */ if( status & AR8035_PHY_STATUS_LINK ) { #define AR8035_PHY_STATUS_SPEED 0xC000 #define AR8035_PHY_STATUS_SPEED_10MBPS 0x0000 #define AR8035_PHY_STATUS_SPEED_100MBPS 0x4000 #define AR8035_PHY_STATUS_SPEED_1000MBPS 0x8000 /*Check current speed */ switch( status & AR8035_PHY_STATUS_SPEED ) { /*10BASE-T */ case AR8035_PHY_STATUS_SPEED_10MBPS: linkSpeed = 10; break; /*100BASE-TX */ case AR8035_PHY_STATUS_SPEED_100MBPS: linkSpeed = 100; break; /*1000BASE-T */ case AR8035_PHY_STATUS_SPEED_1000MBPS: linkSpeed = 1000; break; /*Unknown speed */ default: /*Debug message */ FreeRTOS_printf( ( "Invalid speed ( status %04X )\n", status ) ); break; } #define AR8035_PHY_STATUS_DUPLEX 0x2000 /*Check current duplex mode */ if( status & AR8035_PHY_STATUS_DUPLEX ) { FreeRTOS_printf( ( "Full duplex\n" ) ); } else { FreeRTOS_printf( ( "Half duplex\n" ) ); } /*Update link state */ linkState = TRUE; /*Adjust MAC configuration parameters for proper operation */ /*interface->nicDriver->updateMacConfig(interface); */ } else { /*Update link state */ linkState = FALSE; } /*Process link state change event */ /* nicNotifyLinkChange(interface); */ } /* Just to prevent compiler warnings about unused variable. */ ( void ) linkState; return linkSpeed; } static const char * pcGetPHIName( uint16_t usID ) { const char * pcReturn = ""; static char pcName[ 16 ]; switch( usID ) { case PHY_TI_IDENTIFIER: pcReturn = "TI_dp83869hm"; break; case PHY_REALTEK_IDENTIFIER: pcReturn = "Realtek RTL8212"; break; case PHY_AR8035_IDENTIFIER: pcReturn = "Atheros_ar8035"; break; case PHY_MARVELL_IDENTIFIER: pcReturn = "Marvell_88E1512"; break; default: snprintf( pcName, sizeof pcName, "Unkkwn PHY %04X", usID ); pcReturn = pcName; break; } return pcReturn; } static uint32_t get_IEEE_phy_speed_US( XEmacPs * xemacpsp, uint32_t phy_addr ) { uint16_t phy_identity; uint32_t RetStatus; XEmacPs_PhyRead( xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG, &phy_identity ); const char * pcPHYName = pcGetPHIName( phy_identity ); FreeRTOS_printf( ( "Start %s PHY autonegotiation. ID = 0x%04X\n", pcPHYName, phy_identity ) ); /* Just to prevent compiler warnings about unused variablies. */ ( void ) pcPHYName; switch( phy_identity ) { case PHY_TI_IDENTIFIER: RetStatus = get_TI_phy_speed( xemacpsp, phy_addr ); break; case PHY_REALTEK_IDENTIFIER: RetStatus = get_Realtek_phy_speed( xemacpsp, phy_addr ); break; case PHY_MARVELL_IDENTIFIER: RetStatus = get_Marvell_phy_speed( xemacpsp, phy_addr ); break; case PHY_AR8035_IDENTIFIER: RetStatus = get_AR8035_phy_speed( xemacpsp, phy_addr ); /* RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr); */ /* RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr); */ prvSET_AR803x_TX_Timing( xemacpsp, phy_addr ); break; default: FreeRTOS_printf( ( "Don't know how to handle PHY ID %04X\n", phy_identity ) ); RetStatus = XST_FAILURE; break; } return RetStatus; } static void SetUpSLCRDivisors( u32 mac_baseaddr, s32 speed ) { volatile u32 slcrBaseAddress; u32 SlcrDiv0 = 0; u32 SlcrDiv1 = 0; u32 SlcrTxClkCntrl; u32 gigeversion; volatile u32 CrlApbBaseAddr; u32 CrlApbDiv0 = 0; u32 CrlApbDiv1 = 0; u32 CrlApbGemCtrl; gigeversion = ( ( Xil_In32( mac_baseaddr + 0xFC ) ) >> 16 ) & 0xFFF; if( gigeversion == 2 ) { *( volatile u32 * ) ( SLCR_UNLOCK_ADDR ) = SLCR_UNLOCK_KEY_VALUE; if( mac_baseaddr == ZYNQ_EMACPS_0_BASEADDR ) { slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR; } else { slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR; } if( ( *( volatile u32 * ) ( UINTPTR ) ( slcrBaseAddress ) ) & SLCR_GEM_SRCSEL_EMIO ) { return; } if( speed == 1000 ) { if( mac_baseaddr == XPAR_XEMACPS_0_BASEADDR ) { #ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0; SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1; #endif } else { #ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0 SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0; SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1; #endif } } else if( speed == 100 ) { if( mac_baseaddr == XPAR_XEMACPS_0_BASEADDR ) { #ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0; SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1; #endif } else { #ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0 SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0; SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1; #endif } } else { if( mac_baseaddr == XPAR_XEMACPS_0_BASEADDR ) { #ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0; SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1; #endif } else { #ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0 SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0; SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1; #endif } } if( ( SlcrDiv0 != 0 ) && ( SlcrDiv1 != 0 ) ) { SlcrTxClkCntrl = *( volatile u32 * ) ( UINTPTR ) ( slcrBaseAddress ); SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; SlcrTxClkCntrl |= ( SlcrDiv1 << 20 ); SlcrTxClkCntrl |= ( SlcrDiv0 << 8 ); *( volatile u32 * ) ( UINTPTR ) ( slcrBaseAddress ) = SlcrTxClkCntrl; *( volatile u32 * ) ( SLCR_LOCK_ADDR ) = SLCR_LOCK_KEY_VALUE; } else { FreeRTOS_printf( ( "Clock Divisors incorrect - Please check\n" ) ); } } else if( gigeversion == GEM_VERSION_ZYNQMP ) { /* Setup divisors in CRL_APB for Zynq Ultrascale+ MPSoC */ if( mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR ) { CrlApbBaseAddr = CRL_APB_GEM0_REF_CTRL; } else if( mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR ) { CrlApbBaseAddr = CRL_APB_GEM1_REF_CTRL; } else if( mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR ) { CrlApbBaseAddr = CRL_APB_GEM2_REF_CTRL; } else if( mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR ) { CrlApbBaseAddr = CRL_APB_GEM3_REF_CTRL; } if( speed == 1000 ) { if( mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV1; #endif } } else if( speed == 100 ) { if( mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV1; #endif } } else { if( mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV1; #endif } else if( mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR ) { #ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV0 CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV0; CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV1; #endif } } if( ( CrlApbDiv0 != 0 ) && ( CrlApbDiv1 != 0 ) ) { #if EL1_NONSECURE XSmc_OutVar RegRead; RegRead = Xil_Smc( MMIO_READ_SMC_FID, ( u64 ) ( CrlApbBaseAddr ), 0, 0, 0, 0, 0, 0 ); CrlApbGemCtrl = RegRead.Arg0 >> 32; #else CrlApbGemCtrl = *( volatile u32 * ) ( UINTPTR ) ( CrlApbBaseAddr ); #endif CrlApbGemCtrl &= ~CRL_APB_GEM_DIV0_MASK; CrlApbGemCtrl |= CrlApbDiv0 << CRL_APB_GEM_DIV0_SHIFT; CrlApbGemCtrl &= ~CRL_APB_GEM_DIV1_MASK; CrlApbGemCtrl |= CrlApbDiv1 << CRL_APB_GEM_DIV1_SHIFT; #if EL1_NONSECURE Xil_Smc( MMIO_WRITE_SMC_FID, ( u64 ) ( CrlApbBaseAddr ) | ( ( u64 ) ( 0xFFFFFFFF ) << 32 ), ( u64 ) CrlApbGemCtrl, 0, 0, 0, 0, 0 ); do { RegRead = Xil_Smc( MMIO_READ_SMC_FID, ( u64 ) ( CrlApbBaseAddr ), 0, 0, 0, 0, 0, 0 ); } while( ( RegRead.Arg0 >> 32 ) != CrlApbGemCtrl ); #else *( volatile u32 * ) ( UINTPTR ) ( CrlApbBaseAddr ) = CrlApbGemCtrl; #endif } else { FreeRTOS_printf( ( "Clock Divisors incorrect - Please check\n" ) ); } } else if( gigeversion == GEM_VERSION_VERSAL ) { /* Setup divisors in CRL for Versal */ if( mac_baseaddr == VERSAL_EMACPS_0_BASEADDR ) { CrlApbBaseAddr = VERSAL_CRL_GEM0_REF_CTRL; #if EL1_NONSECURE ClkId = CLK_GEM0_REF; #endif } else if( mac_baseaddr == VERSAL_EMACPS_1_BASEADDR ) { CrlApbBaseAddr = VERSAL_CRL_GEM1_REF_CTRL; #if EL1_NONSECURE ClkId = CLK_GEM1_REF; #endif } if( speed == 1000 ) { if( mac_baseaddr == VERSAL_EMACPS_0_BASEADDR ) { #ifdef XPAR_PSV_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 CrlApbDiv0 = XPAR_PSV_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0; #endif } else if( mac_baseaddr == VERSAL_EMACPS_1_BASEADDR ) { #ifdef XPAR_PSV_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0 CrlApbDiv0 = XPAR_PSV_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0; #endif } } else if( speed == 100 ) { if( mac_baseaddr == VERSAL_EMACPS_0_BASEADDR ) { #ifdef XPAR_PSV_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 CrlApbDiv0 = XPAR_PSV_ETHERNET_0_ENET_SLCR_100MBPS_DIV0; #endif } else if( mac_baseaddr == VERSAL_EMACPS_1_BASEADDR ) { #ifdef XPAR_PSV_ETHERNET_1_ENET_SLCR_100MBPS_DIV0 CrlApbDiv0 = XPAR_PSV_ETHERNET_1_ENET_SLCR_100MBPS_DIV0; #endif } } else { if( mac_baseaddr == VERSAL_EMACPS_0_BASEADDR ) { #ifdef XPAR_PSV_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 CrlApbDiv0 = XPAR_PSV_ETHERNET_0_ENET_SLCR_10MBPS_DIV0; #endif } else if( mac_baseaddr == VERSAL_EMACPS_1_BASEADDR ) { #ifdef XPAR_PSV_ETHERNET_1_ENET_SLCR_10MBPS_DIV0 CrlApbDiv0 = XPAR_PSV_ETHERNET_1_ENET_SLCR_10MBPS_DIV0; #endif } } if( CrlApbDiv0 != 0 ) { #if EL1_NONSECURE Xil_Smc( PM_SET_DIVIDER_SMC_FID, ( ( ( u64 ) CrlApbDiv0 << 32 ) | ClkId ), 0, 0, 0, 0, 0, 0 ); #else CrlApbGemCtrl = Xil_In32( ( UINTPTR ) CrlApbBaseAddr ); CrlApbGemCtrl &= ~VERSAL_CRL_GEM_DIV_MASK; CrlApbGemCtrl |= CrlApbDiv0 << VERSAL_CRL_APB_GEM_DIV_SHIFT; Xil_Out32( ( UINTPTR ) CrlApbBaseAddr, CrlApbGemCtrl ); #endif } else { FreeRTOS_printf( ( "Clock Divisors incorrect - Please check\n" ) ); } } } u32 Phy_Setup_US( XEmacPs * xemacpsp, u32 phy_addr ) { u32 link_speed = 0; u32 conv_present = 0; u32 convspeeddupsetting = 0; u32 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_US( xemacpsp, phy_addr ); 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 if( link_speed != XST_FAILURE ) { SetUpSLCRDivisors( xemacpsp->Config.BaseAddress, 10 ); convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD; } else { FreeRTOS_printf( ( "Phy setup error \n" ) ); return XST_FAILURE; } #elif defined( ipconfigNIC_LINKSPEED1000 ) SetUpSLCRDivisors( xemacpsp->Config.BaseAddress, 1000, , phy_addr ); link_speed = 1000; configure_IEEE_phy_speed_US( xemacpsp, link_speed ); convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD; vTaskDelay( MINIMUM_SLEEP_TIME ); #elif defined( ipconfigNIC_LINKSPEED100 ) SetUpSLCRDivisors( xemacpsp->Config.BaseAddress, 100 ); link_speed = 100; configure_IEEE_phy_speed_US( xemacpsp, link_speed, phy_addr ); convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD; vTaskDelay( MINIMUM_SLEEP_TIME ); #elif defined( ipconfigNIC_LINKSPEED10 ) SetUpSLCRDivisors( xemacpsp->Config.BaseAddress, 10 ); link_speed = 10; configure_IEEE_phy_speed_US( xemacpsp, link_speed, , phy_addr ); convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD; vTaskDelay( MINIMUM_SLEEP_TIME ); #endif /* ifdef ipconfigNIC_LINKSPEED_AUTODETECT */ if( conv_present ) { XEmacPs_PhyWrite( xemacpsp, convphyaddr, XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting ); } FreeRTOS_printf( ( "link speed: %d\n", link_speed ) ); return link_speed; }