/**     io_drivers_npa_56x4.c
 **
 ** Author: Ted Schmitz
 ** Date of original creation February 13, 2009
 **
 **     This file includes the appropriate I/O drivers, like serial I/O &
 ** SEEPROM calls, for the NPA-56x4 AMC board.
 **
 ** Some of the function calls this module resolves are:
 ** kbhit(),
 **
 **/

#include <config.h>

#include <common.h>
//Don't need #include <asm/au1x00.h>
#include "octeon_boot.h"
//#include "octeon_serial.h"
//Don't need #include "octeon-pci-console.h"

#include "ll_bist.h"
#include "diag_mon/ascii_functions.h"
#include "diag_mon/errhand.h"
#include "io_drivers.h"
#include "ll_post.h"

/* external prototypes */
extern int octeon_twsi_set_addr8(uint8_t dev_addr, uint16_t addr);
extern int octeon_twsi_read8_cur_addr(uint8_t dev_addr);
extern int octeon_twsi_write8_addr16(uint8_t dev_addr, uint16_t addr,
                                     uint8_t data);
extern void neg_access_to_i2c_bus(void);
extern void rel_control_of_i2c_bus(void);

//extern void cvmx_set_cycle(uint64_t cycle);

/* local prototypes */
static int send_msg_to_h8(unsigned char * msg_ptr,
                          unsigned char * rcvd_msg_ptr);
static int wait_for_response_from_h8(unsigned char * msg_ptr, 
                                     unsigned char * rcvd_msg_ptr);
static void dump_h8_mb_msg_to_screen(unsigned char * data_ptr);
static void dump_h8_tx_mb_msg_to_screen(unsigned char * data_ptr);

/* the following two variables must be created in the function that uses
   them in order to call these functions before BIST is running from RAM. */
//static unsigned char bist_msg[FPGA_MB_MAX_BYTES]; /* bist msg working space */
//uint8_t bist_rx_msg[FPGA_MB_MAX_BYTES]; /* bist rx msg working space */

//static int one_shot = 0; /* for debug only. delete after use */

static inline uint64_t mips_count_get(void)
{

#if CONFIG_OCTEON /* "CONFIG_OCTEON" is defined somplace */
uint64_t octeon_get_cycles(void);
        return(octeon_get_cycles());
#else
	u32 count;
	asm volatile ("mfc0 %0, $9" : "=r" (count) :);
	return count;
#endif
}

static inline void mips_count_set(u32 v)
{
	asm volatile ("mtc0 %0, $9" : : "r" (v));
}

/*****************************************************************************
 **                  Read Data From SEEPROM
 **
 **   This function reads data from the shared SEEPROM that conatins all the
 ** TLVs.  It also contains the diagnostic data area at the end of the SEEPROM.
 **
 ** 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 bist_read_seeprom(unsigned char * buffer, 
                      unsigned int offset, int length)
{
  int ret_status;             /* status returned from the Uboot call */

  /* call the Uboot driver to read data from the SEEPROM */
  ret_status = eeprom_read((unsigned) BOARD_EEPROM_TWSI_ADDR, 
                           (unsigned) offset,
                           buffer,
                           (unsigned) length);

  /* code we called returns a zero for good completion status */
  if (ret_status == 0)
    return NO_PROBLEM_DETECTED;
  else
    return PROBLEM_DETECTED;

}

/*****************************************************************************
 **                    Write Data To SEEPROM
 **
 **   This function writes data to the shared SEEPROM that conatins all the
 ** TLVs.  It also contains the diagnostic data area at the end of the SEEPROM.
 **
 ** INPUT - "buffer" = pointer to the data to be written to the SEEPROM.
 **       - "offset" = offset of 1st byte to be written to the SEEPROM.
 **       - "length" = how many consecutive bytes to be written to the SEEPROM.
 **
 ** OUTPUT - nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int bist_write_seeprom(unsigned char * buffer, 
                      unsigned int offset, int length)
{
  int ret_status;             /* status returned from the Uboot call */

#if 1 /* preferred method that works now */

  /* call the Uboot driver to write data to the SEEPROM */
  ret_status = eeprom_write((unsigned) BOARD_EEPROM_TWSI_ADDR, 
                            (unsigned) offset,
                            buffer,
                            (unsigned) length);

  /* code we called returns a zero for good completion status */
  if (ret_status == 0)
    return NO_PROBLEM_DETECTED;
  else
    return PROBLEM_DETECTED;

#else /* alternate way.  This also works but is slower */

  unsigned char bist_cmd_payload[FPGA_MB_MAX_BYTES];
  int i;

  /* load the offset of where the data is to be written */
  bist_cmd_payload[BC_SW_OFFSET] = ((offset >> 8) & 0xFF);
  bist_cmd_payload[BC_SW_OFFSET+1] = (offset & 0xFF);

  /* load the number of bytes to be written */
  bist_cmd_payload[BC_SW_LENGTH] = ((length >> 8) & 0xFF);
  bist_cmd_payload[BC_SW_LENGTH+1] = (length & 0xFF);

  /* load the data to be written */
  for (i = 0; i < length; i++)
    bist_cmd_payload[BC_SW_DATA + i] = buffer[i];

  //printf ("length = %0d\n",length);
  //printf ("offset = %08lX\n",offset);
  //printf ("buffer = %p\n",buffer);
  if (length > 256)
    {
    printf("\nBad length parameter in 'bist_write_seeprom(): %04X\n",
           length);
    return PROBLEM_DETECTED;
    }

  if (offset < (unsigned int) 0xFF00)
    {
    printf("\nBad offset parameter in 'bist_write_seeprom(): %04X\n",
           offset);
    return PROBLEM_DETECTED;
    }

  /* tell H8 to do the write.  length is data length + offset & len fields */
