/*
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/****
 *\file:  EthernetMac.c
 *
 *\brief: source file for Ethernet mac handling.
 *
 *\descr: This source file initialize the Ethernet mac for mii and gmii.
 *
 *        The respective function of this file detect the Ethernet card and
 *        check the link, if link is up then it will verify the Packets by
 *        loopback testing on GMII as wellas mii mode.
 *
 *\authour: Antriksh
 *\version: 01a,20Sep2016, An created.
 *
 */
#include "DM8127_EVM.h"
#include "Ethernet_mac.h"
#include "stdio.h"
#include "string.h"
#include "gpio.h"


#define TX_BUF    128
#define RX_BUF    128

/*
 *=====================
 * Global variables
 *=====================
 */
static UINT8 packet_data[TX_BUF];
static UINT8 packet_buffer1[RX_BUF];
static UINT8 packet_buffer2[RX_BUF];

/*
 *  We use pDescBase for a base address. Its easier this way
 *  because we can use indexing off the pointer.
 */
static EMAC_Desc* pDescBase = ( EMAC_Desc* )EMAC_RAM_BASE;

/*
 *  The following are used to allow the ISR to communicate with
 *  the application.
 */
 volatile SINT32 RxCount;
 volatile SINT32 TxCount;
 volatile SINT32 ErrCount;
 volatile EMAC_Desc *pDescRx;
 volatile EMAC_Desc *pDescTx;

/****
 *\brief: Phy detection function.
 *
 *\descr: This function detects the PHY chip on the connected board
 *        it prints the address where Phy found.
 *
 *\param: phyaddr  [IN] PHY base address
 *
 *\return: Dummy variable
 */
UINT16 gmii_phy_detect
(
	UINT16 *phyaddr
)
{
	UINT16 num = 0, i;

	/* Reset Ethernet */
    EMAC_SOFTRESET = 1; // Emac clock should be enable
    while( EMAC_SOFTRESET != 0 );
    delay(50);

    MDIO_CONTROL = 0x40000020;              // Enable MII interface ( MDIOCLK < 12.5MHz )
    delay(10000);
    /* Check for PHYs */

  	for(i=0;i<32;i++)
  	{
   	    if((MDIO_ALIVE & (1 << i)) != 0)
   	    {
#ifdef DEBUG
   	        printf("    PHY found at address %d\n", i);
#else
   	     platform_write("\r\nPHY found at address %d\r\n", i);
#endif
   	        *phyaddr++ = i;
   	    }
  	}
    return num;
}

/* ------------------------------------------------------------------------ *
 *  gmii_phy_getReg( phynum, regnum )                                       *
 * ------------------------------------------------------------------------ */
UINT16 gmii_phy_getReg
(
	SINT16 phynum,
	SINT16 regnum
)
{
    UINT16 value;

    MDIO_USERACCESS0 = 0                    // Read Phy Id 1
        | ( 1 << 31 )                       // [31] Go
        | ( 0 << 30 )                       // [30] Read
        | ( 0 << 29 )                       // [29] Ack
        | ( regnum << 21 )                  // [25-21] PHY register address
        | ( phynum << 16 )                  // [20-16] PHY address
        | ( 0 << 0 );                       // [15-0] Data

    while( MDIO_USERACCESS0 & 0x80000000 ); // Wait for Results

    value = MDIO_USERACCESS0;
    return value;
}

/* ------------------------------------------------------------------------ *
 *  gmii_phy_setReg( phynum, regnum, data )                                 *
 * ------------------------------------------------------------------------ */
void gmii_phy_setReg
(
	SINT16 phynum,
	SINT16 regnum,
	UINT16 data
)
{
    MDIO_USERACCESS0 = 0                    // Read Phy Id 1
        | ( 1 << 31 )                       // [31] Go
        | ( 1 << 30 )                       // [30] Write
        | ( 0 << 29 )                       // [29] Ack
        | ( regnum << 21 )                  // [25-21] PHY register address
        | ( phynum << 16 )                  // [20-16] PHY address
        | ( data << 0 );                    // [15-0] Data

    while( MDIO_USERACCESS0 & 0x80000000 ); // Wait for Results
    delay(1000000 );
}

/* ------------------------------------------------------------------------ *
 *  gmii_phy_dumpRegs( )                                                    *
 * ------------------------------------------------------------------------ */
