/******************************************************************************
 *
 *	EEPROM DIAGNOSTIC
 *
 * This module contains eeprom diagnostic tests
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Gary	     | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 * Currently support the NMC93CS66 4Kbit device on sf641, cg160lx and a1d.
 * and NMC93CS46 1Kbit device on a1d.
 *
 *    ee_read()          ee_wds()
 *    ee_write()         ee_wen()       ee_command()
 *
 *  All access (read write command) to the Eeprom is done serially
 *    (the bits are cycled one at a time) through memory mapped registers.
 *
 *  ESR , The eeprom status register is called ESR (external status reg`)
 *    in the SWIFT spec` and BSR (board status reg`) in the VECTOR spec`.
 *  ECR , The eeprom control register is called EDR (external data reg`)
 *    in the SWIFT spec` and BCR (board control reg`) in the VECTOR
 *    spec`.
 *  All the Delays are component specification delays.
 *
 *  Boards with Uwire interface the EEPROM through 
 *  the Uwire which handles all serial H/W signals.
 *  For more details consult the board`s Uwire interface.
 *
 **********************************************************************/

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

/* forward references  */
/***********************/
private short ee_read();
private void  ee_write();
private void  ee_command();
private void  ee_wen();
private void  ee_wds(); 


/*****************************************************************************
 * eeprom direct approach (including H/W signals handling.) 
 *****************************************************************************/
#if ((BOARD == VECTOR) || (BOARD == CG160LX)) 

#define   LAST_EEPROM_ADDR 0xff 		/* Eeprom size is 255 words */

#define   EEDI    0x20				/* serial data to EEPROM */
#define   EESK    0x40				/* clock to EEPROM        */
#define   EECS    0x80				/* EEPROM chip-select to  */

/*********************************************************************
 *
 *			ee_read(word_addr)
 *
 *  This function reads a word (bit by bit) from an EEPROM address.
 ********************************************************************/

private short ee_read(word_addr)
int word_addr;
{
    short response;
    int i;


    ECR_BITSET(EECS);			/* Eeprom Chip-select   */
    ee_command(0x6, word_addr);  	/* READ command 	*/
    for (i = 0; i < 16; i++) {		/* collect response 	*/
	response <<= 1;			/* shift to next bit    */
	ECR_BITSET(EESK);
	DELAY(10);
	ECR_BITCLEAR(EESK);
	DELAY(10);
	if (ESR_IS_SET(EEDO))		/* data bit is '1' 	*/
	    PATERN_SET(0x1, response);
	else
	    PATERN_CLEAR(0x1, response);
    }
    ECR_BITCLEAR(EECS);			/* remove chip select   */ 
    return response;

}

/**********************************************************************
 *
 *	ee_write(word_addr, ee_word)
 *
 *  This function writes a word (bit by bit) to an EEPROM address.
 *  A check is done after a write action to see that the EEPROM
 *  write cycle has finished.
 *********************************************************************/

private void ee_write(word_addr, ee_word)
int word_addr;
short ee_word;
{
    int i;


    ee_wen();					/* enable writes 	  */
    ECR_BITSET(EECS);				/* Chip-select to EEPROM  */
    ee_command(0x5, word_addr); 		/* WRITE command 	  */
    for (i = 0; i < 16; i++) {
	ECR_BITCLEAR(EESK);			/* clock the bit to EEPROM */
	if (IS_PATERN_SET(0x8000, ee_word)) {   /* check MSbit of ee_word */
	    ECR_BITSET(EEDI);
	} 
	else {
	    ECR_BITCLEAR(EEDI);
	}
	ee_word <<= 1;			  	/* get next command bit   */
	ECR_BITSET(EESK);	  		/* latch the bit 	  */
	DELAY(10);
    }
    ECR_BITCLEAR(EECS);				/* remove chip select     */ 
    DELAY(10);
    ECR_BITSET(EECS);			   /* wait till write is complete */
    DELAY(30);
    while (ESR_IS_CLEAR(EEDO));
    ECR_BITCLEAR(EECS);
    DELAY(10);
    ee_wds();					 /* disable writes   	  */

}


/*********************************************************************
 *
 *			ee_command(command, word_addr)
 *
 *   The EEPROM can either work in command or data r/w mode.
 *   This function transfers the EEPROM to command mode.
 ********************************************************************/

private void ee_command(command, word_addr)
char command;
int  word_addr;
{
    int i;


    for (i = 0; i < 3; i++) {
	ECR_BITCLEAR(EESK);	  		/* clock the bit to EEPROM */
	if (IS_PATERN_SET(0x4, command)) {  	/* check MSbit of command  */
	    ECR_BITSET(EEDI);
	} 
	else {
	    ECR_BITCLEAR(EEDI);
	}
	command <<= 1;	  	  		/* get next command bit    */
	ECR_BITSET(EESK);         		/* latch the previous bit  */
    }
    for (i = 0; i < 8; i++) {			/* send the word address   */
	ECR_BITCLEAR(EESK);
	if (IS_PATERN_SET(0x80, word_addr)) {
	    ECR_BITSET(EEDI);
	} 
	else {
	    ECR_BITCLEAR(EEDI);
	}
	word_addr <<= 1;			/* get next address bit)   */
	ECR_BITSET(EESK);
    }
    DELAY(10);
    ECR_BITCLEAR(EESK);				/* end with clock inactive */
}

   
/**********************************************************************
 *
 *	ee_wen()		eeprom write enable
 *********************************************************************/