#if 1 /* normal mode */
  ret_status = send_bist_cmd_to_h8(BIST_CMD_SEEPROM_WRITE, 
                                   (length + BC_SW_DATA), 
                                   bist_cmd_payload, 0);
#else /* DEBUG - send a bad command to test error logic */
  if (one_shot == (int) 0)
    {
      //printf("\nA - One_shot = %d\n",one_shot);
    one_shot = (int) 1;
    ret_status = send_bist_cmd_to_h8(0x0005, 
                                     (length + BC_SW_DATA), 
                                     bist_cmd_payload, 0);
    one_shot = (int) 1;
    // printf("\nAe - One_shot = %d\n",one_shot);
    }
  else
    {
      //printf("\nB - One_shot = %d\n",one_shot);
    ret_status = send_bist_cmd_to_h8(BIST_CMD_SEEPROM_WRITE, 
                                     (length + BC_SW_DATA), 
                                     bist_cmd_payload, 0);
    one_shot = (int) 1;
    }


#endif /* normal mode */

#endif /* if 1 - preferred method that works now */

}

/*****************************************************************************
 **               Read Data From i2c Device (Other than SEEPROM)
 **
 **   This function reads data from any i2c device (other than the shared 
 ** SEEPROM). Any number of bytes can be read.  This function assumes the
 ** register/offset value and the width of each value read from the i2c device 
 ** are both 8-bits wide.
 **
 ** 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 - nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ** WARNING!!!
 **   I'm not exactly sure what all the various i2c calls do.  Some use a
 **   16-bit register/offset and read 8-bits of data, some uses an 8-bit
 **   register/offset and read 8 bits of data.  Don't know exactly why there
 **   are so many different ways to read/write devices on the i2c bus???
 **
 ****************************************************************************/
int bist_read_i2c_device(unsigned char * buffer, 
                         unsigned char i2c_adrs,
                         unsigned int reg_no, 
                         int length,
                         int err_msg_flag)
{
  int ret_status;             /* status returned from the Uboot call */
  //int tmp;                    /* temp working reg */
  int len;                    /* working length register */

  ret_status = NO_PROBLEM_DETECTED; /* init to okay status */

  if (!buffer || !length)
    {
    printf("\n\nIn 'bist_read_i2c_device()', buffer or length is zero!\n\n");
    ret_status = PROBLEM_DETECTED;  /* flag an error */
    }

  neg_access_to_i2c_bus();        /* negotiate access to shared i2c bus */

  /* select the reg adrs/offset of data to be read */
  if (ret_status == NO_PROBLEM_DETECTED)
    {
    if (octeon_twsi_set_addr8(i2c_adrs, reg_no) < 0)
      ret_status = PROBLEM_DETECTED;  /* flag an error */
    }

  /* if no problems so far, read the data from the device */
  if (ret_status == NO_PROBLEM_DETECTED)
    {
    len = length;
    while (len--)
      {
      int tmp;
      tmp = octeon_twsi_read8_cur_addr(i2c_adrs);
      if (tmp < 0) /* if problem reading last byte */
        {
        ret_status = PROBLEM_DETECTED;  /* flag an error */
        break;                          /* exit loop */
        }

      *buffer++ = (uchar)(tmp & 0xff);  /* no problem. read & save next byte */
      }
    }

  if (ret_status == PROBLEM_DETECTED)
    {
    //clear_i2c_bus();  /* if i2c bus problem detected, clear i2c bus */
    if (err_msg_flag == ENABLE_ERROR_MSGS)
      {
      printf("\nExceeded maximum retries attempting to read data in\n"
             "read_select_data_from_i2c_dev_timed()!\n"
             "buffer = %p, reg no = %04X, length = %08x, device = %02x\n",
             buffer, reg_no, length, i2c_adrs);
      }
    }

  rel_control_of_i2c_bus(); /* relinquish control of i2c bus */

  return ret_status;
}

/*****************************************************************************
 **               Write Data To i2c Device (Other than SEEPROM)
 **
 **   This function writes data to any i2c device (other than the shared 
 ** SEEPROM). Any number of bytes can be written.  This function assumes the
 ** register/offset value and the width of each value written to the i2c device 
 ** are both 8-bits wide.
 **
 ** INPUT - "buffer" = pointer to source data to be written to device. i
 **       - "i2c_adrs" = i2c bus address of i2c device.
 **       - "reg_no" = register number of 1st byte to be written to device.
 **       - "length" = how many consecutive bytes to be written to device.
 **
 ** OUTPUT - nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ** WARNING!!!
 **   I'm not exactly sure what all the various i2c calls do.  Some use a
 **   16-bit register/offset and read 8-bits of data, some uses an 8-bit
 **   register/offset and read 8 bits of data.  Don't know exactly why there
 **   are so many different ways to read/write devices on the i2c bus???
 **
 ****************************************************************************/