void gmii_phy_dumpRegs
(
	void
)
{
    SINT16 i;
    for ( i = 0 ; i < 32 ; i++ )
        printf( "PHY[%d] = %04x\n", i, gmii_phy_getReg( 1, i ) );

    printf( "\n\n" );
}

/* ------------------------------------------------------------------------ *
 *  emac_gmii_init( phynum )                                                       *
 * ------------------------------------------------------------------------ */
SINT16 emac_gmii_init
(
	SINT16 phynum
)
{
    SINT16 i;
    volatile UINT32* pReg;
    SINT16 readData = 0;

    //Enable MAC to operate in GMII mode
	EMAC0_SLIVER_CTRL = 0x000200A1;
#ifdef DEBUG
	printf( "Testing PHY internal loopback\n" );
#else
	Uart_stringSend( "Testing PHY internal loopback\n\r" );
#endif

	EMAC_ALE_CONTROL |= 0x80000000;
	delay( 100000 );
	EMAC_ALE_CONTROL |= 0x40000000;
	delay( 100000 );
	delay( 100000 );
	EMAC_ALE_CONTROL |= 0x00000010;
	delay( 100000 );

    /* ---------------------------------------------------------------- *
     *  Init PHY / MDIO                                                 *
     * ---------------------------------------------------------------- */
    MDIO_CONTROL = 0x40000020;              // Enable MII interface ( MDIOCLK < 12.5MHz )
    delay( 10000);

    gmii_phy_setReg( phynum,  0x001F, 0x8000);   // phy reset /*added*/
    delay( 10000);

    gmii_phy_setReg( phynum,  0, 0x8000);       // phy reset
    delay( 10000);

    /* Disable RGMII mode */
    gmii_phy_setReg( phynum, 0x000D , 0x001F);
    delay( 10000);

    gmii_phy_setReg( phynum, 0x000E , 0x0032);
    delay( 10000);

    gmii_phy_setReg( phynum, 0x000D , 0x401F);
    delay( 10000);

    gmii_phy_setReg( phynum, 0x000E , 0x0050);
    delay( 10000);

    gmii_phy_setReg( phynum,  0, 0x4140);       // Enable external loopback with 1000; Full-Duplex
    delay( 10000);

    //Setup GIG advertisement
    if (readData == 0x4140)
    {
		readData = gmii_phy_getReg( phynum, 9 );
		readData |= 0x200;
		gmii_phy_setReg( phynum, 9, readData);
    }

    // setup the general advertisement
    readData = gmii_phy_getReg( phynum, 4 );
    readData |= 0x01E0;
    gmii_phy_setReg( phynum, 4, readData);

    delay( 10000);
    delay( 10000);

    MDIO_CONTROL = 0x40000020;              // Enable MII interface ( MDIOCLK < 12.5MHz )

	EMAC_STAT_PORT_EN = 0x7;
	EMAC_P2_MAX_BLKS = 0x42;

    /* Gigabit PHY internal loopback*/
    gmii_phy_setReg( phynum,  0, 0x4140 );       // Force 1000mbps, full duplex
    gmii_phy_setReg( phynum,  9, 0x1300 );
    delay( 10000);
#ifdef DEBUG
    printf ("Enabling the GMII interface on DM8127.\r\n");
#else
    Uart_stringSend("\nEnabling the GMII interface on DM8127.\r\n");
#endif
    GMII_SEL = 0x00000000;
#ifdef DEBUG
    printf ( "In GMII mode\n" );
#else
    Uart_stringSend( "In GMII mode\n\r" );
#endif

	EMAC_STAT_PORT_EN = 0x7;
	EMAC_P2_MAX_BLKS = 0x104;

   //gmii_phy_dumpRegs( );

    /* ---------------------------------------------------------------- *
     *  Init EMAC                                                       *
     * ---------------------------------------------------------------- */
    /* 1. Disable RX/TX interrupts */
    EMAC_EWRXEN = 0x00000000;
    EMAC_EWTXEN = 0x00000000;

    /* 2. Clear the MAC control, receive control, & transmit control */

    EMAC0_MACCONTROL = 0;
    EMAC_RXCONTROL = 0;
    EMAC_TXCONTROL = 0;

    /* 3. Initialize all 16 header descriptor pointers RXnHDP & TXnHDP to zero */
    EMAC_RX0HDP = 0;
	EMAC_RX1HDP = 0;
	EMAC_RX2HDP = 0;
	EMAC_RX3HDP = 0;
	EMAC_RX4HDP = 0;
	EMAC_RX5HDP = 0;
	EMAC_RX6HDP = 0;
	EMAC_RX7HDP = 0;

    EMAC_TX0HDP = 0;
	EMAC_TX1HDP = 0;
	EMAC_TX2HDP = 0;
	EMAC_TX3HDP = 0;
	EMAC_TX4HDP = 0;
	EMAC_TX5HDP = 0;
	EMAC_TX6HDP = 0;
	EMAC_TX7HDP = 0;

    /* 4. Clear all 36 statistics registers by writing 0 */
    pReg = &EMAC_RXGOODFRAMES;
    for ( i = 0 ; i < 36 ; i++ )
        *(pReg+i) = 0;//*(pReg+i);

    /* 8. Set RX buffer offset to 0.  Valid data always begins on the 1st byte */
    EMAC_RXBUFFEROFFSET = 0;

    /* 11. Set the appropriate configuration bits in MACCONTROL (do not set the GMIIEN bit yet). */
    EMAC0_MACCONTROL = 0
        | ( 0 << 9 )            // Round robin
        | ( 1 << 7 )            // Gigabit mode
        | ( 0 << 6 )            // TX pacing disabled
        | ( 0 << 5 )            // GMII RX & TX
        | ( 0 << 4 )            // TX flow disabled
        | ( 0 << 3 )            // RX flow disabled
        | ( 0 << 1 )          // Loopback disabled
        /*| ( 1 << 1 )*/            // Loopback enabled
        | ( 1 << 0 )           // full duplex
        | ( 1 << 22 ) 		// CEF
        | ( 1 << 23 );		// CSF


#if 0
	delay( 100000 );
	ale_entry[2] = 0x80000000; /* */
	ale_entry[1] = 0x10000000; /* Entry Type Unicast */
	ale_entry[0] = 0x00000000;
	ale_entry[1] |= 0xBB1300;
	EMAC_ALE_TBLWRD2 = ale_entry[2];
	EMAC_ALE_TBLWRD1 = ale_entry[1];
	EMAC_ALE_TBLWRD0 = ale_entry[0];
#endif

	EMAC_ALE_PORTCTL0 |= 0x13;
	EMAC_ALE_PORTCTL1 |= 0x13;
	EMAC_ALE_PORTCTL2 |= 0x13;

	/* P2 TX Header Priority to Switch Priority Mapping */
	EMAC_P2_TX_PRI_MAP = 0x00;

    /* 12. Clear all unused channel interrupt bits */
    EMAC_RXINTMASKCLEAR = 0xFF;
    EMAC_TXINTMASKCLEAR = 0xFF;

    /* 13. Enable the RX & TX channel interrupt bits. */
    EMAC_RXINTMASKSET = 0xFF;
    EMAC_TXINTMASKSET = 0xFF;

    /* Enable Host Error and Statistics interrupts */
    EMAC_MACINTMASKSET = 0
        | ( 1 << 1 )            // Host Error interrupt mask
        | ( 1 << 0 );           // Statistics interrupt mask

    /* 14. Initialize the receive and transmit descriptor list queues. */

    /* 15. Prepare receive by writing a pointer to the head of the receive buffer descriptor list to RXnHDP. */
    EMAC0_MACSRCADDRLO = 0x03BB1300;   /* bytes 0, 1 */
    EMAC0_MACSRCADDRHI = 0xD967;       /* bytes 2-5 - channel 0 ??? */

    /* 16. Enable the RX & TX DMA controllers. Then set GMIIEN */
    EMAC_RXCONTROL = 1;
    EMAC_TXCONTROL = 1;

    EMAC0_MACCONTROL |= ( 1 << 5 );

    /* 17. Enable the device interrupt wrapper, emulation free mode */
    EMAC_EWRXEN      = 0x00000001; // Enable receive interrupts on channel 0
    EMAC_EWTXEN      = 0x00000001; // Enable transmit interrupts on channel 0


    return 0;
}


