/* ======================================================================
 *   Copyright (C) 2022 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */

/**
 *  \file     EthApp_utils.c
 *
 *  \brief    This file contains common utility functions used by the MCAL Eth
 *            apps
 *
 */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include "stdio.h"
#include "stdarg.h"
#include "stdlib.h"
#include "Std_Types.h"
#include "hw_types.h"
#include "app_utils.h"
#include "Eth.h"
#include "Eth_Irq.h"
#include "Eth_GeneralTypes.h"
#include "EthTrcv.h"
#include "app_utilsEth.h"
#include "soc.h"
#include "hw_ctrl_core.h"
#include "EcuM_Cbk.h"
#include "Mcu.h"
#include "Mcu_Cfg.h"
#include "trace.h"


/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */


/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */
typedef enum CacheP_Type_ {
    CacheP_TYPE_L1P  = (0x0001u), /**< L1 program cache */
    CacheP_TYPE_L1D  = (0x0002u), /**< L1 data cache */
    CacheP_TYPE_L2P  = (0x0004u), /**< L2 program cache */
    CacheP_TYPE_L2D  = (0x0008u), /**< L2 data cache */
    CacheP_TYPE_L1   = (CacheP_TYPE_L1P|CacheP_TYPE_L1D), /**< All L1 cache's */
    CacheP_TYPE_L2   = (CacheP_TYPE_L2P|CacheP_TYPE_L2D), /**< All L2 cache's */
    CacheP_TYPE_ALLP = (CacheP_TYPE_L1P|CacheP_TYPE_L2P), /**< All program cache's */
    CacheP_TYPE_ALLD = (CacheP_TYPE_L1D|CacheP_TYPE_L2D), /**< All data cache's */
    CacheP_TYPE_ALL  = (CacheP_TYPE_L1|CacheP_TYPE_L2)    /**< All cache's */
} CacheP_Type;
uint32  gCacheL1dCacheLineSize = 32;



/* ========================================================================== */
/*                         Internal Function Declarations                     */
/* ========================================================================== */

void CacheP_wbInv(void *addr, uint32 size, uint32 type);
void CacheP_invL1d(void *startAddress, uint32 byteCount);

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

void AppUtils_ethPrintVersionInfo()
{
#if (ETH_VERSION_INFO_API == STD_ON) || (ETHTRCV_VERSION_INFO_API == STD_ON)
    Std_VersionInfoType versioninfo;
#endif  /* #if (ETH_VERSION_INFO_API == STD_ON) */
#if (ETH_VERSION_INFO_API == STD_ON)
    /* Get and print version */
    Eth_GetVersionInfo(&versioninfo);
    AppUtils_printf(" \n");
    AppUtils_printf("\rETH MCAL Version Info\n");
    AppUtils_printf("\r---------------------\n");
    AppUtils_printf("\rVendor ID           : %d\n", versioninfo.vendorID);
    AppUtils_printf("\rModule ID           : %d\n", versioninfo.moduleID);
    AppUtils_printf("\rSW Major Version    : %d\n", versioninfo.sw_major_version);
    AppUtils_printf("\rSW Minor Version    : %d\n", versioninfo.sw_minor_version);
    AppUtils_printf("\rSW Patch Version    : %d\n", versioninfo.sw_patch_version);
    AppUtils_printf(" \n");
#endif  /* #if (ETH_VERSION_INFO_API == STD_ON) */

#if (ETHTRCV_VERSION_INFO_API == STD_ON)
    /* Get and print version */
    EthTrcv_GetVersionInfo(&versioninfo);
    AppUtils_printf(" \n");
    AppUtils_printf("\rETH TRCV MCAL Version Info\n");
    AppUtils_printf("\r---------------------\n");
    AppUtils_printf("\rVendor ID           : %d\n", versioninfo.vendorID);
    AppUtils_printf("\rModule ID           : %d\n", versioninfo.moduleID);
    AppUtils_printf("\rSW Major Version    : %d\n", versioninfo.sw_major_version);
    AppUtils_printf("\rSW Minor Version    : %d\n", versioninfo.sw_minor_version);
    AppUtils_printf("\rSW Patch Version    : %d\n", versioninfo.sw_patch_version);
    AppUtils_printf(" \n");
#endif  /* #if (ETH_VERSION_INFO_API == STD_ON) */
}

