/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 *
 * Edit History
 * Initials        Date        Change Description
 * JZW 9/20/05    Added autodoc comments describing LED flashes for POST failures
 *
 */


#include <bsp_sys.h>
#if BSP_POST_TEST

#include <stdlib.h>
#include <mcreg_def.h>
#include <mcdma_def.h>
#include <string.h>
#include <mc_isr.h>
#include <MII.h>
#include <ncc_post.h>
#include <mctimer.h>
#include <mc_eth.h>
#include <noncache.h>
#include <init.h>
#include <cache.h>
#include <nammu.h>
#include <sysclock.h>
#include <io_ctrl_mod.h>
#include <bdcm_reg.h>
#include <ns9215_a2d.h>
#include <uart_16750.h>
#include <iohub_reg.h>
#include <i2c_def.h>
#include <bele.h>
#include <spi_master_api.h>
#include <gpiomux_def.h>

/*ad*
 *
 * <section>ConnectCore Wi-9P 9215 POST LED flash sequences</section>
 * 
 *
 * @image na_post_connectcore9p9215.png
 *
 *
 * @external
 * @overview    ConnectCore Wi-9P 9215 POST 
 * @platform 	connectcorewi9p9215_a
 * @category BSP:POST:POST_connectcorewi9p9215_a
 * @since 7.3
 *
 *ad*/

/*
 * Data is always read in little endian formation when the receive FIFO is read
 * directly.  This macro swaps the word to the correct endianess when operating
 * in big endian mode.
 */
#ifdef _LITTLE_ENDIAN
    #define FIX_ENDIANNESS(word)        (word)
#else
    #define FIX_ENDIANNESS(word)        swap32(word)
#endif

static void restoreVector (void);
static volatile WORD32 irqFlag[32];      /* flags set in Interrupt */
static int myEthernetAddr[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

static volatile NA_DMA_DESCRIPTOR_TYPE dma_mm_bd[2][2];
static volatile NA_DMA_DESCRIPTOR_TYPE ser_tx_bd[4][2], ser_rx_bd[4][2];
static volatile NA_DMA_DESCRIPTOR_TYPE eth_tx_bd[2], eth_rx_bd[2];

#define POST_ETH_BUF_SIZE 1024
static BYTE txBuffer[2][POST_ETH_BUF_SIZE], rxBuffer[2][POST_ETH_BUF_SIZE];

/* Function prototypes */
static int test_mem_to_mem_dma (void);
static void test_mem_to_mem_dma_stop (void);
static int ethConfigEfe (void);
static int ethAssignDMA (unsigned long addr, int numOfDst, NA_DMA_DESCRIPTOR_TYPE * eth_bd);
static int ethResetEfe (void);
static int ethEnableMac (void);
static int ethDisableMac (void);
static void ethDisableIsr (void);
static void ethEnableIsr (void);
static void ethDisableEfe (void);
static void ethEnableEfe (void);
static void ethEnableDma (void);
static void ethDisableDma (void);
static void ethEnable (void);
static void ethDisable (void);
static int test_serial_loopback (int port);

#define NCC_POST_WAIT_TIME   100000

/* location of the Battery backed NvRAM */
#define RTC_BACKEDUP_RAM_START         0x900600C0
#define RTC_BACKEDUP_RAM_STOP          0x90060100

/*
 * The POST tests is limited for development board. Don't compile the code we don't use.
 * #define NOT_USED_NOW  
 */

/* 
 * This structure is used to store the results of 
 * the POST test. 
 */
static nccPostResultsType nccPostResults = {
    POST_PASSED,
    0,
    0
};


/************************************************/
/*      Timer Control Register                  */
/************************************************/

/*
 * Disables a specified timer. 
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @return 0 	        The device was successfully disabled.
 *
 * @see @link ncc_post_enable_timer 
 */

static int ncc_post_disable_timer(const unsigned int indx)
{
    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, enable, SCM_TCR_DISABLE);

    return (0);
}


/*
 * Enables a specified timer. 
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @return 0 	        The device was successfully enabled.
 *
 */

static int ncc_post_enable_timer(const unsigned int indx)
{

    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, enable, SCM_TCR_ENABLE);
    return (0);
}

/*
 * Selects a timer input clock for a specific timer.
 *
 *
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @param value         The timer clock select value. One of macros in @link Timer_CPU_CLOCK.
 *
 * @return 0            The timer clock is selected.
 *
 */

static int ncc_post_set_timer_clock_select(const  unsigned int indx, const int value)
{
    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, clockSelect, value);
    return (0);
}

/*
 * Selects a timer mode for a specific timer. 
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @param value         The timer mode select value.
 *
 * <list type ="ordered">
 * <item>INTERNAL_TIMER_OR_EXTERNAL_EVENT      0</item>
 * <item>EXTERNAL_LOW_GATED_TIMER  		1</item>
 * <item>EXTERNAL_HIGH_GATED_TIMER		2</item>
 * <item>RESERVED				3</item>
 *</list>
 * @return 0 	        The timer mode is selected.
 *
 */
static int ncc_post_set_timer_mode(const unsigned  int indx, const int value)
{
    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, mode, value);
    return (0);
}


/*
 * Sets timer to either generate interrupt or not.
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @param value         The timer mode select value.
 *
 * <list type ="ordered">
 * <item> NA_TIMER_DISABLE_INTERRUPT 		0 </item>
 * <item> NA_TIMER_ENABLE_INTERRUPT  		1 </item>
 * </list>
 *
 * @return 0 	        The timer interrupt mode is selected.
 *
 */

static int ncc_post_set_timer_interrupt_select(const unsigned int indx, const int value)
{
    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, interruptSelect, value);
    return (0);
}


/*
 * Set timer to either count up or count down.
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @param value         The timer mode select value.
 *
 * <list type ="ordered">
 * <item> NA_TIMER_UP_COUNTER                   0</item>
 * <item> NA_TIMER_DOWN_COUNTER                 1</item>
 * </list>
 *
 * @return 0 	        The timer up/down mode is selected.
 *
 */
static int ncc_post_set_timer_updown_select(const unsigned int indx, const int value)
{
    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, upDownSelect, value);
    return (0);
}


/*
 * Sets timer to either 16 or 32 bits.
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @param value         The timer bit select value.
 *
 * <list type ="ordered">
 * <item> NA_TIMER_16_BIT                       0</item>
 * <item> NA_TIMER_32_BIT                       1</item>
 * </list>
 *
 * @return 0 	        The timer bit mode is selected.
 */
static int ncc_post_set_timer_bit(const unsigned int indx, int value)
{
    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, bitTimer, value);
    return (0);
}


/*
 * Sets timer to either auto reload or not.
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @param value         The timer auto-reload enable or disable.
 *
 * <list type ="ordered">
 * <item> 0  Diable timer reload</item>
 * <item> 1  Enable timer reload</item>
 * </list>
 * 
 * @return 0 	        The timer auto-reload mode is selected.
 *
 */
static int ncc_post_set_timer_reload_enable(const unsigned int indx, const int value)
{

    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, reloadEnable, value);
    return (0);
}


/************************************************/
/*      Timer Reload Control Register           */
/************************************************/


/*
 * Sets timer to either 16 or 32 bits.
 *
 * 
 * @external
 * @category Timer
 * @since 6.2
 *
 * @param indx         Timer value: range [0..15]
 *
 * @param value         The timer bit select value.
 *
 * <list type ="ordered">
 * <item> NA_TIMER_16_BIT                       0</item>
 * <item> NA_TIMER_32_BIT                       1</item>
 * </list>
 *
 * @return 0 	        The timer bit mode is selected.
 *
*/
static int ncc_post_reload_timer_counter(const unsigned int indx, const unsigned int value)
{

    unsigned long int volatile * const addr = TRCR_getAddress(indx);

    narm_write_reg (NA_SCM_TRCR_REG, addr, counter, value);
    return (0);
}


/*
 * Clears the timer interrupt
 *
 */


static int ncc_post_clear_timer_Interrupt(const unsigned int indx)
{
    unsigned int value;
    unsigned long int volatile * const addr = TCR_getAddress(indx);

    narm_write_reg (NA_SCM_TCR_REG, addr, clearInterrupt, 1);  /* Software must write a one and a zero */
    narm_write_reg (NA_SCM_TCR_REG, addr, clearInterrupt, 0);  /* to clear the interrupt */

    /* Hardware issue, if reload is off, shut off select */
    value=narm_read_reg (NA_SCM_TCR_REG, addr, reloadEnable);
    if (!value)   							/* if reload diable */
        narm_write_reg (NA_SCM_TCR_REG, addr, interruptSelect, 0);     	/* to clear the interrupt */
    return (0);
}


/*  Function: static void ncc_post_timer9_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for timer 9 interrupt. 
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer9_isr (void)
{
    irqFlag[27]++;
    ncc_post_clear_timer_Interrupt (9);
}

/*  Function: static void ncc_post_timer8_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for timer 8 interrupt. 
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer8_isr (void)
{
    irqFlag[26]++;
    ncc_post_clear_timer_Interrupt (8);
}

/*  Function: static void ncc_post_timer7_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for timer 7 interrupt. 
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer7_isr (void)
{
    irqFlag[25]++;
    ncc_post_clear_timer_Interrupt (7);
}

/*  Function: static void ncc_post_timer6_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for timer interrupt 6 
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer6_isr (void)
{
    irqFlag[24]++;
    ncc_post_clear_timer_Interrupt (6);
}

/*  Function: static void ncc_post_timer5_isr (void) 
 * 
 *  Description: 
 *     This routine provides the interrupt service routine handler 
 *     for timer interrupt 5.
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer5_isr (void)
{
    irqFlag[23]++;
    ncc_post_clear_timer_Interrupt (5);
}

/*  Function: static void ncc_post_timer4_isr (void) 
 * 
 *  Description: 
 *     This routine provides the interrupt service routine handler 
 *     for timer interrupt 4. 
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer4_isr (void)
{
    irqFlag[22]++;
    ncc_post_clear_timer_Interrupt (4);
}

/*  Function: static void ncc_post_timer3_isr (void) 
 * 
 *  Description: 
 *     This routine provides the interrupt service routine handler 
 *     for timer interrupt 3
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer3_isr (void)
{
    irqFlag[21]++;
    ncc_post_clear_timer_Interrupt (3);
    ncc_post_disable_timer (3);
}

/*  Function: static void ncc_post_timer2_isr (void) 
 * 
 *  Description: 
 *     This routine provides the interrupt service routine handler 
 *     for timer interrupt 2
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer2_isr (void)
{
    irqFlag[20]++;
    ncc_post_clear_timer_Interrupt (2);
    ncc_post_disable_timer (2);
}

/*  Function: static void ncc_post_timer1_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for timer interrupt 1
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_timer1_isr (void)
{

    irqFlag[19]++;
    ncc_post_clear_timer_Interrupt (1);
    ncc_post_disable_timer (1);
}

/*  Function: static void ncc_post_ether_tx_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for the ethernet tx Module interrupt
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_ether_tx_isr (void)
{
    unsigned int ret;

    /* read EFE interrupt status register */
    ret = *(unsigned long volatile *)NA_EFE_ISR_ADDRESS & EFE_ISR_TX_MASK;

    /* acknowledge the interrupt */
    *(unsigned long volatile *)NA_EFE_ISR_ADDRESS = ret;

    irqFlag[5]++;

}