/* ------------------------------------------------------------------------ *
 *  emac_mii_init( phynum )                                                       *
 * ------------------------------------------------------------------------ */
SINT16 emac_mii_init
(
	SINT16 phynum
)
{
    SINT16 i;
    volatile UINT32* pReg;
    SINT16 readData = 0;

    //Enable MAC to operate in MII mode
	EMAC0_SLIVER_CTRL = 0x00020021;
#ifdef DEBUG
	printf( "Testing Ethernet external loopback\n" );
#else
	platform_write( "\r\nTesting Ethernet external loopback\n\r" );
#endif
    /* Reset Ethernet */
    EMAC_SOFTRESET = 1;
    while( EMAC_SOFTRESET != 0 );
    delay( 100 );

    EMAC_ALE_CONTROL |= 0x80000000;
    delay( 10000);
	EMAC_ALE_CONTROL |= 0x40000000;
	delay( 100000 );
	delay( 100000 );
	EMAC_ALE_CONTROL |= 0x00000010;
	delay( 100000 );

    /* ---------------------------------------------------------------- *
     *  Init PHY / MDIO                                                 *
     * ---------------------------------------------------------------- */
    MDIO_CONTROL = 0x40000020;              // Enable MII interface ( MDIOCLK < 12.5MHz )
    delay( 10000);

    gmii_phy_setReg( phynum,  0, 0x8000);       // phy reset
    delay( 10000);

    /* Disable RGMII mode */
    gmii_phy_setReg( phynum, 0x000D , 0x001F);
    delay( 10000);

    gmii_phy_setReg( phynum, 0x000E , 0x0032);
    delay( 10000);

    gmii_phy_setReg( phynum, 0x000D , 0x401F);
    delay( 10000);

    gmii_phy_setReg( phynum, 0x000E , 0x0050);
    delay( 10000);

    gmii_phy_setReg( phynum,  0, 0x2100);       // Enable external loopback with 1000; Full-Duplex
    delay( 10000);

    //Setup GIG advertisement
    if (readData == 0x4140)
    {
		readData = gmii_phy_getReg( phynum, 9 );
		readData |= 0x200;
		gmii_phy_setReg( phynum, 9, readData);
    }

    // setup the general advertisement
    readData = gmii_phy_getReg( phynum, 4 );
    readData |= 0x01E0;
    gmii_phy_setReg( phynum, 4, readData);

    delay( 10000);
    delay( 10000);

    MDIO_CONTROL = 0x40000020;              // Enable MII interface ( MDIOCLK < 12.5MHz )

	EMAC_STAT_PORT_EN = 0x7;
	EMAC_P2_MAX_BLKS = 0x42;

    /* PHY external cable loopback*/
    gmii_phy_setReg( phynum,  0, 0x2100 );       // Force 100mbps, full duplex
    gmii_phy_setReg( phynum,  9, 0x1000 );
    delay( 10000);

    /* Wait for link */
    Uart_stringSend( "Waiting for link..." );
    while( ( gmii_phy_getReg( phynum, 1 ) & 0x04 ) == 0 );
    Uart_stringSend( "\r\nLink Detected" );
    Uart_stringSend ("\r\nEnabling the MII interface on DM8127.\r\n");
    GMII_SEL = 0x00000000;
    Uart_stringSend( "In MII mode\n\r" );

	EMAC_STAT_PORT_EN = 0x7;
	EMAC_P2_MAX_BLKS = 0x104;

   //gmii_phy_dumpRegs( );

    /* ---------------------------------------------------------------- *
     *  Init EMAC                                                       *
     * ---------------------------------------------------------------- */
    /* 1. Disable RX/TX interrupts */
    EMAC_EWRXEN = 0x00000000;
    EMAC_EWTXEN = 0x00000000;

    /* 2. Clear the MAC control, receive control, & transmit control */

    EMAC0_MACCONTROL = 0;
    EMAC_RXCONTROL = 0;
    EMAC_TXCONTROL = 0;

    /* 3. Initialize all 16 header descriptor pointers RXnHDP & TXnHDP to zero */
    EMAC_RX0HDP = 0;
	EMAC_RX1HDP = 0;
	EMAC_RX2HDP = 0;
	EMAC_RX3HDP = 0;
	EMAC_RX4HDP = 0;
	EMAC_RX5HDP = 0;
	EMAC_RX6HDP = 0;
	EMAC_RX7HDP = 0;

    EMAC_TX0HDP = 0;
	EMAC_TX1HDP = 0;
	EMAC_TX2HDP = 0;
	EMAC_TX3HDP = 0;
	EMAC_TX4HDP = 0;
	EMAC_TX5HDP = 0;
	EMAC_TX6HDP = 0;
	EMAC_TX7HDP = 0;

    /* 4. Clear all 36 statistics registers by writing 0 */
    pReg = &EMAC_RXGOODFRAMES;
    for ( i = 0 ; i < 36 ; i++ )
        *(pReg+i) = *(pReg+i);

    /* 8. Set RX buffer offset to 0.  Valid data always begins on the 1st byte */
    EMAC_RXBUFFEROFFSET = 0;

    /* 11. Set the appropriate configuration bits in MACCONTROL (do not set the GMIIEN bit yet). */
    EMAC0_MACCONTROL = 0
        | ( 0 << 9 )            // Round robin
        | ( 1 << 7 )            // Gigabit mode
        | ( 0 << 6 )            // TX pacing disabled
        | ( 0 << 5 )            // GMII RX & TX
        | ( 0 << 4 )            // TX flow disabled
        | ( 0 << 3 )            // RX flow disabled
        | ( 0 << 1 )          // Loopback disabled
        /*| ( 1 << 1 )*/            // Loopback enabled
        | ( 1 << 0 )           // full duplex
        | ( 1 << 22 ) 		// CEF
        | ( 1 << 23 );		// CSF


#if 0
	delay( 100000 );
	ale_entry[2] = 0x80000000; /* */
	ale_entry[1] = 0x10000000; /* Entry Type Unicast */
	ale_entry[0] = 0x00000000;
	ale_entry[1] |= 0xBB1300;
	EMAC_ALE_TBLWRD2 = ale_entry[2];
	EMAC_ALE_TBLWRD1 = ale_entry[1];
	EMAC_ALE_TBLWRD0 = ale_entry[0];
#endif

	EMAC_ALE_PORTCTL0 |= 0x13;
	EMAC_ALE_PORTCTL1 |= 0x13;
	EMAC_ALE_PORTCTL2 |= 0x13;

	/* P2 TX Header Priority to Switch Priority Mapping */
	EMAC_P2_TX_PRI_MAP = 0x00;

    /* 12. Clear all unused channel interrupt bits */
    EMAC_RXINTMASKCLEAR = 0xFF;
    EMAC_TXINTMASKCLEAR = 0xFF;

    /* 13. Enable the RX & TX channel interrupt bits. */
    EMAC_RXINTMASKSET = 0xFF;
    EMAC_TXINTMASKSET = 0xFF;

    /* Enable Host Error and Statistics interrupts */
    EMAC_MACINTMASKSET = 0
        | ( 1 << 1 )            // Host Error interrupt mask
        | ( 1 << 0 );           // Statistics interrupt mask

    /* 14. Initialize the receive and transmit descriptor list queues. */

    /* 15. Prepare receive by writing a pointer to the head of the receive buffer descriptor list to RXnHDP. */
    EMAC0_MACSRCADDRLO = 0x03BB1300;   /* bytes 0, 1 */
    EMAC0_MACSRCADDRHI = 0xD967;       /* bytes 2-5 - channel 0 ??? */

    /* 16. Enable the RX & TX DMA controllers. Then set GMIIEN */
    EMAC_RXCONTROL = 1;
    EMAC_TXCONTROL = 1;

    EMAC0_MACCONTROL |= ( 1 << 5 );

    /* 17. Enable the device interrupt wrapper, emulation free mode */
    EMAC_EWRXEN      = 0x00000001; // Enable receive interrupts on channel 0
    EMAC_EWTXEN      = 0x00000001; // Enable transmit interrupts on channel 0


    return 0;
}

