/**     ll_post_npa_56x4.c
 **
 **   This file contains all low-level POST "C" tests and related code for the
 ** NPA-5651 AMC platform.
 **
 ** Author: Ted Schmitz
 **
 ** Created: December 9, 2008
 **
 **/

#if !defined(__U_BOOT__)
#include <stdio.h>    /* standard library headers */
#else
#include "common.h"  /* common library headers for Uboot environment */
#include <config.h>  /* product config definitions */
#endif

#include "ll_bist.h"
#include "diag_mon/ascii_functions.h"
#include "diag_mon/diag_mon.h"
#include "diag_mon/errhand.h"
#include "diag_mon/errcodes.h"
#include "ll_serial_io.h"
#include "ll_post.h"
#include "ll_post_utils.h"
#include "io_drivers.h"
#include "asm_utils.h"

/* external prototypes */
extern void test_menu(void);
extern void external_start_testing(void);
extern void reset_octeon_i2c_bus(void);

/* local prototypes */
void init_i2c_controller(void);
int wait_for_i2c_completion(void);
int wait_for_i2c_complete_within_time(void);
void clear_i2c_mif_bit(void);
int i2c_start_xmit (void);
void write_to_i2c_data_reg(unsigned long data);
void send_i2c_restart(void);
unsigned char read_from_i2c_data_reg(void);
void sel_master_read_mode(void);
void disable_mster_acks(void);
void i2c_send_stop(void);
void read_teds_seeprom(void);
void disp_seeprom_data(void);
int read_select_data_from_seeprom(unsigned char * buffer, 
                                  unsigned int offset, int length);
int write_select_data_to_seeprom(unsigned char * buffer, 
                                   unsigned int offset, int length);
void reinit_hw_back_to_nf_settings(void);
void calc_write_seeprom_csum(void);
void disp_i2c_data_read(int beg_disp_adrs, int length);
int read_select_data_from_i2c_dev(unsigned char * buffer, 
                                  unsigned char i2c_adrs,
                                  unsigned int offset, int length);
int write_select_data_to_i2c_dev(unsigned char * buffer, 
                                 unsigned char i2c_adrs,
                                 unsigned int offset, int length);
void write_timebase_regs(unsigned long upper, unsigned long lower);
void tbl_delay(unsigned long count);
void debug_cause_i2c_bus_hang(void);
void temp_delay(unsigned long count);

/* local data */
#if 0
/* data read from SEEPROM */
char seeprom_data[100] __attribute__ ((section (".got"))) = {0x00};
#endif
#ifdef STANDALONE
char seeprom_data[MAX_BYTES_TO_READ];   /* data read from SEEPROM */
#else
char seeprom_data[MAX_BYTES_TO_READ];   /* data read from SEEPROM */
#endif
unsigned char bist_test_msg[]={
  //0x10,  /* msg type OLD format */
  //0x00,  /* msg format ver */
  //0x00, 0x01, /* bist command */
  //0x00, 0x0C, /* payload length */
  0xFF, 0xF8, /* data payload - offset */
  0x00, 0x02, /* data payload - length */
  0xAB, 0xCD, /* data payload - data to be written */
}; 

/**   The following array contains all the register offsets in the Dallas
 ** i2c CPU Monitor device.  A zero terminates the array.
 **/
int cpu_mon_reg_index[]={0x15, 0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,
                         0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,
                         0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,
                         0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,
                         0x46,0x47,0x48,0x49,0x4B, 00};

/* adrs where UBoot relocated itself in RAM */
unsigned long uboot_rel_adrs;   

/**
 **   Entry point for phase two low-level POST code.
 **/
void start_ll_phase2_post_code(unsigned long code_rel_offset)
{
  int monitor_entered_flag;             /* flag to indicate if mon entered */
  /*unsigned char data;*/

  //printf("\nStarting 'start_ll_phase2_post_code()...\n");

  monitor_entered_flag = FALSE;         /* init flag to "mon not entered" */
  uboot_rel_adrs = code_rel_offset;     /* save UBoot relocation adrs */
  
  clear_i2c_bus();                      /* make sure bus is free */

#if 1 /* deal with this later */
  /**  Read up the test mode field from the diagnotic information
   ** stored in the SEEPROM.
   ** 1 - If last reset was anything other than a power up, exit now.
   ** 2 - If the 'm' flag is set enter the BIST monitor.
   ** 3 - If escape key pressed, do some clean up and exit but
   **     do not executed any tests.
   **/
  if (read_select_data_from_seeprom_timed((unsigned char *) &test_modes,
                                          TEST_MODE_OS, 
      TOT_TMODE_BYTES) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1190);     /* log the error & exit */
    reinit_hw_back_to_nf_settings();
    return;
    }

  //printf("\ntest_modes = %04X\n",test_modes);
#ifndef FORCE_P2_POWER_UP_MODE /* disable this code to always force PU cond */
  /**
   **  Exit early if this is not a power-on reset
   ** and we are not in any special test mode.
   **/
  /*printf("test_modes = %04x\n",test_modes);*/
  if (
      ((test_modes & TM_PU_RESET_TYPE) != TM_PU_RESET_TYPE) &&
      ((test_modes & TM_CONT_TEST) != TM_CONT_TEST)
     )
    {
    reinit_hw_back_to_nf_settings();
    return;
    }
#endif
  /**
   ** See if escape was pressed previously.  if so skip phase 2 diags 
   **/
  if ((test_modes & TM_ESC_PRESSED) == TM_ESC_PRESSED)
    {
    test_modes &= ~TM_ESC_PRESSED; /* clear the escape key pressed flag */
    if (write_select_data_to_seeprom_timed((unsigned char *) &test_modes,
                                           TEST_MODE_OS, 
	TOT_TMODE_BYTES) == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES1220);     /* log the error & exit */
      reinit_hw_back_to_nf_settings();
      return;
      }

    if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
      report_seeprom_problem(ES1230);   /* log the error & exit */

    reinit_hw_back_to_nf_settings();
    return;                             /* skip diags this one time */
    }

  /**
   ** See if "m" was pressed previously. If so enter monitor now. 
   **/
  if ((test_modes & TM_M_KEY_PRESSED) == TM_M_KEY_PRESSED)
    {
      //printf("\nM key pressed...\n");
    test_modes &= ~TM_M_KEY_PRESSED; /* clear the 'm' key pressed flag */
    if (write_select_data_to_seeprom_timed((unsigned char *) &test_modes,
        TEST_MODE_OS, TOT_TMODE_BYTES) == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES1220);     /* log the error & exit */
      reinit_hw_back_to_nf_settings();
      return;
      }

    if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES1235);     /* log the error & exit */
      reinit_hw_back_to_nf_settings();
      return;
      }

    test_menu();                        /* call test monitor */
    monitor_entered_flag = TRUE;        /* flag mon entered */
    }
  else
    {
    /**   Give the operator the opportunity to enter the BIST monitor
     ** again by displaying the 2nd count down message and checking for
     ** the 'm' one last time.
     **/
#ifdef DISABLE_2ND_COUNT_DOWN_MSG
    if ((disp_countdown_msg(BIST_P2_CD_MSG) | 0x20) == 'm')
      {
      test_menu();                      /* call test monitor */
      monitor_entered_flag = TRUE;        /* flag mon entered */
      }
#endif
    }
#else /* if 0 */

  /* just call the test menu for now.  Delete these lines later */
      test_menu();                      /* call test monitor */
      return;