/*  Function: static void ncc_post_ether_rx_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for the ethernet rx Module interrupt
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_ether_rx_isr (void)
{
    unsigned int ret;

    /* read DMA status register */
    ret = *(unsigned long volatile *)NA_EFE_ISR_ADDRESS & EFE_ISR_RX_MASK;

    /* acknowledge the interrupt */
    *(unsigned long volatile *)NA_EFE_ISR_ADDRESS = ret;

    irqFlag[4]++;

}

/*  Function: static void ncc_post_mmdma_isr (void) 
 * 
 *  Description: 
 *     This routine provides the POST interrupt service routine handler 
 *     for the bbus Module interrupt
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *      none 
 */

static void ncc_post_mmdma_isr (void)
{
    WORD32 status;

    status = *(unsigned long volatile *) BDCM_DSIER01_ADDRESS;
    if (status & 0x80000000)
    {
        *((unsigned long volatile *) BDCM_DSIER01_ADDRESS) = status;
        irqFlag[2]++;
    }

    status = *((unsigned long volatile *) BDCM_DSIER02_ADDRESS);
    if (status & 0x80000000)
    {
        *((unsigned long volatile *)BDCM_DSIER02_ADDRESS) = status;
        irqFlag[2]++;
    }

}

/*  Function: ncc_post_serl_setup (int port)
 *
 *  Description:
 *     This function will setup a Serial Port in internal loopback
 *     mode and tests the transmitter and receiver
 *  Parameters:
 *     none
 *  
 *  Return Value:
 *     none
 *
 */
static void ncc_post_serl_setup(int port)
{
    unsigned divisor;
    int iohub_port = port+2;
    
    /*
     * Disable interrupts from the port
     */
    *NA_IOHUB_DMA_RX_ICR_getAddress(iohub_port) = 0;
    *NA_IOHUB_DMA_TX_ICR_getAddress(iohub_port) = 0;
    *NA_16750_WRAPPER_IE_getAddress(port) = 0;
    *NA_16750_UART_IE_getAddress(port) = 0;
    
    /*
     * Reset the port and its fifos
     */
    *NA_16750_CONFIG_getAddress(port) = 0;
    narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), rxflush, TRUE);
    narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), rxflush, FALSE);
    narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), txflush, TRUE);
    narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), txflush, FALSE);
    *NA_IOHUB_DMA_RX_CONTROL_getAddress(iohub_port) = 0;
    *NA_IOHUB_DMA_TX_CONTROL_getAddress(iohub_port) = 0;

    /*
     * Set direct access mode
     */
    narm_write_reg(NA_IOHUB_DMA_RX_CONTROL, NA_IOHUB_DMA_RX_CONTROL_getAddress(iohub_port), direct, NA_IOHUB_DMA_RX_CONTROL_DIRECT_ACCESS_MODE);
    narm_write_reg(NA_IOHUB_DMA_TX_CONTROL, NA_IOHUB_DMA_TX_CONTROL_getAddress(iohub_port), direct, NA_IOHUB_DMA_TX_CONTROL_DIRECT_ACCESS_MODE);
     
    /*
     * Set baud rate divisor
     */
    divisor = NA_ARM9_INPUT_FREQUENCY / (16 * 9600);

    narm_write_reg(NA_16750_LINE_CONTROL, NA_16750_LINE_CONTROL_getAddress(port), dlab, NA_16750_LINE_CONTROL_ACCESS_BAUD_RATE_DIVISOR);
    narm_write_reg(NA_16750_BAUD_RATE_DIVISOR_LSB, NA_16750_BAUD_RATE_DIVISOR_LSB_getAddress(port), brdl, divisor & 0xff);
    narm_write_reg(NA_16750_BAUD_RATE_DIVISOR_MSB, NA_16750_BAUD_RATE_DIVISOR_MSB_getAddress(port), brdm, divisor >> 8);
    narm_write_reg(NA_16750_LINE_CONTROL, NA_16750_LINE_CONTROL_getAddress(port), dlab, NA_16750_LINE_CONTROL_ACCESS_BUFFERS);
    
    /*
     * Setup line control register:  break disabled, parity disabled, 1 stop bit, 8 data bits
     */
    narm_write_reg(NA_16750_LINE_CONTROL, NA_16750_LINE_CONTROL_getAddress(port), sb, FALSE);
    narm_write_reg(NA_16750_LINE_CONTROL, NA_16750_LINE_CONTROL_getAddress(port), pen, FALSE);
    narm_write_reg(NA_16750_LINE_CONTROL, NA_16750_LINE_CONTROL_getAddress(port), stb, NA_16750_LINE_CONTROL_2_STOP_BITS);
    narm_write_reg(NA_16750_LINE_CONTROL, NA_16750_LINE_CONTROL_getAddress(port), wls, NA_16750_LINE_CONTROL_8_DATA_BITS);
    
    /*
     * Enable internal UART FIFO.  This is different than the wrapper FIFOs.
     */
    narm_write_reg(NA_16750_UART_FIFO_CONTROL, NA_16750_UART_FIFO_CONTROL_getAddress(port), fifoen, TRUE);
    
    /*
     * Enable the transmitter holding register from the UART.  This interrupt will not be
     * seen by software.  It is handled by the hardware wrapper, and needed by the wrapper
     * in order to function.
     */
    narm_write_reg(NA_16750_UART_IE, NA_16750_UART_IE_getAddress(port), etbei, TRUE);
     
    /*
     * Start the wrapper by enabling the transmitter and receiver FIFOs
     */
    narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), rxen, TRUE);
    narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), txen, TRUE);

    /*
     * Enable the transmitter
     */
    narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), enableTransmitter, TRUE);

    /*
     * Enable DTR
     */
    narm_write_reg(NA_16750_MODEM_CONTROL, NA_16750_MODEM_CONTROL_getAddress(port), dtr, TRUE);

    /*
     * Turn on internal loopback
     */
    narm_write_reg(NA_16750_MODEM_CONTROL, NA_16750_MODEM_CONTROL_getAddress(port), llb, TRUE);

    /*
     * Enable transmitter interrupts from the UART which actually go to
     * the wrapper.  This does not generate interrupts that the CPU sees.
     */
    narm_write_reg(NA_16750_WRAPPER_IE, NA_16750_WRAPPER_IE_getAddress(port), tx_idle, TRUE);
}




/*  Function: ncc_post_fputc (int port, char out)
 *
 *  Description:
 *     This function will put one byte data to transmit fifo.
 *
 *  Parameters:
 *     out:     byte to be transmitted
 *  
 *  Return Value:
 *     none
 *
 */
static void ncc_post_fputc (int port, char out)
{
    int iohub_port = port+2;

    /* Wait for room in the transmitter FIFO */
    while (narm_read_reg(NA_IOHUB_IFS, NA_IOHUB_IFS_getAddress(iohub_port), tx_fifo_full) != 0)
    {
        ;
    }

    /* Write the output byte */
    *(BYTE *)NA_IOHUB_DIRECT_MODE_TX_FIFO_getAddress(iohub_port) = out;
}



/*  Function: bsp_printf (char *outString)
 *
 *  Description:
 *     This function will transmit a null terminated string
 *     through specieifed serial port. 
 *
 *  Parameters:
 *     outString:   pointer to a null terminated string
 *  
 *  Return Value:
 *     none
 *
 */
static void ncc_post_printf (int port, char *outString)
{
    char *out = outString;

    while (*out != '\0')
    {
        ncc_post_fputc(port, *out);
        out++;
    }
}

/*  Function: ncc_post_fgetw (int port, int pollTime, WORD32 *data)
 *
 *  Description:
 *     This function will retreive upto 4 bytes of data from
 *     receiver FIFO.
 *
 *  Parameters:
 *     data:        pointer to the location to store up to 4 bytes of data
 *  
 *  Return Value:
 *     size:        size of the data
 *
 */
static char ncc_post_fgetw(int port, int pollTime, WORD32 *data)
{
    int iohub_port = port+2;
    unsigned long wait_time = pollTime * 1000; 
    char size = 0;

    /* Poll for data until we receive something or time out */
    do
    {
        /*
         * If receive FIFO is empty, then try closing the current buffer to force any
         * pending characters into it.
         */
        if (narm_read_reg(NA_IOHUB_IFS, NA_IOHUB_IFS_getAddress(iohub_port), rx_fifo_empty) != 0)
        {
            narm_write_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), rxclose, TRUE);
            while(narm_read_reg(NA_16750_CONFIG, NA_16750_CONFIG_getAddress(port), rxclose) != 0)
            { 
                ;   /* wait for hardware to complete receive buffer close operation */
            }
        }

        if (narm_read_reg(NA_IOHUB_IFS, NA_IOHUB_IFS_getAddress(iohub_port), rx_fifo_empty) == 0)
        {   /* if something in FIFO */
            size = narm_read_reg(NA_IOHUB_DIRECT_MODE_RX_STATUS, NA_IOHUB_DIRECT_MODE_RX_STATUS_getAddress(iohub_port), byte);
            *data = FIX_ENDIANNESS(*NA_IOHUB_DIRECT_MODE_RX_FIFO_getAddress(iohub_port));
        }            
        if (size)
            break; /* data has been read */

    } while(wait_time-- > 0);

    return (size);
}


    
static char ncc_post_fgetc(int port, int pollTime)
{
    static int indx = 0, size = 0;
    static char data[sizeof(WORD32)];

    if (indx == size)
    {
        size = ncc_post_fgetw( port, pollTime, (WORD32 *)data );
        indx = 0;
        if (size == 0)
        {
            /* Timeout */
            indx = 0;
            return -2;
        }
    }

    return (data[indx++] & 0xFF);
}