/* ------------------------------------------------------------------------ *
 *  verify_packet                                                           *
 * ------------------------------------------------------------------------ */
static SINT16 verify_packet
(
	EMAC_Desc* pDesc,
	UINT32 size,
	UINT32 flagCRC
)
{
    SINT16 i;
    UINT32 SizeCRC      = ( flagCRC ) ? size + 4 : size;
    UINT32 packet_flags = pDesc->PktFlgLen;

    /* We must own this packet */
    if ( packet_flags & EMAC_DSC_FLAG_OWNER )
        return 1;

    /* Must be SOP and EOP */
    if ( ( packet_flags & ( EMAC_DSC_FLAG_SOP | EMAC_DSC_FLAG_EOP ) )
                       != ( EMAC_DSC_FLAG_SOP | EMAC_DSC_FLAG_EOP ) )
        return 2;


    /* If flagCRC is set, it must have a CRC */
    if ( flagCRC )
        if ( ( packet_flags & EMAC_DSC_FLAG_PASSCRC ) != EMAC_DSC_FLAG_PASSCRC )
            return 3;

    /* Packet must be correct size */
    if ( ( packet_flags & 0xFFFF ) != SizeCRC )
        return 5;

    /* Offset must be zero, packet size unchanged */
    if ( pDesc->BufOffLen != SizeCRC )
        return 6;

    /* Validate the data */
    for ( i = 0 ; i < size ; i++ )
        if ( pDesc->pBuffer[i] != i )
            return 7;

    return 0;
}