Std_ReturnType AppUtils_ethTrcvInit(EthTrcv_ConfigType *ethTrcvConfigPtr)
{
    Std_ReturnType         retVal = E_NOT_OK;
#if (STD_ON == ETHTRCV_GETTRANSCEIVERMODE_API)
    EthTrcv_ModeType       trcvMode;
#endif

    /* Do EthTrcv driver initialization */
    EthTrcv_Init(ethTrcvConfigPtr);
	//EthTrcv_SetPhyLoopbackMode(0,ETHTRCV_PHYLOOPBACK_EXTERNAL);
#if (STD_ON == ETHTRCV_STARTAUTONEGOTIATION_API)
    /* Start AutoNegotiation (Will not be needed in most of cases as
     * EthTrcv_TransceiverInit will also start auto negotiation. Only if config
     * changes (like speed, duplex etc.) then call below function). Adding here
     * for testing purpose.
     */
    if( ethTrcvConfigPtr->enableAutoNeg == TRUE)
    {
        retVal = EthTrcv_StartAutoNegotiation (ethTrcvConfigPtr->trcvIdx);
        if (E_OK != retVal)
        {
            AppUtils_printf("\rETH_APP:ETHTRCV Initialization failed\n ");
        }
    }
#endif
#if (STD_ON == ETHTRCV_SETTRANSCEIVERMODE_API)
    retVal = EthTrcv_SetTransceiverMode(ethTrcvConfigPtr->trcvIdx,
                                        ETHTRCV_MODE_ACTIVE);
#endif

#if (STD_ON == ETHTRCV_GETTRANSCEIVERMODE_API)
    retVal = EthTrcv_GetTransceiverMode(ethTrcvConfigPtr->trcvIdx, &trcvMode);
    if (E_OK == retVal)
    {
        AppUtils_printf("\rETH_APP: EthTrcv Controller mode change - %s\n",
                    (trcvMode == ETHTRCV_MODE_ACTIVE) ?
                                "ETHTRCV_MODE_ACTIVE" : "ETHTRCV_MODE_DOWN");
    }
#endif

#if (STD_ON == ETHTRCV_GETLINKSTATE_API)
    EthTrcv_LinkStateType  linkState;

    retVal = EthTrcv_GetLinkState(ethTrcvConfigPtr->trcvIdx, &linkState);
    if (E_OK == retVal)
    {
        if (ETHTRCV_LINK_STATE_ACTIVE == linkState)
        {
            AppUtils_printf("\rETH_APP:ETHTRCV Link up\n");
        }
        else
        {
            AppUtils_printf("\rETH_APP:ETHTRCV link down\n");
        }
    }
#endif

#if (STD_ON == ETHTRCV_GETBAUDRATE_API)
    EthTrcv_BaudRateType   baudRate;

    retVal = EthTrcv_GetBaudRate(ethTrcvConfigPtr->trcvIdx, &baudRate);
    if (E_OK == retVal)
    {
        if (ETHTRCV_BAUD_RATE_10MBIT == baudRate)
        {
            AppUtils_printf("\rETH_APP:ETHTRCV baud rate = 10Mbps\n");
        }
        else if (ETHTRCV_BAUD_RATE_100MBIT == baudRate)
        {
            AppUtils_printf("\rETH_APP:ETHTRCV baud rate = 100Mbps\n");
        }
        else if (ETHTRCV_BAUD_RATE_1000MBIT == baudRate)
        {
            AppUtils_printf("\rETH_APP:ETHTRCV baud rate = 1000Mbps\n");
        }
        else
        {
            /* not possible as check is done in function */
        }
    }
#endif

#if (STD_ON == ETHTRCV_GETDUPLEXMODE_API)
    EthTrcv_DuplexModeType duplexMode;

    retVal = EthTrcv_GetDuplexMode(ethTrcvConfigPtr->trcvIdx, &duplexMode);
    if (E_OK == retVal)
    {
        if (ETHTRCV_DUPLEX_MODE_FULL == duplexMode)
        {
            AppUtils_printf("\rETH_APP:ETHTRCV in full duplex mode\n");
        }
        else if (ETHTRCV_DUPLEX_MODE_HALF == duplexMode)
        {
            AppUtils_printf("\rETH_APP:ETHTRCV in half duplex mode\n");
        }
        else
        {
            /* not possible as check is done in function */
        }
    }
#endif

   retVal = EthTrcv_SetPhyLoopbackMode(ethTrcvConfigPtr->trcvIdx, ETHTRCV_PHYLOOPBACK_NONE);
   
   if(E_OK == retVal)
   {
       AppUtils_printf("\rETH_APP:ETHTRCV Normal Operation\n");
   }
   else
   {
       AppUtils_printf("\rETH_APP:ETHTRCV Set to Normal operation failed\n");    
   }

#if (STD_ON == ETHTRCV_SETPHYTXMODE_API)
   
   retVal = EthTrcv_SetPhyTxMode(ethTrcvConfigPtr->trcvIdx, ETHTRCV_PHYTXMODE_NORMAL);
   
   if(E_OK == retVal)
   {
       AppUtils_printf("\rETH_APP:ETHTRCV Tx mode Normal\n");
   }
   else
   {
       AppUtils_printf("\rETH_APP:ETHTRCV Set to Tx mode Normal operation failed\n");    
   }
#endif  

#if (STD_ON == ETHTRCV_GETPHYIDENTIFIER_API)
   uint32 OrgUniqueIdPtr;
   uint8 ModelNrPtr;
   uint8 RevisionNrPtr;
   
   retVal = EthTrcv_GetPhyIdentifier(ethTrcvConfigPtr->trcvIdx, &OrgUniqueIdPtr, 
                                       &ModelNrPtr, &RevisionNrPtr );
   
   if (E_OK == retVal)
   {
       if ((OrgUniqueIdPtr == 0x080028) && (ModelNrPtr == 0xF) &&
               (RevisionNrPtr == 0x01))
       {
           AppUtils_printf("\rETH_APP:ETHTRCV PHY ID is proper. OUI: 0x%x, Model No: 0x%x, Revision No: 0x%x\n", OrgUniqueIdPtr, ModelNrPtr, RevisionNrPtr);
       }
       else
       {
           AppUtils_printf("\rETH_APP:ETHTRCV PHY ID is different. OUI: 0x%x, Model No: 0x%x, Revision No: 0x%x\n", OrgUniqueIdPtr, ModelNrPtr, RevisionNrPtr);
       }
   }   
#endif

#if (STD_ON == ETHTRCV_GETCABLEDIAGNOSTICSRESULT_API)   
   EthTrcv_CableDiagResultType ResultPtr;

   retVal = EthTrcv_GetCableDiagnosticsResult(ethTrcvConfigPtr->trcvIdx, &ResultPtr);

   if (E_OK == retVal)
   {
       if (ResultPtr == ETHTRCV_CABLEDIAG_OK)
       {
           AppUtils_printf("\rETH_APP:ETHTRCV Cable Diagnostics Ok\n");
       }
       else if(ResultPtr == ETHTRCV_CABLEDIAG_ERROR)
       {
           AppUtils_printf("\rETH_APP:ETHTRCV Cable Diagnostics Error\n");
       }
       else
       {
            /*Do nothing*/
       }
   }
#endif 

#if (STD_ON == ETHTRCV_SETPHYTESTMODE_API)

   retVal = EthTrcv_SetPhyTestMode(ethTrcvConfigPtr->trcvIdx, ETHTRCV_PHYTESTMODE_NONE);
//   retVal = EthTrcv_SetPhyTestMode(ethTrcvConfigPtr->trcvIdx, ETHTRCV_PHYTESTMODE_2);
//   retVal = EthTrcv_SetPhyTestMode(ethTrcvConfigPtr->trcvIdx, ETHTRCV_PHYTESTMODE_3);
//   retVal = EthTrcv_SetPhyTestMode(ethTrcvConfigPtr->trcvIdx, ETHTRCV_PHYTESTMODE_4);

   if(E_OK == retVal)
   {
       AppUtils_printf("\rETH_APP:ETHTRCV Phy test mode Normal\n");
   }
   else
   {
       AppUtils_printf("\rETH_APP:ETHTRCV Set to Phy test mode Normal operation failed\n");
   }
#endif

    EthTrcv_MainFunction();    

    return retVal;
}