int bist_write_i2c_device(unsigned char * buffer, 
                          unsigned char i2c_adrs,
                          unsigned int reg_no, 
                          int length)
{
  int ret_status;             /* status returned from the Uboot call */
  //int tmp;                    /* temp working reg */
  int len;                    /* working length register */

  ret_status = NO_PROBLEM_DETECTED; /* init to okay status */

  if (!buffer || !length)
    {
    printf("\n\nIn 'bist_read_i2c_device()', buffer or length is zero!\n\n");
    ret_status = PROBLEM_DETECTED;  /* flag an error */
    }

  neg_access_to_i2c_bus();        /* negotiate access to shared i2c bus */

  /* select the reg adrs/offset of data to be read */
  if (ret_status == NO_PROBLEM_DETECTED)
    {
    if (octeon_twsi_set_addr8(i2c_adrs, reg_no) < 0)
      ret_status = PROBLEM_DETECTED;  /* flag an error */
    }

  /* if no problems so far, read the data from the device */
  if (ret_status == NO_PROBLEM_DETECTED)
    {
    len = length;
    while (len--)
      {
      int tmp;
      tmp = octeon_twsi_write8_addr16(i2c_adrs,reg_no, 
                                      buffer[((length-len)-1)]);
      if (tmp < 0) /* if problem reading last byte */
        {
        ret_status = PROBLEM_DETECTED;  /* flag an error */
        break;                          /* exit loop */
        }

      *buffer++ = (uchar)(tmp & 0xff);  /* no problem. read & save next byte */
      }
    }

  if (ret_status == PROBLEM_DETECTED)
    {
    //clear_i2c_bus();  /* if i2c bus problem detected, clear i2c bus */
    printf("\nExceeded maximum retries attempting to read data in\n"
           "read_select_data_from_i2c_dev_timed()!\n"
           "buffer = %p, reg no = %04X, length = %08x, device = %02x\n",
           buffer, reg_no, length, i2c_adrs);
    }

  rel_control_of_i2c_bus(); /* relinquish control of i2c bus */

  return ret_status;
}

/*****************************************************************************
 **                             Read System Timer
 **
 **   This function gets the time from the system clock in ticks.  One tick
 ** is typically one processor cycle so tick counts vary in speed from system
 ** to system.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Returns the current system tick count converted to a 32-bit value.
 **
 ****************************************************************************/
//unsigned long bist_get_sys_time(void)
uint64_t bist_get_sys_time(void)
{
  uint64_t current_system_tick_count;

  current_system_tick_count = mips_count_get();

  /* return 32-bit value for now.  may change that later */
  //return ((unsigned long) current_system_tick_count & 0xFFFFFFFF);

  return current_system_tick_count;
}

/*****************************************************************************
 **                            Set System Timer
 **
 **   This function writes the system clock to a specific value.  One count
 ** is typically one processor cycle so tick counts vary in speed from system
 ** to system.
 **
 ** INPUT - "val" 32-bit value to be written to the system clock.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void bist_set_sys_time(uint64_t val)
{
  cvmx_set_cycle(val);
}

/*****************************************************************************
 **                 Send A Message To H8 Via FPGA Mailbox
 **
 **   This function sends a message to the H8 processor through the low
 ** priority FPGA mailbox.  Up to 512 bytes of data can be sent at one time.
 ** This includes the BIST command and data payload.
 **
 ** INPUT - "msg_ptr" points to the 8-bit bytes, comprising the BIST message,
 **         to be sent to the H8.  The message must be in the proper format.
 **       - "rcvd_msg_ptr" = pointer to where the response message received
 **         from the H8 is to be written.  NOTE: If this parameter is set to
 **         zero, the calling code does not want the message received from the
 **         h8 copied back to the calling code.
 **
 ** OUTPUT - The BIST message is transmitted on the low-priority FPGA mailbox.
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
static int send_msg_to_h8(unsigned char * msg_ptr,
                          unsigned char * rcvd_msg_ptr)
{
  unsigned short length;         /* length of message */
  int i;

#if 0 /* debug */
  printf("\nIn 'send_msg_to_h8()'... \n");
  dump_h8_tx_mb_msg_to_screen(msg_ptr);
#endif

  /* assemble the length value */
  length = (unsigned short) ((msg_ptr[BIST_MB_MSG_LEN] << 8) & 0xFF00);
  length |= (unsigned short) (msg_ptr[BIST_MB_MSG_LEN+1] & 0x00FF);

  if (length > FPGA_MB_MAX_BYTES)
    {
    printf("\nIn 'send_msg_to_h8()', message has exceeded mailbox size!\n");
    printf("\nmsg length = %04X\n",length);
    return PROBLEM_DETECTED;
    }

  //printf("\n1 - Int Status reg = %02X\n",*BOARD_INT_STATUS_REG);

  /* load mailbox */
  for (i = 0; i < length; i++)
    {
      //printf("\nB - Int Status reg = %02X\n",*BOARD_INT_STATUS_REG);
    *BOARD_LP_XMIT_MBOX = msg_ptr[i];  /* write next byte into mbox fifo */
    wmb();                             /* force the write to the hardware */
    //printf("\nA - Int Status reg = %02X\n",*BOARD_INT_STATUS_REG);
    }

  *BOARD_LP_XMIT_DBELL_0 = (length & 0xFF); /* write LSB of msg length */
  wmb();                             /* force the write to the hardware */

  //printf("\n2 - Int Status reg = %02X\n",*BOARD_INT_STATUS_REG);

  /* write the upper bit of the length to bit 6 of doorbell reg 1 to start
     the transfer.*/
  *BOARD_LP_XMIT_DBELL_1 = ((length >> 2) & 0x40);
  wmb();                             /* force the write to the hardware */

  //printf("\n3 -Int Status reg = %02X\n",*BOARD_INT_STATUS_REG);

  /* wait for command execution time from H8 */
  if (wait_for_response_from_h8(msg_ptr, rcvd_msg_ptr) == PROBLEM_DETECTED)
    return PROBLEM_DETECTED;

  return NO_PROBLEM_DETECTED;
}