#endif /* end if 0 */
  /**
   **  Call all phase II tests now if monitor was not just exited.
   **/
  if (monitor_entered_flag == FALSE)
    external_start_testing();

  /**
   **  Clear the "R" flag that forces tests to execute one time, in case it 
   ** is set.
   **/
  test_modes &= ~TM_FORCE_TESTING; /* clear the 'r' key pressed flag */
  if (write_select_data_to_seeprom_timed((unsigned char *) &test_modes,
      TEST_MODE_OS, TOT_TMODE_BYTES) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1225);     /* log the error & exit */
    reinit_hw_back_to_nf_settings();
    return;
    }

  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
    report_seeprom_problem(ES1237);   /* log the error & exit */

  /**
   **   Check and clear the "Auto Disable" flag if it is currently set. 
   ** And if it is set, also disable the BIST diagnostics since that
   ** is the purpose of the "Auto Disable" mode.
   **/
  /* first get the current extended test modes */
  if (read_select_data_from_seeprom_timed((unsigned char *) &ext_test_modes,
    EXT_TEST_MODES_OS, EXT_TMODES_LEN) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1195);     /* log the error & exit */
    reinit_hw_back_to_nf_settings();
    return;
    }

  if ((ext_test_modes & ETM_AUTO_DIS) == ETM_AUTO_DIS)
    {/* enter here if "Auto Disable" mode is currently active */
    ext_test_modes = 0;                 /* clr all ext test modes */

    /* clear all extended test modes and flags */
    if (write_select_data_to_seeprom_timed((unsigned char *) &ext_test_modes,
      EXT_TEST_MODES_OS, EXT_TMODES_LEN) == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES1228);     /* log the error & exit */
      reinit_hw_back_to_nf_settings();
      return;
      }

    test_modes = TM_DISABLE_POST;   /* clr all test modes & disable BIST */

    if (write_select_data_to_seeprom_timed((unsigned char *) &test_modes,
        TEST_MODE_OS, TOT_TMODE_BYTES) == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES1229);     /* log the error & exit */
      reinit_hw_back_to_nf_settings();
      return;
      }

    if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES1239);   /* log the error & exit */
      reinit_hw_back_to_nf_settings();
      return;
      }

    printf("\nBIST Auto Disable mode completed successfully.\n"
           "Re-configuring BIST back to normal mode (disabled).\n\n");

    } /* end 'if ((ext_test_modes & ETM_AUTO_DIS)...' */

  /**
   **   Don't forget to re-init what hardware we messed with so it does
   ** not cause the normal firmware any problems before we exit back
   ** to normal firmware.
   **/
  reinit_hw_back_to_nf_settings();

} /* end 'start_ll_phase2_post_code()' */

/****************************************************************************
 **              Clear Diagnostic Area Of SEEPROM
 **
 **	This routine sets the entire diagnostic area of the SEEPROM to all
 ** FF's to simulate what the SEEPROM contains when a brand new board is 
 ** powered up.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - The entire diagnostic area of the SEEPROM will be set to FF's.
 **
 ** RETURN - None
 **
 *****************************************************************************/
void clear_diag_seeprom_space(void)
{
  int calc_write_length;              /* calculated write length */
  int results;                        /* results of various function calls */
  int i;

  /* data in uninitialized boards is FF */
  for (i = 0; i < MAX_BYTES_TO_READ; i++)
    seeprom_data[i] = 0xFF;
  //seeprom_data[i] = (i & 0xFF);
  /*seeprom_data[i] = 00;*/

#if 1 /* new way works with any size diag area */
  for (i = 0; i < MAX_BYTES_TO_READ; i += MAX_SEEPROM_WRITE_BLOCK)
    {
    /* calc how many bytes to write this time */
    if (i >= MAX_SEEPROM_WRITE_BLOCK)
      calc_write_length = MAX_SEEPROM_WRITE_BLOCK;
    else
      calc_write_length = (MAX_SEEPROM_WRITE_BLOCK - i);

    /* write up to the next 32 bytes */
    results = 
      write_select_data_to_seeprom_timed((unsigned char *)&seeprom_data[i], 
                                         (BEG_BIST_DATA_OS+i), 
                                         calc_write_length);

    /* report any erros detected during the write */
    if (results == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES1240);     /* log the error & exit */
      return;
      }

    }/* end for */

  printf("\nDone clearing buffer...\n");

#else /* old way */
#ifndef STANDALONE
  /* clear first half. Can only write one page at a time.  Uboot driver may
     handle this properly but just being safe */
  if (write_select_data_to_seeprom_timed((unsigned char *)&seeprom_data[0], 
      BEG_BIST_DATA_OS, 32) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1240);     /* log the error & exit */
    return;
    }

  printf("\nDone clearing 1st half...\n");
  //tbl_delay(MS_25); /* this delay move to seeprom write func */

  /* clear second half */
  if (write_select_data_to_seeprom_timed((unsigned char *) &seeprom_data[32], 
      BEG_BIST_DATA_OS+32, 32) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1240);     /* log the error & exit */
    return;
    }

  printf("\nDone clearing 2nd half...\n");
  tbl_delay(MS_25);
#endif

#endif

}


/****************************************************************************
 **              Read Entire Contents Of SEEPROM Into Buffer
 **
 **	This routine reads the entire contents of the diagnotic area in the
 ** SEEPROM into the module, global table so it can be manipulated and/or 
 ** displayed by other functions.
 **
 ** INPUT - "buf" = pointer to buffer in which data read is to be stored.
 **
 ** OUTPUT - The entire diagnostic area of the SEEPROM will be read into
 **          module global variable "seeprom_data[]".
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 *****************************************************************************/
int read_entire_seeprom_timed(unsigned char * buf)
{
  /* read all bytes into RAM with one call */
  return read_select_data_from_seeprom_timed(buf, BEG_BIST_DATA_OS,
                                             MAX_BYTES_TO_READ);
}