/* ------------------------------------------------------------------------ *
 *                                                                          *
 *  test_gmii_packet( )                                                     *
 *      EMAC tests to send data to external loopback cable.                 *
 *                                                                          *
 * ------------------------------------------------------------------------ */
SINT16 test_gmii_packet
(
	void
)
{
    SINT32 i;
    SINT16 errors = 0;
    UINT32 status;
    EMAC_Desc* pDesc;

    /* ---------------------------------------------------------------- *
     *  Setup EMAC for GMII mode                                        *
     * ---------------------------------------------------------------- */
//    emac_gmii_init( );

    memset( packet_buffer1, 0x00, 128 );
    memset( packet_buffer2, 0x00, 128 );

    /* ---------------------------------------------------------------- *
     *                                                                  *
     *  Setup RX packets                                                *
     *                                                                  *
     * ---------------------------------------------------------------- */
    pDesc            = pDescBase;
    pDesc->pNext     = pDescBase + 1;
    pDesc->pBuffer   = packet_buffer1;
    pDesc->BufOffLen = RX_BUF;
    pDesc->PktFlgLen = EMAC_DSC_FLAG_OWNER;

    pDesc            = pDescBase + 1;
    pDesc->pNext     = 0;
    pDesc->pBuffer   = packet_buffer2;
    pDesc->BufOffLen = RX_BUF;
    pDesc->PktFlgLen = EMAC_DSC_FLAG_OWNER;

    /*
     *  Start RX receiving
     */
    pDescRx = pDescBase;
    EMAC_RX0HDP = ( UINT32 )pDescRx;

    /* ---------------------------------------------------------------- *
     *                                                                  *
     *  Setup TX packets                                                *
     *      Send 2 copies of the same packet using different sizes      *
     *                                                                  *
     * ---------------------------------------------------------------- */
    for ( i = 0 ; i < TX_BUF ; i++ )
        packet_data[i] = i;

    pDesc            = pDescBase + 10;
    pDesc->pNext     = pDescBase + 11;
    pDesc->pBuffer   = packet_data;
    pDesc->BufOffLen = TX_BUF - 4; // 4 bytes for CRC
    pDesc->PktFlgLen = EMAC_DSC_FLAG_OWNER
                     | EMAC_DSC_FLAG_SOP
                     | EMAC_DSC_FLAG_EOP
                     | (TX_BUF - 4);

    pDesc            = pDescBase + 11;
    pDesc->pNext     = 0;
    pDesc->pBuffer   = packet_data;
    pDesc->BufOffLen = TX_BUF - 4; // 4 bytes for CRC
    pDesc->PktFlgLen = EMAC_DSC_FLAG_OWNER
                     | EMAC_DSC_FLAG_SOP
                     | EMAC_DSC_FLAG_EOP
                     | (TX_BUF - 4);

    /*
     *  Start TX sending
     */
    TxCount = 0;
    RxCount = 0;
    pDescTx = pDescBase + 10;
    EMAC_TX0HDP = ( UINT32 )pDescTx;

    delay( 10000);

	/* ACK TX */
	status = EMAC_TX0CP;
    EMAC_TX0CP = status;

    delay( 10000);
    /* ACK RX */
    status = EMAC_RX0CP;
    EMAC_RX0CP = status;

    /* ---------------------------------------------------------------- *
     *                                                                  *
     *  Normally there would be a interrupt to service the EMAC RX/TX   *
     *  transmission.  Instead a short pause and manually call the ISR  *
     *  Interrupt Service Routine to check on the status.               *
     *                                                                  *
     *  You can later add in the ISR and the code to support.           *
     *                                                                  *
     * ---------------------------------------------------------------- */

    /* Busy period */
    delay( 10000);

    /* ---------------------------------------------------------------- *
     *  Check packet and results                                        *
     * ---------------------------------------------------------------- */

    if ( verify_packet( pDescBase, TX_BUF - 4, 1 ) )        // Verify Size + Contents
        errors++;

    if ( verify_packet( pDescBase + 1, TX_BUF - 4, 1 ) )	// Verify Size + Contents
        errors++;
#if 0
    if ( ( status = EMAC_FRAME64 ) != 2 )           // Check # of 64 byte frames
        errors++;
    EMAC_FRAME64 = status;

    if ( ( status = EMAC_FRAME128T255 ) != 2 )      // Check # of 128-255 byte frames
        errors++;
    EMAC_FRAME128T255 = status;

    if ( ( status = EMAC_RXGOODFRAMES ) != 2 )      // Check # of Good RX frames
        errors++;
    EMAC_RXGOODFRAMES = status;

    if ( ( status = EMAC_TXGOODFRAMES ) != 2 )      // Check # of Good TX frames
        errors++;
    EMAC_TXGOODFRAMES = status;
#endif
    return errors;
}