/*****************************************************************************
 **                     Wait For Response Fron H8
 **
 **   This function waits for a response in the receive FPGA mailbox from the
 ** H8 after just sending a BIST command to the H8 through the low-priority
 ** FPGA mailbox.
 **
 ** NOTE:  
 ** This function is called immediately after a new BIST command was sent to 
 ** the H8 through the low-priority FPGA mailbox.  This function then performs
 ** the following logic steps:
 ** 1 - Wait for a response from H8.
 **     To do this do one of two things:
 **     a - wait until bit 0 in FPGA register 0x05 goes high.
 **                - OR -
 **     b - wait until bit 1 in FPGA register 0x05 goes low.
 ** 2 - Read how many bytes are available from H8 from registers:
 **     LSB (bits 7-0) of msg size from register 0x28.
 **     MSb (bit 8) of msg size from bit 6 in register 0x29.
 ** 3 - Read all available bytes from H8 from register 0x2A.
 ** 4 - Clear receive FIFO and let H8 know you have the message by writing
 **     0x6B to register 0x2B.
 ** 5 - The first response from the H8 will always be the time it will take
 **     the H8 to execute the BIST command (or possible an error code if
 **     an illegal command was sent).
 ** 6 - Wait up to the specified time received from the H8 for a 2nd message
 **     from the H8 informing the Octeon that the BIST command has completed.
 ** 6a-  Copy the message received from h8 to the location pointer to by the
 **     calling code in "rcvd_msg_ptr".
 ** 7 - Check the status byte in the message.  If any errors were encountered
 **     log it in the diagnostic area of the SEEPROM and return 
 **     "PROBLEM_DETECTED" to the calling code.
 ** 8 - If command completed with no errors detected, return 
 **     "NO_PROBLEM_DETECTED" to the calling code.
 **
 ** INPUT - "msg_ptr" points to the 8-bit bytes, comprising the BIST message,
 **         just sent to the H8.  The message must be in the proper format.
 **       - "rcvd_msg_ptr" = pointer to where the response message received
 **         from the H8 is to be written.  NOTE: If this parameter is set to
 **         zero, the calling code does not want the message received from the
 **         h8 copied back to the calling code.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the H8 responds correctly and finishes the BIST command within
 **          the specified time.  "PROBLEM_DETECTED" returned otherwise.
 **
 ****************************************************************************/