/****************************************************************************
 **               Dump All Data From DIMM SPD SEEPROM
 ** 
 **    This function retrieves all the data in the DIMM's SPD SEEPROM and
 ** displays it on the screen.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - All DIMM SPD SEEPROM data will be displayed on the screen.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void dump_all_sdram_spd_data(void)
{
  int i;

  for (i = 0; i < DIAG_AREA_LEN; i++)
    seeprom_data[i] = 0;

 
  read_select_data_from_i2c_dev_timed((unsigned char *) &seeprom_data[0], 
                                      SDRAM_SPD_WRITE_DEV,
                                      0, DIMM_SPD_MAX_BYTES, 
                                      ENABLE_ERROR_MSGS);

  disp_i2c_data_read(0, DIMM_SPD_MAX_BYTES);

}

/****************************************************************************
 **               Display Data In Local Global Array
 ** 
 **    This function displays whatever data is currently resident in the
 ** module global array "seeprom_data[]".
 **
 ** INPUT - "beg_disp_adrs" = Beginning address lable to be attached to the
 **         data displayed.
 **       - "length" = Number of locations to be displayed.
 **
 ** OUTPUT - Data resident in module global array "seeprom_data[]" is displayed
 **          on the screen.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void disp_i2c_data_read(int beg_disp_adrs, int length)
{
  int i;
  int adrs;

  adrs = (int) beg_disp_adrs;
  printf("ADRS  DATA\n");
  for (i = 0; i < length; i+=8)
    {
    printf("%04X  %02X %02X %02X %02X %02X %02X %02X %02X\n",  adrs,
           seeprom_data[i], seeprom_data[i+1], seeprom_data[i+2], 
           seeprom_data[i+3], seeprom_data[i+4], seeprom_data[i+5], 
           seeprom_data[i+6], seeprom_data[i+7]);
    adrs += 8;
    }

}

/****************************************************************************
 **                 Display Diagnostic Area Of SEEPROM
 ** 
 **    This function displays the data currently resident in the module global 
 ** array "seeprom_data[]" assuming it contains the data from the diagnostic
 ** area of the SEEPROM.  The data is displayed in raw format followed by
 ** a formatted & titled field for each data item.
 **
 ** INPUT - "seeprom_data" = pointer to a global copy of the data residing 
 **         in the diagnostic area of the SEEPROM.
 **
 ** OUTPUT - Data resident in module global array "seeprom_data[]" is displayed
 **          on the screen.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void disp_seeprom_data(void)
{
  int i;
  int adrs;
  unsigned long * lptr;
  unsigned long * lptr2;
  unsigned short * sptr;
  unsigned char * bptr;

  adrs = (int) BEG_BIST_DATA_OS;
  printf("ADRS  DATA");
#if 0
  for (i = 0; i < MAX_BYTES_TO_READ; i+=8)
    {
    printf("%04X  %02X %02X %02X %02X %02X %02X %02X %02X\n",  adrs,
           (unsigned char) seeprom_data[i], (unsigned char) seeprom_data[i+1], 
	   (unsigned char) seeprom_data[i+2], (unsigned char) seeprom_data[i+3],
	   (unsigned char) seeprom_data[i+4], (unsigned char) seeprom_data[i+5],
	   (unsigned char) seeprom_data[i+6], (unsigned char) seeprom_data[i+7]);
    adrs += 8;
    }
#else
  for (i = 0; i < MAX_BYTES_TO_READ; i++)
    {
    if ((i % 8) == 0)
      {
      printf("\n%04X  ", adrs);
      adrs += 8;
      }

    printf("%02X ",(unsigned char) seeprom_data[i]);
    }

  printf("\n");
#endif

  /* display data in field form */
  printf("\n  Value     Field\t\t  Value     Field\n");

  lptr = (unsigned long *) &seeprom_data[CUR_SEL_TESTS_OS-BEG_BIST_DATA_OS];
  lptr2 = (unsigned long *) 
    &seeprom_data[CURRENT_LOOP_COUNT_OS-BEG_BIST_DATA_OS];
  printf("%08lX <- Test select bits\t%08d <- Current loop count\n",*lptr,
         (int) *lptr2);

  sptr = (unsigned short *) &seeprom_data[TEST_MODE_OS-BEG_BIST_DATA_OS];
  bptr = (unsigned char *) &seeprom_data[ERROR_MODE_OS-BEG_BIST_DATA_OS];
  printf("    %04X <- Test mode bits\t      %02X <- Error mode bits\n",
         *sptr,*bptr);

  printf("     %3u <- FF test num\t\t      %02X <- FF temperature\n",
         (unsigned char) seeprom_data[FF_TEST_NO_OS-BEG_BIST_DATA_OS],
         (unsigned char) seeprom_data[FF_TEMP_OS-BEG_BIST_DATA_OS]);

  printf("      %02X <- FF 12V reading\t      %02X <- FF 5V reading\n",
         (unsigned char) seeprom_data[FF_12V_OS-BEG_BIST_DATA_OS],
         (unsigned char) seeprom_data[FF_5V_OS-BEG_BIST_DATA_OS]);

  printf("      %02X <- FF 3.3V reading\t      %02X <- FF 1.5V reading\n",
         (unsigned char) seeprom_data[FF_3_3V_OS-BEG_BIST_DATA_OS],
         (unsigned char) seeprom_data[FF_1_5V_OS-BEG_BIST_DATA_OS]);

  lptr = (unsigned long *) &seeprom_data[FF_TIME_OS-BEG_BIST_DATA_OS];
  lptr2 = (unsigned long *) &seeprom_data[FF_ERROR_CODE_OS-BEG_BIST_DATA_OS];
  printf("%08lX <- FF time of fail\t%08lX <- FF error code\n",*lptr,
         *lptr2);

  lptr = (unsigned long *) &seeprom_data[FF_ERR_ADRS_OS-BEG_BIST_DATA_OS];
  lptr2 = (unsigned long *) &seeprom_data[FF_EXP_DATA_OS-BEG_BIST_DATA_OS];
  printf("%08lX <- FF error adrs\t%08lX <- FF data exp\n",*lptr,
         *lptr2);

  lptr = (unsigned long *) &seeprom_data[FF_REC_DATA_OS-BEG_BIST_DATA_OS];
  lptr2 = (unsigned long *) &seeprom_data[LF_ERROR_CODE_OS-BEG_BIST_DATA_OS];
  printf("%08lX <- FF bad data rec\t%08lX <- LF error code\n",*lptr,
         *lptr2);

  lptr = (unsigned long *) &seeprom_data[START_TEST_TIME_OS-BEG_BIST_DATA_OS];
  lptr2 = (unsigned long *) &seeprom_data[ACCUM_TEST_TIME_OS-BEG_BIST_DATA_OS];
#if 0 /* normal display */
  printf("%08lX <- Start test time\t%08lX <- Accum test time\n",*lptr,
         *lptr2);
#else /* temp use of this field used for product id */
  printf("%08lX <- Product id     \t%08lX <- Accum test time\n",*lptr,
         *lptr2);
#endif

  lptr = (unsigned long *) &seeprom_data[TOT_TEST_EXECS_OS-BEG_BIST_DATA_OS];
  lptr2 = (unsigned long *) &seeprom_data[TOT_FAILS_OS-BEG_BIST_DATA_OS];
  printf("%08d <- Total executions\t%08d <- Total failures\n",(int)*lptr,
         (int)*lptr2);

  lptr = (unsigned long *) &seeprom_data[EXEC_COUNT_OS-BEG_BIST_DATA_OS];
  bptr = (unsigned char *) &seeprom_data[EXT_TEST_MODES_OS-BEG_BIST_DATA_OS];
  printf("%08d <- Program exc count\t      %02X <- Extended test modes\n",
         (int)*lptr, (int)*bptr);

  printf("      %02X <- Magic number\t      %02X <- Check sum\n",
         (unsigned char) seeprom_data[MAGIC_NUM_OS-BEG_BIST_DATA_OS],
         (unsigned char) seeprom_data[CHECKSUM_OS-BEG_BIST_DATA_OS]);
}

/*****************************************************************************
 **                   Initialize I2C Bus Controller
 **
 **   This function initializes the I2C bus controller as the master.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - I2C controller is initialized and enabled.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void init_i2c_controller(void)
{
#ifndef STANDALONE
#if 0
  volatile unsigned char work;

  I2C_LO_MSTR_ADRS_REG = 00;            /* clr master lo adrs */
  I2C_HI_MSTR_ADRS_REG = 00;            /* clr master hi adrs */
  I2C_LO_SLV_ADRS_REG = 00;             /* clr slave lo adrs */
  I2C_HI_SLV_ADRS_REG = 00;             /* clr slave hi adrs */

  I2C_CLK_DIV_REG = I2C_CLK_DIVISOR;    /* set up clock divisor */
  I2C_IRQ_EN_REG = 00;                  /* disable all i2c irqs */
  I2C_XFER_CNT_REG = 00;                /* clr xfer count */

  /* clear some status bits */
  I2C_EXT_CTRL_REG = (I2C_EXT_CNTL_SRVW | I2C_EXT_CNTL_COMW \
                      | I2C_EXT_CNTL_SRVR | I2C_EXT_CNTL_COMR);

  /* flush master/slave buffers */
  I2C_MODE_CONT_REG = (I2C_MODE_CONT_FMB | I2C_MODE_CONT_FSB);

  work = I2C_MODE_CONT_REG;             /* get contents of mod cont reg */
  work |= (I2C_MODE_CONT_PCL | I2C_MODE_CONT_EUS); /* hold SCL & exit unknwn */
  /* Commented out per request from HW */
  // work |= I2C_MODE_CONT_SPMD;           /* sel fast i2c bus xfer mode */
  I2C_MODE_CONT_REG = work;

  I2C_CONT_REG = 00;                     /* clr control reg */
