/**     npa_56x4_fpga_tests.c
 **
 ** Author: Ted Schmitz
 ** Date of original creation March 26, 2009
 **
 **     This file contains all the various tests to verify the FPGA 
 ** operation from the Octeon's point of view.
 **
 **
 **/
#include <common.h>

#include "ll_bist.h"
#include "diag_mon/errhand.h"
#include "diag_mon/errcodes.h"
#include "npa_56x4_fpga_tests.h"

/* local prototypes */
static void save_dual_port_ram_data(void);
static void restore_dual_port_ram_data(void);

/* module global variables */
static unsigned char dual_port_ram_saved_data[FPGA_MAX_DPR_SIZE];

/*****************************************************************************
 **                       FPGA Dual-Port RAM Test
 **
 **    This test verifies the 128-byte FPGA dual-port RAM located from offset
 ** 0x80 thru 0xFF in the FPGA address space.  This is static RAM so there is
 ** no hardware initialization required to use the RAM.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - The first 128 bytes of the FPGA dual-port RAM are verified to
 **          be in working order.  A zero data pattern will be left in the RAM.
 **        - If any verification step fails, an error structure will be filled
 **          with the appropriate error data and reported back to the BIST
 **          system.
 **
 ** Return - Nothing
 **
 ****************************************************************************/
void fpga_ram_test(void)
{
  unsigned char write_data;       /* 8-bit data written */
  unsigned char read_data;        /* 8-bit data read */
  struct errhand_info eh;         /* err info structure */
  unsigned char next_pot;         /* calc next power of two adrs */
  volatile unsigned char * fpga_ram;/* pointer to FPGA dual port RAM */
  int i;
  int j;

  save_dual_port_ram_data();  /* save cur data in duap-port ram */

  /* build 8-bit data lines test patterns on the stack */
  unsigned char dl_test_pats[] =
    { 0x00, 0xFF, 0xF0, 0x0F, 0x33, 0xDD, 0xAA, 0x55, FPGA_DL_TEST_PAT_TERM};

  fpga_ram = (unsigned char *) FPGA_DP_RAM; /* set up FPGA RAM pointer */

  /* first perform a data lines test */
  for (i = 0; dl_test_pats[i] != FPGA_DL_TEST_PAT_TERM; i++)
    {
    write_data = dl_test_pats[i]; /* load next test pattern */
    *fpga_ram = write_data;                      /* write RAM */
    read_data = *fpga_ram;                       /* read it back */
    if (write_data != read_data)
      {
      /* build an error structure containing all the error information */
      eh.call_type = EH_FAIL;
      eh.error_stop = ES0030;
      eh.sup_error_stop = SES0000;
      eh.severity = SLEVEL_FATAL;
      eh.data_exp[0] = (unsigned int) write_data;
      eh.data_rec[0] = (unsigned int) read_data;
      eh.fail_adrs = (unsigned int) FPGA_DP_RAM;
      eh.disp_size = DISP_SIZE_1B;
      eh.void_ptr = 0;
      eh.fru_list[0] = mb;
      eh.fru_list[1] = 0xFF;

      /* report the error to the BIST system */
      error_handler(&eh);
      restore_dual_port_ram_data(); /* restore orig data in dual-port ram */
      return;
      }
    } /* end for */

  /**
   ** Perform address lines test next 
   **/
  
  /* Power Of Two (POT) = their own adrs. Others = fill value */
  next_pot = 1;
  for (i = 0; i < FPGA_MAX_DPR_SIZE; i++)
    {
    if (i == (int) next_pot)
      {
      /* POT adrs.  Write own adrs to this location */
      fpga_ram[i] = (unsigned char) i;
      next_pot = (next_pot << 1); /* calc nxt POT adrs */
      }
    else
      /* non-POT adrs.  Write fill value to this location */
      fpga_ram[i] = (unsigned char) ADRS_LNS_FILL_CHAR;

    } /* end for */

  /* verify all POT addrs contain their own adrs. Others fill value */
  next_pot = 1;
  for (i = 0; i < FPGA_MAX_DPR_SIZE; i++)
    {
    /* read nxt loc */
    read_data = fpga_ram[i];

    /* verify it contains the correct data */
    if (i == (int) next_pot)
      {
      /* this location should contain next POT adrs */
      if (read_data != next_pot) 
        {
        /* build an error structure containing all the error information */
        eh.call_type = EH_FAIL;
        eh.error_stop = ES0040;
        eh.sup_error_stop = SES0000;
        eh.severity = SLEVEL_FATAL;
        eh.data_exp[0] = (unsigned int) next_pot;
        eh.data_rec[0] = (unsigned int) read_data;
        eh.fail_adrs = (unsigned int) i;
        eh.disp_size = DISP_SIZE_1B;
        eh.void_ptr = 0;
        eh.fru_list[0] = mb;
        eh.fru_list[1] = 0xFF;

        /* report the error to the BIST system */
        error_handler(&eh);
        restore_dual_port_ram_data(); /* restore orig data in dual-port ram */
        return;
        }

      next_pot = (next_pot << 1); /* calc nxt POT adrs */
      }
    else
      {
      /* this location should contain fill pattern */
      if (read_data != ADRS_LNS_FILL_CHAR)
        {
        /* build an error structure containing all the error information */
        eh.call_type = EH_FAIL;
        eh.error_stop = ES0040;
        eh.sup_error_stop = SES0000;
        eh.severity = SLEVEL_FATAL;
        eh.data_exp[0] = (unsigned int) ADRS_LNS_FILL_CHAR;
        eh.data_rec[0] = (unsigned int) read_data;
        eh.fail_adrs = (unsigned int) i;
        eh.disp_size = DISP_SIZE_1B;
        eh.void_ptr = 0;
        eh.fru_list[0] = mb;
        eh.fru_list[1] = 0xFF;

        /* report the error to the BIST system */
        error_handler(&eh);
        restore_dual_port_ram_data(); /* restore orig data in dual-port ram */
        return;
        }
      } /* end 'if (i == (int) next_pot)...' */
    } /* end for */

  /**
   ** Perform cells test
   **/

  for (i = 0; dl_test_pats[i] != FPGA_DL_TEST_PAT_TERM; i++)
    {
    write_data = dl_test_pats[i]; /* load next test pattern */

    /* Write next test pattern to every location (cell) */
    for (j = 0; j < FPGA_MAX_DPR_SIZE; j++)
      fpga_ram[j] = write_data;              /* write next cell */

    /* read all cells back and verify the data */
    for (j = 0; j < FPGA_MAX_DPR_SIZE; j++)
      {
      /* read next location back */
      read_data = fpga_ram[j]; 
      if (read_data != write_data)
        {
        /* build an error structure containing all the error information */
        eh.call_type = EH_FAIL;
        eh.error_stop = ES0050;
        eh.sup_error_stop = SES0000;
        eh.severity = SLEVEL_FATAL;
        eh.data_exp[0] = (unsigned int) write_data;
        eh.data_rec[0] = (unsigned int) read_data;
        eh.fail_adrs = (unsigned int) j;
        eh.disp_size = DISP_SIZE_1B;
        eh.void_ptr = 0;
        eh.fru_list[0] = mb;
        eh.fru_list[1] = 0xFF;

        /* report the error to the BIST system */
        error_handler(&eh);
        restore_dual_port_ram_data(); /* restore orig data in dual-port ram */
        return;
        }

      } /* end 'for (i = 0;...' */

    } /* end 'for (write_data... */

  restore_dual_port_ram_data(); /* restore orig data in dual-port ram */
}