static int wait_for_response_from_h8(unsigned char * msg_ptr, 
                                     unsigned char * rcvd_msg_ptr)
{
 uint8_t bist_rx_msg[FPGA_MB_MAX_BYTES]; /* bist rx msg working space */
 unsigned long cmd_time;        /* cmd execution time rcvd from H8 */
  uint64_t calc_cmd_time;        /* calc maximum command execution time */
  unsigned short length;         /* length of message */
  unsigned short res_type;       /* response message type rcvd from H8 */
  unsigned short cmd;            /* response received for this command */
  unsigned char bval;            /* 8-bit working reg */
  struct errhand_info eh;        /* create an Octeon err hand struct */
  struct h8_error_info h8_eh;    /* create H8 err hand struct */
  unsigned char * bptr;          /* byte pointer */
  int i;

#if 0 /* debug */
  printf("\nA - In 'wait_for_response_from_h8()'...\n");
  bist_set_sys_time(0);        /* reset system clock */
  while (bist_get_sys_time() < (uint64_t) SECS_5U);
  printf("\n - - - START WATCH - - -\n");

  printf("System tim = %08X\n",bist_get_sys_time());
  bist_set_sys_time(0);        /* reset system clock */
  while (bist_get_sys_time() < (uint64_t) SECS_5U);
  printf("System tim = %08X\n",bist_get_sys_time());
  printf("\n - - - STOP WATCH - - -\n");
#endif

  bist_set_sys_time(0);        /* reset system clock */
  /* (1) - Wait up to a maximim time for a response from the H8 */
  do
    {
    bval = *BOARD_INT_STATUS_REG;
    wmb();                             /* force the read from hardware */
    if ((bval & FPGA_INT_STAT_RX_MB_NOT_EMPTY) == FPGA_INT_STAT_RX_MB_NOT_EMPTY)
      break;
    } while (bist_get_sys_time() < (uint64_t) SECS_5U);

 //printf("\nB - In 'wait_for_response_from_h8()'...\n");
  /* make sure we did not run out of time */
  if (bist_get_sys_time() >= (uint64_t) SECS_5U)
    {
    printf("\nNever got a Response from H8 after sending BIST command: "
           "%02X%02X\n",msg_ptr[BIST_MB_CMD], msg_ptr[BIST_MB_CMD+1]);
    return PROBLEM_DETECTED;
    }

  /* assemble 9-bit length value */
  length = (unsigned short) (*BOARD_RECV_DBELL_0); /* (2) - read LSB */
  wmb();                             /* force the read from hardware */
  length |= (unsigned short) ((*BOARD_RECV_DBELL_1 & FPGA_RX_DB_REG_1_USR)
                              << 2);               /* (2) - read/adj MSb */
  wmb();                             /* force the read from hardware */

  /* (3) - now that we have the length, read entire message from H8 */
  if (length <= 0)
    {
    printf("Illegal length value: %04X\n",length);
    length = 0x10;
    }
    
  for (i = 0; i < length; i++)
    {
    bist_rx_msg[i] = *BOARD_RECV_MBOX;
    wmb();                             /* force the read from hardware */
    }

  //dump_h8_mb_msg_to_screen(bist_rx_msg); /* debug */

#if 0 /* debug */
  printf("\nA - Msg received from H8...length = %04X\n",length);
  for (i = 0; i < length; i++)
    printf("Offset %02X = %02X\n",i, bist_rx_msg[i]);
#endif

  /* (4) - clear rx msg & let H8 know we have the msg */
  *BOARD_FLUSH_RECV_MBOX = FPGA_FLUSH_RX_MSG_VAL;
  wmb();                             /* force the write to hw */

  /* build cmd received from H8. */
  cmd = ((bist_rx_msg[BIST_RX_MB_CMD] << 8) & 0xFF00);
  cmd |= (bist_rx_msg[BIST_RX_MB_CMD+1] & 0x00FF);

  /* build message response type received from H8. */
  res_type = ((bist_rx_msg[BIST_RX_MB_RES_TYPE] << 8) & 0xFF00);
  res_type |= (bist_rx_msg[BIST_RX_MB_RES_TYPE+1] & 0x00FF);

  /* (5) - Response type should be "estimated command time."
           If not log & return an error condition. */

  if (res_type & RES_TYPE_CMD_COMP_W_ERS) /* check for cmd err rsp */
    {
      //printf("\nLast command sent to H8 encountered errors!\n");
      //printf("Command was = %04X\n",cmd);

    /* copy H8 error information into an H8 error structure */
    bptr = (unsigned char *) &h8_eh;
    for (i = 0; i < sizeof(struct h8_error_info); i++)
      bptr[i] = bist_rx_msg[BIST_RX_MB_PAYLOAD+i];

#if 0 /* debug */
    printf("\Dump of data pointed to by 'bptr'...\n");
    for (i = 0; i < sizeof(struct h8_error_info); i++)
      printf("%02X = %02X\n",i,bptr[i]);
#endif
    /* now copy H8 error info to Octeon error information struct */
    eh.call_type = (int) h8_eh.err_type;
    eh.error_stop = h8_eh.error_stop;
    eh.sup_error_stop = h8_eh.sup_error_stop;
    eh.severity = (int) h8_eh.severity;
    eh.data_exp[0] = h8_eh.data_exp;
    eh.data_rec[0] = h8_eh.data_rec;
    eh.fail_adrs =  h8_eh.fail_adrs;
    eh.disp_size = h8_eh.disp_size;
    eh.void_ptr = (void *) 0;
    eh.fru_list[0] = 0xFF; /* terminate FRU list */

    /* call the main error handler to log this error */
    error_handler(&eh);

    return PROBLEM_DETECTED;
    }

  if (res_type & RES_TYPE_CMD_COMP_NO_ERS) /* check for cmd no err rsp */
    {
    printf("\nGot 'command completed normally' response when "
           "expecting 'command execution time' response!\n");
    printf("Command = %04X\n",cmd);
    return PROBLEM_DETECTED;
    }

  if ((res_type & RES_TYPE_CMD_EST_TIME) != RES_TYPE_CMD_EST_TIME)
    {
    printf("\nTime - Received illegal response type from H8!\n");
    printf("Command = %04X\n",cmd);
    return PROBLEM_DETECTED;
    }

  /* calculate the command execution time received from the H8 */
  cmd_time = ((bist_rx_msg[BIST_RX_MB_PAYLOAD] << 24) & 0xFF000000);
  cmd_time |= ((bist_rx_msg[BIST_RX_MB_PAYLOAD+1] << 16) & 0x00FF0000);
  cmd_time |= ((bist_rx_msg[BIST_RX_MB_PAYLOAD+2] << 8) & 0x0000FF00);
  cmd_time |= (bist_rx_msg[BIST_RX_MB_PAYLOAD+3] & 0x000000FF);

  /* calc ticks required for milliseconds requested by H8 */
  calc_cmd_time = (uint64_t) (cmd_time * MS_1);

  bist_set_sys_time(0);        /* reset system clock */
  /* (6) - Wait up to the max cmd execution for another response from the H8 */
  do
    {
    bval = *BOARD_INT_STATUS_REG;
    wmb();                             /* force the read from hardware */
    if ((bval & FPGA_INT_STAT_RX_MB_NOT_EMPTY) == FPGA_INT_STAT_RX_MB_NOT_EMPTY)
      break;
    } while (bist_get_sys_time() < (uint64_t) calc_cmd_time);

  /* make sure we did not run out of time */
  if (bist_get_sys_time() >= calc_cmd_time)
    {
    printf("\nH8 successfully reported an execution time but then never\n"
           "complete the BIST command within specified time!");
    printf("\nCommand = %04X\n",cmd);
    return PROBLEM_DETECTED;
    }

  /* assemble 9-bit length value */
  length = (unsigned short) (*BOARD_RECV_DBELL_0); /* (2) - read LSB */
  wmb();                             /* force the read from hardware */
  length |= (unsigned short) ((*BOARD_RECV_DBELL_1 & FPGA_RX_DB_REG_1_USR)
                              << 2);               /* (2) - read/adj MSb */
  wmb();                             /* force the read from hardware */

  /* (3) - now that we have the length, read entire message from H8 */
  for (i = 0; i < length; i++)
    {
    bist_rx_msg[i] = *BOARD_RECV_MBOX;
    wmb();                             /* force the read from hardware */
    }

  //dump_h8_mb_msg_to_screen(bist_rx_msg); /* debug */

#if 0 /* debug */
  printf("\nB - Msg received from H8...length = %04X\n",length);
  //for (i = 0; i < length; i++)
  for (i = 0; i < 16; i++)
    {
    printf("Offset %02X = %02X\n",i, bist_rx_msg[i]);
    }

    return PROBLEM_DETECTED;
#endif

  /* (6a) - Copy the entire message received from h8 back to calling code,
            if "rcvd_msg_ptr" ius not set to NULL (0x00) */
  if (rcvd_msg_ptr != 0)
    {
    for (i = 0; i < length; i++)
      rcvd_msg_ptr[i] = bist_rx_msg[i];
    }

  /* (4) - clear rx msg & let H8 know we have the msg */
  *BOARD_FLUSH_RECV_MBOX = FPGA_FLUSH_RX_MSG_VAL;
  wmb();                             /* force the write to hardware */

  /* build cmd received from H8. */
  cmd = ((bist_rx_msg[BIST_RX_MB_CMD] << 8) & 0xFF00);
  cmd |= (bist_rx_msg[BIST_RX_MB_CMD+1] & 0x00FF);

  /* build message response type received from H8. */
  res_type = ((bist_rx_msg[BIST_RX_MB_RES_TYPE] << 8) & 0xFF00);
  res_type |= (bist_rx_msg[BIST_RX_MB_RES_TYPE+1] & 0x00FF);

  /* (7) - Response type should be "command completed with no errors."
           If not log & return an error condition. */

  /* (8) */
  if (res_type & RES_TYPE_CMD_COMP_NO_ERS) /* check for cmd no err rsp */
    return NO_PROBLEM_DETECTED;            /* yes. exit. done & no errs det */

  /**    At this point the H8 recognized the command sent above, returned
   ** an execution time, and responded within that time.  However, the
   ** resonse type indicate the command encountered some problem and
   ** needs to report an error to the system.  It is likely a test failed
   ** and a formatted error structure is ready from the H8.  Read it in
   ** and call the error handler for processing.
   **/
  if (res_type & RES_TYPE_CMD_COMP_W_ERS) /* check for cmd err rsp */
    {
#if 1 /* new, correct way */
    /* copy H8 error information into an H8 error structure */
    bptr = (unsigned char *) &h8_eh;
    for (i = 0; i < sizeof(struct h8_error_info); i++)
      bptr[i] = bist_rx_msg[BIST_RX_MB_PAYLOAD+i];

#if 0 /* debug */
    printf("\Dump of data pointed to by 'bptr'...\n");
    for (i = 0; i < sizeof(struct h8_error_info); i++)
      printf("%02X = %02X\n",i,bptr[i]);
#endif
    /* now copy H8 error info to Octeon error information struct */
    eh.call_type = (int) h8_eh.err_type;
    eh.error_stop = h8_eh.error_stop;
    eh.sup_error_stop = h8_eh.sup_error_stop;
    eh.severity = (int) h8_eh.severity;
    eh.data_exp[0] = h8_eh.data_exp;
    eh.data_rec[0] = h8_eh.data_rec;
    eh.fail_adrs =  h8_eh.fail_adrs;
    eh.disp_size = h8_eh.disp_size;
    eh.void_ptr = (void *) 0;

    //printf("\nsize of frus = %02X\n",sizeof (eh.fru_list));
    /* copy the FRU list to the Octeon error handler */
    for (i = 0; i < MAX_FRUS; i++)
      eh.fru_list[i] = (unsigned long) h8_eh.fru_list[i];

    /* call the main error handler to log this error */
    error_handler(&eh);

#else /* old way */
    printf("\nLast command sent to H8 encountered errors!\n");
    printf("Command = %04X\n",cmd);
#endif
    return PROBLEM_DETECTED;
    }

  /* any other response is also an error */
  printf("\nComplete - Received illegal or bad response type from H8!\n");
  printf("Response = %04X\n",res_type);
  printf("Command = %04X\n",cmd);
  return PROBLEM_DETECTED;

}