#endif
#endif
}

/*****************************************************************************
 **     Initialize All Hardware Back To Normal Firmware Settings
 **
 **   This function initializes the I2C bus controller and other pertinent
 ** hardware in the same way the normal firmware uses it and/or expects it.  
 ** This is done before handing control back to Normal Firmware.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - I2C controller is initialized and enabled.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void reinit_hw_back_to_nf_settings(void)
{
#ifndef STANDALONE
#if 0 /* fix later for NPA-56x4, etc. */
  volatile unsigned char work;
  char bwork;                           /* 8-bit working register */

  /* first clear all the LEDs */
  bwork = SYS_LED_REG;                  /* read cur contents of LED reg */
  bwork &= (~ALL_SYS_LEDS_MASK & 0xFF); /* clear all sys led bits */
  bwork|= (HB_LED | POWER_LED);         /* set OK and HB LED bits */
  SYS_LED_REG = bwork;                  /* turn off all but OK and HB LEDs */

  /* need a little time for previous instruction to propogate PCI bus */
  tbl_delay(MS_5);

  clear_i2c_bus();                      /* make sure bus is free */

  I2C_LO_MSTR_ADRS_REG = 00;            /* clr master lo adrs */
  I2C_HI_MSTR_ADRS_REG = 00;            /* clr master hi adrs */
  I2C_LO_SLV_ADRS_REG = 00;             /* clr slave lo adrs */
  I2C_HI_SLV_ADRS_REG = 00;             /* clr slave hi adrs */

  I2C_CLK_DIV_REG = I2C_CLK_DIVISOR;    /* set up clock divisor */
  I2C_IRQ_EN_REG = 00;                  /* disable all i2c irqs */
  I2C_XFER_CNT_REG = 00;                /* clr xfer count */

  /* clear some status bits */
  I2C_EXT_STAT_REG = (I2C_EXT_CNTL_SRVW | I2C_EXT_CNTL_COMW \
                      | I2C_EXT_CNTL_SRVR | I2C_EXT_CNTL_COMR);

  /* flush master/slave buffers */
  I2C_MODE_CONT_REG = (I2C_MODE_CONT_FMB | I2C_MODE_CONT_FSB);

  work = I2C_MODE_CONT_REG;             /* get contents of mod cont reg */
  work |= (I2C_MODE_CONT_PCL | I2C_MODE_CONT_EUS); /* hold SCL & exit unknwn */
  /* Commented out per request from HW */
  // work |= I2C_MODE_CONT_SPMD;           /* sel fast i2c bus xfer mode */
  I2C_MODE_CONT_REG = work;

  I2C_CONT_REG = 00;                    /* clr control reg */
#endif
#endif

}

/****************************************************************************
 **             Read Data From SEEPROM Within Specified Time
 **
 **   This function reads any number of bytes from the SEEPROM starting from
 ** any random location.  If the SEEPROM  does not respond within a 
 ** predetermined amount of time, a bad status is returned to the calling code.
 **
 ** NOTE:  This function uses a different bits in the i2c control register
 **        depending on how many total bytes are to be received.
 **
 ** INPUT - "buffer" = pointer to where data read from SEEPROM is to be
 **         written.
 **       - "offset" = offset of 1st byte to be read from SEEPROM.
 **       - "length" = how many consecutive bytes to be read from SEEPROM.
 **
 ** OUTPUT - nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int read_select_data_from_seeprom_timed(unsigned char * buffer, 
                                        unsigned int offset, int length)
{
  int result;               /* results of last function call */
  int retry_count;
  int outer_retry_count;

#if 1 /* once debugged, really don't need this on the read */
  if (offset < BEG_BIST_DATA_OS)
    {
    printf("\n\nBIST ERROR!!!\n");
    printf("Attempting to read from SEEPROM at offset %04X!\n",offset);
    printf("This is not within the diagnostic area!\n");
    return PROBLEM_DETECTED;
    }
#endif

#if 1 /* new way */

  outer_retry_count = 0;
  do
    {

    /* retry up to predetermined number of times, if write fails */
    retry_count = 0;
    do
      {
      /* read the data from the SEEPROM */
      result = bist_read_seeprom(buffer, offset, length);

      if (result == NO_PROBLEM_DETECTED)
        return NO_PROBLEM_DETECTED;  /* ret 'operation completed normally' */

      } while (retry_count++ < MAX_I2C_READ_RETRYS);

    printf("\nProblem reading data from SEEPROM in function...\n"
           "read_select_data_from_seeprom_timed()!!!\n");

    reset_octeon_i2c_bus(); /* reset octeon hw and try again */

    } while (outer_retry_count++ < 2);

    printf("\nProblem reading data from SEEPROM in function...\n"
           "read_select_data_from_seeprom_timed() after reseting i2c bus!!!\n");
  return PROBLEM_DETECTED;    /* return 'error' status */

#else /* old way */

  /* read the data from the SEEPROM */
  if (bist_read_seeprom(buffer, offset, length) == NO_PROBLEM_DETECTED)
    return NO_PROBLEM_DETECTED;
  else
    return PROBLEM_DETECTED;
#endif

}

/****************************************************************************
 **           Read Data From i2c device (other than SEEPROM)
 **
 **   This function reads any number of bytes from the selected i2c device
 ** starting from any random location.  If the device does not respond
 ** within a predetermined amount of time, a bad status is returned to the
 ** calling code.
 **
 ** INPUT - "buffer" = pointer to where data read from device is to be
 **         written.
 **       - "i2c_adrs" = i2c bus address of i2c device.
 **       - "reg_no" = register number of 1st byte to be read from device.
 **       - "length" = how many consecutive bytes to be read from device.
 **       - "err_msg_flag" = Flag to disable error messages from displaying 
 **         on screen.  Possible values: DISABLE_ERROR_MSGS, ENABLE_ERROR_MSGS.
 **
 ** OUTPUT - Noting
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the i2c device responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int read_select_data_from_i2c_dev_timed(unsigned char * buffer, 
                                        unsigned char i2c_adrs,
                                        unsigned int reg_no, 
                                        int length,
                                        int err_msg_flag)
{
#ifdef STANDALONE
  return NO_PROBLEM_DETECTED;
#else

  int ret_status;             /* status returned from the call */


  ret_status = bist_read_i2c_device(buffer, i2c_adrs, reg_no, length,
                                    err_msg_flag);

  return ret_status;
#endif
}