/*  Function: void report_error (WORD32 test, WORD32 error) 
 * 
 *  Description: 
 * 
 *      This function stores the test results into a structure 
 *      that is eventually passed back to the application that 
 *      started the POST. 
 * 
 *  Parameters: 
 * 
 *     test         indicates which test function failed 
 *     error        indicates which part of the test function failed. 
 *   
 *  Return Value: 
 * 
 *     none 
 * 
 */
static void report_error (WORD32 test, WORD32 error)
{
    nccPostResults.ccode = POST_FAILED;
    nccPostResults.testCode = test;
    nccPostResults.subtestCode = error;
}


/* This function test timer2-timer15.
 *
 *  Parameters: 
 *      timer: which timer is under test
 * 
 *  Return Values: 
 *      POST_PASSED : Test Pass 
 *      POST_FAILED : Test Fail 
 *
 *
*/
static int post_test_timer (WORD32 timer)
{
    int test = 2, i;
    int error = 0;
    WORD32 ref_timer = 1;
    WORD32 ref_timer_reload = 0x20000;
    WORD32 test_timer_reload = 0x500;
    int             isr_id;
    NA_ISR_HANDLER  isr_handler;

    /* Clear the interrupt flags */
    for (i = 0; i < 32; i++)
        irqFlag[i] = 0;

    if ((timer < 2) || (timer > 9))    /* only work for timer 2 to 9 */
    {
        error = 1;
        report_error (test, error);
        return POST_FAILED;
    }

    switch (timer)
    {
    case 2:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER2_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer2_isr;
        goto _cont;        

    case 3:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER3_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer3_isr;
        goto _cont;        

    case 4:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER4_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer4_isr;
        goto _cont;        

    case 5:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER5_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer5_isr;
        goto _cont;        

    case 6:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER6_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer6_isr;
        goto _cont;        

    case 7:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER7_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer7_isr;
        goto _cont;        

    case 8:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER8_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer8_isr;
        goto _cont;        

    case 9:
        /*Install interrupt handler and enable interrupt */
        isr_id = TIMER9_INTERRUPT;
        isr_handler = (NA_ISR_HANDLER) ncc_post_timer9_isr;
        goto _cont;        
_cont:
        naIsrInstall (isr_id, (NA_ISR_HANDLER) isr_handler, NULL); 
        break;
    default:
        break;
    }

    /*Install interrupt handler and enable interrupt for reference timer, which is timer 1 */
    naIsrInstall (TIMER1_INTERRUPT, (NA_ISR_HANDLER) ncc_post_timer1_isr, NULL);

    /* Test timer */
    ncc_post_set_timer_clock_select (timer, 5);           /* set timer timer select to 1/32 */
    ncc_post_set_timer_mode (timer, 0);                  /* set timer timer to internal timer */
    ncc_post_set_timer_interrupt_select (timer, 1);       /* enable timer timer interrupt */
    ncc_post_set_timer_updown_select (timer, 1);          /* set timer clock #0 as a downcounter */
    ncc_post_set_timer_bit (timer, 1);                   /* set timer as 32 bit timer */
    ncc_post_set_timer_reload_enable (timer, 0);          /* disable timer reload */
    ncc_post_reload_timer_counter (timer, test_timer_reload);
    ncc_post_enable_timer (timer);                      /* Enable Timer */

    /* Reference timer */

    ncc_post_set_timer_clock_select (ref_timer, 5);       /* set timer timer select to 1/32 */
    ncc_post_set_timer_mode (ref_timer, 0);              /* set timer timer to internal timer */
    ncc_post_set_timer_interrupt_select (ref_timer, 1);   /* enable timer timer interrupt */
    ncc_post_set_timer_updown_select (ref_timer, 1);      /* set timer clock #0 as a downcounter */
    ncc_post_set_timer_bit (ref_timer, 1);               /* set timer as 32 bit timer */
    ncc_post_set_timer_reload_enable (ref_timer, 0);      /* disable timer reload */
    /* set the reference two as long as testing timer */
    ncc_post_reload_timer_counter (ref_timer, ref_timer_reload);
    ncc_post_enable_timer (ref_timer);                  /* Enable Timer */

    while ((irqFlag[18] == 0) &&
           (irqFlag[19] == 0) &&
           (irqFlag[20] == 0) &&
           (irqFlag[21] == 0) &&
           (irqFlag[22] == 0) && 
           (irqFlag[23] == 0) && 
           (irqFlag[24] == 0) && 
           (irqFlag[25] == 0) && 
           (irqFlag[26] == 0) && 
           (irqFlag[27] == 0));

    if (irqFlag[timer + 18] == 0)
    {
        error = timer;
        report_error (test, error);
    }

    ncc_post_set_timer_interrupt_select (timer, 0);
    ncc_post_set_timer_interrupt_select (ref_timer, 0);

    ncc_post_disable_timer (timer);
    ncc_post_disable_timer (ref_timer);

    switch (timer)
    {
    case 2:
        /*Uninstall interrupt handler and disable interrupt */
        naIsrUninstall (TIMER2_INTERRUPT);
        break;

    case 3:
        /*Uninstall interrupt handler and disable interrupt */
        naIsrUninstall (TIMER3_INTERRUPT);
        break;

    case 4:
        /*Uninstall interrupt handler and disable interrupt */
        naIsrUninstall (TIMER4_INTERRUPT);
        break;

    case 5:
        /*Uninstall interrupt handler and disable interrupt */
        naIsrUninstall (TIMER5_INTERRUPT);
        break;

    case 6:
        /*Uninstall interrupt handler and disable interrupt */
        naIsrUninstall (TIMER6_INTERRUPT);
        break;

    case 7:
        /*Uninstall interrupt handler and disable interrupt */
        naIsrUninstall (TIMER7_INTERRUPT);
        break;

    default:
        break;
    }

    /*Uninstall interrupt handler and disable interrupt for reference timer, which is timer 1 */
    naIsrUninstall (TIMER1_INTERRUPT);

    return (error ? POST_FAILED : POST_PASSED);
}

/*  Function: int test_mem_to_mem_dma_stop 
 * 
 *  Description: 
 *     This routine does the clean up after routine test_mem_to_mem_dma() is called.
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 *		none
 */
static void test_mem_to_mem_dma_stop (void)
{
    *((unsigned long volatile *) BDCM_DCR01_ADDRESS) = 0;
    *((unsigned long volatile *) BDCM_DCR02_ADDRESS) = 0;
    naIsrUninstall (EXTERNAL_DMA_INTERRUPT);
}

/*  Function: int test_mem_to_mem_dma 
 * 
 *  Description: 
 *     This routine executes a memory-to-memory dma test using External DMA channels  
 *     one and two simultaneously.  A pattern is generated to be moved from 
 *     one block to another.  All destination blocks are verified after the 
 *     dma operation is complete. 
 * 
 *  Parameters: 
 *      none 
 * 
 *  Return Values: 
 * 
 *      POST_PASSED 
 *      POST_FAILED 
 */