/*****************************************************************************
 **                 Send A BIST Command To H8
 **
 **   This function sends a message to the H8 processor through the low
 ** priority FPGA mailbox.  Up to 512 bytes of data can be sent at one time.
 ** This includes the BIST command and data payload.
 **
 ** INPUT - "cmd" = 16-bit BIST command to be sent to the H8.
 **       - "length" = length of data pointed to by "data_ptr".  This is only
 **         the data associated with this particular BIST command (if any).
 **         A message header is added and message lengths adjusted before this
 **         command is sent to the H8.
 **         NOTE: If there is no data associated with the command this parameter 
 **               must be set to zero.
 **       - "data_ptr" points to any data associated with this particular BIST
 **         comand. Not all BIST command require data.  But if they do, the
 **         data pointed to by this variable, must be in the appropriate
 **         format for this particular command. Headers and message parameters
 **         are added/adjusted before the actual BIST message is sent to 
 **         the H8.
 **       - "rcvd_msg_ptr" = pointer to where the response message received
 **         from the H8 is to be written.  NOTE: If this parameter is set to
 **         zero, the calling code does not want the message received from the
 **         h8 copied back to the calling code.
 **
 ** OUTPUT - The BIST message is transmitted on the low-priority FPGA mailbox.
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ** NOTE:  This function will attempt to send the BIST command to the H8 up
 **        to "MAX_H8_RETRY_COUNT" times before returning a bad status to the
 **        calling code.
 **
 ****************************************************************************/