/****************************************************************************
 **                 Write Data To SEEPROM Within Specified Time
 **
 **   This function writes up to 32 bytes of data to the SEEPROM starting from
 ** any random location.  If the SEEPROM  does not respond within a 
 ** predetermined amount of time, a bad status is returned to the calling code.
 **
 ** NOTE:  For some reason, the H8 SEEPROM write fuinction does not work well
 **        when more than 32 bytes of data are to be written at one time.  So
 **        the calling code must make certain the data length is 32 bytes or
 **        less per call.  A check is make in this function to return an error
 **        if the length exceeds 32 bytes.
 **
 ** INPUT - "buffer" = pointer to data that is to be written to SEEPROM.
 **       - "offset" = offset of 1st byte to be written to SEEPROM.
 **       - "length" = how many consecutive bytes to be written to SEEPROM.
 **
 ** OUTPUT - nothing
 **
 ** RETURN -"NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int write_select_data_to_seeprom_timed(unsigned char * buffer, 
                                       unsigned int offset, int length)
{
  int result;               /* results of last function call */
  int retry_count;

  //printf("\nIn write_select_data_to_seeprom_timed()...\n");
  //printf("buffer = %p, offset = %04X, length = %0d\n",buffer,offset,length);

#ifdef STANDALONE
  return NO_PROBLEM_DETECTED;
#else
#if 1 /* once debugged, may not need this check */
  if (offset < BEG_BIST_DATA_OS)
    {
    printf("\n\nBIST ERROR!!!\n");
    printf("Attempting to write to SEEPROM at offset %04X!\n",offset);
    printf("This is not within the diagnostic area!\n");
    printf("Data length = %04X\n",length);
    return PROBLEM_DETECTED;
    }

  if (length > MAX_SEEPROM_WRITE_BLOCK)
    {
    printf("\n\nBIST ERROR!!!\n");
    printf("Attempting to write more than %0d bytes to SEEPROM at offset "
           "%04X!\n",MAX_SEEPROM_WRITE_BLOCK, offset);
    printf("Data length = %04X\n",length);
    return PROBLEM_DETECTED;
    }
#endif

#if 1 /* new way */

  /* retry up to predetermined number of times, if write fails */
  retry_count = 0;
  do
    {
    /* write the data to the SEEPROM */
    result = bist_write_seeprom(buffer, offset, length);

    if (result == NO_PROBLEM_DETECTED)
      return NO_PROBLEM_DETECTED;  /* ret 'operation completed normally' */

    } while (retry_count++ < MAX_I2C_WRITE_RETRYS);

  printf("\nProblem writing data to SEEPROM in function...\n"
         "write_select_data_to_seeprom_timed()!!!\n");

  return PROBLEM_DETECTED;    /* return 'error' status */

#else /* old way */
  /* write the data to the SEEPROM */
  if (bist_write_seeprom(buffer, offset, length) == NO_PROBLEM_DETECTED)
    return NO_PROBLEM_DETECTED;
  else
    return PROBLEM_DETECTED;
#endif

#endif

    tbl_delay(MS_25);                /* need a little extra time to finish */
}

/****************************************************************************
 **                               Clear I2C Bus
 **
 **   This function is called usually when a problem has been detected on the
 ** i2c bus to clear the bus and attempt to return control to the i2c bus
 ** controller.  However, this function can also be called to reset the i2c
 ** controller and clear any bis hangs even if no hang is detected, but 
 ** remember, if this function is called, the i2c controller must be
 ** re-initialized before it can be used again because this function resets
 ** the i2c controller.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - I2c bus controller is reset and the bus is cleared several 
 **          times in an attempt to restore normal operation to the i2c bus.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void clear_i2c_bus(void)
{
#if 0 /* fix this for cavium products */
#ifndef STANDALONE
  int loop_count = 9;                   /* max i2c bus reset attempts */
  char bwork;                           /* 8-bit working register */
  int i;

#if 0
  /* exit immediately if no i2c condition exists */
    if ((I2C_DIR_CTRL_REG & (I2C_DIR_CNTL_SCL | I2C_DIR_CNTL_SDA)) == 
        (I2C_DIR_CNTL_SCL | I2C_DIR_CNTL_SDA))
    {
    printf("\nI2C bus is not hung...exiting.\n");
    return;
    }
#endif

#if 0
  printf("\nI2C bus hung.  Attempting to reset the bus...");
#endif

  I2C_EXT_CTRL_REG = I2C_EXT_CNTL_SRST; /* put i2c cntrlr in reset state */

  for (i = 0; i < loop_count; i++)
    {
    I2C_DIR_CTRL_REG = I2C_DIR_CNTL_CSDA; /* set SCL low, SDA high */
    tbl_delay(MS_1);                    /* hold SDL low for short time */

    /* set both SCL & SDA high */
    I2C_DIR_CTRL_REG = (I2C_DIR_CNTL_CSCL | I2C_DIR_CNTL_CSDA);
    tbl_delay(MS_1);                    /* hold SDL high for short time */

    if ((I2C_DIR_CTRL_REG & (I2C_DIR_CNTL_SCL | I2C_DIR_CNTL_SDA)) == 
        (I2C_DIR_CNTL_SCL | I2C_DIR_CNTL_SDA))
      {
#if 0
      printf("Success!  \nI2C bus is now ready for normal traffic!\n");
#endif
      break;                            /* bus released so exit now */
      }
    }

  bwork = I2C_EXT_CTRL_REG;             /* get cur contenst of reg */
  bwork &= ~I2C_EXT_CNTL_SRST;          /* clear reset bit */
  I2C_EXT_CTRL_REG = bwork;             /* release reset to i2c cntrlr */

#if 0
  if (i >= loop_count)
    printf("Failed! \nI2C bus is still hung!\n");
#endif

#endif
#endif
}

/****************************************************************************
 **   Write Data To i2c Device other than SEEPROM Within Predetermined Time
 **
 **   This function writes any number of bytes to an i2c device other than
 ** the  SEEPROM starting from any random location.  If the i2c device does
 ** not respond with a predetermined time, an error will be returned to the 
 ** calling code.
 **
 ** INPUT - "buffer" = pointer to data that is to be written to the device.
 **       - "i2c_adrs" = i2c bus write address of i2c device.
 **       - "reg_sel" = 1st byte to be written to device.  This parameter is 
 **         the first value written to the device after is it selected for 
 **         writing. This is basically a register select byte.  Most devices 
 **         have more than one place data can be written (registers).  
 **       - "length" = how many consecutive bytes of source data are to be 
 **         written to the device.
 **
 ** OUTPUT - nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the i2c device responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int write_select_data_to_i2c_dev_timed(unsigned char * buffer, 
                                       unsigned char i2c_adrs,
                                       unsigned int reg_sel, int length)
{
#ifdef STANDALONE
  return NO_PROBLEM_DETECTED;
#else
  int ret_status;

  ret_status = bist_write_i2c_device(buffer, i2c_adrs, reg_sel, length);

  return ret_status;
#endif
}

/****************************************************************************
 **     Calculate And Write Checksum To SEEPROM Within Specified Time
 **
 **   This function re-calculates the checksum on the diagnostic area of
 ** the SEEPROM and re-writes it to the check sum field.  This function
 ** would be called after any data was changed in the diagnostic area of the
 ** SEEPROM.  If any malfunctions are detected accessing the i2c bus,
 ** an error status will be returned to the calling code.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Diagnostic area check sum in SEEPROM will be re-written with
 **          re-calculated check sum value.
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int calc_write_seeprom_csum_timed(void)
{
  unsigned char csum;                   /* calculated check sum */
  unsigned char loc_seeprom_data[MAX_BYTES_TO_READ]; /* loc storage for data */

  /* get all the diag area data */
  if (read_entire_seeprom_timed(&loc_seeprom_data[0]) == PROBLEM_DETECTED)
    return PROBLEM_DETECTED;
  csum = 0;                             /* clear csum to start with */

  /* calc all but last byte into check sum */
  csum = calc_csum_on_diag_area((unsigned char *) &loc_seeprom_data[0]); 

  if (write_select_data_to_seeprom_timed(&csum, CHECKSUM_OS, 1) 
      == PROBLEM_DETECTED)
    return PROBLEM_DETECTED;

  return NO_PROBLEM_DETECTED;
}