static int test_mem_to_mem_dma (void)
{

    volatile WORD32 timeout;

    WORD32 test = 1;
    WORD32 error = 0;
    WORD32 temp32, i;

    BYTE temp8, arrayIndex;
    unsigned long volatile *dma_src_addr[4], *dma_des_addr[4];

    /* Clear the interrupt flags */
    for (i = 0; i < 32; i++)
        irqFlag[i] = 0;

    /* First BUILD the DMA buffer descriptors */
    for (i = 0; i < 4; i++)
    {
        dma_src_addr[i] = (unsigned long volatile *) 0;
        dma_des_addr[i] = (unsigned long volatile *) 0;
    }

    for (i = 0; i < 4; i++)
    {
        dma_src_addr[i] = (unsigned long volatile *) malloc (sizeof (WORD32) * 0x100);
        dma_des_addr[i] = (unsigned long volatile *) malloc (sizeof (WORD32) * 0x100);
        if ((dma_src_addr[i] == NULL) || (dma_des_addr[i] == NULL))
        {
            error = 1;
            report_error (test, error);
            goto test_mem_to_mem_dma_done;
        }
    }

    /* Now Generate the Source Data */
    for (temp8 = 0; temp8 < 4; temp8++)
    {
        for (temp32 = 0; temp32 < 0x100; temp32++)
        {
            *(unsigned long volatile *) (dma_src_addr[temp8] + temp32) = temp32;
        }
    }

	/* Now clean up the dest Data */
    for (temp8 = 0; temp8 < 4; temp8++)
    {
        for (temp32 = 0; temp32 < 0x100; temp32++)
        {
            *(unsigned long volatile *) (dma_src_addr[temp8] + temp32) = 0;
        }
    }

    dma_mm_bd[0][0].src_addr = (WORD32) dma_src_addr[0];        /* 0x1000D000;  */
    dma_mm_bd[0][0].dst_addr = (WORD32) dma_des_addr[0];        /* 0x1000E000;  */
    dma_mm_bd[0][0].buf_len = 0x400;
    dma_mm_bd[0][0].flag = 0x50000000;  /* I|F|L */

    dma_mm_bd[0][1].src_addr = (WORD32) dma_src_addr[1];        /* 0x1000D100;  */
    dma_mm_bd[0][1].dst_addr = (WORD32) dma_des_addr[1];        /* 0x1000E100;  */
    dma_mm_bd[0][1].buf_len = 0x400;
    dma_mm_bd[0][1].flag = 0xD0000000;  /* W|I|F|L */

    dma_mm_bd[1][0].src_addr = (WORD32) dma_src_addr[2];        /* 0x1000D200;  */
    dma_mm_bd[1][0].dst_addr = (WORD32) dma_des_addr[2];        /* 0x1000E200;  */
    dma_mm_bd[1][0].buf_len = 0x400;
    dma_mm_bd[1][0].flag = 0x50000000;  /* I|F|L */

    dma_mm_bd[1][1].src_addr = (WORD32) dma_src_addr[3];        /* 0x1000D300;  */
    dma_mm_bd[1][1].dst_addr = (WORD32) dma_des_addr[3];        /* 0x1000E300;  */
    dma_mm_bd[1][1].buf_len = 0x400;
    dma_mm_bd[1][1].flag = 0xD0000000;  /* W|I|F|L */

    /*Install interrupt handler and enable interrupt */
    if (naIsrInstall (EXTERNAL_DMA_INTERRUPT, (NA_ISR_HANDLER) ncc_post_mmdma_isr, NULL))
    {
        error = 2;
        report_error (test, error);
        goto test_mem_to_mem_dma_done;
    }

    /* Setup the DMA Controllers */
    *((unsigned long volatile *) BDCM_DBDP01_ADDRESS)  = (unsigned) &dma_mm_bd[0][0];    
    *((unsigned long volatile *) BDCM_DSIER01_ADDRESS) = 0x1e00000;      /* enable NCIE, ECIE, NRIE, CAIE */    
    *((unsigned long volatile *) BDCM_DCR01_ADDRESS)   = 0xa1e20000;

    *((unsigned long volatile *) BDCM_DBDP02_ADDRESS)  = (unsigned) &dma_mm_bd[1][0];
    *((unsigned long volatile *) BDCM_DSIER02_ADDRESS) = 0x1e00000;      /* enable NCIE, ECIE, NRIE, CAIE */
    *((unsigned long volatile *) BDCM_DCR02_ADDRESS )  = 0xa1e20000;
    /* Allow the timers to operate Now wait for the Operation to complete */
    timeout = 6000000;

    while ((irqFlag[2] < 2) && timeout)
        timeout--;

    if (!timeout)
    {
        error = 3;
        report_error (test, error);
        goto test_mem_to_mem_dma_done;
    }

    /* Now Verify the Receive Data */
    for (arrayIndex = 0; arrayIndex < 0x4; arrayIndex++)
    {
        for (i = 0; i < 0x100; i++) /* The size of the array has to match with the DMA length */
        {
            if (*((unsigned long volatile *) (dma_src_addr[arrayIndex] + i)) != *((unsigned long volatile *) (dma_des_addr[arrayIndex] + i)))
            {
                error = 4;
                report_error (test, error);
                goto test_mem_to_mem_dma_done;
            }
        }
    }

    test_mem_to_mem_dma_done:
    test_mem_to_mem_dma_stop ();

    for (i = 0; i < 4; i++)
    {
        if (dma_src_addr[i])
            free ((void *)dma_src_addr[i]);
        if (dma_des_addr[i])
            free ((void *)dma_des_addr[i]);
    }

    return (error ? POST_FAILED : POST_PASSED);
}

static int ethConfigEfe (void)
{

    /* Enable Receive and Transmit Interrupts                   */
    /*                                                          */
    /*      Interrupt Enable Register                           */
    /*          tx idle                                         */
    /*          tx error                                        */
    /*          tx done                                         */
    /*          tx buffer not ready                             */
    /*          tx buffer closed                                */
    /*          rx buffer full                                  */
    /*          rx no buffer                                    */
    /*          rx A done                                       */
    /*          rx B done                                       */
    /*          rx C done                                       */
    /*          rx D done                                       */
    /*          rx buffer closed                                */
    /*          rx overflow data                                */
    /*                                                          */

/*    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, txidle, 1); */

    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, txerr, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, txdone, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, txbufnr, 0);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, txbufc, 0);

    /* This cause a race condition with rxdone*) when set */
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxbr, 0);

    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxbufful, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxnobuf, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxdonea, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxdoneb, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxdonec, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxdoned, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxbufc, 0);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxovfl_data, 1);
    narm_write_reg (NA_EFE_IER_REG, NA_EFE_IER_ADDRESS, rxovfl_stat, 0);

 
    /* Install Ethernet Interrupt Handler                       */
    /*                                                          */
    /*      System Control Module                               */
    /*          Transmit Interrupt                              */
    /*          Receive Interrupt                               */
    /*                                                          */
    /*     naIsrInstall (ETH_RECEIVE_INTERRUPT, ncc_post_ether_rx_isr  ethReceiveHandler ,(void *)  ETH_RECEIVE_INTERRUPT);  */
/*     naIsrInstall (ETH_TRANSMIT_INTERRUPT,  ncc_post_ether_tx_isr  ethTransmitHandler  , (void *)ETH_TRANSMIT_INTERRUPT); */

    return (0);
}

static int ethAssignDMA (unsigned long addr, int numOfDst, NA_DMA_DESCRIPTOR_TYPE * eth_bd)
{
    int i;
    NA_DMA_DESCRIPTOR_TYPE *eth_addr;

    for (i = 0; i < numOfDst; i++)
    {
        eth_addr = (NA_DMA_DESCRIPTOR_TYPE *) ((unsigned long) eth_bd + (unsigned long) (i * 0x10));
        *(unsigned long *) (addr + 0x10 * i) = (unsigned long) (eth_addr)->src_addr;
        *(unsigned long *) (addr + 0x4 + 0x10 * i) = (unsigned long) (eth_addr)->buf_len;
        *(unsigned long *) (addr + 0x8 + 0x10 * i) = (unsigned long) (eth_addr)->dst_addr;
        *(unsigned long *) (addr + 0xc + 0x10 * i) = (unsigned long) (eth_addr)->flag;
    }
    return 0;
}

#define PHY_RESET_PIN   90
#define PHY_RESET       0
#define PHY_ENABLE      1

static int ethResetEfe (void)
{
    int i;
    int value;
    int bufLen = POST_ETH_BUF_SIZE;

    NAconfigureGPIOpin(PHY_RESET_PIN, NA_GPIO_OUTPUT_STATE, PHY_RESET); 
    for (i = 0; i < 100; i++);
    NAsetGPIOpin(PHY_RESET_PIN, PHY_ENABLE);

    /*  Reset Ethernet Front End Module                     */
    /*                                                      */
    /*      General Control Register 01                     */
    /*          Reset the MAC and STAT                      */
    /*                                                      */
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, mac_hrst, 1);
    for (i = 0; i < 10000; i++);

    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, mac_hrst, 0);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, srst, 0);

    /* transmit FIFO water mark - 100% full */
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, etxwm, 1);
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, rxram, 0);

    /*  Configure the MAC Core                              */
    /*                                                      */
    /*      MAC Configuration Register 02                   */
    /*          Full Duplex                                 */
    /*          Pad frames 64 bytes                         */
    /*          Append CRC to Tx frame                      */
    /*          Check length/type field Tx and Rx frames    */
    /*                                                      */
    narm_write_reg (NA_EFE_MCR02_REG, NA_EFE_MCR02_ADDRESS, paden, 1);
    narm_write_reg (NA_EFE_MCR02_REG, NA_EFE_MCR02_ADDRESS, crcen, 1);
    narm_write_reg (NA_EFE_MCR02_REG, NA_EFE_MCR02_ADDRESS, flenc, 1);
    narm_write_reg (NA_EFE_MCR02_REG, NA_EFE_MCR02_ADDRESS, fulld, 1);

    /*  Configure the MAC Station Address Logic (SAL)           */
    /*                                                          */
    /*      Station Address Filter Register                     */
    /*          Promiscuous mode (accept all Frames)            */
    /*          Multicast mode                                  */
    /*          Broadcast mode                                  */
    /*      Station Address Register (1-3)                      */
    /*          Unicast Address (ethernet address)              */
    /*                                                          */