int send_bist_cmd_to_h8(unsigned short cmd, unsigned short length,
                        unsigned char * data_ptr,
                        unsigned char * rcvd_msg_ptr)
{
  unsigned char bist_msg[FPGA_MB_MAX_BYTES]; /* bist msg working space */
  unsigned short work_length;   /* working msg length */
  int result;                /* results returned from various function calls */
  int max_retry_count;          /* max retries before returning an error 
                                   condition back to the calling function */
  int i;

  max_retry_count = 0;
  do
    {
    /* clear rx msg & let H8 know octeon is ready for next msg to start with */
    *BOARD_FLUSH_RECV_MBOX = FPGA_FLUSH_RX_MSG_VAL;

#if 0
#if 0
    printf("\nIn 'send_bist_cmd_to_h8()'...\n");
    printf("cmd = %04x, length = %04X, data_ptr = %08lX\n",cmd, length,
           (unsigned long ) data_ptr);
#endif
    printf("\nSending command [%04X] to H8\n",cmd);
#endif

    bist_msg[BIST_MB_MSG_TYPE] = BIST_MB_TYPE; /* set mb msg type */
    bist_msg[BIST_MB_VER] = BIST_MB_MSG_VER; /* format version */
    bist_msg[BIST_MB_CMD] = ((cmd >> 8) & 0xFF); /* build BIST cmd field */
    bist_msg[BIST_MB_CMD+1] = (cmd  & 0xFF);

    /* calc actual BIST message length */
    work_length = length;            /* start with payload length */
    work_length += BIST_MSG_HDR_LEN; /* add header length */

    /* add adjusted length to BIST msg header */
    bist_msg[BIST_MB_MSG_LEN] = ((work_length >> 8) & 0xFF);
    bist_msg[BIST_MB_MSG_LEN+1] = (work_length & 0xFF);

    /* add payload (if any) to working BIST message buffer */
    i = 0;
    while (i < length)
      {
      bist_msg[BIST_MB_PAYLOAD + i] = data_ptr[i];
      i++;
      }

    //printf("\nbefore call to 'send_msg_to_h8()'...\n");
    //dump_h8_tx_mb_msg_to_screen(bist_msg);

    /* send the BIST msg to H8 */
    result = send_msg_to_h8(bist_msg, rcvd_msg_ptr); 

    if (result == NO_PROBLEM_DETECTED)  /* return now if all went well */
      {
      return (result);
      }

    } while(max_retry_count++ < MAX_H8_RETRY_COUNT);

  return (result);                 /* return error staus to calling code */
}

/*****************************************************************************
 **                 Dump Mailbox Message From H8 To Screen
 **
 **   This is a debug function to dump a message received through the FPGA
 ** mailbox from the H8 to the screen.  
 **
 ** INPUT - "data_ptr" points to the complete H8 message to be dumped.
 **         the H8.
 **
 ** OUTPUT - The mailbox message is formatted and dumped to the screen.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
static void dump_h8_mb_msg_to_screen(unsigned char * data_ptr)
{
  unsigned short length;              /* length of response message */
  unsigned short swork;               /* 16-bit working register */
  unsigned short resp_type;           /* calc 16-bit response type */
  int i;

  /* build response type */
  resp_type = ((data_ptr[BIST_RX_MB_RES_TYPE] << 8) & 0xFF00);
  resp_type |= (data_ptr[BIST_RX_MB_RES_TYPE+1] & 0x00FF);

  printf("\nReceived H8 response message type: %04X - ",resp_type);
  
  if (resp_type == RES_TYPE_CMD_COMP_NO_ERS)
    printf("Cmd completed, no errors.\n");
  else  if (resp_type == RES_TYPE_CMD_COMP_W_ERS)
    printf("Cmd completed, WITH errors.\n");
  else  if (resp_type == RES_TYPE_CMD_EST_TIME)
    printf("Estimated time.\n");
  else
    printf("UNKNOWN RESPONSE!!!\n");

  printf("Message type:    %02X      Message format version: %02X\n",
         data_ptr[BIST_RX_MB_MSG_TYPE], data_ptr[BIST_RX_MB_VER]);

  /* build message length type */
  length = ((data_ptr[BIST_RX_MB_MSG_LEN] << 8) & 0xFF00);
  length |= (data_ptr[BIST_RX_MB_MSG_LEN+1] & 0x00FF);

  /* build command in message */
  swork = ((data_ptr[BIST_RX_MB_CMD] << 8) & 0xFF00);
  swork |= (data_ptr[BIST_RX_MB_CMD+1] & 0x00FF);

  printf("Message command: %04X    Message length:         %04X\n",
         swork, length);

  printf("Message header (bytes 0-7):\n");
  for (i = 0; i < BIST_RX_MSG_HDR_LEN; i++)
    {
    printf("%02X = %02X\n",i,data_ptr[i]);
    }

  printf("Message payload (bytes 8 thru ...):\n");
  for (; i < length; i++)
    {
    printf("%02X = %02X\n",i,data_ptr[i]);
    }

}