/* Function to access Ethernet PHY MMD indirect registers. These registers
 * are access through sequence of writes through MII registers */
Std_ReturnType AppUtils_ethTrcvWriteMMDIndirect(uint8 ctrlIdx,
                                                   uint8 trcvIdx,
                                                   uint32 regIdx,
                                                   uint16 regVal)
{
    Std_ReturnType         retVal = E_OK;

    retVal = Eth_WriteMii(ctrlIdx, trcvIdx, 0x0D, 0x001F);

    retVal += Eth_WriteMii(ctrlIdx, trcvIdx, 0x0E, regIdx);

    retVal += Eth_WriteMii(ctrlIdx, trcvIdx, 0x0D, 0x401F);

    retVal += Eth_WriteMii(ctrlIdx, trcvIdx, 0x0E, regVal);

    if (((Std_ReturnType) E_OK) != retVal)
    {
        retVal = E_NOT_OK;
    }

    return retVal;
}

 /*******************************************************************************
 *
 * \brief PHY DP83869HM delay config function
 *
 *        This function is used for configuring the receive and transmit delays
 *        for DP83869HM PHY on Am263x.
 *        For PHY configuration, need to configure DP83869HM’s RGMII Control
 *        Register (RGMIICTL) for RGMII mode and RGMII Delay Control Register
 *        (RGMIIDCTL).
 *
 *******************************************************************************
 */
