/******************************************************************************
 *
 *  AFE	DIAGNOSTIC
 *
 * This module contains cpu diagnostic tests
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Lior	     | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 *   This module checks the operation of the AFE (FX210).
 *
 *****************************************************************************/

#include "cc_def.h"
#include "diag.h"

/*
 * AFE registers definitions
 */
#define	AFE_CFG_ADDR	AFE_ADDR
#define AFE_CFG		*((volatile byte *) AFE_CFG_ADDR)

#define	AFE_THOLD_ADDR	AFE_ADDR + 0x2
#define AFE_THOLD	*((volatile byte *) AFE_THOLD_ADDR)

#define	AFE_TX_DATA_ADDR	AFE_ADDR + 0x4
#define AFE_TX_DATA	*((volatile byte *) AFE_TX_DATA_ADDR)

#define	AFE_RX_DATA_ADDR	AFE_ADDR + 0x6
#define AFE_RX_DATA	*((volatile byte *) AFE_RX_DATA_ADDR)

#define AFE_CFG_BIT_SET(pattern)	{ afe_cfg_shadow |= pattern; \
					 AFE_CFG = afe_cfg_shadow; }
#define AFE_CFG_BIT_CLEAR(pattern)	{ afe_cfg_shadow &= ~(pattern); \
					 AFE_CFG = afe_cfg_shadow; }
#define AFE_CFG_SET(pattern)		{ afe_cfg_shadow = pattern; \
					 AFE_CFG = afe_cfg_shadow; }

#define AFE_TX_FIFO_ENABLE  AFE_CFG_BIT_SET(0x10);
#define AFE_RX_FIFO_ENABLE  AFE_CFG_BIT_SET(0x20);

#define AFE_SET_THOLD(n)    AFE_THOLD = (n << 4) + n

/* 
 * Forward declarations
 */
private char * init_afe();
#pragma interrupt (afe_tx_handler);
#pragma interrupt (afe_rx_handler);


#define AFE_RX 1
#define AFE_TX 0
#define PATTERN_SIZE 32
#define MAX_THOLD 12
#define FIRST_CHAR  'a'
#define LAST_CHAR   'a' + 32
#define AFE_TIMEOUT 0x100000

/*
 * Variables
 */
unsigned char cur_thold;    /* Current receive/transmit threshold */
char	cur_tx_char;
char	rx_buffer[PATTERN_SIZE * 2];
volatile unsigned int rx_num;
char	afe_cfg_shadow = 0;


/****************************************************************************
 *
 *	Test_afe__()
 *
 * The AFE is put into Digital loopback mode. A 32 byte test pattern is
 * transmitted through it, then received and compared.
 ****************************************************************************/
public char *test_afe__()
{
int i;
char *ep;

    /*
     * Loop the test on the possible thresholds
     */
    for (cur_thold = 1; cur_thold <= MAX_THOLD; cur_thold <<= 1) {
	/*
	 * Clear the receive buffer
	 */
	for (i=0; i < PATTERN_SIZE * 2; i++) {
	    rx_buffer[i] = 0x0;
	}
	rx_num = 0;

	/*
	 * Init the AFE
	 */
	ep = init_afe();
	if (ep != NULL) {
	    return ep;
	}

	/*
	 * First fill up the transmit FIFO
	 */
	AFE_TX_FIFO_ENABLE;
	for (i=1, cur_tx_char = FIRST_CHAR; i <= MAX_THOLD; i++) {
		AFE_TX_DATA = cur_tx_char;
		cur_tx_char++;
	}

	AFE_RX_FIFO_ENABLE;

	AFE_CFG_BIT_SET(0xe);      /* Transmit/Receive enable , FS enable */
        _interrupt_enable();

	/*
	 * Now, wait until transmit/receive is completed
	 */
	i = 0;
	while (i < AFE_TIMEOUT &&  rx_num <= PATTERN_SIZE) {
	    i++;
	}

	_interrupt_disable();
    	AFE_CFG_SET(0x1);	    /* Disable every thing, (8000 Hz) */
	mask_interrupt__(AFE_RX);
	mask_interrupt__(AFE_TX);

	/*
	 * Now, check the results
	 */
	if (i >= AFE_TIMEOUT) {
	    strcpy(error, "FAILURE: TIMEOUT, NO AFE INTERRUPTS RECEIVED");
	    return error;
	}

	/*
	 * Work around the AFE/ASIC problem .
	 * Strange 0xff value is sent to the receive FIFO in the begining
	 * Therfore, skip garbege until FIRST_CHAR is found and then compare
	 * the other characters
	 */
	for (i=0; i < PATTERN_SIZE; i++) {
	    if (rx_buffer[i] == FIRST_CHAR)
		break;
	}
	for (cur_tx_char = FIRST_CHAR; (unsigned) cur_tx_char < LAST_CHAR; i++) {
		if (rx_buffer[i] != cur_tx_char) {
		    strcpy(error, "FAILURE: TRANSMIT AND RECEIVED PATTERNS DON'T MATCH");
		    return error;
		}
		cur_tx_char++;
	}
	if (debug_flag) {
	    strcpy(msg__, "AFE TEST PASSED, THRESHOLD ");
	    bin_to_hex__(cur_thold, &msg__[strlen(msg__)], 'B');
	    print_str(msg__);
	}
    }
    return NULL;
}