/*    narm_write_reg (NA_EFE_SAFR_REG, NA_EFE_SAFR_ADDRESS, pro, 1);*/
    narm_write_reg (NA_EFE_SAFR_REG, NA_EFE_SAFR_ADDRESS, pra, 1);
    narm_write_reg (NA_EFE_SAFR_REG, NA_EFE_SAFR_ADDRESS, broad, 1);

    narm_write_reg (NA_EFE_SAR_REG, NA_EFE_SAR01_ADDRESS, octet1, myEthernetAddr[0]);
    narm_write_reg (NA_EFE_SAR_REG, NA_EFE_SAR01_ADDRESS, octet2, myEthernetAddr[1]);
    narm_write_reg (NA_EFE_SAR_REG, NA_EFE_SAR02_ADDRESS, octet1, myEthernetAddr[2]);
    narm_write_reg (NA_EFE_SAR_REG, NA_EFE_SAR02_ADDRESS, octet2, myEthernetAddr[3]);
    narm_write_reg (NA_EFE_SAR_REG, NA_EFE_SAR03_ADDRESS, octet1, myEthernetAddr[4]);
    narm_write_reg (NA_EFE_SAR_REG, NA_EFE_SAR03_ADDRESS, octet2, myEthernetAddr[5]);

    /*  Setup the Buffer Descriptor                             */
    /*                                                          */
    /*      Receive Buffer Descriptor Pointer Register (A-D)    */
    /*                                                          */
    /*          Rx A    2 buffers         64 bytes              */
    /*          Rx B    2 buffers        128 bytes              */
    /*          Rx C    2 buffers        256 bytes              */
    /*          Rx D    2 buffers       2048 bytes              */
    /*                                                          */
    /*      Transmit Buffer Descriptor Pointer Register         */
    /*          Tx      2 buffers       1024 bytes              */
    /*                                                          */
    /*                                                          */

    eth_rx_bd[0].src_addr = (unsigned long) &rxBuffer[0];
    eth_rx_bd[0].dst_addr = (unsigned long) 0;
    eth_rx_bd[0].buf_len = bufLen;

    eth_rx_bd[0].flag = 0x60000000;

    eth_rx_bd[1].src_addr = (unsigned long) &rxBuffer[1];
    eth_rx_bd[1].dst_addr = (unsigned long) 0;
    eth_rx_bd[1].buf_len = bufLen;

    eth_rx_bd[1].flag = 0xe0000000;

    *((unsigned long volatile *) NA_EFE_RXABDPR_ADDRESS) = (unsigned long) eth_rx_bd;
    *((unsigned long volatile *) NA_EFE_RXBBDPR_ADDRESS) = (unsigned long) eth_rx_bd;
    *((unsigned long volatile *) NA_EFE_RXCBDPR_ADDRESS) = (unsigned long) eth_rx_bd;
    *((unsigned long volatile *) NA_EFE_RXDBDPR_ADDRESS) = (unsigned long) eth_rx_bd;

    eth_tx_bd[0].src_addr = (unsigned long) &txBuffer[0];
    eth_tx_bd[0].dst_addr = (unsigned long) 0;
    eth_tx_bd[0].buf_len = bufLen / 2;

    eth_tx_bd[0].flag = 0x70000000;

    eth_tx_bd[1].src_addr = (unsigned long) &txBuffer[1];
    eth_tx_bd[1].dst_addr = (unsigned long) 0;
    eth_tx_bd[1].buf_len = bufLen / 2;

    eth_tx_bd[1].flag = 0xf0000000;

    *((unsigned long volatile *) NA_EFE_TXBDPR_ADDRESS )= 0x0;

    /* The following four lines is for loopbk test only */
    narm_write_reg (NA_EFE_SAFR_REG, NA_EFE_SAFR_ADDRESS, pro, 1);      /*send any packet */
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rxen, 0);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, loopbk, 1);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rxen, 1);

    /*  * (unsigned long *) 0xa0601000 = &eth_tx_bd[0]; */
    ethAssignDMA ((unsigned long) NA_EFE_TXBD_ADDRESS, 2, (NA_DMA_DESCRIPTOR_TYPE *) eth_tx_bd);

    /* Inform receiver that buffer descriptor (A,B,C,D) is available */
    *((unsigned long volatile *)NA_EFE_RXBDFR_ADDRESS) |= 0x0f;

    /*  Enable Initialization of the Buffer Descriptor          */
    /*                                                          */
    /*      General Control Register 01                         */
    /*          Init RXPP buffer descriptor                     */
    /*      General Status Register                             */
    /*          RXPP init completed                             */
    /*          Clear RCPP init                                 */
    /*                                                          */
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, erxinit, 1);
    do
    {
        value = narm_read_reg (NA_EFE_GSR_REG, NA_EFE_GSR_ADDRESS, rxinit);
    }
    while (value == 0);

    narm_write_reg (NA_EFE_GSR_REG, NA_EFE_GSR_ADDRESS, rxinit, 0);
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, erxinit, 0);

    /*  Setup the statistical counters                          */
    /*                                                          */
    /*      Config General Control Register 02                  */
    /*          Clear Statistics Counters                       */
    /*          Enable Statistics Counters                      */
    /*                                                          */
    narm_write_reg (NA_EFE_GCR02_REG, NA_EFE_GCR02_ADDRESS, clrcnt, 0);
    narm_write_reg (NA_EFE_GCR02_REG, NA_EFE_GCR02_ADDRESS, sten, 1);
    return (0);
}

static int ethEnableMac (void)
{
    /* enable Ethernet receiver logic */
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rxen, 1);

    /*  Turn on the MAC                                         */
    /*                                                          */
    /*      MAC Control Register 01                             */
    /*          Enable MAC Control Sublayer/Rx domain logic      */
    /*          Enable MAC Receive Function                      */
    /*          Enable MAC Control Sublayer/Tx domain logic      */
    /*          Enable MAC Transmit Function                     */
    /*          Enable MAC Receiver                             */
    /*                                                          */

    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rpemcsr, 0);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rperfun, 0);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rpemcst, 0);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rpetfun, 0);

#ifdef RMII_SUPPORT
    /*  Enable RMII                                         */
    /*                                                      */
    /*      PHY Support Register                            */
    /*          Enable the MII                               */
    /*                                                      */
    narm_write_reg (NA_EFE_PSR_REG, NA_EFE_PSR_ADDRESS, rpermii, 0);
#endif

    /*  Turn on Ethernet Front End Module                   */
    /*                                                      */
    /*      General Control Register 01                     */
    /*          Enable the MAC and STAT                      */
    /*                                                      */

/*    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, mac_hrst, 0); */

    return 0;
}

static int ethDisableMac (void)
{
    /*  Select the PHY interface                            */
    /*                                                      */
    /*      PHY Support Register                            */
    /*          Reset the MII                               */
    /*                                                      */
    narm_write_reg (NA_EFE_PSR_REG, NA_EFE_PSR_ADDRESS, rpermii, 1);

    /*  Reset the MAC Core (Alcatel PEMAC)                  */
    /*                                                      */
    /*      MAC Configuration Register 01                   */
    /*          Enable RX_WR, TX_RD, MAC, SAL               */
    /*          Reset MAC Control Sublayer/Rx domain logic  */
    /*          Reset MAC Receive Function                  */
    /*          Reset MAC Control Sublayer/Tx domain logic  */
    /*          Reset MAC Transmit Function                 */
    /*         
     */
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, srst, 1);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rpemcsr, 1);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rperfun, 1);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rpemcst, 1);
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rpetfun, 1);
    return (0);
}

static void ethDisableIsr (void)
{
    naInterruptDisable (ETH_RECEIVE_INTERRUPT);
    naInterruptDisable (ETH_TRANSMIT_INTERRUPT);
}

static void ethEnableIsr (void)
{
    naInterruptEnable (ETH_RECEIVE_INTERRUPT);
    naInterruptEnable (ETH_TRANSMIT_INTERRUPT);
}

static void ethDisableEfe (void)
{
    /* disable Ethernet receiver logic */
    narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, rxen, 0);

	narm_write_reg (NA_EFE_MCR01_REG, NA_EFE_MCR01_ADDRESS, loopbk, 0); /*clean up loopback bit*/
	narm_write_reg (NA_EFE_SAFR_REG, NA_EFE_SAFR_ADDRESS, pro, 0);      /*clean up promiscuous */

    /* disable rx and tx FIFO */
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, erx, 0);
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, etx, 0);
}

static void ethEnableEfe (void)
{
    /* enable FIFO */
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, erx, 1);
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, etx, 1);
}

static void ethEnableDma (void)
{
    /*  Enable the DMA for Receiver and Transmitter             */
    /*                                                          */
    /*      General Control Register 01                         */
    /*          Rx DMA                                          */
    /*          Tx DMA                                          */
    /*                                                          */
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, erxdma, 1);
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, etxdma, 1);
}

static void ethDisableDma (void)
{
    /*  Enable the DMA for Receiver and Transmitter             */
    /*                                                          */
    /*      General Control Register 01                         */
    /*          Rx DMA                                          */
    /*          Tx DMA                                          */
    /*                                                          */
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, erxdma, 0);
    narm_write_reg (NA_EFE_GCR01_REG, NA_EFE_GCR01_ADDRESS, etxdma, 0);
}

static void ethEnable (void)
{
    ethEnableEfe ();
    ethResetEfe ();
    ethEnableDma ();
    ethEnableMac ();
    ethEnableIsr ();
}

static void ethDisable (void)
{
    ethDisableIsr ();
    ethDisableMac ();
    ethDisableEfe ();
    ethDisableDma ();
}

/* 
 * Function ncc_post_eth_loopback()
 *
 *   This function sets up ethernet module for a DMA loopback test.  Two seperate 
 * receive and transmit DMA buffer descriptors are used for this test.  The
 * purpose of this test is to verify if both the transmit and receive DMA channels
 * function correctly.   There is no actual ethernet packet is used in this test. 
 * As the result, the PRO bit in the SAFR register is set to 1.
 * Parameters: 
 *      none 
 * 
 *  Return Values: 
 * 
 *      POST_PASSED 
 *      POST_FAILED 
 */

static int ncc_post_eth_loopback (void)
{
    int test = 3, error = 0;
    volatile int i;
    char ch;
    int timeout = 0;
    int bufLen = POST_ETH_BUF_SIZE;
    volatile NA_DMA_DESCRIPTOR_TYPE *tx_dmadb1, *tx_dmadb2;

    /* Clear the interrupt flags */
    for (i = 0; i < 32; i++)
        irqFlag[i] = 0;

    ethDisable ();
    ethConfigEfe ();

    ch = 0x01;
    memset (txBuffer[0], ch, bufLen);   /* fill up the tx buffer[0] with "1" */
    ch = 0x02;
    memset (txBuffer[1], ch, bufLen);   /* fill up the tx buffer[1] with "2" */

    /*Install interrupt handler and enable interrupt */
    naIsrInstall (ETH_TRANSMIT_INTERRUPT, (NA_ISR_HANDLER) ncc_post_ether_tx_isr, NULL);
    naIsrInstall (ETH_RECEIVE_INTERRUPT, (NA_ISR_HANDLER) ncc_post_ether_rx_isr, NULL);
    ethDisableIsr ();

    ethEnable ();               /* set up the DMA and start the transfer */

    timeout = 1500000 * 5;

    while (((irqFlag[5] < 1) || (irqFlag[4] < 1)) && timeout)
        timeout--;

    if (!timeout)
    {
        error = 1;
        report_error (test, error);
        goto ncc_post_eth_loopback_done;
    }

    tx_dmadb1 = (NA_DMA_DESCRIPTOR_TYPE *) NA_EFE_TXBD_ADDRESS;
    tx_dmadb2 = (NA_DMA_DESCRIPTOR_TYPE *) (NA_EFE_TXBD_ADDRESS + 4);

    for (i = 0; i < 1000; i++);

    if ((tx_dmadb1->flag & DMA_FULL_MASK) || (tx_dmadb2->flag & DMA_FULL_MASK))
    {
        error = 2;
        report_error (test, error);
        goto ncc_post_eth_loopback_done;
    }

    if (!(eth_rx_bd[0].flag & DMA_FULL_MASK) || !(eth_rx_bd[0].flag & DMA_FULL_MASK))
    {
        error = 3;
        report_error (test, error);
        goto ncc_post_eth_loopback_done;
    }

    if ((eth_rx_bd[0].buf_len != tx_dmadb1->buf_len) || (eth_rx_bd[1].buf_len != tx_dmadb2->buf_len))
    {
        error = 4;
        report_error (test, error);
        goto ncc_post_eth_loopback_done;
    }

    for (i = 0; i < 10000; i++);

    if (memcmp
        ((const void *) eth_rx_bd[0].src_addr, (const void *) tx_dmadb1->src_addr,
         eth_rx_bd[0].buf_len - 4 /*not include CRC */ ) ||
        memcmp ((const void *) eth_rx_bd[1].src_addr, (const void *) tx_dmadb2->src_addr,
                eth_rx_bd[1].buf_len - 4 /*not include CRC */ ))
    {
        error = 5;
        report_error (test, error);
        goto ncc_post_eth_loopback_done;
    }

  ncc_post_eth_loopback_done:
    ethDisable ();
    naIsrUninstall (ETH_TRANSMIT_INTERRUPT);
    naIsrUninstall (ETH_RECEIVE_INTERRUPT);
    return (error ? POST_FAILED : POST_PASSED);
}