private void ee_wen()
{
    ECR_BITSET(EECS);
    ee_command(0x4, 0xc0);
    ECR_BITCLEAR(EECS);
}


/**********************************************************************
 *
 *	ee_wds()		eeprom write disable
 *********************************************************************/

private void ee_wds()
{
    ECR_BITSET(EECS);
    ee_command(0x4, 0x0);
    ECR_BITCLEAR(EECS);
}

#endif	/* BOARD == VECTOR or CG160LX */


/*****************************************************************************
 *
 * EEPROM interfaced through a  Uwire.
 *
 *  In this mode Uwire is responsible for H/W signal handling.
 *  It is S/W responsibility to activate CHIP SELECT and correct clock.
 *  and pass correct commands sequences to the device.
 *  CHIP SELECT is done in H/W by the Macro CONFIG_UWIRE.
 *  The Macro DESELECT_UWIRE deactivates CHIP SELECT in H/W.
 *  Exact timing of CONFIG_UWIRE & DESELECT_UWIRE is critical for EE commands.
 *
 *****************************************************************************/
#if (BOARD == A1D)

#if (EEPROM_TYPE == NMC93CS66)

#define LAST_EEPROM_ADDR 0xff 		/* Eeprom size is 255 bytes */
#define READ_CMD_LSB 0x0
#define READ_CMD_MSB 0x6
#define WRITE_CMD_LSB 0x0
#define WRITE_CMD_MSB 0x5
#define WEN_MSB 0x4
#define WEN_LSB 0xff
#define WDS_MSB 0x4
#define WDS_LSB 0x0

#endif
#if (EEPROM_TYPE == NMC93CS46)

#define LAST_EEPROM_ADDR 0x3f 		/* Eeprom size is 64 bytes */
#define READ_CMD_LSB 0x80
#define READ_CMD_MSB 0x1
#define WRITE_CMD_LSB 0x40
#define WRITE_CMD_MSB 0x1
#define WEN_LSB 0x3f
#define WEN_MSB 0x1
#define WDS_LSB 0x0
#define WDS_MSB 0x1

#endif

/*********************************************************************
 *
 *			ee_read(word_addr)
 *
 *  This function reads a word from an EEPROM address.
 ********************************************************************/

private short ee_read(word_addr)
char word_addr;
{
    short res;
    char command[2], data[2];

    command[0] = READ_CMD_MSB;
    command[1] = READ_CMD_LSB | word_addr;

    CONFIG_UWIRE(EEP);
    write_uwire(2, command);
    read_uwire(2, data);
    res = (short) (data[0] << 8) | (short) data[1];
    DESELECT_UWIRE;
    return res;
}

/**********************************************************************
 *
 *	ee_write(word_addr, ee_word)
 *
 *  This function writes a word to an EEPROM address.
 *  Write must be preceded by Write enable and succeeded by Write disable.
 *  After command, address and data word were programmed, CHIP SELECT 
 *  must be immediately turned low and high.  
 *  Then a delay of approximately 10 msec is required for the write to complete. 
 *
 *********************************************************************/

private void ee_write(word_addr, ee_word)
char word_addr;
short ee_word;
{
    char data[4], status[1];
    int i;

    data[0] = WRITE_CMD_MSB;
    data[1] = WRITE_CMD_LSB | word_addr;
    data[2] = ee_word >> 8;
    data[3] = ee_word;
    status[0] = 0;

    CONFIG_UWIRE(EEP);
    ee_wen();
    write_uwire(4, data);
    DESELECT_UWIRE;	     /* CHIP SELECT brought low & high after write. */
    for (i = 0; i < 10; i++);
    CONFIG_UWIRE(EEP);
    while (status[0] == 0x0)			/* approx` 10 msec delay */
        read_uwire(1, status);
    ee_wds();
    DESELECT_UWIRE;
}

/**********************************************************************
 *
 *	ee_wen()		eeprom write enable
 *********************************************************************/

private void ee_wen()
{
    char data[2];
    int i;
    data[0] = WEN_MSB;
    data[1] = WEN_LSB;

    write_uwire(2, data);
    DESELECT_UWIRE;
    for (i = 0; i < 10; i++);
    CONFIG_UWIRE(EEP);
}

/**********************************************************************
 *
 *	ee_wds()		eeprom write disable
 *********************************************************************/

private void ee_wds()
{
    char data[2];
    int i;
    data[0] = WDS_MSB;
    data[1] = WDS_LSB;

    write_uwire(2, data);
    DESELECT_UWIRE;
    for (i = 0; i < 10; i++);
    CONFIG_UWIRE(EEP);
}

#endif	/* BOARD == A1D */

/****************************************************************************
 *
 * Test_eeprom__()
 *
 * This test reads the last word of the eeprom, complements it, writes back
 * and then verifies that it was written correctly. The original value is
 * then restored.
 *
 ****************************************************************************/
public char *test_eeprom__()
{
    short save_val=0, val= 0;
    

    save_val = ee_read(LAST_EEPROM_ADDR);
    ee_write(LAST_EEPROM_ADDR, ~save_val);
    val = ee_read(LAST_EEPROM_ADDR);
    ee_write(LAST_EEPROM_ADDR, save_val);
    if( ((short) ~save_val) == val) {
	if (debug_flag) {
	    strcpy(msg__, "EEPROM write/read to last address PASSED");
	    print_str (msg__);
	}
	return NULL;				 /* Test succeeded */
    }
    else {
	strcpy(error,  "FAILURE: WRITE/READ ERROR");
        return error;
    }
}