/*****************************************************************************
 **                     Save Dual-Port RAM Data
 **
 **    This function saves all the data in the fpga dual-port RAM prior to
 ** running tests on the dual-port memory.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - All dual-port RAM data is save in module, global variables.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
static void save_dual_port_ram_data(void)
{
  volatile unsigned char * fpga_ram;/* pointer to FPGA dual port RAM */
  int i;

  fpga_ram = (unsigned char *) FPGA_DP_RAM; /* set up FPGA RAM pointer */

  for (i = 0; i < FPGA_MAX_DPR_SIZE; i++)
    dual_port_ram_saved_data[i] = fpga_ram[i];
}

/*****************************************************************************
 **                     Restore Dual-Port RAM Data
 **
 **    This function restores all the data in the fpga dual-port RAM after
 ** running tests on the dual-port memory.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - All dual-port RAM locates are restores to the original values
 **          prior to running the dual-port RAM test.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
static void restore_dual_port_ram_data(void)
{
  volatile unsigned char * fpga_ram;/* pointer to FPGA dual port RAM */
  int i;

  fpga_ram = (unsigned char *) FPGA_DP_RAM; /* set up FPGA RAM pointer */

  for (i = 0; i < FPGA_MAX_DPR_SIZE; i++)
    fpga_ram[i] = dual_port_ram_saved_data[i];
}