/*  Function: int test_serial_loopback (int port) 
 * 
 *  Description: 
 *     This routine executes a loopback test of the Serial Ports.  A pattern is  
 *     transmitted using internal loopback and verified on the receive side. 
 * 
 *  Parameters: 
 *      port: Port number to be tested
 * 
 *  Return Values: 
 * 
 *     POST_PASSED 
 *     POST_FAILED 
 */
static int test_serial_loopback (int port)
{
    int  test = 4, error = 0;
    char txData[32] = "PowerOnSelfTestForSerialPort";
    char *recPtr;
    int iohub_port = port + 2;

    ncc_post_serl_setup(port);

    /* flush the data */
    while (ncc_post_fgetc(port, 100) != (char)(-2));

    ncc_post_printf(port, txData);

    recPtr = txData;

    while (*recPtr != '\0')
    {    
        if (*recPtr != ncc_post_fgetc(port, 1000))
        {
            error = port+1;
            report_error (test, error);
            break;
        }

        recPtr++;
    }

    /* 
     * Disable interrupts from the port
     */
    *NA_IOHUB_DMA_RX_ICR_getAddress(iohub_port) = 0;
    *NA_IOHUB_DMA_TX_ICR_getAddress(iohub_port) = 0;
    *NA_16750_WRAPPER_IE_getAddress(port) = 0;
    *NA_16750_UART_IE_getAddress(port) = 0;
    
    /*
     * Reset the port and its fifos
     */
    *NA_16750_CONFIG_getAddress(port) = 0;
    *NA_IOHUB_DMA_RX_CONTROL_getAddress(iohub_port) = 0;
    *NA_IOHUB_DMA_TX_CONTROL_getAddress(iohub_port) = 0;

    return (error ? POST_FAILED : POST_PASSED);
}


/* SPI register setting defines */
#define SPI_DMA_RX_NRIP_MASK    0x20000000
#define SPI_DMA_TX_NRIP_MASK    0x00400000

#define SPI_MIN_DIVISOR_VALUE           9   /* SPI minimum divisor value for clock genertaion */

#define SPI_DISABLED                    0
#define SPI_ENABLED                     1

#define SPI_DMA_CPU_CONTROLLED          0
#define SPI_DMA_MODE                    0
#define SPI_FOUR_RXBYTE                 0

#define NARM_IO_MOD_DMA_CONTROL_ce      31, 31
#define NARM_IO_MOD_DMA_CONTROL_ca      30, 30
#define NARM_IO_MOD_DMA_CONTROL_flexio  29, 29
#define NARM_IO_MOD_DMA_CONTROL_direct  28, 28

#define NARM_SPI_MOD_all                    31, 0
#define NARM_IO_MOD_DMA_CONFIG_IRQ_BITS     0x01E00000

#define NARM_SPI_IRQ_STATUS_REG     (unsigned long volatile *)0x90030000

#define NARM_SPI_DMA_RX_CONTROL_REG (unsigned long volatile *)0x90030004
#define NARM_SPI_DMA_RX_DESC_REG    (unsigned long volatile *)0x90030008
#define NARM_SPI_RX_CONFIG_REG      (unsigned long volatile *)0x9003000C

#define NARM_SPI_DMA_TX_CONTROL_REG (unsigned long volatile *)0x90030018
#define NARM_SPI_DMA_TX_DESC_REG    (unsigned long volatile *)0x9003001C
#define NARM_SPI_TX_CONFIG_REG      (unsigned long volatile *)0x90030020

#define NARM_SPI_RX_STATUS_FIFO_REG (unsigned long volatile *)0x90030010
#define NARM_SPI_RX_FIFO_REG        (unsigned long volatile *)0x90030014

#define NARM_SPI_CONFIG_REG         (unsigned long volatile *)0x90031000
#define NARM_SPI_RESET_REG          (unsigned long volatile *)0xA0900180

#define NARM_SPI_ENABLE_REG         (unsigned long volatile *)0x90031020
#define NARM_SPI_STATUS_REG         (unsigned long volatile *)0x90031024

#define NARM_SPI_CONFIG_mode                5, 4
#define NARM_SPI_CONFIG_bitOrder            2, 2
#define NARM_SPI_CONFIG_slave               1, 1
#define NARM_SPI_CONFIG_master              0, 0
#define NARM_SPI_CONFIG_rxbyte              3, 3
#define NARM_SPI_CONFIG_discard             11, 8
#define NARM_SPI_CONFIG_mlb                 12, 12

#define NARM_SPI_CLK_GEN_REG        (unsigned long volatile *)0x90031010
#define NARM_SPI_CLK_GEN_enable             16, 16
#define NARM_SPI_CLK_GEN_divisor             9, 0

#define SPI_RESET   (0x1 << 5)

#define SPI_LOOPBACK_BUF_LEN  64

static unsigned int volatile spiTxFlag = 0;
static unsigned int volatile spiRxFlag = 0;

/*
 * This routine configures SPI master to use DMA.
 * It sets up SPI and DMA registers.
 */
static void spi_hardware_setup(void)
{
    int divisor;

    narm_write_reg (NARM_SPI_CONFIG,  NARM_SPI_CONFIG_REG, mlb, SPI_ENABLED); 
    narm_write_reg (NARM_SPI_CONFIG,  NARM_SPI_CONFIG_REG, mode, 0); 
    narm_write_reg (NARM_SPI_CONFIG,  NARM_SPI_CONFIG_REG, bitOrder, 1); 
    narm_write_reg (NARM_SPI_CONFIG,  NARM_SPI_CONFIG_REG, rxbyte, SPI_FOUR_RXBYTE); 
    narm_write_reg (NARM_SPI_CONFIG,  NARM_SPI_CONFIG_REG, slave, SPI_DISABLED); 
    narm_write_reg (NARM_SPI_CONFIG,  NARM_SPI_CONFIG_REG, master, SPI_ENABLED); 
   
    /*
     * Set baud rate divisor
     */
    divisor = NA_ARM9_INPUT_FREQUENCY / (500*1024);

    if (divisor < SPI_MIN_DIVISOR_VALUE)
        divisor = SPI_MIN_DIVISOR_VALUE;

    /* set up divisor */
    narm_write_reg (NARM_SPI_CLK_GEN,  NARM_SPI_CLK_GEN_REG, enable, SPI_DISABLED); 
    narm_write_reg (NARM_SPI_CLK_GEN,  NARM_SPI_CLK_GEN_REG, divisor, divisor); 
    narm_write_reg (NARM_SPI_CLK_GEN,  NARM_SPI_CLK_GEN_REG, enable, SPI_ENABLED); 
}

#ifdef NETOS_GNU_TOOLS
static NA_DMA_DESCRIPTOR_TYPE txc_buffer_descriptors[NASPI_MAX_DESCRIPTORS] __attribute__ ((aligned(32)));
static NA_DMA_DESCRIPTOR_TYPE rxc_buffer_descriptors[NASPI_MAX_DESCRIPTORS] __attribute__ ((aligned(32)));
#else
#pragma alignvar (32)
static NA_DMA_DESCRIPTOR_TYPE txc_buffer_descriptors[NASPI_MAX_DESCRIPTORS];
#pragma alignvar (32)
static NA_DMA_DESCRIPTOR_TYPE rxc_buffer_descriptors[NASPI_MAX_DESCRIPTORS];
#endif

/*
 * This routine sets up DMA buffer descriptors.
 */
static void spi_setup_dma(char *const writeBuffer, char *readBuffer, int bufferLength)
{
#ifdef CACHE_ENABLED
    physical_address_t physTx, physRx;
#endif
    int byteLeft = bufferLength;
    int i;
    NA_DMA_DESCRIPTOR_TYPE *txDescPtr;
    NA_DMA_DESCRIPTOR_TYPE *rxDescPtr;

    /*
     * setup all buffer descriptors
     */

#ifdef CACHE_ENABLED
    /* Setup Tx buffer */
    if (!spiNAVaToPhys ((const void *) writeBuffer, &physTx))
        netosFatalError ("spi tx DMA Cache error", 1, 1);

    spiNABeforeDMA (NA_MEMORY_TO_DEVICE_DMA, writeBuffer, NULL, bufferLength);

    /* Setup Rx buffer */
    if (!spiNAVaToPhys ((const void *) readBuffer, &physRx))
        netosFatalError ("spi rx DMA Cache error", 1, 1);

    spiNABeforeDMA (NA_DEVICE_TO_MEMORY_DMA, NULL, readBuffer, bufferLength);
#endif

    for (i = 0; i < NASPI_MAX_DESCRIPTORS; i++)
    {
        txDescPtr = &txc_buffer_descriptors[i];
        rxDescPtr = &rxc_buffer_descriptors[i];

        /*Setup the tx buffer descriptor, and use the physical address in the DMA buffer descriptor */
        txDescPtr->src_addr = (WORD32)(writeBuffer + i * NASPI_MAX_DMABUFFER_LENGTH);
        rxDescPtr->src_addr = (WORD32)(readBuffer + i * NASPI_MAX_DMABUFFER_LENGTH);
        txDescPtr->dst_addr = 0;
        rxDescPtr->dst_addr = 0;

        if (byteLeft <= NASPI_MAX_DMABUFFER_LENGTH)
        {
            txDescPtr->buf_len = byteLeft;
            rxDescPtr->buf_len = byteLeft;
            txDescPtr->flag = DMA_WRAP_MASK | DMA_INTERRUPT_MASK | DMA_LAST_MASK | DMA_FULL_MASK;
            rxDescPtr->flag = DMA_WRAP_MASK | DMA_INTERRUPT_MASK | DMA_LAST_MASK;
            break;
        }
        else
        {
            txDescPtr->buf_len = NASPI_MAX_DMABUFFER_LENGTH;
            rxDescPtr->buf_len = NASPI_MAX_DMABUFFER_LENGTH;
            txDescPtr->flag = DMA_FULL_MASK;       
            rxDescPtr->flag = 0;  
        }

        byteLeft -= NASPI_MAX_DMABUFFER_LENGTH;
    }
}