/*****************************************************************************
 **                 Dump Mailbox Message To H8 To Screen
 **
 **   This is a debug function to dump a message, that will be or was 
 ** transmitted to the H8 through the FPGA mailbox, to the screen.  
 **
 ** INPUT - "data_ptr" points to the complete H8 message to be dumped.
 **         the H8.
 **
 ** OUTPUT - The mailbox message is formatted and dumped to the screen.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
static void dump_h8_tx_mb_msg_to_screen(unsigned char * data_ptr)
{
  unsigned short length;              /* length of response message */
  unsigned short swork;               /* 16-bit working register */
  int i;

  printf("\n - - - Transmit Message To H8 - - -\n");

  printf("Message type:    %02X      Message format version: %02X\n",
         data_ptr[BIST_RX_MB_MSG_TYPE], data_ptr[BIST_RX_MB_VER]);

  /* build message length type */
  length = ((data_ptr[BIST_MB_MSG_LEN] << 8) & 0xFF00);
  length |= (data_ptr[BIST_MB_MSG_LEN+1] & 0x00FF);

  /* build command in message */
  swork = ((data_ptr[BIST_MB_CMD] << 8) & 0xFF00);
  swork |= (data_ptr[BIST_MB_CMD+1] & 0x00FF);

  printf("Message command: %04X    Message length:         %04X\n",
         swork, length);

  printf("Message header (bytes 0-7):\n");
  for (i = 0; i < BIST_MSG_HDR_LEN; i++)
    {
    printf("%02X = %02X\n",i,data_ptr[i]);
    }

  printf("Message payload (bytes 6 thru ...):\n");
  for (; i < length; i++)
    {
    printf("%02X = %02X\n",i,data_ptr[i]);
    }

}

/*****************************************************************************
 **                          H8 Reset Octeon Command
 **
 **   This function sends a command to the H8 to reset the Octeon.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - A BIST command is sent to the H8 in which the H8 will reset
 **          the Octeon (this) processor.
 **          back an error.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void h8_reset_octeon(void)
{
  int ret_status;             /* status returned from the Uboot call */

   /* This BIST command may come back but only beasue is takes the H8 a little
      time to reset the Octeon. */
  ret_status = send_bist_cmd_to_h8(BIST_CMD_RST_OCTEON, 0, 0, 0);

  tbl_delay(MS_25);                    /* hold SDL low for short time */


}

/*  Call some unused funcs to get rid of warnings */
void default_call_function(void)
{
  unsigned char tst_msg[] = "test";

  /* dummy calls to get rid of warnings */
  dump_h8_mb_msg_to_screen(tst_msg); 
  dump_h8_tx_mb_msg_to_screen(tst_msg);
}

/*****************************************************************************
 **                    H8 Configure XAUI Mux Command
 **
 **   This function sends a command to the H8 to configure the XAUI Mux to the
 ** mode selected by the calling code.
 **
 ** INPUT - "mux_mode" = the mode in which the octeon should be configured
 **         as defined below:
 **
 ** Value  Description
 ** -----  --------------------------------------------------------------
 ** 0x00   Configure mux according to current switch settings (normal mode)
 ** 0x01   Connect QLM1 & QLM3 to AMC connector.
 ** 0x02   Connect QLM1 & QLM3 to Front panel PHYs.
 ** 0x04   Loop data coming in from the AMC connector back to the AMC 
 **        connector.
 ** 0x08   Loop data from QLM1 & QLM3 back to QLM1 & QLM3 respectively.
 **
 **        All these mux modes are define in the appropriate "ll_bist.h"
 **        module near symbol "DIAG_BOARD_CONFIG_PORTS_INACTIVE".
 **
 ** OUTPUT - A BIST command is sent to the H8 to configure the XAUI mux.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void h8_config_xaui_mux(unsigned char mux_mode)
{
  unsigned char bist_cmd_payload[FPGA_MB_MAX_BYTES];
  int ret_status;             /* status returned from the Uboot call */

  bist_cmd_payload[BC_MD_SEL] = mux_mode; /* set up mux mode in payload */

  /* tell H8 to configure the XAUI mux to the requested mode */
  ret_status = send_bist_cmd_to_h8(BIST_CMD_MUX_DIAG, BC_MD_LEN, 
                                   bist_cmd_payload, 0);

}