/****************************************************************************
 **                   Display Count Down Message
 **
 **   This function displays a count down message beginning with a 
 ** predetermined count then decrements the count by one each second until 
 ** a key is pressed or the time is up.  Status is then return to the calling
 ** code.
 **
 ** INPUT - "msg_no" - which count-down message is to be displayed as follows:
 **         BIST_P1_CD_MSG = Phase one count down message
 **         BIST_P2_CD_MSG = Phase two count down message
 **
 **         If message number is not valid, no count down message will be 
 **         displayed.  In this case it will up to the calling code to display
 **         a message before calling this function.
 **
 ** OUTPUT - Count down message is displayed and decremented each second
 **
 ** RETURN - The key pressed is returned to the calling code.  If no key is
 **          pressed within the count down period, a zero is returned.
 **
 ****************************************************************************/
char disp_countdown_msg(int msg_no)
{
  unsigned long digit;
  char key;

  if (msg_no == BIST_P1_CD_MSG)
    printf("\nPress ESC, R, or M now...5\b");
  else if (msg_no == BIST_P2_CD_MSG)
    printf("\nPress M to enter diagnostic monitor now...5\b");

#ifdef STANDALONE
  digit = 5;
  
  do 
    {
    sleep(1);   /* delay 1 second */
    if (kbhit())
      {
      printf("0\n");
      return(readch());
      }
    digit--;
    } while (digit != 0);

  return 0;

#else
  digit = 5;
  bist_set_sys_time(0);       /* clear time base */

  do
    {
    if ((bist_get_sys_time() > SEC_1) && (digit == 5))
      {
      llputchar_when_ready('4');
      llputchar_when_ready('\b');
      digit = 4;
      }

    if ((bist_get_sys_time() > SECS_2) && (digit == 4))
      {
      llputchar_when_ready('3');
      llputchar_when_ready('\b');
      digit = 3;
      }

    if ((bist_get_sys_time() > SECS_3U) && (digit == 3))
      {
      llputchar_when_ready('2');
      llputchar_when_ready('\b');
      digit = 2;
      }

    if ((bist_get_sys_time() > SECS_4U) && (digit == 2))
      {
      llputchar_when_ready('1');
      llputchar_when_ready('\b');
      digit = 1;
      }

    if (check_for_key() == TRUE)
      {
      key = llgetchar(); /* read the key */
      printf("\n");
      return key;
      }

    /* loop up to 5 seconds */
    } while (bist_get_sys_time() < SECS_5U);

  printf("0\n");
  return 0;
#endif
}

/****************************************************************************
 **               Report SEEPROM Problem To Error Handler
 **
 **   This function displays a problem with reading or writing data from/to
 ** the i2c SEEPROM device.  Some other function detected the problem.  This
 ** function is just reporting the error.  The suppplimental error code
 ** will be 0x0020 for all calls to this function.
 **
 ** NOTE:  Since an error was detected accessing the SEEPROM, this function
 **        will not attempt to read or write datat to the SEEPROM.  This error
 **        wil then only be displayed and not logged.
 **
 ** INPUT - "error_stop" = the 16-bit error stop portion of the 32-bit error
 **         code.
 **
 ** OUTPUT - Display the error on the screen.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void report_seeprom_problem(unsigned short error_stop)
{
#if 0 /* cannot really do it this way since SEEPROM is the problem */
  struct errhand_info eh;               /* error info struct */

  /* no test number or execution count associated with this failure */
  cur_test = 0;
  cur_loop = 0;

  eh.call_type = EH_ERR_CODE_FRU;
  eh.error_stop = error_stop;
  eh.sup_error_stop = SES0020;
  eh.severity = SLEVEL_FATAL;

  eh.fru_list[0] = mb;
  eh.fru_list[1] = 0xff;

  error_handler(&eh);		/* display an error */

#else

  printf("\nERROR! Problems accessing the SEEPROM!\n");
  printf("Error code = %04x-%04x\n", error_stop, SES0020);

#endif
}

/****************************************************************************
 **               Report SEEPROM Problem To Error Handler
 **
 **   This function logs an problem with reading or writing data from/to
 ** the i2c SEEPROM device.  Some other function detected the problem.  This
 ** function is just reporting the error.  The suppplimental error code
 ** will be 0x0020 for all calls to this function.
 **
 ** INPUT - "error_stop" = the 16-bit error stop portion of the 32-bit error
 **         code.
 **         "exp" = the expected 32-bit data pattern
 **         "rcv" = the actual (incorrect) 32-bit data pattern
 **         "adrs" = the register/data/device address at which the error occured
 **
 ** OUTPUT - Diagnostic area check sum in SEEPROM will be re-written with
 **          re-calculated check sum value.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void report_seeprom_problem_long(unsigned short error_stop, unsigned int exp,
        unsigned int rcv, unsigned int adrs)
{
    struct errhand_info eh;         /* error info struct */

    eh.call_type = EH_ERR_CODE_FRU;
    eh.error_stop = error_stop;
    eh.sup_error_stop = SES0020;
    eh.severity = SLEVEL_FATAL;

    eh.data_exp[0] = exp;           /* expected data */
    eh.data_rec[0] = rcv;           /* received data */
    eh.fail_adrs = adrs;            /* failed address */
    eh.disp_size = DISP_SIZE_4B;    /* display as long */

    eh.fru_list[0] = mb;
    eh.fru_list[1] = 0xff;

    error_handler(&eh);
}

/****************************************************************************
 **               Report I2c Device Problem To Error Handler
 **
 **   This function logs an problem with reading or writing data from/to
 ** an i2c device other than the SEEPROM device.  Some other function detected
 ** the problem.  This function is just reporting the error.  The suppplimental
 ** error code  will be 0x0030 for all calls to this function.
 **
 ** INPUT - "error_stop" = the 16-bit error stop portion of the 32-bit error
 **         code.
 **
 ** OUTPUT - Diagnostic area check sum in SEEPROM will be re-written with
 **          re-calculated check sum value.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void report_i2c_device_problem(unsigned short error_stop)
{
  struct errhand_info eh;               /* error info struct */

  /* no test number or execution count associated with this failure */
  cur_test = 0;
  cur_loop = 0;

  eh.call_type = EH_ERR_CODE_FRU;
  eh.error_stop = error_stop;
  eh.sup_error_stop = SES0030;
  eh.severity = SLEVEL_FATAL;

  eh.fru_list[0] = mb;
  eh.fru_list[1] = 0xff;

  error_handler(&eh);		/* display an error */
}

/****************************************************************************
 **                        Reset The Unit
 **
 **   This function causes the hardware on the unit, including the CPU,
 ** to be reset.  
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Unit will be reset.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void reset_unit(void)
{
#ifdef STANDALONE
  return;
#else

#if 1 /* the following logic does work.  This logic instructs 
         the H8 to reset the Octeon */
  printf("\nInstructing H8 to reset the Octeon...\n");

  h8_reset_octeon();
#endif

#if 0 /* This logic has the octeon rest itself through an FPGA register */
  printf("\nPerforming a Soft Rest on the Octeon...\n");

  /* reset the Octeon. This option works correctly but also hangs quite often */
  *BOARD_RESET_REG = FPGA_BD_RST_OCT_RST_BIT;

  //ll_asm_reset_unit(); /* this works but does hang ocasionally */

#endif

