This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TIDA-010010: Sample code for TIDA-010010

Part Number: TIDA-010010

Hi team,

I can't see the sample code for TIDA-010010.
Could you please share phy_init.c file?

Best regards,
Iwata Etsuji

  • Hi Etsuji-san,

    Please find attached the phy_init.c file which was used for TIDA-010010.

    Regards,

    Thomas

    phy_init.c
    #include <ti/csl/soc.h>
    #include <ti/csl/hw_types.h>
    #include <ti/csl/csl_timer.h>
    #include <ti/csl/arch/csl_arch.h>
    #include <ti/csl/csl_i2c.h>
    #include <ti/csl/cslr.h>
    #include <ti/csl/soc/am572x/src/cslr_control_core_pad_io.h>
    #include <ti/drv/pm/pmhal.h>
    #include <ti/drv/pm/pmlib.h>
    #include <ti/drv/pm/Power.h>
    #include <ti/drv/pm/PowerExtended.h>
    #include <ti/drv/pm/PowerDevice.h>
    #include <ti/drv/pm/include/pmlib_boardconfig.h>
    #include <ti/drv/pm/include/prcm/pmhal_i2cComm.h>
    #include <ti/drv/pm/include/prcm/pmhal_pmicComm.h>
    #if defined (SOC_TDA2EX) || defined (SOC_DRA72x)
    #include <ti/drv/pm/include/pmic/pmhal_tps65917.h>
    #elif defined (SOC_TDA3XX) || defined (SOC_DRA78x)
    #include <ti/drv/pm/include/pmic/pmhal_tps65917.h>
    #include <ti/drv/pm/include/pmic/pmhal_tps659039.h>
    #include <ti/drv/pm/include/pmic/pmhal_lp8731.h>
    #elif defined(SOC_AM574x) || defined (SOC_AM572x) || defined (SOC_AM571x)
    #include <ti/drv/pm/include/pmic/pmhal_tps659037.h>
    #else
    #include <ti/drv/pm/include/pmic/pmhal_tps659039.h>
    #endif
    #include <ti/drv/gpio/GPIO.h>
    #include <ti/drv/gpio/soc/GPIO_v1.h>
    #include <ti/board/src/evmAM572x/include/evmam572x_pinmux.h>
    
    #include <ti/sysbios/knl/Clock.h>
    
    
    /* -------------------------------------------------------------------------- */
    /*                 Internal Function Definitions                              */
    /* -------------------------------------------------------------------------- */
    #if defined (__ARM_ARCH_7A__)
    PowerDevice_Cfg_t PowerDevice_config __attribute__ ((section (".noinit")));
    #elif defined (_TMS320C6X)
    #pragma DATA_SECTION(PowerDevice_config, ".noinit")
    PowerDevice_Cfg_t PowerDevice_config;
    #else
    #pragma NOINIT(PowerDevice_config)
    PowerDevice_Cfg_t PowerDevice_config;
    #endif
    
    /** I2C System Clock - PER_96M_CLK:  96 MHz */
    #define PM_TEST_UTILS_I2C_SYSTEM_CLOCK       (96000000U)
    
    /** I2C Internal Clock -  9.6 MHz , Fast Mode of Communication is
     *  is used here. A pre-scaler of 23 would be calculated here. Refer
     *  TRM for details on the different I2C modes.
     */
    #define PM_TEST_UTILS_I2C_INTERNAL_CLOCK     (9600000U)
    
    /** I2C Output Clock -  400 KHz, This complies with the Fast Mode
     *  of the I2C operation of 100 Kbps.
     */
    #define PM_TEST_UTILS_I2C_OUTPUT_CLOCK       (400000U)
    
    /**
     * When checking for I2C IRQSTATUS setting this count is used to
     * repeatedly check the status. This number is empirically derived.
     */
    #define PM_TEST_UTILS_I2C_TIMEOUT_COUNT      (4000U)
    
    /** Write Flag used when checking for the transfer status. */
    #define PM_TEST_UTILS_I2C_WRITE              (1U)
    
    /** Read Flag used when checking for the transfer status. */
    #define PM_TEST_UTILS_I2C_READ               (2U)
    
    
    /**
     * \brief   This function performs the I2C initialization to talk to PMIC.
     *
     * \param   None.
     *
     * \retval  None.
     */
    static int32_t PmTestUtilsI2cInit(void);
    
    /**
     * \brief   This function reads a byte from the PMIC via I2C
     *
     * \param   i2cNum   Instance Id of the I2C. 1 - for I2C1, 2 - for I2C2
     * \param   i2cDevAddr  I2C Slave address for the PMIC
     * \param   regAddr     Pointer to the register address which is to be read.
     * \param   regValue    Pointer to the location where the read value will be
     *                      placed.
     * \param   numRegs     Number of registers to be read.
     *
     * \retval  status      Pass or fail value of the operations. STW_SOK - If Pass
     *                      STW_EFAIL - If Fail
     */
    static int32_t PmTestUtilsI2cReadByte(uint32_t i2cNum, uint32_t i2cDevAddr,
                                          const uint8_t *regAddr,
                                          uint8_t *regValue,
                                          uint32_t numRegs);
    
    /**
     * \brief   This function writes a byte of data to the register of PMIC via I2C
     *
     * \param   i2cNum   Instance Id of the I2C. 1 - for I2C1, 2 - for I2C2
     * \param   i2cDevAddr  I2C Slave address for the PMIC
     * \param   regAddr     Pointer to the register address which is to be written.
     * \param   regValue    Pointer to the location where the write value will be
     *                      placed.
     * \param   numRegs     Number of registers to be written.
     *
     * \retval  status      Pass or fail value of the operations. STW_SOK - If Pass
     *                      STW_EFAIL - If Fail
     */
    static int32_t PmTestUtilsI2cWriteByte(uint32_t i2cNum, uint32_t i2cDevAddr,
                                           const uint8_t *regAddr,
                                           const uint8_t *regValue,
                                           uint32_t numRegs);
    
    /**
     * \brief   Poll for Bus Busy and return when bus is not busy or timed out.
     *
     * \param   i2cNum      The I2C number used on the board to connect to the
     *                      desired PMIC.
     *
     * \retval  status      Pass or fail value of the operations. STW_SOK - If Pass
     *                      STW_EFAIL - If Fail
     */
    static int32_t PmTestUtilsI2cWaitForBB(uint32_t i2cNum);
    
    /**
     * \brief  Poll for the given flags and return when any of the flags is set or
     *         timed out.
     *
     * \param   i2cNum      The I2C number used on the board to connect to the
     *                      desired PMIC.
     * \param   flags       Flag to be waited for.
     *
     * \retval  status      Pass or fail value of the operations. STW_SOK - If Pass
     *                      STW_EFAIL - If Fail
     */
    static int32_t PmTestUtilsI2cWaitForFlags(uint32_t i2cNum, uint32_t flags);
    
    /**
     * \brief  Write the given number of bytes to the given slave address.
     *
     * \param   i2cNum      The I2C number used on the board to connect to the
     *                      desired PMIC.
     * \param   slaveAddr   Address to which the data should be written.
     * \param   data        Data to be written.
     * \param   count       Number of Bytes to be written.
     *
     * \retval  status      Pass or fail value of the operations. STW_SOK - If Pass
     *                      STW_EFAIL - If Fail
     */
    static int32_t PmTestUtilsI2cWrite(uint32_t i2cNum,
                                       uint8_t slaveAddr, const uint8_t data[],
                                       uint8_t count);
    
    /**
     * \brief  Read one byte from the given slave address.
     *
     * \param   i2cNum      The I2C number used on the board to connect to the
     *                      desired PMIC.
     * \param   slaveAddr   Address to which the data should be written.
     * \param   value       Data to be read is returned.
     *
     * \retval  status      Pass or fail value of the operations. STW_SOK - If Pass
     *                      STW_EFAIL - If Fail
     */
    static int32_t PmTestUtilsI2cRead(uint32_t i2cNum,
                                      uint8_t  slaveAddr,
                                      uint8_t *value);
    /**
     * \brief Check the status of the transfer and handle the error conditions.
     *
     * \param   i2cNum  The I2C number used on the board to connect to the
     *                  desired PMIC.
     * \param   xfr     Transfer Type. Can be any one of PM_TEST_UTILS_I2C_WRITE or
     *                  PM_TEST_UTILS_I2C_READ.
     *
     * \retval  status      Pass or fail value of the operations. STW_SOK - If Pass
     *                      STW_EFAIL - If Fail
     */
    static int32_t PmTestUtilsI2cCheckXfrStatus(uint32_t i2cNum, uint32_t xfr);
    
    static void delay(uint32_t delay)
    {
        volatile uint32_t i;
        for (i = 0; i < (1000 * delay); ++i) ;
    }
    
    
    /*
     * Table containing pointers to the functions to program I2C to talk to PMIC IC.
     */
    static const pmhalI2cCommOperations_t gPmicI2cfunc = {
        &PmTestUtilsI2cInit,
        &PmTestUtilsI2cReadByte,
        &PmTestUtilsI2cWriteByte,
        NULL,
        NULL
    };
    
    /* GPIO Driver board specific pin configuration structure */
    GPIO_PinConfig gpioPinConfigs[] =
    {
        /* Output pin : AM572x EVM PHY1 Reset */
        GPIO_DEVICE_CONFIG(5, 17) |
        GPIO_CFG_OUTPUT ,
    
        /* Output pin : AM572x EVM PHY2 Reset */
        GPIO_DEVICE_CONFIG(3, 29) |
        GPIO_CFG_OUTPUT
    };
    
    /* GPIO Driver call back functions */
    GPIO_CallbackFxn gpioCallbackFunctions[] = {
        NULL,
        NULL
    };
    
    /* GPIO Driver configuration structure */
    GPIO_v1_Config GPIO_v1_config = {
        gpioPinConfigs,
        gpioCallbackFunctions,
        sizeof(gpioPinConfigs) / sizeof(GPIO_PinConfig),
        sizeof(gpioCallbackFunctions) / sizeof(GPIO_CallbackFxn),
        0,
        };
    
    
    void dp83867_reset_sequence(void)
    {
        uint32_t regVal = 0;
        /* configure GPIOs as outputs*/
    
        /* pinmux */
        /* AM572x EVM GPIO5_17 RESET PHY1 */
        CSL_FINS(regVal, CONTROL_CORE_PAD_IO_PAD_RMII_MHZ_50_CLK_RMII_MHZ_50_CLK_MUXMODE, 0xEU);
        ((CSL_padRegsOvly) CSL_MPU_CORE_PAD_IO_REGISTERS_REGS)->PAD_RMII_MHZ_50_CLK = regVal;
    
        /* AM572x EVM GPIO3_29 RESET PHY2 */
        CSL_FINS(regVal, CONTROL_CORE_PAD_IO_PAD_VIN2A_DE0_VIN2A_DE0_MUXMODE, 0xEU);
        ((CSL_padRegsOvly) CSL_MPU_CORE_PAD_IO_REGISTERS_REGS)->PAD_VIN2A_DE0 = regVal;
    
        /* configure GPIO */
        GPIO_init();
    
        /* Reset sequence: 1us reset asserted; then first PHY needs to wait for 201 ms before second PHY comes out of reset */
        GPIO_write(0, 0);   /* set GPIO5_17 to low */
        GPIO_write(1, 0);   /* set GPIO3_29 to low */
        delay(1);        /* data sheet requires >1us;  Note: delay(1*125)=1ms -->  1-> 8us*/
        GPIO_write(0, 1);   /* set GPIO5_17 to high */
        delay(201*125);       /* 201ms */
        GPIO_write(1, 1);   /* set GPIO3_29 to high */
    }
    
    
    
    
    void dp83867_pmic_init(void)
    {
        const pmhalPmicOperations_t *pmicOps;
        uint32_t    retVal;
    
        /* Register the I2C functions with the PMIC Communication to ensure the
         * PMIC can be communicated with I2C driver
         */
        PMHALI2CCommRegister(&gPmicI2cfunc);
        pmicOps = PMHALTps659037GetPMICOps();
        retVal = PMHALPmicRegister(pmicOps);
        if(retVal != 0)
            return;
    
        /* enable the PHY voltage supplies */
        PMHALPmicSetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY2V5,2500,PM_TIMEOUT_INFINITE,FALSE);
        PMHALPmicSetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY1V0,1000,PM_TIMEOUT_INFINITE,FALSE);
        PMHALPmicEnableRegulator(PMHAL_PRCM_PMIC_REGULATOR_EPHY2V5);
        PMHALPmicEnableRegulator(PMHAL_PRCM_PMIC_REGULATOR_EPHY1V0);
    
        // Example to read out the configured PMIC voltage
        //PMHALPmicGetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY2V5, &retVal);
        //PMHALPmicGetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY1V0, &retVal);
    }
    
    
    void dp83867_register_init(void)
    {
        // register dump
    
        ENETPHY_UserAccessWrite();
    
    
    }
    
    static int32_t PmTestUtilsI2cInit(void)
    {
        int32_t  status = STW_SOK;
        uint32_t timeout;
        uint32_t baseAddr = SOC_I2C1_BASE;
    
    #if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
        /* Force Wake-up clock domain L4PER1 */
        PMHALCMSetCdClockMode(PMHAL_PRCM_CD_L4PER1,
                              PMHAL_PRCM_CD_CLKTRNMODES_SW_WAKEUP,
                              PM_TIMEOUT_NOWAIT);
    
    #else
        /* Force Wake-up clock domain L4PER */
        PMHALCMSetCdClockMode(PMHAL_PRCM_CD_L4PER,
                              PMHAL_PRCM_CD_CLKTRNMODES_SW_WAKEUP,
                              PM_TIMEOUT_NOWAIT);
    #endif
    
        /* Enable I2C1 for PMIC Communication */
        PMHALModuleModeSet(PMHAL_PRCM_MOD_I2C1,
                           PMHAL_PRCM_MODULE_MODE_ENABLED,
                           PM_TIMEOUT_INFINITE);
        /*
         * Do a soft reset so we can clear any incorrect state and
         * configure to suit the PMIC communication.
         */
        I2CSoftReset(baseAddr);
    
        /*
         * Ensure that the reset is completed. The RDONE bit is set
         * only when the I2C is enabled, so enable I2C before
         * checking for the reset completion.
         */
        I2CMasterEnable(baseAddr);
    
        timeout = 50U;  /* Approximately 50ms */
        while ((I2CSystemStatusGet(baseAddr) !=
                I2C_SYSS_RDONE_RSTCOMP)
               && (timeout > 0))
        {
            PMUtilsMinDelayMS((uint32_t) 1U);
            timeout--;
        }
    
        if (timeout == 0)
        {
            status = STW_EFAIL;
        }
    
        if (status == STW_SOK)
        {
            /* Disable I2C so we can configure for the PMIC communication. */
            I2CMasterEnable(baseAddr);
    
            /* Configure the I2C BUS clock frequency (I2C_SCL). */
            I2CMasterInitExpClk(baseAddr,
                                PM_TEST_UTILS_I2C_SYSTEM_CLOCK,
                                PM_TEST_UTILS_I2C_INTERNAL_CLOCK,
                                PM_TEST_UTILS_I2C_OUTPUT_CLOCK);
    
            /*
             * The PMIC communication is always as a master so we don't have
             * to configure the I2C own address. However, it doesn't hurt.
             */
            I2COwnAddressSet(baseAddr, 0,
                             I2C_OWN_ADDR_0);
    
            /*
             * Make sure the I2C is not in Forced Idle Mode by setting it to No
             * Idle mode.
             */
            I2CSyscInit(baseAddr,
                        (uint32_t) (I2C_AUTOIDLE_DISABLE |
                                    I2C_CUT_OFF_BOTH_CLK |
                                    I2C_ENAWAKEUP_DISABLE |
                                    I2C_NO_IDLE_MODE));
    
            /*
             * Configure the I2C:
             *    Select Fast/Standard Mode
             *    Select normal mode (vs. start byte mode)
             *    Select 7-bit slave address mode
             *
             * Note that this API writes the 32-bit value passed to the I2C_CON
             * register; the config bits not mentioned below is set to zero.
             */
            I2CConfig(baseAddr, I2C_CFG_N0RMAL_MODE |
                      I2C_CFG_7BIT_SLAVE_ADDR |
                      I2C_OPMODE_FAST_STAND_MODE);
    
            /* PMIC Comm uses polling mode; disable all the interrupts. */
            I2CMasterIntDisableEx(baseAddr, I2C_INT_ALL);
    
            /*
             * Bypass the Tx/Rx FIFO. For PRCM access we always read one byte
             * at a time so FIFO is bypassed.
             */
            I2CFIFOThresholdConfig(baseAddr,
                                   0, I2C_TX_MODE);
            I2CFIFOThresholdConfig(baseAddr,
                                   0, I2C_RX_MODE);
            I2CFIFOClear(baseAddr, I2C_TX_MODE);
            I2CFIFOClear(baseAddr, I2C_RX_MODE);
    
            /* Enable I2C module. */
            I2CMasterEnable(baseAddr);
    
            /*
             * This is required to ensure that the I2C communication continues
             * even if A15 (the master core) is debug halted on a breakpoint.
             */
            I2CMasterEnableFreeRun(baseAddr);
        }
    
        /* Clear status register  */
        I2CMasterIntClearEx(baseAddr, I2C_INT_ALL);
    
        return status;
    }
    
    static int32_t PmTestUtilsI2cReadByte(uint32_t i2cNum, uint32_t i2cDevAddr,
                                          const uint8_t *regAddr,
                                          uint8_t *regValue,
                                          uint32_t numRegs)
    {
        int32_t status = STW_SOK;
        status = PmTestUtilsI2cWrite(i2cNum, i2cDevAddr, regAddr, 1U);
    
        /* Then read the value sent by the slave.  */
        if (status == STW_SOK)
        {
            status = PmTestUtilsI2cRead(i2cNum, i2cDevAddr, regValue);
        }
        else
        {
            *regValue = 0U;
        }
        return status;
    }
    
    static int32_t PmTestUtilsI2cWriteByte(uint32_t i2cNum, uint32_t i2cDevAddr,
                                           const uint8_t *regAddr,
                                           const uint8_t *regValue,
                                           uint32_t numRegs)
    {
        uint8_t  data[2];
        uint8_t  count       = (uint8_t) 2U;
        int32_t  status      = STW_SOK;
        uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
    
        data[0] = *regAddr;
        data[1] = *regValue;
        status  = PmTestUtilsI2cWrite(i2cNum, i2cDevAddr, data, count);
    
        if (status == STW_SOK)
        {
            /*
             * Generate a stop condition and ensure the
             * bus is free before returning.
             */
            I2CMasterStop(baseAddress);
    
            status = PmTestUtilsI2cWaitForFlags(i2cNum,
                                                I2C_INT_BUS_FREE |
                                                I2C_INT_ADRR_READY_ACESS);
    
            I2CFlushFifo(baseAddress);
    
            /* Clear the data count and all the flags. */
            I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
            I2CSetDataCount(baseAddress, (uint32_t) 0U);
        }
        return status;
    }
    
    static int32_t PmTestUtilsI2cRead(uint32_t i2cNum,
                                      uint8_t  slaveAddr,
                                      uint8_t *value)
    {
        int32_t  status      = STW_SOK;
        uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
    
        /* Set the slave address */
        I2CMasterSlaveAddrSet(baseAddress,
                              (uint32_t) slaveAddr);
    
        /* Configure to read 1 data word from the PMIC register.  */
        I2CSetDataCount(baseAddress, (uint32_t) 1U);
    
        /*
         * Configure i2c as master-receive and enable.
         * Make sure stop condition is generated after the transaction.
         */
        I2CMasterControl(baseAddress,
                         (uint32_t) (I2C_CFG_MST_RX | I2C_CFG_START | I2C_CFG_STOP));
    
        /* Read the data if the data is ready. */
        status = PmTestUtilsI2cCheckXfrStatus(i2cNum,
                                              (uint32_t) PM_TEST_UTILS_I2C_READ);
        if (status == STW_SOK)
        {
            *value = I2CMasterDataGet(baseAddress);
        }
        else
        {
            *value = 0U;
        }
    
        /* Wait for I2C access ready before returning. */
        if (status == STW_SOK)
        {
            uint32_t flags = I2C_INT_ADRR_READY_ACESS |
                             I2C_INT_BUS_FREE;
            status = PmTestUtilsI2cWaitForFlags(i2cNum, flags);
        }
    
        /* Clear the status of the I2C  */
        I2CFlushFifo(baseAddress);
        I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
        I2CSetDataCount(baseAddress, (uint32_t) 0U);
    
        return status;
    }
    
    static int32_t PmTestUtilsI2cWrite(uint32_t i2cNum,
                                       uint8_t slaveAddr, const uint8_t data[],
                                       uint8_t count)
    {
        int32_t  status = STW_SOK;
        uint32_t rawSt;
        uint8_t  i;
        uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
    
        /*
         * Poll the BUS BUSY bit to ensure the bus is not busy before initiating
         * the transaction on the bus.
         */
        status = PmTestUtilsI2cWaitForBB(i2cNum);
    
        if (status == STW_SOK)
        {
            /* Set the slave address */
            I2CMasterSlaveAddrSet(baseAddress,
                                  (uint32_t) slaveAddr);
    
            /* Configure to send 'count' data words */
            I2CSetDataCount(baseAddress, (uint32_t) count);
    
            /*
             * Configure i2c as master-transmitter, enable and set start condition.
             * Stop condition is NOT generated as this could be a part of write
             * followed by read (combined format).
             */
            I2CMasterControl(baseAddress,
                             I2C_CFG_MST_TX | I2C_CFG_START);
    
            /* Transmit 'count' bytes.  */
            for (i = 0; ((i < count) && (status == STW_SOK)); i++)
            {
                /*
                 * Check the status to see if the data can be transferred and
                 * send data.
                 */
                status = PmTestUtilsI2cCheckXfrStatus(
                    i2cNum,
                    (uint32_t)
                    PM_TEST_UTILS_I2C_WRITE);
                if (status == PM_SUCCESS)
                {
                    I2CMasterDataPut(baseAddress, data[i]);
                }
    
                /* Clear XRDY flags */
                rawSt = I2CMasterIntRawStatus(baseAddress);
                I2CMasterIntClearEx(baseAddress,
                                    rawSt & I2C_INT_TRANSMIT_READY);
            }
    
            /*
             * Once we complete writing the 'count' bytes, wait for the
             * ARDY flag to be set. This flag indicates that the I2C
             * is access ready for next transmission. ARDY can also be
             * set if we received NACK so ensure it is not the case.
             */
            if (status == STW_SOK)
            {
                status = PmTestUtilsI2cWaitForFlags(i2cNum,
                                                    I2C_INT_ADRR_READY_ACESS);
                if (status == STW_SOK)
                {
                    rawSt = I2CMasterIntRawStatus(baseAddress);
                    if ((rawSt & I2C_INT_NO_ACK) != 0)
                    {
                        status = STW_EFAIL;
                        /* Clear the NACK flag. */
                        I2CMasterIntClearEx(baseAddress,
                                            rawSt & I2C_INT_NO_ACK);
                    }
    
                    /* Clear the ARDY flag. */
                    I2CMasterIntClearEx(baseAddress,
                                        rawSt & I2C_INT_ADRR_READY_ACESS);
                }
            }
        }
    
        return status;
    }
    
    static int32_t PmTestUtilsI2cWaitForFlags(uint32_t i2cNum, uint32_t flags)
    {
        int32_t  status = STW_SOK;
        uint32_t timeout;
        uint32_t rawSt;
        uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
    
        timeout = PM_TEST_UTILS_I2C_TIMEOUT_COUNT;
    
        rawSt = I2CMasterIntRawStatus(baseAddress);
    
        while (((rawSt & flags) == 0) && (timeout > 0U))
        {
            rawSt = I2CMasterIntRawStatus(baseAddress);
            timeout--;
        }
    
        if (timeout == 0U)
        {
            status = STW_EFAIL;
        }
    
        return status;
    }
    
    static int32_t PmTestUtilsI2cWaitForBB(uint32_t i2cNum)
    {
        int32_t  status = STW_SOK;
        uint32_t timeout;
        uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
    
        /*
         * Clear all current interrupts first.
         */
        I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
    
        /*
         * Poll the BUS BUSY bit to ensure the bus is not busy before initiating
         * the transaction on the bus.
         */
        for (timeout = PM_TEST_UTILS_I2C_TIMEOUT_COUNT; timeout > 0U; --timeout)
        {
            if (I2CMasterBusBusy(baseAddress) == 0)
            {
                break;
            }
            I2CMasterIntClearEx(baseAddress, I2C_INT_BUS_BUSY);
        }
    
        if (timeout == 0U)
        {
            status = STW_EFAIL;
        }
    
        /*
         * Clear all current interrupts.
         */
        I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
    
        return status;
    }
    
    static int32_t PmTestUtilsI2cCheckXfrStatus(uint32_t i2cNum, uint32_t xfr)
    {
        int32_t  status = STW_SOK;
        uint32_t rawSt;
        uint32_t flags = I2C_INT_ADRR_READY_ACESS | I2C_INT_NO_ACK |
                         I2C_INT_ARBITRATION_LOST;
        uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
    
        if (xfr == PM_TEST_UTILS_I2C_WRITE)
        {
            flags |= I2C_INT_TRANSMIT_READY;
        }
        else if (xfr == PM_TEST_UTILS_I2C_READ)
        {
            flags |= I2C_INT_RECV_READY;
        }
        else
        {
            status = STW_EFAIL;
        }
    
        /*
         * Wait for any of the following conditions to occur and
         * handle them in the loop before transmitting data.
         * NACK, AL, XRDY/RRDY, ARDY
         */
        if (status == STW_SOK)
        {
            status = PmTestUtilsI2cWaitForFlags(i2cNum, flags);
        }
    
        if (status == STW_SOK)
        {
            rawSt = I2CMasterIntRawStatus(baseAddress);
    
            /*
             * When I2C is configured as master-transmitter and didn't
             * receive ACK from slave, NACK condition is generated. The
             * following could cause this situation:
             * 1. No receiver is present on the bus with the transmitted
             *    address; board issue
             * 2. Receiver is not ready to communicate with the master
             *    (probably a board/pmic device issue).
             * 3. Receiver gets data or commands it doesn't understand
             *    (incorrect PMIC)
             * 4. Receiver can't receive any more data bytes.
             *
             * NACK can be handled by a master by either generating a
             * STOP condition or a repeated START condition to start
             * a new transfer. In PMIC COMM we generate a STOP
             * condition to abort the transfer and clear the NACK
             * flag.
             *
             * I2C HW clears STT and STP bits in I2C_CON registers.
             */
            if ((rawSt & I2C_INT_NO_ACK) != 0)
            {
                I2CMasterStop(baseAddress);
                I2CMasterIntClearEx(baseAddress,
                                    rawSt & I2C_INT_NO_ACK);
                status = STW_EFAIL;
            }
            /*
             * Arbitration loss occurs when multiple masters initiate
             * transfer at the same time. Only one master wins and others
             * loose the arbitration. The arbitration loss flag is set
             * if this local host lost the arbitration. After an
             * arbitration loss, the local host can continue to generate
             * clock till the end of the byte transfer on the bus and
             * must restart the transmission. Recovering from arbitration
             * loss slightly complicates the code and this can be added
             * if there is a need. At present we clear the flag  and
             * return error.
             *
             * When arbitration loss occurs, the I2C HW clears the
             * STT, STP and MST bits. The local host switches to the
             * slave mode.
             */
            else if ((rawSt & I2C_INT_ARBITRATION_LOST) != 0)
            {
                I2CMasterIntClearEx(baseAddress,
                                    rawSt & I2C_INT_ARBITRATION_LOST);
                status = STW_EFAIL;
            }
            /*
             * ARDY flag is set to indicate that the local host is access
             * ready. We are in the middle of a data transfer and hence
             * it is bad if we get ARDY flag set. For example, if we
             * get NACKed, the ARDY flag is set in the middle of data
             * transfer.
             */
            else if ((rawSt & I2C_INT_ADRR_READY_ACESS) != 0)
            {
                I2CMasterIntClearEx(baseAddress,
                                    rawSt & I2C_INT_ADRR_READY_ACESS);
                status = STW_EFAIL;
            }
            /*
             * XRDY flag is set when the TX FIFO is empty or the TX FIFO
             * threshold is not reached. This means the local host can
             * transmit now.
             *
             * RRDY flag is set when the RX FIFO is empty or the RX FIFO
             * threshold is not reached. This means the local host can
             * receive now.
             */
            else if (((xfr == PM_TEST_UTILS_I2C_WRITE) &&
                      ((rawSt & I2C_INT_TRANSMIT_READY) != 0)) ||
                     ((xfr == PM_TEST_UTILS_I2C_READ) &&
                      ((rawSt & I2C_INT_RECV_READY) != 0)))
            {
                /*
                 * Return success so that the caller can send/receive the data
                 * Note that the caller needs to clear the XRDY/RRDY flag as
                 * needed.
                 */
                status = STW_SOK;
            }
            else
            {
                /*
                 * We should not get here...
                 */
                status = STW_EFAIL;
            }
        }
    
        return status;
    }
    

  • Thomas-san,

    Thank you so much for your help.

    Could you please also share enet_phy.c file, since I had some misunderstanding.
    Once you could share it, I will close this thread.

    Best regards,
    Iwata Etsuji
  • Hi Etsuji-san,

    Please find attached the file.

    Regards,

    Thomas

    enet_phy.c
    /**
     * enet_phy.c
     *
     *
     * Copyright (c) 2018 Texas Instruments Incorporated ALL RIGHTS RESERVED
     *
    */
    
    #include <stdio.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Idle.h>
    #include <ti/sysbios/knl/Task.h>
    
    #include <xdc/runtime/Timestamp.h>
    
    #include <ti/csl/cslr_mdio.h>
    #include <ti/csl/src/ip/mdio/V2/cslr_mdio.h>
    #include <ti/csl/csl_mdio.h>
    #include <ti/csl/src/ip/mdio/V2/csl_mdio.h>
    #include <ti/csl/csl_mdioAux.h>
    #include <ti/csl/src/ip/mdio/V2/csl_mdioAux.h>
    #include <ti/board/src/evmAM572x/device/enet_phy.h>
    
    /* UART Header files */
    #include <ti/drv/uart/UART.h>
    #include <ti/drv/uart/src/UART_osal.h>
    #include <ti/drv/uart/UART_stdio.h>
    
    
    #include "board_dpphy.h"
    
    /* R A N D O M  N U M B E R  S U P P O R T */
    #define COMMON_RANDOM_MAX        0xFFFFu
    
    /* Enable the below macro to have prints on the IO Console */
    //#define IO_CONSOLE
    
    #ifndef IO_CONSOLE
    #define ENET_PHY_log                UART_printf
    #else
    #define ENET_PHY_log                printf
    #endif
    
    static uint32_t RandomSeed = 1u;
    
    static uint32_t cpswRandom(void)
    {
      RandomSeed = (RandomSeed * (1103515245u)) + (12345u);
      return ((uint32_t) (RandomSeed/(65536u)) % (COMMON_RANDOM_MAX + 1u));
    }
    
    
    static uint32_t cpswRandomRange(uint32_t min, uint32_t max)
    {
      uint32_t iTmp;
    
      iTmp =  cpswRandom();
      iTmp %= ((max - min) + 1u);
      iTmp += min;
      return(iTmp);
    }
    
    static void ENETPHY_DisablePhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum);
    static void ENETPHY_PhyTimeOut(ENETPHY_Handle hPhyDev);
    static void ENETPHY_ResetPhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum);
    static void ENETPHY_SwRestartPhy(ENETPHY_Handle hPhyDev, uint32_t PhyNum);
    
    
    static void ENETPHY_DefaultState  (ENETPHY_Handle hPhyDev);
    static void ENETPHY_FindingState  (ENETPHY_Handle hPhyDev);
    static void ENETPHY_FoundState    (ENETPHY_Handle hPhyDev);
    static void ENETPHY_InitState     (ENETPHY_Handle hPhyDev);
    static void ENETPHY_LinkedState   (ENETPHY_Handle hPhyDev);
    static void ENETPHY_LinkWaitState (ENETPHY_Handle hPhyDev);
    static void ENETPHY_LoopbackState (ENETPHY_Handle hPhyDev);
    static void ENETPHY_NwayStartState(ENETPHY_Handle hPhyDev);
    static void ENETPHY_NwayWaitState (ENETPHY_Handle hPhyDev);
    
    #define   _cpswIsGigPhy(hPhyDev) 	(TRUE)
    
    #define ENETPHY_NOT_FOUND  0xFFFFu    /*  Used in Phy Detection */
    
    /*CHECK:: PhyState field breakup  */
    #define ENETPHY_DEV_OFFSET      (0u)
    #define ENETPHY_DEV_SIZE        (5u)
    #define ENETPHY_DEV_MASK        (0x1f<<ENETPHY_DEV_OFFSET)
    
    #define ENETPHY_STATE_OFFSET    (ENETPHY_DEV_SIZE+ENETPHY_DEV_OFFSET)
    #define ENETPHY_STATE_SIZE      (5u)
    #define ENETPHY_STATE_MASK      (0x1fu<<ENETPHY_STATE_OFFSET)
        #define INIT       (1u<<ENETPHY_STATE_OFFSET)
        #define FINDING    (2u<<ENETPHY_STATE_OFFSET)
        #define FOUND      (3u<<ENETPHY_STATE_OFFSET)
        #define NWAY_START (4u<<ENETPHY_STATE_OFFSET)
        #define NWAY_WAIT  (5u<<ENETPHY_STATE_OFFSET)
        #define LINK_WAIT  (6u<<ENETPHY_STATE_OFFSET)
        #define LINKED     (7u<<ENETPHY_STATE_OFFSET)
        #define LOOPBACK   (8u<<ENETPHY_STATE_OFFSET)
    
    #define ENETPHY_SPEED_OFFSET    (ENETPHY_STATE_OFFSET+ENETPHY_STATE_SIZE)
    #define ENETPHY_SPEED_SIZE      (1u)
    #define ENETPHY_SPEED_MASK_NDK      (1u<<ENETPHY_SPEED_OFFSET)
    
    #define ENETPHY_DUPLEX_OFFSET   (ENETPHY_SPEED_OFFSET+ENETPHY_SPEED_SIZE)
    #define ENETPHY_DUPLEX_SIZE     (1u)
    #define ENETPHY_DUPLEX_MASK     (1u<<ENETPHY_DUPLEX_OFFSET)
    
    #define ENETPHY_TIM_OFFSET      (ENETPHY_DUPLEX_OFFSET+ENETPHY_DUPLEX_SIZE)
    #define ENETPHY_TIM_SIZE        (10u)
    #define ENETPHY_TIM_MASK        (0x3ffu<<ENETPHY_TIM_OFFSET)
    
    /* we are working with 100ms ticks here */
      #define ENETPHY_FIND_TO (  1u<<ENETPHY_TIM_OFFSET)
        #define ENETPHY_RECK_TO (20u<<ENETPHY_TIM_OFFSET)
        #define ENETPHY_LINK_TO (50u<<ENETPHY_TIM_OFFSET)
        #define ENETPHY_NWST_TO (50u<<ENETPHY_TIM_OFFSET)
        #define ENETPHY_NWDN_TO (80u<<ENETPHY_TIM_OFFSET)
        #define ENETPHY_MDIX_TO (27u<<ENETPHY_TIM_OFFSET) /* 2.74 Seconds <--Spec and empirical */
    
    #define ENETPHY_SMODE_OFFSET    (ENETPHY_TIM_OFFSET+ENETPHY_TIM_SIZE)
    #define ENETPHY_SMODE_SIZE      (7u)
    #define ENETPHY_SMODE_MASK      (0x7fu<<ENETPHY_SMODE_OFFSET)
        #define SMODE_LPBK   (0x40u<<ENETPHY_SMODE_OFFSET)
        #define SMODE_AUTO   (0x20u<<ENETPHY_SMODE_OFFSET)
        #define SMODE_FD1000 (0x10u<<ENETPHY_SMODE_OFFSET)
        #define SMODE_FD100  (0x08u<<ENETPHY_SMODE_OFFSET)
        #define SMODE_HD100  (0x04u<<ENETPHY_SMODE_OFFSET)
        #define SMODE_FD10   (0x02u<<ENETPHY_SMODE_OFFSET)
        #define SMODE_HD10   (0x01u<<ENETPHY_SMODE_OFFSET)
        #define SMODE_ALL    (0x1fu<<ENETPHY_SMODE_OFFSET)
    
    #define ENETPHY_CHNG_OFFSET    (ENETPHY_SMODE_OFFSET+ENETPHY_SMODE_SIZE)
    #define ENETPHY_CHNG_SIZE      (1u)
    #define ENETPHY_CHNG_MASK      (1u<<ENETPHY_CHNG_OFFSET)
        #define ENETPHY_CHANGE (1u<<ENETPHY_CHNG_OFFSET)
    
    #define ENETPHY_TIMEDOUT_OFFSET    (ENETPHY_CHNG_OFFSET+ENETPHY_CHNG_SIZE)
    #define ENETPHY_TIMEDOUT_SIZE      (1u)     /*  30 Bits used */
    #define ENETPHY_TIMEDOUT_MASK   ((uint32_t)(1u<<ENETPHY_TIMEDOUT_OFFSET))
    #define ENETPHY_MDIX_SWITCH     ((uint32_t)(1u<<ENETPHY_TIMEDOUT_OFFSET))
    
    #define ENETPHY_MDIX_OFFSET    (ENETPHY_TIMEDOUT_OFFSET+ENETPHY_TIMEDOUT_SIZE)
    #define ENETPHY_MDIX_SIZE      (1u)     /*  31 Bits used */
    #define ENETPHY_MDIX_MASK      ((uint32_t)(1u<<ENETPHY_MDIX_OFFSET))
    #define ENETPHY_MDIX           ((uint32_t)(1u<<ENETPHY_MDIX_OFFSET))
    
    
    #ifndef VOLATILE32
    #define VOLATILE32(addr) (*((volatile uint32_t *)(addr)))
    #endif
    
    int32_t cpsw_g_speed_set = 0;
    int32_t cpsw_g_soft_reset_status = 0;
    
    /*User Calls*********************************************************       */
    
    /* Updates book-keeping with info provided, programs ControlReg
     * with clkdiv,enable bits*/
    int32_t ENETPHY_Init(ENETPHY_Handle hPhyDev, uint32_t miibase, uint32_t inst, uint32_t PhyMask, uint32_t MLinkMask, uint32_t MdixMask, uint32_t PhyAddr, uint32_t ResetBit, uint32_t MdioBusFreq, uint32_t MdioClockFreq,int32_t verbose)
    {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
    
      int32_t  ret =0 ;
      uint32_t phy;
    
      ((ENETPHY_DEVICE *) hPhyDev)->miibase   = miibase;
      ((ENETPHY_DEVICE *) hPhyDev)->inst      = inst;
      ((ENETPHY_DEVICE *) hPhyDev)->PhyMask   = PhyMask;
      ((ENETPHY_DEVICE *) hPhyDev)->MLinkMask = MLinkMask;
      ((ENETPHY_DEVICE *) hPhyDev)->MdixMask  = MdixMask;
    
      (void)verbose;/* remove if not required */
    
      *PhyState &= ~ENETPHY_MDIX_MASK;   /* Set initial State to MDI */
    
      CSL_MDIO_setClkDivVal((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, (MdioBusFreq/MdioClockFreq - 1));
      CSL_MDIO_enableFaultDetect((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase);
      CSL_MDIO_disablePreamble((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase);
      CSL_MDIO_enableStateMachine((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase);
    
    #ifdef DP83867
    #if 0  // debug register access for DP83867
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_PHYIDR1, PhyAddr, &phy);
      ENET_PHY_log("DP%d PHYIDR1:0x%X\n", PhyAddr, phy);
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_PHYIDR2, PhyAddr, &phy);
      ENET_PHY_log("DP%d PHYIDR2:0x%X\n", PhyAddr, phy);
    
      // debug print of bootstrap registers
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_STRAP_STS1, PhyAddr, &phy);
      ENET_PHY_log("DP%d STRAP1:0x%X\n", PhyAddr, phy);
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_STRAP_STS2, PhyAddr, &phy);
      ENET_PHY_log("DP%d STRAP2:0x%X\n", PhyAddr, phy);
    #endif
    
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, PhyAddr, &phy);
      phy |= DP_AUTO_NEGOTIATION_ENABLE | DP_DUPLEX_MODE;
      ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR,PhyAddr,phy);
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_ANAR, PhyAddr, &phy);
      phy |= DP_TX_FD | DP_TX | DP_10_FD | DP_10BASETE_EN;
      ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_ANAR,PhyAddr,phy);
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_CFG1, PhyAddr, &phy);
      phy |= DP_1000BASE_T_FULL_DUPLEX | DP_1000BASE_T_HALF_DUPLEX;
      // TM: Disabling 1000M bit mode capability
      //phy &= ~((1<<9) | (1<<8));
      ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_CFG1,PhyAddr,phy);
    
      /* only disable clock out of second PHY */
      if(PhyAddr != 0)
      {
          ENETPHY_UserAccessRead(hPhyDev, ENETPHY_IO_MUX_CFG, PhyAddr, &phy);
          phy &= ~(DP_CLK_O_DISABLE);
          ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_IO_MUX_CFG,PhyAddr,phy);
      }
    
      /* set RGMII Delay Control Register TX Delay) */
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_RGMIIDCTL, PhyAddr, &phy);
      phy &= ~(0xF<<4);
      phy |= 0x3<<4;        /* set RGMII_TX_DELAY_CTRL to 1.00 ns */
      ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_RGMIIDCTL, PhyAddr, phy);
    
    #else
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_CNTRL_REG, PhyAddr, &phy);
      phy |= NWAY_AUTOMDIX_ENABLE;
      ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_CNTRL_REG,PhyAddr,phy);
    #endif
    	(void)ResetBit; /* suppress warning */
    
    	unsigned int i;
    
    	*PhyState=INIT;
    
        ret = 0;
    
      return ret;
    }/* end of function ENETPHY_Init*/
    
    void ENETPHY_SetPhyMode(ENETPHY_Handle hPhyDev,uint32_t PhyMode)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t CurrentState;
    
      ((ENETPHY_DEVICE *) hPhyDev)->PhyMode = PhyMode;   /* used for AUTOMIDX, planned to replace PhyState fields */
      *PhyState &= (~ENETPHY_SMODE_MASK);
    
      if (0u != (PhyMode & NWAY_LPBK))
        {
        *PhyState |= SMODE_LPBK;
        }
      if (0u != (PhyMode & NWAY_AUTO))
        {
         *PhyState |= SMODE_AUTO;
        }
      if (0u != (PhyMode & NWAY_FD1000) )
        {
        *PhyState |= SMODE_FD1000;
        }
      if (0u!= (PhyMode & NWAY_FD100))
        {
        *PhyState |= SMODE_FD100;
        }
      if (0u != (PhyMode & NWAY_HD100))
        {
        *PhyState |= SMODE_HD100;
        }
      if (0u != (PhyMode & NWAY_FD10))
        {
        *PhyState |= SMODE_FD10;
        }
      if (0u != (PhyMode & NWAY_HD10))
        {
        *PhyState |= SMODE_HD10;
        }
    
      CurrentState = (*PhyState) & ENETPHY_STATE_MASK;
      if ( ((CurrentState == NWAY_START)|| (CurrentState == NWAY_WAIT)) ||
           ( ((CurrentState == LINK_WAIT) || (CurrentState == LINKED) ) || (CurrentState == LOOPBACK)) )
        {
        *PhyState = ( (*PhyState)&(~ENETPHY_STATE_MASK)) | (FOUND | ENETPHY_CHANGE);
        }
    
         ENET_PHY_log("SetPhyMode:%08x Auto:%d, FD10:%d, HD10:%d, FD100:%d, HD100:%d, FD1000:%d LPBK:%d\n", (unsigned int)PhyMode,
         (unsigned int)(PhyMode & NWAY_AUTO), (unsigned int)(PhyMode & MII_NWAY_FD10),(unsigned int)(PhyMode & MII_NWAY_HD10),(unsigned int)(PhyMode & MII_NWAY_FD100),
         (unsigned int)(PhyMode & MII_NWAY_HD100), (unsigned int)(PhyMode & NWAY_FD1000),
         (unsigned int)(PhyMode & NWAY_LPBK)  );
    
    	  }
    
    uint32_t ENETPHY_GetPhyMode(ENETPHY_Handle hPhyDev)
    {
        uint32_t  PhyMode =0;
        uint32_t  status_reg = 0,control_reg = 0,advertize_reg;
        uint32_t  PhyNum,j;
        uint32_t  PhyMask   = ((ENETPHY_DEVICE *) hPhyDev)->PhyMask;
    
        PhyNum = 0;
        for(j = 1;PhyNum < 32;PhyNum++)
        {
          if( 0u != ( j & PhyMask))
    	{
    	break;
    	}
          j = j<<1;
        }
    
        if(0u != _cpswIsGigPhy(hPhyDev))
        {
           /* read gig status */
           ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, &control_reg);
           /* read gig status */
           ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_STATUS, PhyNum, &status_reg);
        }
        /* figure out if gig connected at FD 1000 or not first */
        if ((0u != (control_reg & MII_NWAY_MY_FD1000)) && (0u != (status_reg & MII_NWAY_REM_FD1000)) )
        {
            PhyMode |= NWAY_FD1000;
        }
    
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BCR, PhyNum, &control_reg);
        if(0u != (control_reg & MII_AUTO_NEGOTIATE_EN)  )
        {
           PhyMode |= NWAY_AUTO;
        }
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &status_reg);
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, &advertize_reg);
    
        /* Check for 10/100 capabilities of PHYs */
        if((0u != (control_reg & MII_ENETPHY_100))|| (0u != (PhyMode & NWAY_AUTO)) )
        {
           if(0u != (advertize_reg & MII_NWAY_FD100))
    	    {
    	    PhyMode |= NWAY_FD100;
    	    }
           if(0u != (advertize_reg & MII_NWAY_HD100))
    	    {
    	    PhyMode |= NWAY_HD100;
    	    }
    
        }
    
        if(((control_reg & MII_ENETPHY_100) == 0) || (0u != (PhyMode & NWAY_AUTO)) )
        {
           if(0u != (advertize_reg & MII_NWAY_FD10))
    	    {
    	    PhyMode |= NWAY_FD10;
    	    }
           if(0u != (advertize_reg & MII_NWAY_HD10))
    	    {
    	    PhyMode |= NWAY_HD10;
    	    }
    
        }
        return PhyMode;
    }
    /* ENETPHY_Tic is called every 10 mili seconds to process Phy states         */
    
    int32_t ENETPHY_Tic(ENETPHY_Handle hPhyDev,uint32_t* mdioStatus)
    {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t  CurrentState;
      int32_t   ret = 0;
    
      *mdioStatus = MDIO_EVENT_NOCHANGE;
    
      /*Act on current state of the Phy */
      CurrentState=*PhyState;
      switch(CurrentState&ENETPHY_STATE_MASK)
        {
        case INIT:         ENETPHY_InitState(hPhyDev);      break;
        case FINDING:      ENETPHY_FindingState(hPhyDev);   break;
        case FOUND:        ENETPHY_FoundState(hPhyDev);     break;
        case NWAY_START:   ENETPHY_NwayStartState(hPhyDev); break;
        case NWAY_WAIT:    ENETPHY_NwayWaitState(hPhyDev);  break;
        case LINK_WAIT:    ENETPHY_LinkWaitState(hPhyDev);  break;
        case LINKED:       ENETPHY_LinkedState(hPhyDev);    break;
        case LOOPBACK:     ENETPHY_LoopbackState(hPhyDev);  break;
        default:           ENETPHY_DefaultState(hPhyDev);   break;
        }
    
      /*  Check is MDI/MDIX mode switch is needed */
    
      if(0u != ((*PhyState) & ENETPHY_MDIX_SWITCH) )
        {
    
        uint32_t Mdix;
    
        *PhyState &= (~ENETPHY_MDIX_SWITCH);  /* Clear Mdix Flip indicator */
    
        if(0u != ((*PhyState) & ENETPHY_MDIX))
    	{
          Mdix = 1;
    	}
        else
    	{
          Mdix = 0;
        }
        ret = (int32_t)(_MIIMDIO_MDIXFLIP | Mdix);
    
        }
      else
        {
    
      /*Return state change to user */
      /** CHECK : report MDIO_LINKEVENTS as MDIO_EVENT_NOCHANGE, MDIO_EVENT_LINKDOWN,
       * MDIO_EVENT_PHYERROR,MDIO_EVENT_LINKUP
       * Currently ENETPHY_CHNG_MASK set for any state transition*/
    
        if (0u != ((*PhyState) & ENETPHY_CHNG_MASK))
       {
    	if(  ( ((*PhyState) & ENETPHY_STATE_MASK) == LINKED) && ((CurrentState & ENETPHY_STATE_MASK) != LINKED) )
    		{
    		/* we have just entered LInked state */
    		*mdioStatus = MDIO_EVENT_LINKUP;
    		}
    	if(  ((CurrentState & ENETPHY_STATE_MASK) == LINKED) && ( ( (*PhyState) & ENETPHY_STATE_MASK) != LINKED))
    		{
    		/* we started in Linked state and we have a state change */
    		*mdioStatus = MDIO_EVENT_LINKDOWN;
    		}
    	*PhyState &= (~ENETPHY_CHNG_MASK);
    	ret = (int32_t)(TRUE);
        }
       else
       {
    	ret = (int32_t)(FALSE);
    	}
        }
    
      return ret;
    
    }
    
    
    void ENETPHY_LinkChange(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t  PhyNum,PhyStatus;
    
      PhyNum = ( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
    
      ENET_PHY_log("ENETPHY_LinkChange: PhyNum = %d\n", (unsigned int)PhyNum);
    
      if (0u != (ENETPHY_GetLinked(hPhyDev)) )
        {
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
    
        if ((PhyStatus & MII_ENETPHY_LINKED) == 0u)
          {
          *PhyState &= (~(ENETPHY_TIM_MASK | ENETPHY_STATE_MASK));
          if (0u!=((*PhyState) & SMODE_AUTO))
            {
            ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_AUTO_NEGOTIATE_EN|MII_RENEGOTIATE);
            *PhyState |= ((ENETPHY_CHANGE | ENETPHY_NWST_TO) | NWAY_START);
            }
           else
            {
            *PhyState|= ((ENETPHY_CHANGE | ENETPHY_LINK_TO) | LINK_WAIT);
            }
          }
        }
      }
    
      /* returns 0 if current Phy has AutoMdix support, otherwise 0 */
    static int32_t ENETPHY_MdixSupported(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t PhyNum;
      int32_t ret;
    
      if((((ENETPHY_DEVICE *) hPhyDev)->PhyMode & NWAY_AUTOMDIX) == 0)
      {
        ret = (0);  /* AutoMdix not turned on */
      }
      else
      {
        PhyNum = ((*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
      if( ((1<<PhyNum) & ((ENETPHY_DEVICE *) hPhyDev)->MdixMask) == 0)
        {
    	ret = 0;  /*  Phy does not support AutoMdix*/
        }
    
        ret = 1;
      }
      return ret;
      }
    
    /* If current Phy has AutoMdix support add Mdix Delay to the Timer State Value */
    static void ENETPHY_MdixDelay(ENETPHY_Handle hPhyDev)
      {
      uint32_t Delay;
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
    
    
      if(ENETPHY_MdixSupported(hPhyDev) != 0)
        {
      /* Get the Delay value in milli-seconds and convert to ten-milli second value */
      Delay = cpswRandomRange(_AUTOMDIX_DELAY_MIN, _AUTOMDIX_DELAY_MAX);
      Delay /= 10;
    
      /*  Add AutoMidx Random Switch Delay to AutoMdix Link Delay */
    
      Delay += (ENETPHY_MDIX_TO>>ENETPHY_TIM_OFFSET);
    
      /* Change Timeout value to AutoMdix standard */
        *PhyState &= (~(ENETPHY_TIM_MASK));  /* Clear current Time out value */
      *PhyState |=  (Delay<<ENETPHY_TIM_OFFSET);     /* Set new value */
        }
      return;
    
      }
    
    void ENETPHY_DisablePhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum)
      {
      ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, (MII_ENETPHY_ISOLATE | MII_ENETPHY_PDOWN) );
    
      ENET_PHY_log("ENETPHY_DisablePhy(%d)\n",(unsigned int)PhyNum);
    
      }
    
    void ENETPHY_InitState(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t CurrentState;
    
      CurrentState=*PhyState;
      CurrentState = (CurrentState & (~ENETPHY_TIM_MASK)) | (ENETPHY_FIND_TO);
      CurrentState=(CurrentState & (~ENETPHY_STATE_MASK)) | (FINDING);
      CurrentState=(CurrentState & (~ENETPHY_SPEED_MASK_NDK));
      CurrentState=(CurrentState & (~ENETPHY_DUPLEX_MASK));
      CurrentState|=ENETPHY_CHANGE;
    
      *PhyState=CurrentState;
    
      }
    
    void ENETPHY_FindingState(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t  PhyMask  = ((ENETPHY_DEVICE *) hPhyDev)->PhyMask;
      uint32_t  PhyNum,i,j;
    
      PhyNum=ENETPHY_NOT_FOUND;
    
      if (0u!= ((*PhyState) & ENETPHY_TIM_MASK))
        {
        *PhyState=( (*PhyState) & (~ENETPHY_TIM_MASK) ) | (( (*PhyState) & ENETPHY_TIM_MASK) - (1 << ENETPHY_TIM_OFFSET));
        }
       else
        {
        j =1;
        for(i=0; i<32; i++)
            {
            if( PhyMask & j)
                {
                if( CSL_MDIO_isPhyAlive((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, i))
                    {
                        PhyNum=i;
                        break;
                    }
                }
            j = j << 1;
            }
        if (PhyNum!=ENETPHY_NOT_FOUND)
          {
          /*  Phy Found! */
          *PhyState = ((*PhyState) & (~ENETPHY_DEV_MASK) ) | ((PhyNum & ENETPHY_DEV_MASK) << ENETPHY_DEV_OFFSET);
          *PhyState = ( (*PhyState) & (~ENETPHY_STATE_MASK) ) | (FOUND);
          *PhyState|=ENETPHY_CHANGE;
    
          ENET_PHY_log("ENETPHY_FindingState: PhyNum: %d\n",(unsigned int)PhyNum);
    
          }
         else
          {
    
          ENET_PHY_log("ENETPHY_FindingState: Timed Out looking for a Phy!\n");
          *PhyState|=ENETPHY_RECK_TO;  /* Set Timer */
          }
        }
      }
    
    void ENETPHY_FoundState(ENETPHY_Handle hPhyDev)
     {
      uint32_t *PhyState  = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t  PhyMask   = ((ENETPHY_DEVICE *) hPhyDev)->PhyMask;
      uint32_t  MLinkMask = ((ENETPHY_DEVICE *) hPhyDev)->MLinkMask;
      uint32_t  PhyNum,PhyStatus,NWAYadvertise,NWAY1000advertise=0,m,phynum,i,j;
      uint32_t PhyDummy;
    
      static  uint32_t auto_neg1 = 0xFFFFFFFF,auto_neg2= 0xFFFFFFFF;
    
    
      if (( (*PhyState) & ENETPHY_SMODE_MASK) == 0)
        {
        return;
        }
    
      PhyNum = ((*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
        j =1;
        for(phynum=0; phynum<32; phynum++)
            {
            if(0u!= (PhyMask & j))
                {
                if( CSL_MDIO_isPhyAlive((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, phynum))
                    {
                        ENETPHY_DisablePhy(hPhyDev,phynum);
                    }
                }
            j = j << 1;
            }
      /* If Aries SWR2 reset then don't reset phy*/
      /*  Reset the Phy and proceed with auto-negotiation */
      if(( 0u != cpsw_g_speed_set) || ((0u ==cpsw_g_soft_reset_status) || ((auto_neg1 & (1 << PhyNum)) == 0) )  )
      {
          ENETPHY_ResetPhy(hPhyDev,PhyNum);
      }
    
      /*  Set the way Link will be Monitored */
      /* Check the Link Selection Method */
      if (0u != ((1 << PhyNum) & MLinkMask) )
        {
      CSL_MDIO_enableLinkStatusChangeInterrupt((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase,  ((ENETPHY_DEVICE *) hPhyDev)->inst, PhyNum);
        }
        else
        {
      CSL_MDIO_disableLinkStatusChangeInterrupt((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase,  ((ENETPHY_DEVICE *) hPhyDev)->inst, PhyNum);
        }
      /* Get the Phy Status */
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
    
    
     /*  For Phy Internal loopback test, need to wait until Phy
          found, then set Loopback */
      if (0u != ((*PhyState) & SMODE_LPBK))
        {
        /* Set Phy in Loopback */
    
        ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_ENETPHY_LOOP|MII_ENETPHY_FD);
        /* Do a read to ensure ENETPHY_LOOP has completed */
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyDummy);
        *PhyState = ( (*PhyState) & (~ENETPHY_STATE_MASK) ) | (LOOPBACK);
        *PhyState|=ENETPHY_CHANGE;
        return;
        }
    
      ENET_PHY_log("Enable Phy to negotiate external connection\n");
    
    
      NWAYadvertise=MII_NWAY_SEL;
      if (0u != ((*PhyState) & SMODE_FD100))
      {
        NWAYadvertise |= MII_NWAY_FD100;
        }
      if (0u != ((*PhyState) & SMODE_HD100))
        {
        NWAYadvertise |= MII_NWAY_HD100;
        }
      if (0u != ((*PhyState) & SMODE_FD10))
        {
        NWAYadvertise |= MII_NWAY_FD10;
        }
      if (0u != ((*PhyState) & SMODE_HD10))
        {
        NWAYadvertise |= MII_NWAY_HD10;
        }
      if (0u != ((*PhyState) & SMODE_FD1000))
        {
    	  NWAY1000advertise= ENETPHY_1000BT_FD;
        }
    
      *PhyState &= ( ~(ENETPHY_TIM_MASK | ENETPHY_STATE_MASK));
      if ((0u != (PhyStatus & MII_NWAY_CAPABLE)) && (0u != ( (*PhyState) & SMODE_AUTO)) )   /*NWAY Phy Detected*/
      {
        if(( 0u != cpsw_g_speed_set) || ((0u ==cpsw_g_soft_reset_status) || ((auto_neg1 & (1 << PhyNum)) == 0) )  )
        {
           /*For NWAY compliant Phys                                                */
    	ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, NWAYadvertise);
           /* for gig negotiation */
          if(0u != _cpswIsGigPhy(hPhyDev))
          {
              ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, NWAY1000advertise);
          }
    
          ENET_PHY_log("NWAY Advertising: ");
          if (0u != ((*PhyState) & SMODE_FD1000))
    	{
    	ENET_PHY_log("FullDuplex-1000 ");
    	}
          if (0u != (NWAYadvertise & MII_NWAY_FD100))
    	{
    	ENET_PHY_log("FullDuplex-100 ");
    	}
          if (0u != (NWAYadvertise & MII_NWAY_HD100))
    	{
    	ENET_PHY_log("HalfDuplex-100 ");
    	}
          if (0u != (NWAYadvertise & MII_NWAY_FD10))
    	{
    	ENET_PHY_log("FullDuplex-10 ");
    	}
          if (0u != (NWAYadvertise & MII_NWAY_HD10))
    	{
    	ENET_PHY_log("HalfDuplex-10 ");
    	}
    
          ENET_PHY_log("\n");
    
          ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_AUTO_NEGOTIATE_EN );
          ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_AUTO_NEGOTIATE_EN|MII_RENEGOTIATE|MII_ENETPHY_FD);
         *PhyState|= ( (ENETPHY_CHANGE | ENETPHY_NWST_TO) | NWAY_START);
        }
        else
        {
          *PhyState |= ( (ENETPHY_CHANGE | ENETPHY_NWST_TO) | NWAY_START);
          auto_neg1 = auto_neg1 & (~(1 << PhyNum));
        }
      }
      else
      {
        *PhyState &= (~SMODE_AUTO);   /*The Phy is not capable of auto negotiation!  */
        m=NWAYadvertise;
        j = 0x8000u;
    
        for(i=0;(i<16);i++)
        {
    	if(0u != (j & m))
    	{
    	    break;
    	}
    	j = j >> 1 ;
    
        }
        m=j;
        j=0;
    
        /* figure out if gig connected at FD 1000 or not first */
        if ((NWAY1000advertise & MII_NWAY_MY_FD1000)== MII_NWAY_MY_FD1000)
        {
             j = MII_ENETPHY_1000;
             j |= MII_ENETPHY_FD;
        }
        else
        {
            if (0u != (m & (MII_NWAY_FD100 | MII_NWAY_HD100)) )
            {
               j=MII_ENETPHY_100;
               m&=(MII_NWAY_FD100|MII_NWAY_HD100);
            }
            if (0u != (m & (MII_NWAY_FD100 | MII_NWAY_FD10)) )
    	    {
               j |= MII_ENETPHY_FD;
        }
        }
    
        ENET_PHY_log("Requested PHY mode %s Duplex %s Mbps\n",(j & MII_ENETPHY_FD) ? "Full":"Half",
    			(j & MII_ENETPHY_1000) ? "1000":((j & MII_ENETPHY_100) ? "100":"10"));
    
        if((0u != cpsw_g_speed_set) || ( (0u == cpsw_g_soft_reset_status) || ((auto_neg2 & (1 << PhyNum)) == 0) ))
        {
           if(0u != (j & MII_ENETPHY_1000))
           {
              ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, j);
           }
           else
           {
               ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, j);
               ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, NWAYadvertise);
           }
           cpsw_g_speed_set = 0;
        }
        else
        {
           auto_neg2 = auto_neg2 & (~(1 << PhyNum));
        }
        *PhyState &= (~ENETPHY_SPEED_MASK_NDK);
        if(0u != (j & MII_ENETPHY_1000) )
        {
            *PhyState|=(1<<ENETPHY_DUPLEX_OFFSET);
            ((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 1;
        }
        else
        {
            ((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 0;
        }
        if (0u != (j & MII_ENETPHY_100) )
        {
           *PhyState|=(1<<ENETPHY_SPEED_OFFSET);
        }
        *PhyState &= (~ENETPHY_DUPLEX_MASK);
        if (0u != (j & MII_ENETPHY_FD) )
        {
           *PhyState|=(1<<ENETPHY_DUPLEX_OFFSET);
        }
        *PhyState |= ((ENETPHY_CHANGE | ENETPHY_LINK_TO) | LINK_WAIT);
      }
        ENETPHY_MdixDelay(hPhyDev);  /* If AutoMdix add delay */
    
      }
    
    void ENETPHY_ResetPhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum)
      {
        uint32_t data;
    
        data = MII_ENETPHY_RESET;
    
        /* Reset the phy */
        ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, data);
    
        /* wait till the reset bit is auto cleared */
        while(data & MII_ENETPHY_RESET)
        {
            /* Read the reset */
            if(ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BCR, PhyNum, &data) != TRUE)
            {
                break;
            }
        }
    
      }
    
    
    void ENETPHY_SwRestartPhy(ENETPHY_Handle hPhyDev, uint32_t PhyNum)
      {
        uint32_t data;
    
        data = SW_RESTART;
    
        /* Reset the phy */
        ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_CTRL, PhyNum, data);
    
        /* wait till the reset bit is auto cleared */
        while(data & SW_RESTART)
        {
            /* Read the reset */
            if(ENETPHY_UserAccessRead(hPhyDev, ENETPHY_CTRL, PhyNum, &data) != TRUE)
            {
                break;
            }
        }
    
      }
    
    void ENETPHY_NwayStartState(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t PhyNum,PhyMode,PhyDummy;
    
      PhyNum = ( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
    
      /*Wait for Negotiation to start                                            */
    
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BCR, PhyNum, &PhyMode);
    
      if((PhyMode&MII_RENEGOTIATE)==0)
        {
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum,&PhyDummy); /*Flush pending latch bits*/
        *PhyState &= (~(ENETPHY_STATE_MASK|ENETPHY_TIM_MASK));
        *PhyState |= ((ENETPHY_CHANGE | NWAY_WAIT) |ENETPHY_NWDN_TO);
        ENETPHY_MdixDelay(hPhyDev);  /* If AutoMdix add delay */
        }
       else
        {
        if (0u != ((*PhyState) & ENETPHY_TIM_MASK) )
    	{
    	*PhyState=( (*PhyState) & (~ENETPHY_TIM_MASK)) | ( ( (*PhyState) & ENETPHY_TIM_MASK)-(1 << ENETPHY_TIM_OFFSET));
    	}
         else
    	{
          ENETPHY_PhyTimeOut(hPhyDev);
        }
      }
      }
    
    void ENETPHY_NwayWaitState(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t  PhyNum,PhyStatus,NWAYadvertise = 0,NWAYREadvertise = 0,NegMode,i,j;
      uint32_t NWAY1000advertise = 0, NWAY1000REMadvertise = 0;
    
      PhyNum=( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
    
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
    
      if (0u != (PhyStatus & MII_NWAY_COMPLETE))
        {
        *PhyState|=ENETPHY_CHANGE;
        *PhyState &= (~ENETPHY_SPEED_MASK_NDK);
        *PhyState &= (~ENETPHY_DUPLEX_MASK);
    
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, &NWAYadvertise);
        ENETPHY_UserAccessRead(hPhyDev, ENETPHY_LINK_PARTNER_ABLTY, PhyNum, &NWAYREadvertise);
        /* read gig status */
        if(0u != _cpswIsGigPhy(hPhyDev))
        {
    	ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, &NWAY1000advertise);
    	ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_STATUS, PhyNum, &NWAY1000REMadvertise);
        }
    
        /* figure out if gig connected at FD 1000 or not first */
        if ((0u !=(NWAY1000advertise & MII_NWAY_MY_FD1000)) && (0u!=(NWAY1000REMadvertise & MII_NWAY_REM_FD1000)) )
    	{
          NegMode = MII_NWAY_MY_FD1000;
    	}
        else
    	{
    	NegMode = 0u;
    	}
    
        if (NegMode == 0u)
          {
    	/* continue checking for 100 and 10 connection */
    
    	/* Negotiated mode is we and the remote have in common */
    	NegMode = NWAYadvertise & NWAYREadvertise;
    
    	ENET_PHY_log("Phy: %d, ",(unsigned int)( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET);
    	ENET_PHY_log("NegMode %04X, NWAYadvertise %04X, NWAYREadvertise %04X\n",
    		   (unsigned int)NegMode,  (unsigned int)NWAYadvertise, (unsigned int)NWAYREadvertise);
    
    	/* Limit negotiation to fields below */
    	NegMode &= ( (MII_NWAY_FD100|MII_NWAY_HD100) | (MII_NWAY_FD10|MII_NWAY_HD10));
    
    	if (NegMode == 0u)
    	  {
    	    NegMode=(MII_NWAY_HD100|MII_NWAY_HD10)&NWAYadvertise; /*or 10 ?? who knows, Phy is not MII compliant*/
    	  }
    
    	j = 0x8000u;
    	for(i = 0; i <16 ; i++)
    	{
    	    if (0u != (j & NegMode))
    	    {
    		break;
    	    }
    	    j = j >> 1;
    	}
    
    	NegMode=j;
    
    
    	ENET_PHY_log("Negotiated connection: ");
    
    
    	if (0u != (NegMode & MII_NWAY_FD100))
    	    {
    		ENET_PHY_log("FullDuplex 100 Mbs\n");
    	    }
    	if (0u != (NegMode & MII_NWAY_HD100))
    	    {
    	    ENET_PHY_log("HalfDuplex 100 Mbs\n");
    	    }
    	if (0u != (NegMode & MII_NWAY_FD10))
    	    {
    	    ENET_PHY_log("FullDuplex 10 Mbs\n");
    	    }
    	if (0u != (NegMode & MII_NWAY_HD10))
    	    {
    	    ENET_PHY_log("HalfDuplex 10 Mbs\n");
    	    }
    
    	((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 0u;
          }
        else
          {
    
    	/* found 1000 negotiated connection! */
    	ENET_PHY_log("Negotiated connection: ");
    	ENET_PHY_log("FullDuplex 1000 Mbs\n");
    
    	((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 1u;
          }
    
        if (NegMode != 0u)
          {
          if (0u != (PhyStatus & MII_ENETPHY_LINKED))
    	{
            *PhyState=( (*PhyState) & (~ENETPHY_STATE_MASK)) | LINKED;
    	}
           else
    	{
            *PhyState=( (*PhyState) & (~ENETPHY_STATE_MASK)) | LINK_WAIT;
    	}
          if (0u != (NegMode & (MII_NWAY_FD100 | MII_NWAY_HD100)) )
    	{
            *PhyState=( (*PhyState) & (~ENETPHY_SPEED_MASK_NDK)) | (1 << ENETPHY_SPEED_OFFSET);
    	}
          if (0u != (NegMode & (MII_NWAY_FD100 | MII_NWAY_FD10 | MII_NWAY_MY_FD1000)))
    	{
            *PhyState=( (*PhyState) & (~ENETPHY_DUPLEX_MASK)) | (1 << ENETPHY_DUPLEX_OFFSET);
    	}
          }
        }
       else
        {
        if ( 0u != ( (*PhyState) & ENETPHY_TIM_MASK) )
    	{
    	*PhyState=( (*PhyState) & (~ENETPHY_TIM_MASK)) | (( (*PhyState) & ENETPHY_TIM_MASK)-(1 << ENETPHY_TIM_OFFSET));
    	}
         else
    	{
          ENETPHY_PhyTimeOut(hPhyDev);
        }
      }
    
      }
    
    void ENETPHY_LinkWaitState(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t  PhyStatus;
      uint32_t  PhyNum;
    
      PhyNum=( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
    
      ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
    
      if (0u != (PhyStatus & MII_ENETPHY_LINKED) )
        {
        *PhyState=( (*PhyState) & (~ENETPHY_STATE_MASK) ) | LINKED;
        *PhyState|=ENETPHY_CHANGE;
        }
       else
        {
        if (0u != ( (*PhyState) & ENETPHY_TIM_MASK)  )
    	{
          *PhyState=(*PhyState&~ENETPHY_TIM_MASK)|((*PhyState&ENETPHY_TIM_MASK)-(1<<ENETPHY_TIM_OFFSET));
    	}
         else
    	{
          ENETPHY_PhyTimeOut(hPhyDev);
        }
      }
      }
    
    void ENETPHY_PhyTimeOut(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState;
      if(ENETPHY_MdixSupported(hPhyDev) == 0)
        {
        return;  /* AutoMdix not supported */
        }
      PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
    
      /*  Indicate MDI/MDIX mode switch is needed */
      *PhyState|=ENETPHY_MDIX_SWITCH;
    
      /* Toggle the MDIX mode indicatir */
      if(0u != ( (*PhyState) & ENETPHY_MDIX) )
        {
        *PhyState &= (~ENETPHY_MDIX_MASK);       /* Current State is MDIX, set to MDI */
        }
      else
        {
        *PhyState |=  ENETPHY_MDIX_MASK;      /* Current State is MDI, set to MDIX */
        }
      /* Reset state machine to FOUND */
      *PhyState = ( (*PhyState) & (~ENETPHY_STATE_MASK)) | (FOUND);
      }
    
    void ENETPHY_LoopbackState(ENETPHY_Handle hPhyDev)
    {
        (void)((ENETPHY_DEVICE *) hPhyDev); /* remove if not needed, to avoid warning */
      return;
    }
    
    void ENETPHY_LinkedState(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      uint32_t  PhyNum   = ( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
    
      if (CSL_MDIO_isPhyLinked((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, PhyNum))
        {
         return;  /* if still Linked, exit*/
        }
    
      /* Not Linked */
      *PhyState &= (~(ENETPHY_STATE_MASK | ENETPHY_TIM_MASK));
      if (0u != ( (*PhyState) & SMODE_AUTO) )
      {
        *PhyState |= ( (ENETPHY_CHANGE | NWAY_WAIT) | ENETPHY_NWDN_TO);
      }
       else
        {
        *PhyState |= ( (ENETPHY_CHANGE | ENETPHY_LINK_TO) | LINK_WAIT);
        }
      ENETPHY_MdixDelay(hPhyDev);  /* If AutoMdix add delay */
    
      }
    
    void ENETPHY_DefaultState(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      /*Awaiting a ENETPHY_Init call                                             */
      *PhyState|=ENETPHY_CHANGE;
      }
    
    /* Simple Query Functions for reporting speed,duplex */
    /* ENETPHY_GetDuplex is called to retrieve the Duplex info */
    int32_t ENETPHY_GetDuplex(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      return(( (*PhyState) & ENETPHY_DUPLEX_MASK) ? 1:0);  /* return 0 or a 1  */
      }
    
    /* ENETPHY_GetSpeed is called to retreive the Speed info */
    int32_t ENETPHY_GetSpeed(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      int32_t ret = 0 ;
    
      if (((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 == 1)
        {
        ret = 2; /* if we are linked at 1000, we return a value of 2 */
        }
      else
        {
        ret = ( (*PhyState) & ENETPHY_SPEED_MASK_NDK);
        }
    
      return ret;
      }
    
    /* ENETPHY_GetPhyNum is called to retreive the Phy Device Adr info*/
    int32_t ENETPHY_GetPhyNum(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      return((int32_t)(( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET));
      }
    
    /* ENETPHY_GetLoopback is called to Determine if the LOOPBACK state has been reached*/
    int32_t ENETPHY_GetLoopback(ENETPHY_Handle hPhyDev)
      {
      uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
      return(( (*PhyState) & ENETPHY_STATE_MASK) == LOOPBACK);
      }
    
    /* ENETPHY_GetLinked is called to Determine if the LINKED state has been reached*/
    int32_t ENETPHY_GetLinked(ENETPHY_Handle hPhyDev)
      {
        uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
        return (( (*PhyState) & ENETPHY_STATE_MASK) == LINKED);
      }
    
    /************************************
    ***
    *** Waits for MDIO_USERACCESS to be ready and reads data
    *** If 'WaitForData' set, waits for read to complete and returns Data,
    *** otherwise returns 0
    *** Note: 'data' is 16 bits but we use 32 bits
    ***        to be consistent with rest of the code.
    ***
    **************************************/
    uint32_t ENETPHY_UserAccessRead(ENETPHY_Handle hPhyDev, uint32_t regadr, uint32_t phyadr, uint32_t *data)
      {
        uint16_t data16;
        CSL_MDIO_USERACCESS    user_access_reg;
    
        /* Wait till transaction completion if any */
         do
         {
             CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
         }
         while(user_access_reg.go);
    
    
        if(regadr <= 0x1F)
        {
            //CSL_MDIO_phyRegRead(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, regadr, &data16);
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = regadr;
            user_access_reg.write = 0U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
            /* wait for command completion */
             do
             {
                 CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
             }
             while(user_access_reg.go);
    
             CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
             /* Store the data if the read is acknowledged */
             if(user_access_reg.ack)
             {
                 *data = user_access_reg.data & MDIO_USERACCESS_DATA;
                 return 1u;
             }
    
             return 0u;
    
        }else
        {
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_REGCR_REG;
            user_access_reg.data = EXT_REG_ADDRESS_ACCESS;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_ADDR_REG;
            user_access_reg.data = regadr;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_REGCR_REG;
            user_access_reg.data = EXT_REG_DATA_NORMAL_ACCESS;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_ADDR_REG;
            user_access_reg.write = 0U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
            CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            /* Store the data if the read is acknowledged */
            if(user_access_reg.ack)
            {
                *data = user_access_reg.data & MDIO_USERACCESS_DATA;
                return 1u;
            }
    
            return 0u;
    
    #if 0
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
                                 EXT_REG_ADDRESS_ACCESS);
    
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG,
                                 regadr);
    
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
                                 EXT_REG_DATA_NORMAL_ACCESS);
    
            CSL_MDIO_phyRegRead(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG, &data16);
    
            *data = (uint32_t)data16;
    #endif
        }
    
        return 1;
    #if 0
        CSL_MDIO_USERACCESS    user_access_reg;
    
        /* Wait till transaction completion if any */
        do
        {
            CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
        }
        while(user_access_reg.go);
    
        user_access_reg.phyAddr = phyadr;
        user_access_reg.regAddr = regadr;
        user_access_reg.write = 0U;
        user_access_reg.go = 1U;
    
        if(regadr<=0x1F)
        {
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
        } else // extended register access
        {
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
                                 EXT_REG_ADDRESS_ACCESS);
    
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG,
                                 regadr);
    
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
                                 EXT_REG_DATA_NORMAL_ACCESS);
            CSL_MDIO_phyRegRead(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG, data);
        }
    
    
        /* wait for command completion */
        do
        {
            CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
        }
        while(user_access_reg.go);
    
        CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
        /* Store the data if the read is acknowledged */
        if(user_access_reg.ack)
        {
            *data = user_access_reg.data & MDIO_USERACCESS_DATA;
            return 1u;
        }
    
        return 0u;
    #endif
      }
    
    
    /************************************
    ***
    *** Waits for MDIO_USERACCESS to be ready and writes data
    ***
    **************************************/
    void ENETPHY_UserAccessWrite(ENETPHY_Handle hPhyDev, uint32_t regadr, uint32_t phyadr, uint32_t data)
      {
        CSL_MDIO_USERACCESS    user_access_reg;
    
        /* Wait till transaction completion if any */
        do
        {
            CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
        }
        while(user_access_reg.go);
    
        if(regadr <= 0x1F)
        {
            //CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, regadr, (uint16_t) data);
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = regadr;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            user_access_reg.data = data;
    
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* wait for command completion */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
        }else
        {
    
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_REGCR_REG;
            user_access_reg.data = EXT_REG_ADDRESS_ACCESS;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_ADDR_REG;
            user_access_reg.data = regadr;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_REGCR_REG;
            user_access_reg.data = EXT_REG_DATA_NORMAL_ACCESS;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
            user_access_reg.phyAddr = phyadr;
            user_access_reg.regAddr = ENETPHY_ADDR_REG;
            user_access_reg.data = data;
            user_access_reg.write = 1U;
            user_access_reg.go = 1U;
            CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
            /* Wait till transaction completion if any */
            do
            {
                CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
            }
            while(user_access_reg.go);
    
    #if 0
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
                                 EXT_REG_ADDRESS_ACCESS);
    
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG,
                                 regadr);
    
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
                                 EXT_REG_DATA_NORMAL_ACCESS);
    
            CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG, (uint16_t) data);
    #endif
        }
    
    
    #if 0
        CSL_MDIO_USERACCESS    user_access_reg;
    
        /* Wait till transaction completion if any */
        do
        {
            CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
        }
        while(user_access_reg.go);
    
        user_access_reg.phyAddr = phyadr;
        user_access_reg.regAddr = regadr;
        user_access_reg.write = 1U;
        user_access_reg.go = 1U;
        user_access_reg.data = data;
    
        CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
    
        /* wait for command completion */
        do
        {
            CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
        }
        while(user_access_reg.go);
    #endif
        }
    
    
    void ENETPHY_SetLoopback(ENETPHY_Handle hPhyDev, uint32_t phyadr, uint32_t loopback_mode)
    {
        uint32_t data, i;
    
        if(loopback_mode == RGMII_DELAY_CONTROL)
        {
            ENETPHY_UserAccessRead(hPhyDev, 0x86, phyadr, &data);
            for(i=0; i<16; i++)
            {
                ENETPHY_UserAccessRead(hPhyDev, 0x86, phyadr, &data);
                data &= ~(0xf0);
                data |= i << 4;
                ENETPHY_UserAccessWrite(hPhyDev, 0x86, phyadr, data);
            }
            return;
        }
    
        if(loopback_mode == REVERSE_LOOPBACK)
        {
            // enable reverse loopback
             data = 0x0020;
             ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BISCR, phyadr, data);
             data = 0x4000; // SW restart
             ENETPHY_UserAccessWrite(hPhyDev, 0x1f, phyadr, data);
             return;
        }
    
        if(loopback_mode == DIGITAL_LOOPBACK)
        {
            // enable reverse loopback
             data = 0x8000;
             ENETPHY_UserAccessWrite(hPhyDev, 0x1f, phyadr, data);
             data = 0x0140;
             ENETPHY_UserAccessWrite(hPhyDev, 0x00, phyadr, data);
    
             ENETPHY_UserAccessRead(hPhyDev, 0x32, phyadr, &data);
    
             data = 0x00D3;
             ENETPHY_UserAccessWrite(hPhyDev, 0x32, phyadr, data);
             data = 0x0004;
             ENETPHY_UserAccessWrite(hPhyDev, 0x16, phyadr, data);
             data = 0x4000; // SW restart
             ENETPHY_UserAccessWrite(hPhyDev, 0x1f, phyadr, data);
             return;
        }
    
    
        /* configure the Loopback Configuration Register */
        if(loopback_mode == NO_LOOPBACK)
        {
    
            ENETPHY_UserAccessRead(hPhyDev, ENETPHY_LOOPCR, phyadr, &data); // debug only
            data = 0xE721;
            ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
        }
        else
        {
            ENETPHY_UserAccessRead(hPhyDev, ENETPHY_LOOPCR, phyadr, &data); // debug only
            data = 0xE720;
            ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
        }
    
        /* perform a SW_RESTART in LOOPCR register */
        ENETPHY_SwRestartPhy(hPhyDev, phyadr);
    
        /* configure the loopback mode */
        switch(loopback_mode)
        {
            case NO_LOOPBACK:
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
                data &= ~(0x3Fu);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
                data &= ~(1u<<14);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
                break;
            case MII_LOOPBACK:
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
                data &= ~(0x3Fu);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
                data |= (1u<<14);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
                break;
            case PCS_LOOPBACK:
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
                data &= ~(0x3Fu);
                data |= (1u<<0);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
                data &= ~(1u<<14);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
                break;
            case DIGITAL_LOOPBACK:
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
                data &= ~(0x3Fu);
                data |= (1u<<2);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
                data &= ~(1u<<14);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
                break;
            case ANALOG_LOOPBACK:
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
                data &= ~(0x3Fu);
                data |= (2u<<2);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
                data &= ~(1u<<14);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
                break;
            case EXTERNAL_LOOPBACK:
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
                data &= ~(0x3Fu);
                data |= (4u<<2);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
                data &= ~(1u<<14);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
                break;
            case REVERSE_LOOPBACK:
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
                data &= ~(0x3Fu);
                data |= (8u<<2);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
                ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
                data &= ~(1u<<14);
                ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
                break;
            default:
                break;
        }
    }
    
    /********************************************************************************************************************************/
    /* void MicroSecDelayWithoutYield(U32 uSDelay) */
    /* */
    /* Delay for xx microseconds WITHOUT yielding (no TASK switch). This function provides a MINIMUM delay. The actual delay */
    /* using this function may be more than you requested (due to HWI/SWI still running). */
    /* */
    /* Parameters: */
    /* - uSDelay: number of microseconds to delay */
    /* */
    /* Returns: none */
    /* */
    /* Notes: Public API function that can be called from the TASK level. */
    /********************************************************************************************************************************/
    void MicroSecDelayWithoutYield(uint32_t uSDelay )
    {
        UInt task_restore_key = Task_disable(); /* Disable TASKS so we can't get preempted by a higher TASK. */
        uint64_t usec_delay_in_ticks = 0;
        uint64_t StartTicks = 0;
        uint64_t CurrentTicks = 0;
        xdc_runtime_Types_FreqHz freq;
        xdc_runtime_Types_Timestamp64 BigTicksStamp;
    
        if( uSDelay != 0 )
        {
            /* Figure out how many ticks it takes to equal 1uS. */
            Timestamp_getFreq(&freq);
            usec_delay_in_ticks = (uint64_t)((freq.lo / 1000000) * uSDelay);
    
            /* We don't have to worry about checking for a roll over. Our max DSP frequency is 375MHz, or 2.66nS per "tick". A U64
            variable is 1.8 x 10 to the 19th power (really f'ing big). It will take over 1500 years for the Timestamp to roll over. */
            Timestamp_get64(&BigTicksStamp);
            StartTicks = BigTicksStamp.hi;
            StartTicks = StartTicks << 32;
            StartTicks = StartTicks | BigTicksStamp.lo;
            while( CurrentTicks < (StartTicks + usec_delay_in_ticks) )
            {
                /* Do nothing while we wait for the delay to expire. */
                Timestamp_get64(&BigTicksStamp);
                CurrentTicks = BigTicksStamp.hi;
                CurrentTicks = CurrentTicks << 32;
                CurrentTicks = CurrentTicks | BigTicksStamp.lo;
            }
        }
    
        Task_restore(task_restore_key); /* Restore TASK's to their previous state. */
    }