/****************************************************************************
 *
 *	Init_afe()
 *
 ****************************************************************************/
private char * init_afe()
{
unsigned char cmd[2];
unsigned char fdk = 0;

    AFE_CFG_SET(0x1);		    /* Disable every thing, (8000 Hz) */
    AFE_SET_THOLD(cur_thold);

    /*
     * Init the AFE FX210 via the Uwire interface
     */
    CONFIG_UWIRE(AFE);

    cmd[0] = 0x02; /* Write control register */
    cmd[1] = 0x4d; /* Non-Delayed, Digital loopback, Power amp disabled */
    write_uwire(2, cmd);
    
    cmd[0] = 0x06; /* Read control register */
    /*
    cmd[1] = 0x00;
    */
    write_uwire(1, cmd);
    read_uwire(1, &fdk);
    if (fdk != cmd[1]) {
	strcpy(error, "FAILURE: CAN'T WRITE TO CONTROL REGISTER");
	return error;
    }
    if (debug_flag) {
	strcpy(msg__, "WRITE TO CONTROL REGISTER SUCCEEDED");
	print_str(msg__);
    }
    cmd[0] = 0x4a; /* Enable Transmit PCM */
    cmd[1] = 0x80;
    write_uwire(2, cmd);

    cmd[0] = 0x52; /* Enable Receive PCM */
    cmd[1] = 0x80;
    write_uwire(2, cmd);

    DESELECT_UWIRE;

    /*
     * Init ICU & Dispatch table
     */
    _interrupt_disable();
    icu_init__();
    set_handler__(AFE_RX, afe_rx_handler);
    set_handler__(AFE_TX, afe_tx_handler);

    return NULL;
}

#ifdef OLD
/****************************************************************************
 *
 *	Afe_tx_handler()
 *
 * This handler is called for transmission , when the number of data left
 * in the transmit FIFO is less than the threshold number.
 * It writes one character to the FIFO and returns
 ****************************************************************************/
private void afe_tx_handler()
{
	AFE_TX_DATA = cur_tx_char;
        cur_tx_char++;
}

/****************************************************************************
 *
 *	Afe_rx_handler()
 *
 * This handler is called for reception , when the number of data 
 * in the receive FIFO is greater or equal than the threshold number.
 * It reads one character and returns
 ****************************************************************************/
private void afe_rx_handler()
{
	rx_buffer[rx_num] = AFE_RX_DATA;
	rx_num++;
}
#endif

/****************************************************************************
 *
 *      Afe_tx_handler()
 *
 * This handler is called for transmission ,  when the number of data left
 * in the transmit FIFO is less than the threshold number.
 * In this case the routine transmits (12 - threshold - 1) bytes.
 ****************************************************************************/
private void afe_tx_handler()
{
int i;
    for (i=0; i < MAX_THOLD - cur_thold; i++) {
        AFE_TX_DATA = cur_tx_char;
        cur_tx_char++;
    }
}

/****************************************************************************
 *
 *      Afe_rx_handler()
 *
 * This handler is called for reception ,  when the number of data
 * in the receive FIFO is greater or equal than the threshold number.
 * In this case the routine read these bytes.
 ****************************************************************************/
private void afe_rx_handler()
{
int i;

    for (i=1; i <= cur_thold; i++) {
        rx_buffer[rx_num] = AFE_RX_DATA;
        rx_num++;
    }
}