#if 0 /* the following logic does work but not well */

  void (*ptr)(void);                    /* function pointer */

  /* this works on the Octeon processor but not reliably.  In fact reseting the
     Octeon this way only works once then the secodn time around there is a
     problem setting upt the SDRAM controller.  This may be fixable but I have 
     not spent any time looking into this issue yet. */
  ptr = (void *) (RESTART_VECTOR);      /* jump to researt vector */

  printf("\nJumping to restart vector %016qx...\n",RESTART_VECTOR);
  (*ptr)();

#endif

  while(1);              /* wait here until reset happens */
  /* should never make it to the end of this function */

#endif /* STANDALONE */
}

/****************************************************************************
 **                Phase Two Error Logic Test Function
 **
 **   This function is used to test the Phase II error handler logic.  It does 
 ** not test any hardware and is normally disabled.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - An error, including all the error information, will be reported
 **          to the error handler.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void ph2_err_logic_test(void)
{
  struct errhand_info eh;
  char err_msg[] = "This is a test of the Phase II error handler logic.  No "
                   "test has\n"
                   "actually failed!!!";

  eh.call_type = EH_DATA_ADRS_MSG_FRU;
  eh.error_stop = ES2500;
  eh.sup_error_stop = SES1000;
  eh.severity = SLEVEL_FATAL;
  eh.data_exp[0] = 0x3333333333333333ull;
  eh.data_exp[1] = 0xAAAAAAAAAAAAAAAAull;
  eh.data_exp[2] = 0x5555555555555555ull;
  eh.data_exp[3] = 0xDDDDDDDDDDDDDDDDull;
  eh.data_rec[0] = 0x3333331333333333ull;
  eh.data_rec[1] = 0xAAAAAAAAAAAAAAAAull;
  eh.data_rec[2] = 0x5555551555555555ull;
  eh.data_rec[3] = 0xDDDDDDDDDDDDDDDDull;
  eh.fail_adrs = 0x800000008010000Cull;
  eh.void_ptr = (void *) err_msg;
  eh.disp_size = DISP_SIZE_16B;

  eh.fru_list[0] = slot1;
  eh.fru_list[1] = slot2;
  eh.fru_list[2] = ps1;
  eh.fru_list[3] = f1;
  eh.fru_list[4] = dimm1;
  eh.fru_list[5] = mb;
  eh.fru_list[6] = 0xff;

  error_handler(&eh);		/* display an error */

}

/****************************************************************************
 **                 Write To CPU Time Base Registers
 **
 **   This function provides the means to set any value into the CPU upper
 ** and lower time base registers from the "C" code.
 **
 ** INPUT - "upper" = the value to be written into the upper time base CPU
 **         register (TBU).
 **       - "lower" = the value to be written into the lower time base CPU
 **         register (TBL).
 **
 ** OUTPUT - Both the upper and lower time base CPU registers will be written
 **          with data supplied by the calling code.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void write_timebase_regs(unsigned long upper, unsigned long lower)
{
#ifdef STANDALONE
#else

  bist_set_sys_time(lower); /* call Cavium equivalent */

#endif
}

/****************************************************************************
 **           Delay Program Execution Using Time Base Registers
 **
 **   This function delays program execution using the CPU upper and lower
 ** time base registers to time the delay.  Both the upper and lower CPU
 ** time base registers are cleared, then this function waits for the lower
 ** time base ragister to reach the count specified by the calling code.
 **
 ** INPUT - "count" = the numnber of CPU tick counts to delay.  Tick counts
 **         tied directly to the clock spped of the CPU.
 **
 ** OUTPUT - Both the upper and lower time base CPU registers will be cleared
 **          then the lower time base register will be written with data 
 **          supplied by the calling code.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void tbl_delay(unsigned long count)
{
#ifdef STANDALONE
  temp_delay(10000);
#else
  write_timebase_regs(0,0);          /* clear timer */

  while (bist_get_sys_time() < count);
#endif
}

void uptime(unsigned long *count)
{
#ifdef STANDALONE

#else
    *count = bist_get_sys_time();
#endif
}

/* Software delay used if no other delay is available.  Typically not used */
void temp_delay(unsigned long count)
{
  int i, j, k;
  unsigned long scrap;

  for (i = 0; i < count; i++)
    {
    for (j = 0; j < count; j++)
      {
      for (k = 0; k < count; k++)
        {
        scrap = ~scrap;
        }
      }
    }
}

/****************************************************************************
 **               Check Diagnostic Area Of SEEPROM
 **
 **   This function checks to see if the diagnostic area of the SEEPROM is
 ** valid.  If the the area is not valid, this function sets up the diagnostic
 ** area to default values.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - The diagnostic area of the SEEPROM will be set to default 
 **          values if the current contens are not valid.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void check_diag_area(void)
{
  unsigned char loc_seeprom_data[MAX_BYTES_TO_READ]; /* loc storage for data */
  int results;                        /* results of various function calls */
  int valid_flag;                     /* diag area valid flag */
  unsigned char csum;                 /* calculated check sum */
  unsigned long prod_id;              /* 32-bit product id */
  int calc_write_length;              /* calculated write length */
  int i;

  valid_flag = TRUE;                  /* assume the diag are is valid */
  /* pre-clear the local storage */
  for (i = 0; i < MAX_BYTES_TO_READ; i++)
    loc_seeprom_data[i] = 0;

  /* read entire diagnostic area from SEEPROM */
  results = read_select_data_from_seeprom_timed((unsigned char *) 
                                                &loc_seeprom_data[0], 
                                                BEG_BIST_DATA_OS,
                                                MAX_BYTES_TO_READ);
  if (results == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES2630);     /* log the error & exit */
    return;
    }

#if 0 /* DEBUG */
    {
    unsigned short adrs = 0;
    printf("\nCurrent contents...\n");
    printf("ADRS  DATA\n");
    for (i = 0; i < MAX_BYTES_TO_READ; i+=8)
      {
      printf("%04X  %02X %02X %02X %02X %02X %02X %02X %02X\n",  adrs,
             loc_seeprom_data[i], loc_seeprom_data[i+1], loc_seeprom_data[i+2], 
             loc_seeprom_data[i+3], loc_seeprom_data[i+4], loc_seeprom_data[i+5], 
             loc_seeprom_data[i+6], loc_seeprom_data[i+7]);
      adrs += 8;
      }
    }