/*
 * This routine enables SPI TX/RX DMA
 */
static void spi_enable(void)
{
    naInterruptEnable(SPI_INTERRUPT);

    /* enable SPI DMA by toggle the CE bit */
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_TX_CONTROL_REG, ce, SPI_DISABLED);
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_TX_CONTROL_REG, ce, SPI_ENABLED);      

    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_RX_CONTROL_REG, ce, SPI_DISABLED);
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_RX_CONTROL_REG, ce, SPI_ENABLED);      
}


/*
 * This routine disables SPI TX/RX DMA
 */
static void spi_disable(void)
{
    naInterruptDisable(SPI_INTERRUPT);

    /* disable SPI DMA */
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_RX_CONTROL_REG, ce, SPI_DISABLED);      
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_TX_CONTROL_REG, ce, SPI_DISABLED);      

    naIsrUninstall(SPI_INTERRUPT);    
}

/*
 * SPI Interrupt Service Routine.
 */
static void spi_master_isr(int isr)
{
    unsigned long status;
    NA_UNUSED_PARAM(isr);

    status = *NARM_SPI_IRQ_STATUS_REG;

    /* Acknowledge interrupt */
    *NARM_SPI_IRQ_STATUS_REG = status; 

    /* Normal RX completion */
    if (status & SPI_DMA_RX_NRIP_MASK)
        spiRxFlag++;

    /* Normal TX completion */
    if (status & SPI_DMA_TX_NRIP_MASK)
        spiTxFlag++;
}

/*
 * This is the initialization function called from netosStartup() in BSP
 */
static void ncc_post_initialize_spi(void)
{
    volatile int count;

    memset(rxc_buffer_descriptors, 0, (sizeof(NA_DMA_DESCRIPTOR_TYPE) * NASPI_MAX_DESCRIPTORS));
    memset(txc_buffer_descriptors, 0, (sizeof(NA_DMA_DESCRIPTOR_TYPE) * NASPI_MAX_DESCRIPTORS));

    *NARM_SPI_RESET_REG &= ~SPI_RESET;
    for (count = 0; count < 100000; count++);
    *NARM_SPI_RESET_REG |= SPI_RESET;

    naIsrInstall (SPI_INTERRUPT, (NA_ISR_HANDLER)spi_master_isr, NULL);

    /* setup SPI DMA for Rx */
    narm_write_reg (NARM_SPI_MOD, NARM_SPI_DMA_RX_CONTROL_REG, all, 0);
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_RX_CONTROL_REG, ce, SPI_DISABLED);      
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_RX_CONTROL_REG, flexio, SPI_DMA_CPU_CONTROLLED);
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_RX_CONTROL_REG, direct, SPI_DMA_MODE); 
    
    /* enable irq bits for Rx */
    narm_write_reg (NARM_SPI_MOD,  NARM_SPI_RX_CONFIG_REG, all, NARM_IO_MOD_DMA_CONFIG_IRQ_BITS); 

    /* setup SPI DMA for Tx */
    narm_write_reg (NARM_SPI_MOD, NARM_SPI_DMA_TX_CONTROL_REG, all, 0);
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_TX_CONTROL_REG, ce, SPI_DISABLED);      
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_TX_CONTROL_REG, flexio, SPI_DMA_CPU_CONTROLLED);       
    narm_write_reg (NARM_IO_MOD_DMA_CONTROL, NARM_SPI_DMA_TX_CONTROL_REG, direct, SPI_DMA_MODE); 
    /* enable irq bits for Tx */
    narm_write_reg (NARM_SPI_MOD,  NARM_SPI_TX_CONFIG_REG, all, NARM_IO_MOD_DMA_CONFIG_IRQ_BITS); 

    /* setup SPI Configuration */
    narm_write_reg (NARM_SPI_MOD,  NARM_SPI_CONFIG_REG, all, 0); 

    *NARM_SPI_DMA_TX_DESC_REG = (unsigned long)txc_buffer_descriptors; 
    *NARM_SPI_DMA_RX_DESC_REG = (unsigned long)rxc_buffer_descriptors; 
}

int ncc_post_spi_loopback(void)
{
    int error=0, test=8;
    static char writeBuffer[SPI_LOOPBACK_BUF_LEN];
    static char readBuffer[SPI_LOOPBACK_BUF_LEN];
    volatile int i, timeout = 20000;

    ncc_post_initialize_spi();

    for (i=0; i<SPI_LOOPBACK_BUF_LEN; i++)
    {
        writeBuffer[i] = (i%256)?i%256:1;
    }

    spiTxFlag = 0;
    spiRxFlag = 0;

    spi_hardware_setup();

    spi_setup_dma(writeBuffer, readBuffer, SPI_LOOPBACK_BUF_LEN);
    
    spi_enable();

    /* wait for spi done */
    while (timeout && (!spiTxFlag || !spiRxFlag))
    {
        /* Should this be a tx_thread_sleep(1) or something in order to 
         * allow lower priority threads to run as well? 
         */
        for (i=0; i<100; i++);

        timeout--;
    }

    if (!timeout)
    {
        error = 1;
        report_error (test, error);
        goto done_spi;
    }

    for (i = 0; i < SPI_LOOPBACK_BUF_LEN; i++)
    {
        if (writeBuffer[i] != readBuffer[i])
        {
            error = 2;
            report_error (test, error);
            goto done_spi;
        }
    }

    done_spi:
    spi_disable();
    return (error ? POST_FAILED : POST_PASSED);
}

/* SPI */
#define NARM_SPI_CONFIG_REG         (unsigned long volatile *)0x90031000
#define NARM_SPI_CONFIG_slave               1, 1
#define NARM_SPI_CONFIG_master              0, 0

#define NARM_SPI_CLK_GEN_REG        (unsigned long volatile *)0x90031010
#define NARM_SPI_CLK_GEN_enable             16, 16
#define NARM_SPI_CLK_GEN_divisor             9, 0


/* Setting time & time alarm registers */
#define NA_RTC_REG_TIME_TIME       (unsigned long volatile *)0x90060008
#define NA_RTC_REG_CALENDAR_TIME    (unsigned long volatile *)0x9006000C
#define NA_RTC_REG_TIME_hours      29, 24
#define NA_RTC_REG_CALENDAR_year   23, 16


static int ncc_post_access_regs(void)
{
    int idx;
    WORD32 volatile value;

    /* Read some of the serial UART registers */
    for (idx = 0; idx < 4; idx++)
    {
        value = narm_read_reg (NA_16750_CONFIG, NA_16750_CONFIG_getAddress(idx), mode);
        value = narm_read_reg (NA_16750_WRAPPER_IE, NA_16750_WRAPPER_IE_getAddress(idx), cts);
        value = narm_read_reg (NA_16750_INTERRUPT_STATUS, NA_16750_INTERRUPT_STATUS_getAddress(idx), cts);
        value = narm_read_reg (NA_16750_RECV_CHAR_GAP_CONTROL, NA_16750_RECV_CHAR_GAP_CONTROL_getAddress(idx), value);
        value = narm_read_reg (NA_16750_RECV_BUFFER_GAP_CONTROL, NA_16750_RECV_BUFFER_GAP_CONTROL_getAddress(idx), value);
        value = narm_read_reg (NA_16750_RECV_CHAR_MATCH_CONTROL, NA_16750_RECV_CHAR_MATCH_CONTROL_0_getAddress(idx), data);

        value = narm_read_reg (NA_16750_TRANSMIT_BYTE_COUNT, 
                            NA_16750_TRANSMIT_BYTE_COUNT_getAddress(idx), txcount);
        narm_write_reg (NA_16750_TRANSMIT_BYTE_COUNT, 
                       NA_16750_TRANSMIT_BYTE_COUNT_getAddress(idx), txcount, value);

        value = narm_read_reg (NA_16750_RECV_CHAR_MATCH_CONTROL, 
                            NA_16750_RECV_CHAR_MATCH_CONTROL_0_getAddress(idx), data);
        narm_write_reg (NA_16750_RECV_CHAR_MATCH_CONTROL, 
                        NA_16750_RECV_CHAR_MATCH_CONTROL_0_getAddress(idx), data, value);

        value = narm_read_reg (NA_16750_ARM_WAKEUP, NA_16750_ARM_WAKEUP_getAddress(idx), enable);
        narm_write_reg (NA_16750_ARM_WAKEUP, NA_16750_ARM_WAKEUP_getAddress(idx), enable, value);
    }

    /* SPI */
    value = narm_read_reg (NARM_SPI_CONFIG, NARM_SPI_CONFIG_REG, master);
    narm_write_reg (NARM_SPI_CONFIG, NARM_SPI_CONFIG_REG, master, value);

    value = narm_read_reg (NARM_SPI_CLK_GEN, NARM_SPI_CLK_GEN_REG, divisor);
    narm_write_reg (NARM_SPI_CLK_GEN, NARM_SPI_CLK_GEN_REG, divisor, value);

    /* I2C */
    value = narm_read_reg (NARM_I2C_CONFIG_REG, NA_I2C_CONFIG_REG_ADDRESS, clk_ref);
    narm_write_reg (NARM_I2C_CONFIG_REG, NA_I2C_CONFIG_REG_ADDRESS, clk_ref, value);

    return POST_PASSED;
}