void AppUtils_ethAm263xPHYDelayConfig(Eth_ConfigType *pEthConfigPtr, uint32 phyAddr)
{
    uint32              regIdx;
    uint16              regVal;

    regVal = 0x8000;
    regIdx = 0x1F;
    AppUtils_ethTrcvWriteMMDIndirect(pEthConfigPtr->ctrlIdx, phyAddr,
                                     regIdx,
                                     regVal);
    AppUtils_delay(1000U);
    regVal = 0x11;
    regIdx = 0x86;
    AppUtils_ethTrcvWriteMMDIndirect(pEthConfigPtr->ctrlIdx, phyAddr,
                                     regIdx,
                                     regVal);
    AppUtils_delay(1000U);
    regVal = 0x0D0;
    regIdx = 0x32;
    AppUtils_ethTrcvWriteMMDIndirect(pEthConfigPtr->ctrlIdx, phyAddr,
                                     regIdx,
                                     regVal);
    AppUtils_delay(1000U);
    regVal = 0x61F;
    regIdx = 0x170;
    AppUtils_ethTrcvWriteMMDIndirect(pEthConfigPtr->ctrlIdx, phyAddr,
                                     regIdx,
                                     regVal);
    AppUtils_delay(1000U);
    regVal = 0x4000;
    regIdx = 0x1F;
    AppUtils_ethTrcvWriteMMDIndirect(pEthConfigPtr->ctrlIdx, phyAddr,
                                     regIdx,
                                     regVal);
    AppUtils_delay(1000U);
}

void EcuM_cacheInvalidate(uint8 *startAddress, uint32 byteCount)
{
CacheP_invL1d((void *)startAddress, byteCount);
}

/* =========================Function separator========================= */

void EcuM_cacheWbInv(uint8 *startAddress, uint32 byteCount)
{
CacheP_wbInv((void *)startAddress, byteCount, CacheP_TYPE_ALLD);
}

/* =========================Function separator========================= */

/* FUNCTION DEF: void CacheP_invL1d(uint32_t blockPtr, uint32_t byteCnt)
 *
 *       r0 - contains blockPtr
 *       r1 - contains byteCnt
 */
        asm(".global CacheP_invL1d");
        asm(".type CacheP_invL1d,%function");
        //asm(".section ".text.cache","ax",%progbits
        asm(".arm");
asm("CacheP_invL1d:");
        asm("push    {r4}");
        asm("add     r1, r0, r1");              // calculate last address
        asm("ldr     r3, l1dCacheLineSizeInvL1dAddr");
        asm("ldr     r3, [r3]");
        asm("sub     r4, r3, #1");
        asm("bic     r0, r0, r4");              // align blockPtr to cache line