#endif

  /* make sure magic number is there */
  if (loc_seeprom_data[MAGIC_NUM_OS - BEG_BIST_DATA_OS] != MAGIC_NUM)
    {
#if 1
    printf("\nMagic number in diagnostic area of SEEPROM is invalid!\n"
           "Expected value: %02X, Actual value: %02X\n", MAGIC_NUM,
           loc_seeprom_data[MAGIC_NUM_OS - BEG_BIST_DATA_OS]);
#endif
    valid_flag = FALSE;                /* flag diag area is corrupt */
    }

  /* cal csum on local copy of diag area */
  csum = calc_csum_on_diag_area(&loc_seeprom_data[0]); 

  if (loc_seeprom_data[CHECKSUM_OS - BEG_BIST_DATA_OS] != csum)
    {
#if 1
    printf("\nBad csum in diagnostic area of SEEPROM.\n"
           "Calc csum = %02X, SEEPROM csum = %02X\n",csum,
           loc_seeprom_data[CHECKSUM_OS - BEG_BIST_DATA_OS]);
#endif
    valid_flag = FALSE;                /* flag diag area is corrupt */
    }

  /**  If diagnostic area is not valid, set all data to default values 
   ** and write it back to the SEEPROM.
   **/
  if (valid_flag == FALSE)
    {
    printf("\nSetting diagnotics area of SEEPROM to default values...");
    /* start by clearing all the space */
    for (i = 0; i < MAX_BYTES_TO_READ; i++)
      loc_seeprom_data[i] = 0;

    /* select all default tests (32 bits total) */
    loc_seeprom_data[CUR_SEL_TESTS_OS - BEG_BIST_DATA_OS] = 
      ((DEFAULT_LL_TESTS >> 24) & 0xFF);
    loc_seeprom_data[(CUR_SEL_TESTS_OS+1) - BEG_BIST_DATA_OS] = 
      ((DEFAULT_LL_TESTS >> 16) & 0xFF);
    loc_seeprom_data[(CUR_SEL_TESTS_OS+2) - BEG_BIST_DATA_OS] = 
      ((DEFAULT_LL_TESTS >> 8) & 0xFF);
    loc_seeprom_data[(CUR_SEL_TESTS_OS+3) - BEG_BIST_DATA_OS] = 
      (DEFAULT_LL_TESTS & 0xFF);

    /* set up default test mode(s) */
    loc_seeprom_data[TEST_MODE_OS - BEG_BIST_DATA_OS] = 
      ((TM_DISABLE_POST >> 8) & 0xFF);
    loc_seeprom_data[(TEST_MODE_OS+1) - BEG_BIST_DATA_OS] = 
      (TM_DISABLE_POST & 0xFF);

    /* Set up default error mode */
    loc_seeprom_data[ERROR_MODE_OS - BEG_BIST_DATA_OS] =
      get_def_error_mode();

    /* set default execution count to 1 (32 bits total) */
    loc_seeprom_data[EXEC_COUNT_OS - BEG_BIST_DATA_OS] = 0;
    loc_seeprom_data[(EXEC_COUNT_OS+1) - BEG_BIST_DATA_OS] = 0;
    loc_seeprom_data[(EXEC_COUNT_OS+2) - BEG_BIST_DATA_OS] = 0;
    loc_seeprom_data[(EXEC_COUNT_OS+3) - BEG_BIST_DATA_OS] = 1;

    /* don't forget to set up the magic number */
    loc_seeprom_data[MAGIC_NUM_OS - BEG_BIST_DATA_OS] = MAGIC_NUM;

    prod_id = (unsigned long) get_prod_id();

    /* save product id (32 bits total) */
    loc_seeprom_data[PROD_ID_OS - BEG_BIST_DATA_OS] = 
      ((prod_id >> 23) & 0xFF);
    loc_seeprom_data[(PROD_ID_OS+1) - BEG_BIST_DATA_OS] = 
      ((prod_id >> 16) & 0xFF);
    loc_seeprom_data[(PROD_ID_OS+2) - BEG_BIST_DATA_OS] = 
      ((prod_id >> 8) & 0xFF);
    loc_seeprom_data[(PROD_ID_OS+3) - BEG_BIST_DATA_OS] = 
      (prod_id & 0xFF);

    /* cal csum on local copy of diag area */
    csum = calc_csum_on_diag_area(&loc_seeprom_data[0]); 
    loc_seeprom_data[CHECKSUM_OS - BEG_BIST_DATA_OS] = csum;

#if 0 /* DEBUG */
    {
    unsigned short adrs = 0;
    printf("\nDefault contents...\n");
    printf("ADRS  DATA\n");
    for (i = 0; i < MAX_BYTES_TO_READ; i+=8)
      {
      printf("%04X  %02X %02X %02X %02X %02X %02X %02X %02X\n",  adrs,
             loc_seeprom_data[i], loc_seeprom_data[i+1], loc_seeprom_data[i+2], 
             loc_seeprom_data[i+3], loc_seeprom_data[i+4], loc_seeprom_data[i+5], 
             loc_seeprom_data[i+6], loc_seeprom_data[i+7]);
      adrs += 8;
      }
    }
#endif

  /* Can only write one page at a time.  Uboot driver may
     handle this properly but just being safe */

#if 1 /* new way works with any size diag area */
    for (i = 0; i < MAX_BYTES_TO_READ; i += MAX_SEEPROM_WRITE_BLOCK)
      {
      /* calc how many bytes to write this time */
      if (i >= MAX_SEEPROM_WRITE_BLOCK)
        calc_write_length = MAX_SEEPROM_WRITE_BLOCK;
      else
        calc_write_length = (MAX_SEEPROM_WRITE_BLOCK - i);

      /* write up to the next 32 bytes */
      results = write_select_data_to_seeprom_timed(&loc_seeprom_data[i], 
                                                   (BEG_BIST_DATA_OS+i), 
                                                   calc_write_length);

      /* report any erros detected during the write */
      if (results == PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES2640);     /* log the error & exit */
        return;
        }

      }/* end for */

#else /* old way */
    //printf("&loc_seeprom_data[0] = %08lX\n", (u32) &loc_seeprom_data[0]);

    /* write (1st 32-bytes) all the default values to the diag area of SEEPROM */
    results = write_select_data_to_seeprom_timed(&loc_seeprom_data[0], 
                                                 BEG_BIST_DATA_OS, 
                                                 32);
    if (results == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES2640);     /* log the error & exit */
      return;
      }

    //printf("&loc_seeprom_data[32] = %08lX\n", (u32) &loc_seeprom_data[32]);

    /* The following delay is required or the 2nd write below fails */
    //tbl_delay(MS_25); /* THIS IS NOW DONE IN DRIVER */

    /* write 2nd 32-bytes*/
    results = write_select_data_to_seeprom_timed(&loc_seeprom_data[32], 
                                                 (BEG_BIST_DATA_OS+32), 
                                                 32);
    if (results == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES2640);     /* log the error & exit */
      return;
      }

    /* write remainder */
    results = write_select_data_to_seeprom_timed(&loc_seeprom_data[64], 
                                                 (BEG_BIST_DATA_OS+64), 
                                                 (MAX_BYTES_TO_READ-64));
    if (results == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES2640);     /* log the error & exit */
      return;
      }
#endif

    printf("Done.\n");

    } /* end 'if (valid_flag == FALSE)... */

}

/****************************************************************************
 **           Calculate Check Sum On Diagnostic Area Of SEEPROM
 **
 **   This function calculates the check sum on the data buffer pointed to by
 ** the calling code.  This buffer must be in the format of the diagnostic
 ** are of the SEEPROM.
 **
 ** INPUT - "buf" - pointer to a buffer containing an image of the diagnostic
 **         area of the SEEPROM.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - 8-bit calculated check sum of the buffer pointer to by "buf".  
 **          The buffer is assumed to be formatted like the diagnostic area of 
 **          the SEEPROM.
 **
 ****************************************************************************/
unsigned char calc_csum_on_diag_area(unsigned char * buf)
{
  unsigned char csum;                 /* calculated check sum */
  int i;

  csum = 0;                           /* clear the sum */

  /* calc all but last byte into check sum */
  for (i = 0; i < (MAX_BYTES_TO_READ-1); i++)
    {
    csum += buf[i];
    }

  csum &= 0xFF;                     /* ensure csum is 8-bits */

  return csum;
}

/****************************************************************************
 **                                 Function Stub
 **
 **   This function does nothing except provide a pace for the Uboot code
 ** to reference without actuall executing any of the BIST main code.  This
 ** is necessary to force Uboot to link in all BIST code even if BIST is
 ** not enabled for execution.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void dummy_bist_call(void)
{
  int i;
  int j;

  for (i = 0; i< 5; i++)
    j = i+j;
}