static int ncc_post_rtc_backup(void)
{
    WORD32 error = 0, test = 7, count = 0;
    WORD32 temp, *addr = (WORD32 *)RTC_BACKEDUP_RAM_START;
    WORD32 volatile value;

    /* put RTC in normal mode */
    narm_write_reg (NA_SCM_RTC_REG,  NA_SCM_RTCMC_ADDRESS, standbyMode, SCM_RTC_NORMAL_MODE);


    /* wait for normal mode */
    while (count++ < NCC_POST_WAIT_TIME)
    {
        if (narm_read_reg(NA_SCM_RTC_REG, NA_SCM_RTCMC_ADDRESS, standbyStatus))
            break;
    }

    if (count >= NCC_POST_WAIT_TIME)
    {
        error = 1;
        report_error (test, error);
        goto done_rtc_backup;
    }

    /* read backup memory */
    temp = *addr;
    *addr = count;

    if (*addr != count)
    {
        error = 2;
        report_error (test, error);
        goto done_rtc_backup;
    }

    /* put the old value back */
    *addr = temp;
        
    /* RTC, time register */
    value = narm_read_reg (NA_RTC_REG_TIME, NA_RTC_REG_TIME_TIME, hours);
    value = narm_read_reg (NA_RTC_REG_CALENDAR, NA_RTC_REG_CALENDAR_TIME, year);

    done_rtc_backup:
    /* put RTC back in standby mode */
    narm_write_reg (NA_SCM_RTC_REG,  NA_SCM_RTCMC_ADDRESS, standbyMode, SCM_RTC_STANDBY_MODE);

    if (error)
        return POST_FAILED;
    else
        return POST_PASSED;
}

static void ncc_post_a2d_isr (void)
{
    irqFlag[14]++;

    /*
     * Ack interrupt by writing 1 and then 0.
     */
    narm_write_reg(NA_A2D_CONFIG, NA_A2D_CONFIG_ADDRESS, intclr, 1);
    narm_write_reg(NA_A2D_CONFIG, NA_A2D_CONFIG_ADDRESS, intclr, 0);
}


static int ncc_post_a2d_test(void)
{
    unsigned long configReg;
    unsigned long clkConfig;
    WORD32 error = 0, test = 6;

    irqFlag[14] = 0;
    configReg = *NA_A2D_CONFIG_ADDRESS;
    clkConfig = *NA_A2D_CLOCK_CONFIG_ADDRESS;
        
    if (naIsrInstall(ADC_INTERRUPT, (NA_ISR_HANDLER) ncc_post_a2d_isr, NULL) != SUCCESS)
    {
        error = 1;
        report_error (test, error);
        goto a2d_test_done;
    }

    /*
     * Enable the A/D module in SCM.
     */
    narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, adc, SCM_CCR_ENABLE_CLOCK);
    narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, adc, SCM_RSR_ENABLE_MODULE);

    /*
     * Disable the A2D channel.
     */
    narm_write_reg(NA_A2D_CONFIG, NA_A2D_CONFIG_ADDRESS, adcen, FALSE);
    narm_write_reg(NA_A2D_CONFIG, NA_A2D_CONFIG_ADDRESS, dmaen, FALSE);

    /*
     * Configure number of inputs.
     */
    narm_write_reg(NA_A2D_CONFIG, NA_A2D_CONFIG_ADDRESS, sel, 7);

    narm_write_reg(NA_A2D_CLOCK_CONFIG, NA_A2D_CLOCK_CONFIG_ADDRESS, n, 0x20);
    narm_write_reg(NA_A2D_CLOCK_CONFIG, NA_A2D_CLOCK_CONFIG_ADDRESS, wait, 0);

    /*
     * Turn the channel on
     */
    narm_write_reg(NA_A2D_CONFIG, NA_A2D_CONFIG_ADDRESS, adcen, TRUE);

    #ifdef HAVE_A2D_PERIPHERAL
    {
        int count = 0;

        naInterruptEnable(ADC_INTERRUPT);

        do
        {
            if (irqFlag[14])
                break;
        } while (count++ < 10000);

        if (irqFlag[14] == 0)
        {
            error = 2;
            report_error (test, error);
            goto a2d_test_done;
        }
    }
    #endif

    a2d_test_done:
    /* put the original values back */
    *NA_A2D_CONFIG_ADDRESS = configReg;
    *NA_A2D_CLOCK_CONFIG_ADDRESS = clkConfig;        
    
    naInterruptDisable(ADC_INTERRUPT);
    naIsrUninstall(ADC_INTERRUPT);

    if (error)
        return POST_FAILED;
    else
        return POST_PASSED;
}

/*   
 *  
 *   
 *  Function: static void restoreVector(void)  
 * 
 *  Description: 
 *     when use 32 bit flash and cache is on, there are two bits in Memory 
 *     Module Configuration Register need to be cleaned upon power up reset,  
 *     so we don't have vector table in reset.s, instead, we restore the  
 *     vector table here, please refer to reset.s 
 * 
 *  Parameters: 
 *     none 
 *   
 *  Return Value: 
 *     none 
 * 
 */
static void restoreVector (void)
{
    /* 

       Since the branch instruction have a limitation in ranch, it must branch to a local location (PC+20) 
       From that location it can use the jump instruction to execute the interrupt handler since the range is higher  
       with its 32bit. 

       The setup of the vector table is in sync with reset.s, tx_ill.s, and restoreVector() !! 
       Any changes made here must be adjusted in those files. 

     */
    /*
       !! Don't change any thing in reset.s, tx_ill.s, and setupVectorTable() !!
     */
#define LOAD_PC_WITH_WORD_AT_PC_PLUS_20     0xe59ff018

    *(unsigned long volatile *) (0x0) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;
    *(unsigned long volatile *) (0x4) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;
    *(unsigned long volatile *) (0x8) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;
    *(unsigned long volatile *) (0xc) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;
    *(unsigned long volatile *) (0x10) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;
    *(unsigned long volatile *) (0x14) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;
    *(unsigned long volatile *) (0x18) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;
    *(unsigned long volatile *) (0x1c) = LOAD_PC_WITH_WORD_AT_PC_PLUS_20;

    *(unsigned long volatile *) (0x20) = (WORD32) Reset_Handler_ROM;
    *(unsigned long volatile *) (0x24) = (WORD32) Undefined_Handler;
    *(unsigned long volatile *) (0x28) = (WORD32) SWI_Handler;
    *(unsigned long volatile *) (0x2c) = (WORD32) Prefetch_Handler;
    *(unsigned long volatile *) (0x30) = (WORD32) Abort_Handler;
    *(unsigned long volatile *) (0x34) = (WORD32) Reset_Handler_ROM;
    *(unsigned long volatile *) (0x38) = (WORD32) __tx_irq_handler;     /*using the same isr apis */
    *(unsigned long volatile *) (0x3c) = (WORD32) FIQ_Handler;
    NASetIRQ(IRQ_ENABLED);     /* Will need to enable interrupt for ISR to work in POST */
}


/*  Function: nccPostResultsType *ncc_post (void)   
 * 
 *  Description: 
 *     The PowerOn Self Test (POST) function is responsible for 
 *     executing a diagnostic test of the NS9750 chip and it's 
 *     associated peripherals.  When encountering a failure, 
 *     the POST will display an LED blink error pattern.  All 
 *     fatal errors will cause the blink pattern to repeat  
 *     forever stopping the poweron process. 
 * 
 *  Parameters: 
 *     none 
 *   
 *  Return Value: 
 *     A pointer to the nccPostResultsType structure which contains the POST test info.
 * 
 */

nccPostResultsType *ncc_post (void)
{
    int ccode = 0;
    int index1;
    unsigned long naPdCCR = *NA_SCM_CCR_ADDRESS;
    unsigned long naPdRSR = *NA_SCM_RSR_ADDRESS;

    for (index1 = 0; index1 < 32; index1++)
        irqFlag[index1] = 0;

    /*restore the vector table so we can get interrupt going */
    restoreVector ();

    *NA_SCM_CCR_ADDRESS |= 0x7BFF;  /* to turn on clocks to required modules */
    *NA_SCM_RSR_ADDRESS |= 0x7BFF;  /* reset the modules */
    
    /* Test: #1. DMA memory-to-memory test. The following code test memory to memory DMA transfer. */
    ccode = test_mem_to_mem_dma ();

    /* Test: #2. Timer test. The following tests timer2-timer15 count down and irq generating feature. */
    if (ccode == POST_PASSED)
    {
        for (index1 = 2; index1 < 10; index1++)
        {
            if ((ccode = post_test_timer (index1)) == POST_FAILED)
                break;
        }
    }
 

    /* Test: #3. Ethernet loopback test. The following tests ethernet loopback */
    if (ccode == POST_PASSED)
    {
	    ccode = ncc_post_eth_loopback (); 
    }

    /* Test: #4. Serial channel test. The following tests serial loopback on serial channel 0-3 */
    if (ccode == POST_PASSED)
    {
        for (index1 = 0; index1 < 4; index1++)
        {
            if ((ccode = test_serial_loopback (index1)) == POST_FAILED)
                break;
        }
    }

    /* Test: #5. Other register access */
    if (ccode == POST_PASSED)
    {
	    ccode = ncc_post_access_regs(); 
    }

    /* Test: #6. A2D register test */
    if (ccode == POST_PASSED)
    {
	    ccode = ncc_post_a2d_test (); 
    }


    /* Test: #7. RTC and battery backed up RAM test */
    if (ccode == POST_PASSED)
    {
	    ccode = ncc_post_rtc_backup(); 
    }

    /* Test: #8. SPI loopback test */
    if (ccode == POST_PASSED)
    {
	    ccode = ncc_post_spi_loopback(); 
    }

    *NA_SCM_CCR_ADDRESS = naPdCCR;
    *NA_SCM_RSR_ADDRESS = naPdRSR;   
    
    NASetIRQ(IRQ_DISABLED);     /* Will need to disable interrupt after POST is done. */    
    return &nccPostResults;
}

#endif /* BSP_POST_TEST */