asm("invL1dCache_loop:");
        asm("mcr     p15, #0, r0, c7, c6, #1"); // invalidate single entry in L1D cache
        asm("add     r0, r0, r3 ");     // increment address by cache line size
        asm("cmp     r0, r1");          // compare to last address
        asm("blo     invL1dCache_loop");        // loop if > 0
        asm("dsb");                             // drain write buffer
        asm("pop     {r4}");
        asm("bx      lr");                      // return

asm("l1dCacheLineSizeInvL1dAddr: .long  gCacheL1dCacheLineSize");

/* =========================Function separator========================= */

/* FUNCTION DEF: void CacheP_wbInv(void *addr, uint32_t size, uint32_t type)
 *
 * Writes back and invalidates the range of MVA in data cache.
 * First, wait on any previous cache operation.
 *
 *       r0 - contains blockPtr
 *       r1 - contains byteCnt
 *       r2 - contains bitmask of cache type (unused)
 */
        asm(".global CacheP_wbInv");
        asm(".type CacheP_wbInv,%function");
       // asm(".section".text.cache","ax",%progbits");
        asm(".arm");
asm("CacheP_wbInv:");
        asm("push    {r4, r5}");
        asm("dmb");         // Ensure all previous memory accesses complete
        asm("add     r1, r0, r1");    // calculate last address
        asm("ldr     r4, l1dCacheLineSizeWbInvAddr");
        asm("ldr     r4, [r4]");
        asm("sub     r5, r4, #1");
        asm("bic     r0, r0, r5");         // align blockPtr to cache line
asm("writebackInv:");
        asm("mcr     p15, #0, r0, c7, c14, #1"); // writeback inv a cache line
        asm("add     r0, r0, r4");      // increment address by cache line size
        asm("cmp     r0, r1");                // compare to last address
        asm(" blo     writebackInv");             // loop if count > 0
        asm("dsb");                              // drain write buffer
        asm("pop     {r4, r5}");
        asm("bx      lr");

asm("l1dCacheLineSizeWbInvAddr: .long gCacheL1dCacheLineSize");

/* =========================Function separator========================= */

void SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_0(void)
{
AppUtils_SchM_Enter_EXCLUSIVE_AREA_0();
}

/* =========================Function separator========================= */

void SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_0(void)
{
     AppUtils_SchM_Exit_EXCLUSIVE_AREA_0(); 
}

/* =========================Function separator========================= */

void SchM_Enter_EthTrcv_ETHTRCV_EXCLUSIVE_AREA_0(void)
{
AppUtils_SchM_Enter_EXCLUSIVE_AREA_0();
}

/* =========================Function separator========================= */

void SchM_Exit_EthTrcv_ETHTRCV_EXCLUSIVE_AREA_0(void)
{
  AppUtils_SchM_Exit_EXCLUSIVE_AREA_0();
}

/* =========================Function separator========================= */

void Eth_appPrint( uint32 txHostErrorCh,
                   uint32 txHostErrorCode,
                   uint32 rxHostErrorCh,
                   uint32 rxHostErrorCode)
{
    AppUtils_printf("\r\nHost error..!!!");
    if (rxHostErrorCh)
    {
        AppUtils_printf("\r\n RX channel = %d, Host error Rx code = %d",
                         rxHostErrorCh, rxHostErrorCode);
    }

    if (txHostErrorCh)
    {
        AppUtils_printf("\r\n Error TX channel = %d, error code = %d",
                         txHostErrorCh, txHostErrorCode);
    }
}

/* =========================Function separator========================= */