/* ------------------------------------------------------------------------ *
 *                                                                          *
 *  emac_gmii_test( )                                                       *
 *                                                                          *
 * ------------------------------------------------------------------------ */
STATUS emac_gmii_test
(
	void *testargs
)
{
	UINT16 phyaddr[32];
    SINT16 errors = 0, num, i;

	 Uart_stringSend("\r\n==================================="
					 "\r\n         Ethernet Test             "
					 "\r\n===================================\r\n");
//    UINT32 data;
//
//    *(VUINT32 *)0x4a10000 &= 0x7FF;
    /* Detect PHYs */
    num = gmii_phy_detect( phyaddr );
    num = num; /* for compiler warnings */

    /* Setup EMAC for GMII mode */
    emac_gmii_init( phyaddr[0]);
    /* Test EMAC in GMII mode*/
    for ( i = 0 ; i < 10 ; i++ )
        errors += test_gmii_packet( );

    if (!errors)
    	{
#ifdef DEBUG
    		printf("Packet verification passed!!\n");
			printf("PHY internal loopback test completed\n");
#else
    	Uart_stringSend("Packet verification passed\n\r"
    			        "PHY internal loopback test completed\n\r");
#endif

    	}
    	else
    	{
#ifdef DEBUG
    		printf("Packet verification failed\n");
			printf("PHY internal loopback test failed\n");
#else
    	Uart_stringSend("Packet verification passed\n"
    			        "\rPHY internal loopback test failed\n\r");
#endif

    		return errors;
    	}

    EMAC_RESET1 = 0x0001;
	while( EMAC_RESET1 != 0 );
	delay( 100 );

	EMAC_RESET2 = 0x0001;
	while( EMAC_RESET2 != 0 );
	delay( 100 );
	EMAC_RESET3 = 0x0001;
	while( EMAC_RESET3 != 0 );
	delay( 100 );

    /* Setup EMAC for MII mode */
    emac_mii_init( phyaddr[0] );

    /* Test EMAC in MII mode*/
    for ( i = 0 ; i < 10 ; i++ )
        errors += test_gmii_packet( );

    if (!errors)
       	{

#ifdef DEBUG
    		printf("Packet verification passed!!\n");
    		printf("Ethernet external loopback test completed\n");
#else
    	Uart_stringSend("\rPacket verification passed\n\r"
    			        "Ethernet external loopback test completed\n\r");
#endif
    	Uart_stringSend("\r\n-------------------------X-----------------------------");
       		return errors;
       	}
       	else
       	{
#ifdef DEBUG
       		printf("Packet verification failed\n");
       		printf("Ethernet external loopback test failed\n");
#else
    	Uart_stringSend("Packet verification failed\n\r"
    			        "Ethernet external loopback test failed\n\r");
#endif
    	  /* Reset Ethernet */
    	    EMAC_SOFTRESET = 1;
    	    while( EMAC_SOFTRESET != 0 );
    	    delay( 100 );
    	    Uart_stringSend("\r\n-------------------------X-----------------------------");
       		return errors;
       	}

}