/* TRCV */
void EthTrcvInitRGMII(uint8 CtrlIdx)
{

	uint8 phy_addr;
    phy_addr = ETH_TRCV_IDX; 

	uint16 control;
	uint16 status;
	uint16 status_speed;
	uint32 timeout_counter = 0;
	uint32 phyregtemp;
	int i;
	uint32 RetStatus;

	/* Start PHY autonegotiation */

	Eth_ReadMii(CtrlIdx, phy_addr, 0x001F, (uint16 *)&phyregtemp);
	phyregtemp |= 0x8000;
	Eth_WriteMii(CtrlIdx, phy_addr, 0x1F, phyregtemp);
	RetStatus = Eth_ReadMii(CtrlIdx, phy_addr, 0x1F, (uint16 *)&phyregtemp);
	if (RetStatus != E_OK) {
		/*Error during sw reset*/
	}

	Eth_ReadMii(CtrlIdx, phy_addr, 0, (uint16 *)&phyregtemp);
	phyregtemp |= 0x8000;
	Eth_WriteMii(CtrlIdx, phy_addr, 0, phyregtemp);

	/*
	 * Delay
	 */
	for(i=0;i<5;i++);

	RetStatus = Eth_ReadMii(CtrlIdx, phy_addr, 0, (uint16 *)&phyregtemp);
	if (RetStatus != E_OK) {
		/*Error during reset*/
		
	}

	/* FIFO depth */
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_TI_CR, PHY_TI_CRVAL);
	RetStatus = Eth_ReadMii(CtrlIdx, phy_addr, PHY_TI_CR, (uint16 *)&phyregtemp);
	if (RetStatus != E_OK) {
		/*Error writing to 0x10*/
	}

	/* TX/RX tuning */
	/* Write to PHY_RGMIIDCTL */
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
	RetStatus = Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, 0xA8);
	if (RetStatus != E_OK) {
		/*Error in tuning*/
		
	}

	/* Read PHY_RGMIIDCTL */
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
	RetStatus = Eth_ReadMii(CtrlIdx, phy_addr, PHY_ADDAR, (uint16 *)&phyregtemp);
	if (RetStatus != E_OK) {
		/*Error in tuning */	
	}

	/* Write PHY_RGMIICTL */
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, PHY_RGMIICTL);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
	RetStatus = Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, 0xD3);
	if (RetStatus != E_OK) {
		
		
	}

	/* Read PHY_RGMIICTL */
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, PHY_RGMIICTL);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
	RetStatus = Eth_ReadMii(CtrlIdx, phy_addr, PHY_ADDAR, (uint16 *)&phyregtemp);
	if (RetStatus != E_OK) {
		/*Error in tuning*/
		
	}

	/* SW workaround for unstable link when RX_CTRL is not STRAP MODE 3 or 4 */
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, PHY_TI_CFG4);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
	RetStatus = Eth_ReadMii(CtrlIdx, phy_addr, PHY_ADDAR, (uint16 *)&phyregtemp);
	phyregtemp &= ~(PHY_TI_CFG4RESVDBIT7);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, PHY_TI_CFG4);
	Eth_WriteMii(CtrlIdx, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
	RetStatus = Eth_WriteMii(CtrlIdx, phy_addr, PHY_ADDAR, phyregtemp);

	Eth_ReadMii(CtrlIdx, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
	control |= IEEE_ASYMMETRIC_PAUSE_MASK;
	control |= IEEE_PAUSE_MASK;
	control |= ADVERTISE_100;
	Eth_WriteMii(CtrlIdx, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);

    Eth_WriteMii(CtrlIdx,phy_addr,9,0x0000);

	Eth_ReadMii(CtrlIdx, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);

	control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
	control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
	Eth_WriteMii(CtrlIdx, phy_addr, IEEE_CONTROL_REG_OFFSET, control);

	Eth_ReadMii(CtrlIdx, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
	Eth_ReadMii(CtrlIdx, phy_addr, IEEE_STATUS_REG_OFFSET, &status);

	/* Waiting for PHY to complete autonegotiation */

	while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
		timeout_counter++;

		if (timeout_counter == 30) {
			/*Auto negotiation error */
			
		}
		Eth_ReadMii(CtrlIdx, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
	}
	/* autonegotiation complete */

	Eth_ReadMii(CtrlIdx, phy_addr, PHY_STS, &status_speed);
	if ((status_speed & 0xC000) == 0x8000) {
	     /* speed set to 1000 */
	} else if ((status_speed & 0xC000) == 0x4000) {
		/* speed set to 100 */
	} else {
		/* speed set to 10 */
	}

}

#ifdef __cplusplus
}
#endif
