/**   mem_test_56x4.c
 **
 **   This module includes all the low-level DDR2 RAM tests for the 
 ** NPA-56x4 AMC card which contains a Cavium processor.
 **
 **   These tests run from FLASH after the DDR2 controller is set up but 
 ** before the Uboot code is moved into RAM.
 **
 ** Created by Ted Schmitz, October 9, 2008
 **
 **/

#include <common.h>
//#include <asm-mips/global_data.h>

#include "mem_test_npa56x4.h"
#include "phase1_error_handler.h"
#include "diag_mon/errcodes.h"
#include "ll_bist.h"
#include "ll_post_types.h"
#include "common_mem_test.h"
#include "asm_utils.h"
#include "ll_post_utils.h"

#include "cvmx.h"

/* local variables */
/* cannot use globals in phase I tests */
//static uint64_t ddr_mem_size;   /* total number of bytes of DDR RAM */
//static int test_results_flag;   /* flag indicating test passed or failed */
void disp_tlbs(void);
void disp_lmcx_regs(void);

//#define ENABLE_DATA_LINES_DEBUG /* def to turn on data lines test debug info */

  /*-------------------*/
  /*  form_evict_addr  */
  /*-------------------*/
  /* Returns an address that when written to will cause the L2Cache to flush
   * 'addr' from the cache. 'Increment' controls how far away and in what
   * direction to find the evicting cache block. To use the next higher
   * cache block, set 'Increment' to 0x80; while to use the next lower cachce
   * block, set 'Increment' to -0x80.
   */
uint64_t
form_evict_addr (uint64_t p1, uint64_t increment)
{
    uint64_t    p2, l2cSet, mid, high;

    if (OCTEON_IS_MODEL (OCTEON_CN38XX) ||
	OCTEON_IS_MODEL (OCTEON_CN56XX) ||
	OCTEON_IS_MODEL (OCTEON_CN58XX)   ) {
          /* These devices use an 11-bit wide cache index. */
        l2cSet = ((p1 >> 17) & 0x3FFll) ^ ((p1 >> 7) & 0x3FFll);

        p2 = p1 + increment;  /* One cache block more */

        mid = (p2 >> 7) & 0x3FFLL;
        high = mid ^ l2cSet;

        p2 = (p2 & 0xFF801FFFFLL) | (high << 17);
    } else if (OCTEON_IS_MODEL (OCTEON_CN31XX) ||
               OCTEON_IS_MODEL (OCTEON_CN30XX) ||
               OCTEON_IS_MODEL (OCTEON_CN52XX) ||
               //OCTEON_IS_MODEL (OCTEON_CN51XX) ||
               OCTEON_IS_MODEL (OCTEON_CN50XX)   ) {
          /* These devices use an 9-bit wide cache index. */
        l2cSet = ((p1 >> 16) & 0x1FFll) ^ ((p1 >> 7) & 0x1FFll);

        p2 = p1 + increment;  /* One cache block more */

        mid = (p2 >> 7) & 0x1FFLL;
        high = mid ^ l2cSet;
        p2 = (p2 & 0xFFC00FFFFLL) | (high << 16);
    } else {
	p2 = 0;
    //fatal ("form_evict_address: unrecognized Octeon version\n");
    printf("\nIn 'form_evict_address()' unrecognized Octeon version\n");
    }

    //printf("\np1 = %08lX\n",(u32) p1);
    //printf("\np2 = %08lX\n",(u32) p2);
    return (p2);
}

#if 0 /* don't think I need this any more */
/*****************************************************************************
 **                Main Memory Test Function                                **
 **                                                                         **
 **   This is the main function that calls all the DDR memory tests in the  **
 ** proper order.                                                           **
 **                                                                         **
 ** NOTE:  It would help to know how many and the length, in bytes, of each **
 **        DIMM.  Some tests use this information to properly test the      **
 **        boundaries of each DIMM and to help determine which DIMM is bad  **
 **        when a malfunction is detected.                                  **
 **                                                                         **
 ****************************************************************************/
void run_memory_tests(void)
{
  //DECLARE_GLOBAL_DATA_PTR;      /* setup gbl data ptr, need some global data */
  //test_results_flag = PASS;     /* init test results flag */

  //ddr_mem_size = gd->ram_size;  /* get total size of ddr RAM in bytes */

  /**  Set up l2C, core icache & dcache, and ecc hardware as you need it
       for this test.
       Individual tests may have to adjust and/or monitor various memory
       registers for their needs.

       Make sure the Icache & Dcache is on for Core 0 or the RAM tests will 
       run too slow.
  **/

  ram_data_lines_test();        /* test data lines on all DIMMs */
  ram_address_lines_test();     /* test address lines on all DIMMs */
  ram_cells_test();             /* test each location of RAM on all DIMMs */
  ddr_ram_ecc_test();           /* test the DDR RAM ECC Cells */
}
#endif

/*****************************************************************************
 **                  Cavium RAM Data Lines Test - Phase I
 **
 **   This function verifies the data lines to the DDR RAM by writing and
 ** reading a variety of test patterns designed to verify each data pin 
 ** connected to the DDR memory.  This is a Phase I test and is called by
 ** the phase I test manager.
 **
 **  The Cavium processor has 128 data bits.  The first 64 are connected to one
 ** DIMM the last 64 are connected to the 2nd DIMM.
 **
 ** NOTE:  This function assumes there are four DIMMs available for now.
 **
 ** INPUT - "test_no" = test number for this test.
 **       - "exec_count" = current execution count.
 **
 ** OUTPUT - The data lines in at least the first four DIMM sockets will be
 **          verified to be working.
 **        - Module global variable "test_results_flag" will be set to "FAIL"
 **          if any problems are detected by the data lines test.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void data_lines_test(int test_no, int exec_count)
{
  uint64_t * tp;                /* pointer to test patterns */
  volatile uint64_t * llptr;    /* 64-bit data working pointer */
  /* NOTE: All pointers are still only 32-bits long even though they may
           point to 64-bit data!!!
  */
  uint64_t cur_lo_test_pat;     /* current lower 64-bit test pattern */
  uint64_t data_read;           /* data read back from DIMM */
  uint64_t fail_adrs;           /* address where failure was detected */
  uint32_t lwork;               /* 32-bit working reg */
  int test_results_flag;        /* flag indicating test passed or failed */
  union b64_data b64;           /* union to manage a 64-bit test pattern */
  struct error_data eh;         /* create an err hand struct */
  int i;

  hl_spin_wheel();             /* let operator know we are not hung */

  /**   Must set up TLB to access the 0x00000004 10000000 - 0x00000004 1FFFFFFF 
   ** area - DR1 region. This region is 256MB long for both the TNPA-5644 & 
   ** TNPA-5654 boards.  In this case we use TLB 0 entry.
   **/
  //disp_tlbs();
  ll_write_tlb_entry(0, BEG_ADRS_LINES_TEST_ADDR_DR1, 
                     BEG_ADRS_LINES_TEST_ADDR_DR1, ADRS_LINES_TEST_LENGTH_DR1,
                     TLB_DVG_BITS);
  //disp_tlbs();

  test_results_flag = PASS;     /* init flag */

  /**   Start out by writing and verifying some basic patterns to see if we 
   ** have any stuck-ats or stuck-to's.
   **/
  tp = (uint64_t *) &data_test_pats_64b[0]; /* get pointer to test patterns */
  llptr = (uint64_t *) BEG_DATA_LINES_TEST_ADDR; /* data lines test beg adrs */

  while(*tp != (uint64_t) END_OF_TABLE)
    {
    cur_lo_test_pat = *tp;      /* get next test pat from table */

#ifdef ENABLE_DATA_LINES_DEBUG /* debug */
    //printf("tp = %08lX\n",(unsigned long) tp);
    printf("test pat = %016qx\n",cur_lo_test_pat);
#endif

    llptr[0] = cur_lo_test_pat; /* write next test pat to lower DIMM */
    llptr[1] = ~cur_lo_test_pat; /* write inverse of test pat to upper DIMM */

    /**
     ** NOTE: We really need to know how many DIMMS there are and the 
     **       beginning and ending address of each to test the data lines
     **       on each DIMM.  But for now we will assume four DIMMs.
     **/
    //llptr[0] += 0x2030405060708090ull; /* DEBUG - mess up the data in ram */

#if 0 /* hard way, read/write 2MB data */
    ll_asm_flush_cache(BEG_ADRS_LINES_TEST_ADDR_DR1,CACHE_FLUSH_READ_LENGTH);
#else /* easy way - flush L2 cache in hardare */
    ll_flush_l2c();  /* flush L2 cache in hardware */
#endif
    hl_spin_wheel();             /* let operator know we are not hung */
    /* read data back on lower DIMM and verify it */
    data_read = llptr[0];       /* read back lower 64 bits (1st DIMM ) */

    if (data_read != cur_lo_test_pat)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0080;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = cur_lo_test_pat;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    /* read data back on upper DIMM and verify it */
    data_read = llptr[1];       /* read back upper 64 bits (2nd DIMM ) */

    if (data_read != ~cur_lo_test_pat)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0085;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork+8;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = cur_lo_test_pat;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    /**
     ** Do it again but reverse which DIMM gets what test pattern.
     **/
    llptr[0] = ~cur_lo_test_pat; /* write inverse of test pat to lower DIMM */
    llptr[1] = cur_lo_test_pat; /* write cur test pat to upper DIMM */

    //ll_asm_flush_cache(BEG_ADRS_LINES_TEST_ADDR_DR1,CACHE_FLUSH_READ_LENGTH);
    ll_flush_l2c();  /* flush L2 cache in hardware */
    hl_spin_wheel();             /* let operator know we are not hung */

    /* read data back on lower DIMM and verify it */
    data_read = llptr[0];       /* read back lower 64 bits (1st DIMM ) */

    if (data_read != ~cur_lo_test_pat)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0080;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = ~cur_lo_test_pat;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    /* read data back on upper DIMM and verify it */
    data_read = llptr[1];       /* read back upper 64 bits (2nd DIMM ) */

    if (data_read != cur_lo_test_pat)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0085;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork+8;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = cur_lo_test_pat;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    tp++;                       /* inc pointer to next test pattern */
    } /* end while */

  /** Okay so far.  Now walk a one and a zero through the data lines to
   ** check for any single bit being stuck to any other bit.
   **/
#ifdef ENABLE_DATA_LINES_DEBUG
  printf("Starting walking 1's test...\n");
#endif
  i = 0;

  do /* walking 1's on lower DIMM, walking 0's on upper DIMM */
    {/* calc next walking 1's pattern for lower 32-bits */
    if (i <= 31)
      {
      b64.llwork = 0;
      b64.ul.lo_work = ((1 << i) & 0xFFFFFFFF);
      }
    else
      { /* calc next walking 1's pattern for upper 32-bits */
      b64.llwork = 0;
      b64.ul.up_work = ((1 << (i-32)) & 0xFFFFFFFF);
      }

    llptr[0] = b64.llwork;          /* write walking 1's to lower DIMM */
    llptr[1] = ~b64.llwork;         /* write walking 0's to upper DIMM */

#ifdef ENABLE_DATA_LINES_DEBUG /* debug */
    printf("i = %0d\n",i);
    printf("next W1's pattern = %016qx\n",b64.llwork);
#endif

    //ll_asm_flush_cache(BEG_ADRS_LINES_TEST_ADDR_DR1,CACHE_FLUSH_READ_LENGTH);
    ll_flush_l2c();  /* flush L2 cache in hardware */
    hl_spin_wheel();             /* let operator know we are not hung */

    /* read data back on lower DIMM and verify it */
    data_read = llptr[0];       /* read back lower 64 bits (1st DIMM ) */

    if (data_read != b64.llwork)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0080;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = b64.llwork;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    /* read data back on upper DIMM and verify it */
    data_read = llptr[1];       /* read back upper 64 bits (2nd DIMM ) */

    if (data_read != ~b64.llwork)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0085;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork+8;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = ~b64.llwork;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    i++;
    } while (b64.llwork != 0x8000000000000000ull);

#ifdef ENABLE_DATA_LINES_DEBUG
  printf("Starting walking 0's test...\n");
#endif

  i = 0;
  do /* walking 0's on lower DIMM, walking 1's on upper DIMM */
    {
    if (i <= 31)
      {/* calc next walking 1's pattern for lower 32-bits */
      b64.llwork = 0xFFFFFFFFFFFFFFFFull;
      b64.ul.lo_work = ~((1 << i) & 0xFFFFFFFF);
      }
    else
      { /* calc next walking 1's pattern for upper 32-bits */
      b64.llwork = 0xFFFFFFFFFFFFFFFFull;
      b64.ul.up_work = ~((1 << (i-32)) & 0xFFFFFFFF);
      }

#ifdef ENABLE_DATA_LINES_DEBUG /* debug */
    //printf("i = %0d\n",i);
    printf("next W0's pattern = %016qx\n",b64.llwork);
#endif

    llptr[0] = b64.llwork;         /* write walking 0's to lower DIMM */
    llptr[1] = ~b64.llwork;          /* write walking 1's to upper DIMM */

    //ll_asm_flush_cache(BEG_ADRS_LINES_TEST_ADDR_DR1,CACHE_FLUSH_READ_LENGTH);
    ll_flush_l2c();  /* flush L2 cache in hardware */
    hl_spin_wheel();             /* let operator know we are not hung */

    /* read data back on lower DIMM and verify it */
    data_read = llptr[0];       /* read back lower 64 bits (1st DIMM ) */

    if (data_read != b64.llwork)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0080;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = b64.llwork;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    /* read data back on upper DIMM and verify it */
    data_read = llptr[1];       /* read back upper 64 bits (2nd DIMM ) */

    if (data_read != ~b64.llwork)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0085;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork+8;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = ~b64.llwork;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */
      return;
      }

    i++;
    } while (b64.llwork != 0x7FFFFFFFFFFFFFFFull);

  ll_restore_tlb_entry_0(); /* restore TLB 0 back to original values */

  /* everything passed */
  if (test_results_flag == PASS)
    printf("Passed\n");

}

/*****************************************************************************
 **                  Cavium RAM Address Lines Test - Phase I
 **
 **   This function verifies the address lines to the DDR RAM by writing and
 ** reading a specific test patterns designed to verify each address pin 
 ** connected to the DDR memory.  This is a Phase I test and is called by
 ** the phase I test manager.
 **
 **  The Cavium processor has 128 data bits.  The first 64 are connected to one
 ** DIMM the last 64 are connected to the 2nd DIMM.  Therefore, each DIMM has
 ** its own address and data lines the require verification.
 **
 ** NOTE:  This function assumes there are four DIMMs available for now.
 **
 ** INPUT - "test_no" = test number for this test.
 **       - "exec_count" = current execution count.
 **       - Global variable "ddr_mem_size" must contain the total bytes
 **         of DDR RAM available in the system.
 **
 ** OUTPUT - The data lines in at least the first four DIMM sockets will be
 **          verified to be working.
 **        - Module global variable "test_results_flag" will be set to "FAIL"
 **          if any problems are detected by the data lines test.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void address_lines_test(int test_no, int exec_count)
{
  DECLARE_GLOBAL_DATA_PTR;      /* setup gbl data ptr, need some global data */
  uint64_t ddr_mem_size;        /* total number of bytes of DDR RAM */
  uint64_t llwork;              /* 64-bit working reg */
  int test_results_flag;        /* flag indicating test passed or failed */
  struct error_data eh;         /* create an err hand struct */
  uint64_t asm_result_array[ASM_TEST_DATA_LEN]; /* asm test results array */
  int i;
 
  /**   Must set up TLB to access the 0x00000004 10000000 - 0x00000004 1FFFFFFF 
   ** area - DR1 region. This region is 256MB long for both the TNPA-5644 & 
   ** TNPA-5654 boards.  In this case we use TLB 0 entry.
   **/
  //disp_tlbs();
  hl_spin_wheel();             /* let operator know we are not hung */
  ll_write_tlb_entry(0, BEG_ADRS_LINES_TEST_ADDR_DR1, 
                     BEG_ADRS_LINES_TEST_ADDR_DR1, ADRS_LINES_TEST_LENGTH_DR1,
                     TLB_DVG_BITS);

  //disp_tlbs();

  test_results_flag = PASS;     /* init the flag */

  ddr_mem_size = gd->ram_size;  /* get total size of ddr RAM in bytes */
  //ddr_mem_size = 0x0000000080000000ull; /* DEBUG - force 2BG size */

  //printf("\nddr_mem_size = %016qx\n", ddr_mem_size);

  /**   If more than 2GB of DDR RAM are present on this board we must set up 
   ** TLB's to access the 0x00000000 80000000 - 0x00000001 00000000 (or more)
   ** area - DR2 region. This region is 3.5GB long for boards with 4GB of RAM
   ** but only 2GB long for other boards. The test works fine until it crosses 
   ** the 2GB boundary.  So TLB's need to be set up to access DDR RAM past the
   *  2GB boundary.  Unfortunately, quite a number of TLB's need to be set up
   ** to access DDR RAM past 0x00000000 80000000.  If 4GB is available, we will 
   ** need 8 TLB regions set up (each 256MB long) to allow access to that entire 
   ** region.
   **
   ** In this case we use TLB's 2 - 9 (8 total).
   **/
  if (ddr_mem_size > RAM_BOUNDARY_2GB)
    {
    llwork = RAM_BOUNDARY_2GB;       /* start TLBs at 2GB boundary */
    for (i = 2; i < 10; i++)
      {
        //printf("\nSetting TLB #%02d\n",i);
      ll_write_tlb_entry(i, llwork, llwork, RAM_TLB_LEN, TLB_DVG_BITS);
      llwork += RAM_TLB_LEN; /* calc beg adrs of next region */
      if (llwork >= ddr_mem_size)
        break;
      }
    }

  /**    Write the address lines data to all regions in ascending physical
   ** address order before reading it all back.
   **/

  /* write DR0 region of DDR RAM */
#if 0
  printf("\nWriting DR0 region...\n");
  printf("Beg adrs lines test = %016qx\n",(u64) BEG_ADRS_LINES_TEST_ADDR_DR0);
  printf("End adrs lines test = %016qx\n",
         (u64) (BEG_ADRS_LINES_TEST_ADDR_DR0 + ADRS_LINES_TEST_LENGTH_DR0));
#endif
  ll_ram_adrs_lines_fill_talt_rel(BEG_ADRS_LINES_TEST_ADDR_DR0, 
                                  (BEG_ADRS_LINES_TEST_ADDR_DR0 +
                                   ADRS_LINES_TEST_LENGTH_DR0),
                                 ASM_CODE_REL_ADRS_L2C);

  /* write DR2 region of DDR RAM */
  hl_spin_wheel();             /* let operator know we are not hung */

  /* calc length of DR2 region (Total RAM - DR0 & DR1 region lengths) */
  llwork = (ddr_mem_size - LEN_OF_DR0_DR1_REGIONS);

#if 0
  printf("Writing DR2 region...\n");
  printf("Beg adrs lines test = %016qx\n",(u64) BEG_ADRS_LINES_TEST_ADDR_DR2);
  printf("End adrs lines test = %016qx\n",
         (u64) (BEG_ADRS_LINES_TEST_ADDR_DR2 + llwork));
#endif
  ll_ram_adrs_lines_fill_talt_rel(BEG_ADRS_LINES_TEST_ADDR_DR2, 
                                 (BEG_ADRS_LINES_TEST_ADDR_DR2 + llwork),
                                 ASM_CODE_REL_ADRS_L2C);

  /* write DR1 region of DDR RAM */
  hl_spin_wheel();             /* let operator know we are not hung */
#if 0
  printf("Writing DR1 region...\n");
  printf("Beg adrs lines test = %016qx\n",(u64) BEG_ADRS_LINES_TEST_ADDR_DR1);
  printf("End adrs lines test = %016qx\n",
         (u64) (BEG_ADRS_LINES_TEST_ADDR_DR1 + ADRS_LINES_TEST_LENGTH_DR1));
#endif
  ll_ram_adrs_lines_fill_talt_rel(BEG_ADRS_LINES_TEST_ADDR_DR1, 
                                  (BEG_ADRS_LINES_TEST_ADDR_DR1 +
                                   ADRS_LINES_TEST_LENGTH_DR1),
                                 ASM_CODE_REL_ADRS_L2C);

  /* verify DR0 region contains the correct data pattern */
  hl_spin_wheel();             /* let operator know we are not hung */
  //printf("Reading DR0 region...\n");
  ll_asm_adrs_lines_data_verify_talt_rel((u64)BEG_ADRS_LINES_TEST_ADDR_DR0,
                           ((u64)BEG_ADRS_LINES_TEST_ADDR_DR0 + 
                            ADRS_LINES_TEST_LENGTH_DR0),
                            &asm_result_array[0],ASM_CODE_REL_ADRS_L2C);

  /* see if the code detected any errors */
  if (asm_result_array[ASM_TEST_RESULTS] == ASM_TEST_FAILED)
    {
    eh.call_type = EH_DISP_TYP_INFO;
    eh.error_stop = ES0090;
    eh.sup_error_stop = SES0000;
    eh.fail_adrs = asm_result_array[ASM_TEST_ADRS_AT_FAULT];
    eh.exp_data = asm_result_array[ASM_TEST_EXP_DATA];
    eh.rec_data = asm_result_array[ASM_TEST_BAD_DATA];
    eh.length = (int) BYTES_8;
    eh.test_no = test_no;
    eh.exec_count = exec_count;

    p1_error_handler(&eh);        /* report the error to the system */
    test_results_flag = FAIL;
    ll_restore_all_tlb_entrys(); /* restore all TLBs back to default values */
    return;
    }

  /* verify DR2 region contains the correct data pattern */
   hl_spin_wheel();             /* let operator know we are not hung */
 //printf("Reading DR2 region...\n");
  ll_asm_adrs_lines_data_verify_talt_rel((u64)BEG_ADRS_LINES_TEST_ADDR_DR2,
                           (BEG_ADRS_LINES_TEST_ADDR_DR2 + llwork),
                            &asm_result_array[0],ASM_CODE_REL_ADRS_L2C);

  /* see if the code detected any errors */
  if (asm_result_array[ASM_TEST_RESULTS] == ASM_TEST_FAILED)
    {
    eh.call_type = EH_DISP_TYP_INFO;
    eh.error_stop = ES0100;
    eh.sup_error_stop = SES0000;
    eh.fail_adrs = asm_result_array[ASM_TEST_ADRS_AT_FAULT];
    eh.exp_data = asm_result_array[ASM_TEST_EXP_DATA];
    eh.rec_data = asm_result_array[ASM_TEST_BAD_DATA];
    eh.length = (int) BYTES_8;
    eh.test_no = test_no;
    eh.exec_count = exec_count;

    p1_error_handler(&eh);        /* report the error to the system */
    test_results_flag = FAIL;
    ll_restore_all_tlb_entrys(); /* restore all TLBs back to default values */
    return;
    }

  /* verify DR1 region contains the correct data pattern */
  hl_spin_wheel();             /* let operator know we are not hung */
  //printf("Reading DR1 region...\n");
  ll_asm_adrs_lines_data_verify_talt_rel((u64)BEG_ADRS_LINES_TEST_ADDR_DR1,
                           ((u64)BEG_ADRS_LINES_TEST_ADDR_DR1 + 
                            ADRS_LINES_TEST_LENGTH_DR1),
                            &asm_result_array[0],ASM_CODE_REL_ADRS_L2C);

  /* see if the code detected any errors */
  if (asm_result_array[ASM_TEST_RESULTS] == ASM_TEST_FAILED)
    {
    eh.call_type = EH_DISP_TYP_INFO;
    eh.error_stop = ES0095;
    eh.sup_error_stop = SES0000;
    eh.fail_adrs = asm_result_array[ASM_TEST_ADRS_AT_FAULT];
    eh.exp_data = asm_result_array[ASM_TEST_EXP_DATA];
    eh.rec_data = asm_result_array[ASM_TEST_BAD_DATA];
    eh.length = (int) BYTES_8;
    eh.test_no = test_no;
    eh.exec_count = exec_count;

    p1_error_handler(&eh);        /* report the error to the system */
    test_results_flag = FAIL;
    ll_restore_all_tlb_entrys(); /* restore all TLBs back to default values */
    return;
    }

  ll_restore_all_tlb_entrys(); /* restore all TLBs back to default values */

 /* everything passed */
  if (test_results_flag == PASS)
    printf("Passed\n");

}

/*****************************************************************************
 **                     Cavium RAM Cells Test - Phase I
 **
 **   This function verifies every location (single cell) in every DDR DIMM 
 ** is capable of reading and writing a variety of test patterns proving each
 ** cell has no stuck-ats or stuck-to bits.  In this case, each Cell is
 ** 64-bits long.   This is a Phase I test and is called by the phase I test 
 ** manager.
 **
 **  The Cavium processor has 128 data bits.  The first 64 are connected to one
 ** DIMM the last 64 are connected to the 2nd DIMM.  Therefore, each DIMM has
 ** its own address and data lines the require verification.
 **
 ** NOTE:  This function assumes there are four DIMMs available for now.
 **
 ** INPUT - "test_no" = test number for this test.
 **       - "exec_count" = current execution count.
 **       - Global variable "ddr_mem_size" must contain the total bytes
 **         of DDR RAM available in the system.
 **
 ** OUTPUT - The RAM cells in at least the first four DIMM sockets will be
 **          verified to be working.
 **        - Module global variable "test_results_flag" will be set to "FAIL"
 **          if any problems are detected by the cells test.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void ram_cells_test(int test_no, int exec_count)
{
  /* NOTE: All pointers are still only 32-bits long even though they may
           point to 64-bit data!!!
  */
  DECLARE_GLOBAL_DATA_PTR;      /* setup gbl data ptr, need some global data */
  uint64_t ddr_mem_size;        /* total number of bytes of DDR RAM */
  uint64_t * tp   ;             /* pointer to 64-bit test patterns */
  uint64_t exp_data;            /* data expected back from DIMM */
  uint64_t llwork;              /* 64-bit working register */
  int test_results_flag;        /* flag indicating test passed or failed */
  struct error_data eh;         /* create an Phase I err hand struct */
  uint64_t asm_result_array[ASM_TEST_DATA_LEN]; /* asm test results array */
  int i;

  hl_spin_wheel();             /* let operator know we are not hung */
  /**   Must set up TLB to access the 0x00000004 10000000 - 0x00000004 1FFFFFFF 
   ** area - DR1 region. This region is 256MB long for both the TNPA-5644 & 
   ** TNPA-5654 boards.  In this case we use TLB 0 entry.
   **/
  ll_write_tlb_entry(0, BEG_ADRS_LINES_TEST_ADDR_DR1, 
                     BEG_ADRS_LINES_TEST_ADDR_DR1, ADRS_LINES_TEST_LENGTH_DR1,
                     TLB_DVG_BITS);

  test_results_flag = PASS;     /* init the flag */

  ddr_mem_size = gd->ram_size;  /* get total size of ddr RAM in bytes */

  //printf("\nddr_mem_size = %016qx\n", ddr_mem_size);

  /**   If more than 2GB of DDR RAM are present on this board we must set up 
   ** TLB's to access the 0x00000000 80000000 - 0x00000001 00000000 (or more)
   ** area - DR2 region. This region is 3.5GB long for boards with 4GB of RAM
   ** but only 2GB long for other boards. The test works fine until it crosses 
   ** the 2GB boundary.  So TLB's need to be set up to access DDR RAM past the
   *  2GB boundary.  Unfortunately, quite a number of TLB's need to be set up
   ** to access DDR RAM past 0x00000000 80000000.  If 4GB is available, we will 
   ** need 8 TLB regions set up (each 256MB long) to allow access to that entire 
   ** region.
   **
   ** In this case we use TLB's 2 - 9 (8 total).
   **/
  if (ddr_mem_size > RAM_BOUNDARY_2GB)
    {
    llwork = RAM_BOUNDARY_2GB;       /* start TLBs at 2GB boundary */
    for (i = 2; i < 10; i++)
      {
        //printf("\nSetting TLB #%02d\n",i);
      ll_write_tlb_entry(i, llwork, llwork, RAM_TLB_LEN, TLB_DVG_BITS);
      llwork += RAM_TLB_LEN; /* calc beg adrs of next region */
      if (llwork >= ddr_mem_size)
        break;
      }
    }

  tp = (u64 *) data_test_pats_64b;    /* point to beg of test patterns */

  /**    Perform a cells test on a small piece of RAM we can use to
   ** relocate the actual test for all the remaining blocks of RAM. We
   ** can run this part of the test in L2 cache or maybe from FLASH since 
   ** the block size we are testing is very small.  But we need to run 
   ** from RAM to test the large blocks of remaining RAM.
   **/
  //printf("\nTesting relocatable RAM region...\n");
  do
    {
    exp_data = *tp;                      /* load next test pattern */

    //printf("Next test pattern = %016qx\n",exp_data);

    invalidate_L1_Dcache();

    /* run from FLASH */
    /* write 1st-1k of DR0 region of DDR RAM  */
    ll_fill_ram(BEG_ADRS_LINES_TEST_ADDR_DR0, 
                (BEG_ADRS_LINES_TEST_ADDR_DR0 + RAM_LOGIC_REL_LENGTH),
                exp_data);

    /* need to flush data out of L2 & L1 cache */
    ll_asm_flush_cache(BEG_ADRS_LINES_TEST_ADDR_DR1,CACHE_FLUSH_READ_LENGTH);

    /* run from FLASH */
    hl_spin_wheel();             /* let operator know we are not hung */
    /* verify 1st-1k of DR0 region of DDR RAM (this works!) */
    ll_asm_ram_cells_verify(BEG_ADRS_LINES_TEST_ADDR_DR0, 
                   (BEG_ADRS_LINES_TEST_ADDR_DR0 + RAM_LOGIC_REL_LENGTH),
                    &asm_result_array[0], exp_data);

    /* check the results and report any failures */
    if (asm_result_array[ASM_TEST_RESULTS] == ASM_TEST_FAILED)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0110;
      eh.sup_error_stop = SES0000;
      eh.fail_adrs = asm_result_array[ASM_TEST_ADRS_AT_FAULT];
      eh.exp_data = asm_result_array[ASM_TEST_EXP_DATA];
      eh.rec_data = asm_result_array[ASM_TEST_BAD_DATA];
      eh.length = (int) BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_all_tlb_entrys();/* restore all TLBs back to default values */
      return;
      }

    tp++;                             /* inc pointer to next test pattern */
    } while (*tp != (u64) END_OF_TABLE);
  //printf("\nFinished testing relocatable RAM region...\n");

  /**   At this point a very small portion of DDR RAM has been tested
   ** and can be used to tet the rest of DR RAM.  So relocate the test 
   ** code into this pre-tested DDR RAM area and test the rest of DDR RAM.
   **/
  tp = (u64 *) data_test_pats_64b;    /* point to beg of test patterns */
  do
    {
    exp_data = *tp;                      /* load next test pattern */

    //printf("Next test pattern = %016qx\n",exp_data);
    //printf("Writing RAM region DR0...\n");
    hl_spin_wheel();             /* let operator know we are not hung */
    /* write DR0 region of DDR RAM (- area where code is executing) */
    ll_ram_fill_rel((BEG_ADRS_LINES_TEST_ADDR_DR0 + RAM_LOGIC_REL_LENGTH), 
                   (BEG_ADRS_LINES_TEST_ADDR_DR0 + ADRS_LINES_TEST_LENGTH_DR0),
                    ASM_CODE_REL_ADRS_RAM, exp_data);

    //printf("Writing RAM region DR2...\n");
    /* write DR2 region of DDR RAM */
    /* calc length of DR2 region (Total RAM - DR0 & DR1 region lengths) */
    hl_spin_wheel();             /* let operator know we are not hung */
    llwork = (ddr_mem_size - LEN_OF_DR0_DR1_REGIONS);
    ll_ram_fill_rel(BEG_ADRS_LINES_TEST_ADDR_DR2, 
                   (BEG_ADRS_LINES_TEST_ADDR_DR2 + llwork),
                   ASM_CODE_REL_ADRS_RAM, exp_data);

    //printf("Writing RAM region DR1...\n");
    hl_spin_wheel();             /* let operator know we are not hung */
    /* write DR1 region of DDR RAM */
    ll_ram_fill_rel(BEG_ADRS_LINES_TEST_ADDR_DR1, 
                   (BEG_ADRS_LINES_TEST_ADDR_DR1 +
                   ADRS_LINES_TEST_LENGTH_DR1),
                   ASM_CODE_REL_ADRS_RAM, exp_data);

    /**
     ** All DDR RAM is written, now read it back and verify it.
     **/

    //printf("Verifying RAM region DR0...\n");
    hl_spin_wheel();             /* let operator know we are not hung */
    /* verify DR0 region of DDR RAM (- area where code is executing) */
    ll_asm_ram_cells_verify_rel(
                   (BEG_ADRS_LINES_TEST_ADDR_DR0 + RAM_LOGIC_REL_LENGTH), 
                   (BEG_ADRS_LINES_TEST_ADDR_DR0 + ADRS_LINES_TEST_LENGTH_DR0),
                    &asm_result_array[0], ASM_CODE_REL_ADRS_RAM, exp_data);

    /* check the results and report any failures */
    if (asm_result_array[ASM_TEST_RESULTS] == ASM_TEST_FAILED)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0115;
      eh.sup_error_stop = SES0000;
      eh.fail_adrs = asm_result_array[ASM_TEST_ADRS_AT_FAULT];
      eh.exp_data = asm_result_array[ASM_TEST_EXP_DATA];
      eh.rec_data = asm_result_array[ASM_TEST_BAD_DATA];
      eh.length = (int) BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_all_tlb_entrys();/* restore all TLBs back to default values */
      return;
      }

    //printf("Verifying RAM region DR2...\n");
    hl_spin_wheel();             /* let operator know we are not hung */
    /* verify DR2 region of DDR RAM */
    ll_asm_ram_cells_verify_rel(BEG_ADRS_LINES_TEST_ADDR_DR2, 
                   (BEG_ADRS_LINES_TEST_ADDR_DR2 + llwork),
                    &asm_result_array[0], ASM_CODE_REL_ADRS_RAM, exp_data);

    /* check the results and report any failures */
    if (asm_result_array[ASM_TEST_RESULTS] == ASM_TEST_FAILED)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0120;
      eh.sup_error_stop = SES0000;
      eh.fail_adrs = asm_result_array[ASM_TEST_ADRS_AT_FAULT];
      eh.exp_data = asm_result_array[ASM_TEST_EXP_DATA];
      eh.rec_data = asm_result_array[ASM_TEST_BAD_DATA];
      eh.length = (int) BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_all_tlb_entrys();/* restore all TLBs back to default values */
      return;
      }

    //printf("Verifying RAM region DR1...\n");
    hl_spin_wheel();             /* let operator know we are not hung */
    /* verify DR1 region of DDR RAM */
    ll_asm_ram_cells_verify_rel(BEG_ADRS_LINES_TEST_ADDR_DR1, 
                   (BEG_ADRS_LINES_TEST_ADDR_DR1 +
                   ADRS_LINES_TEST_LENGTH_DR1),
                    &asm_result_array[0], ASM_CODE_REL_ADRS_RAM, exp_data);

    /* check the results and report any failures */
    if (asm_result_array[ASM_TEST_RESULTS] == ASM_TEST_FAILED)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0125;
      eh.sup_error_stop = SES0000;
      eh.fail_adrs = asm_result_array[ASM_TEST_ADRS_AT_FAULT];
      eh.exp_data = asm_result_array[ASM_TEST_EXP_DATA];
      eh.rec_data = asm_result_array[ASM_TEST_BAD_DATA];
      eh.length = (int) BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      test_results_flag = FAIL;
      ll_restore_all_tlb_entrys();/* restore all TLBs back to default values */
      return;
      }

   tp++;                             /* inc pointer to next test pattern */
    } while (*tp != (u64) END_OF_TABLE);

  ll_restore_all_tlb_entrys(); /* restore all TLBs back to default values */
  invalidate_L1_Dcache();

  /* everything passed */
  if (test_results_flag == PASS)
    printf("Passed\n");

}

/*****************************************************************************
 **                  Cavium RAM ECC Cells Test - Phase I
 **
 **   This function verifies the ECC generation and verification logic is
 ** working and every ECC location (single cell) in every DDR DIMM 
 ** is capable of reading and writing a variety of test patterns proving each
 ** ECC cell has no stuck-ats or stuck-to bits.  ECC cells are each 32-bits 
 ** long and contain the syndrome bits for each 12-bit DDR2 RAM cell.  This is
 ** a Phase I test and is called by the phase I test manager.
 **
 ** Test:
 ** - ECC single bit detection.  
 **   There is no way to force a single bit error because we do not have
 **   the ability to write data to RAM and leave the ECC bits alone.  When
 **   ECC is disabled, all ECC bits get written to zero.
 **   So we will have to settle for forcing multi-bit errors.  To do this
 **   we will write data to a location with ECC disabled (forcing all ECC
 **   bits to zero).  Then enable ECC checking and read the data back from
 **   that same location.  We had better get at least a single-bit error
 **   but much more likely get multi-bit errors proving the ECC generation
 **   and checking is working.
 ** - ECC Data Lines test
 **   Verifiy all 32 ECC data bits, on each DIMM, are connected.  This is
 **   a little difficult because we cannot read the actual ECC Data bits back
 **   from the ECC cell but we can read the data the was supposably written
 **   to that cell on the last data write to memory when ECC generation was
 **   enabled.
 ** - ECC Address Lines test
 **   We do not run an ECC address lines test because we have no ability to 
 **   view was is in the ECC cells.  Instead we rely on the normal DDR RAM
 **   address lines test, with ECC enabled, to verify the ECC cells address
 **   lines as well.
 ** - ECC Cells test
 **    ~ Enable ECC generation and checking.
 **    ~ Clear all ECC error registers.
 **    ~ Write a series of special data test patterns that will in turn write
 **      an appropriate test pattern to the ECC cells to verify not bits are
 **      stuck low or high or stuck to another bit.
 **    ~ Verify no ECC failures were detected.
 ** - Clean up any lingering EC failure registers.
 ** - Enable ECC generation/detection again and clear all of memory to 
 **   reset all data and set up initial ECC cells.
 **
 ** NOTE:  This function assumes there are four DIMMs available for now.
 **
 ** INPUT - "test_no" = test number for this test.
 **       - "exec_count" = current execution count.
 **       - Global variable "ddr_mem_size" must contain the total bytes
 **         of DDR RAM available in the system.
 **
 ** OUTPUT - The ECC cells in at least the first four DIMM sockets will be
 **          verified to be working.
 **        - Module global variable "test_results_flag" will be set to "FAIL"
 **          if any problems are detected by the cells test.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void ddr_ram_ecc_test(int test_no, int exec_count)
{
  /* NOTE: All pointers are still only 32-bits long even though they may
           point to 64-bit data!!!
  */
  DECLARE_GLOBAL_DATA_PTR;      /* setup gbl data ptr, need some global data */
  uint64_t ddr_mem_size;        /* total number of bytes of DDR RAM */
  uint64_t * llptr;             /* 64-bit data working pointer */
  uint64_t * tp   ;             /* pointer to 64-bit test patterns */
  uint64_t data_read;           /* data read back from DIMM */
  uint64_t exp_data;            /* data expected back from DIMM */
  uint64_t data_read_sav;       /* saved data read back from DIMM */
  uint64_t exp_data_sav;        /* saved data expected back from DIMM */
  uint64_t fail_adrs;           /* address where failure was detected */
  uint32_t lwork;               /* 32-bit working reg */
  uint64_t llwork;              /* 64-bit working reg */
  char umsg[80];                /* user created message */
  int test_results_flag;        /* flag indicating test passed or failed */
  struct error_data eh;         /* create an err hand struct */
  u32 i;

  test_results_flag = PASS;     /* init the flag */
  ddr_mem_size = gd->ram_size;  /* get total size of ddr RAM in bytes */

  /**
   ** Disable ECC & clear all ECC errror registers 
   **/
  llwork = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); /* read DDR CFG 0 reg */
  llwork &= ~LMC_MEM_CFG0_ECC_ENA;  /* clear ECC enable bit */
  llwork &= ~LMC_MEM_CFG0_DED_ERR;  /* clear any double-bit ECC errores */
  llwork &= ~LMC_MEM_CFG0_SEC_ERR;  /* clear any single-bit ECC errores */
  cvmx_write_csr(CVMX_LMCX_MEM_CFG0(0), llwork); /* disable ECC & clr errors */

  llptr = (u64 *) BEG_ADRS_LINES_TEST_ADDR_DR0; /* point to beg of RAM */

  /* write data and force ECC syndrome bits to zero */
  *llptr = 0x1234567887654321ull;
  diag_flush_cache(CACHE_FLUSH_ADR_DATA_LINES_TEST); /* flush Dcache to RAM */

  /* verify there are no ECC errors detected */
  data_read = (cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)) & LMC_MEM_CFG0_ECC_ERRS);
  exp_data = 0x0ull; /* no ecc error bits should be set at this point */

  if (data_read != exp_data)
    {
    eh.call_type = EH_DISP_TYP_INFO;
    eh.error_stop = ES0150;
    eh.sup_error_stop = SES0000;
    lwork = (uint32_t) llptr;
    fail_adrs = (uint64_t) lwork;
    eh.fail_adrs = fail_adrs;
    eh.exp_data = exp_data;
    eh.rec_data = data_read;
    eh.length = BYTES_8;
    eh.test_no = test_no;
    eh.exec_count = exec_count;

    p1_error_handler(&eh);        /* report the error to the system */
    //report_error(0x00, fail_adrs, exp_data, data_read, BYTES_8);
    test_results_flag = FAIL;
    clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */
    return;
    }

  /**
   **    Now turn on ECC checking, read the same address we wrote above.
   ** Should see an ECC error proving the ECC logic is actually working.
   **/
  llwork = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); /* read DDR CFG 0 reg */
  llwork |= LMC_MEM_CFG0_ECC_ENA;
  cvmx_write_csr(CVMX_LMCX_MEM_CFG0(0), llwork); /* enable ECC gen/checking */

  llwork = *llptr;               /* read data from loc with bad ECC bits */

  /* read DDR config reg */
  data_read = (cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)) & LMC_MEM_CFG0_ECC_ERRS);
  exp_data = 0x0ull; /* set up "no ECC error bits active" for compare */

  if (data_read == exp_data)  /* if no ECC errors, report an error */
    {
    eh.call_type = EH_DISP_TYP_INFO;
    eh.error_stop = ES0160;
    eh.sup_error_stop = SES0000;
    lwork = (uint32_t) llptr;
    fail_adrs = (uint64_t) lwork;
    eh.fail_adrs = fail_adrs;
    eh.exp_data = exp_data;
    eh.rec_data = data_read;
    eh.length = BYTES_8;
    eh.test_no = test_no;
    eh.exec_count = exec_count;

    p1_error_handler(&eh);        /* report the error to the system */
    //report_error(0x00, fail_adrs, exp_data, data_read, BYTES_8);
    test_results_flag = FAIL;
    clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */
    return;
    }

  /* Verify ECC error address captured the correct failure address */
  llwork = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); /* read DDR CFG 0 reg */
  llwork |= LMC_MEM_CFG0_ECC_ENA;
  cvmx_write_csr(CVMX_LMCX_MEM_CFG0(0), llwork); /* enable ECC gen/checking */

  llwork = *llptr;               /* read data from loc with bad ECC bits */

  /* read the "Failing Address" register */
  data_read = cvmx_read_csr(CVMX_LMCX_FADR(0));
  exp_data = EXP_FAIL_ADRS_REG; /* set up expected data in "LMC_FADR" reg */

  if (data_read != exp_data)  /* correct address captured? */
    {
    eh.call_type = EH_DISP_TYP_INFO;
    eh.error_stop = ES0170;
    eh.sup_error_stop = SES0000;
    lwork = (uint32_t) llptr;
    fail_adrs = (uint64_t) lwork;
    eh.fail_adrs = fail_adrs;
    eh.exp_data = exp_data;
    eh.rec_data = data_read;
    eh.length = BYTES_8;
    eh.test_no = test_no;
    eh.exec_count = exec_count;

    p1_error_handler(&eh);        /* report the error to the system */
    //report_error(0x00, fail_adrs, exp_data, data_read, BYTES_8);
    test_results_flag = FAIL;
    clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */
    return;
    }

  /* clear all ECC errors but leave ECC enabled */
  llwork = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); /* read DDR CFG 0 reg */
  llwork &= ~LMC_MEM_CFG0_DED_ERR;  /* clear any double-bit ECC errores */
  llwork &= ~LMC_MEM_CFG0_SEC_ERR;  /* clear any single-bit ECC errores */
  cvmx_write_csr(CVMX_LMCX_MEM_CFG0(0), llwork); /* clr all ECC errors */

  /**
   **  Verify the data lines to the ECC cells by writing then reading a
   ** special set of data patterns that will produce the appropriate
   ** bit patterns to verify the data lines to the ECC cells.
   **/
  tp = (u64 *) ecc_data_test_pats_64b;    /* point to beg of test patterns */

  do
    {
    exp_data = *tp;                      /* load next test pattern */
    *llptr = exp_data;                   /* write it to test location */
    diag_flush_cache(CACHE_FLUSH_ADR_DATA_LINES_TEST); /* flush Dcache to RAM */
    data_read = *llptr;                  /* read it back */

    /* verify data did not change */
    data_read_sav = data_read;      /* save copies in case we need it later */
    exp_data_sav = exp_data;
    if (data_read != exp_data)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0180;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = exp_data;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      //report_error(0x00, fail_adrs, exp_data, data_read, BYTES_8);
      test_results_flag = FAIL;
      clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */
      return;
      }

    /* verify no ECC errors are detected using this test pattern */
    data_read = (cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)) & LMC_MEM_CFG0_ECC_ERRS);
    exp_data = 0x0ull; /* no ecc error bits should be set */

    if (data_read != exp_data)
      {
      eh.call_type = EH_DISP_TYP_INFO_MSG;
      eh.error_stop = ES0150;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = exp_data;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      /* create an additional msg to be displayed */
      sprintf(umsg, "Data exp = %016X\nData rec = %016X\n",exp_data_sav, 
              data_read_sav);
      p1_error_handler(&eh);        /* report the error to the system */
      //report_error(umsg, fail_adrs, exp_data, data_read, BYTES_8);
      test_results_flag = FAIL;
      clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */
      return;
      }

    tp++;                             /* inc pointer to next test pattern */
    } while (*tp != (u64) END_OF_TABLE);

  /**  Write a variety of special test patterns to RAM that will verify the
   ** data lines in each ECC cell are not stuck at any level or stuck to 
   ** another bit.
   **/
  tp = (u64 *) ecc_data_test_pats_64b;    /* point to beg of test patterns */

  do
    {
    llptr = (u64 *) BEG_ADRS_LINES_TEST_ADDR_DR0; /* point to beg of RAM */
    exp_data = *tp;                      /* load next test pattern */

    /* fill ECC Cells with next test pattern */
    for (i = 0; i < (u32) ddr_mem_size; i++)
      llptr[i] = exp_data;

    //diag_flush_cache(CACHE_FLUSH_ADR_DATA_LINES_TEST); /* flush Dcache to RAM */

    /* read back and verify every location */
    exp_data = *tp;                      /* load exp data */
    do
      {
      data_read = *llptr;             /* read next 8-byte location */

      if (data_read != exp_data)
        {
        eh.call_type = EH_DISP_TYP_INFO;
        eh.error_stop = ES0190;
        eh.sup_error_stop = SES0000;
        lwork = (uint32_t) llptr;
        fail_adrs = (uint64_t) lwork;
        eh.fail_adrs = fail_adrs;
        eh.exp_data = exp_data;
        eh.rec_data = data_read;
        eh.length = BYTES_8;
        eh.test_no = test_no;
        eh.exec_count = exec_count;

        p1_error_handler(&eh);        /* report the error to the system */
        //report_error(0x00, fail_adrs, exp_data, data_read, BYTES_8);
        test_results_flag = FAIL;
        clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */
        return;
        }

      llptr++;                        /* inc pointer to next 8-byte adrs */
      } while ((u32) llptr < (u32) ddr_mem_size); /* loop till reach end of DDR2 RAM */

    /* verify no ECC errors are detected using this test pattern */
    data_read = (cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)) & LMC_MEM_CFG0_ECC_ERRS);
    exp_data = 0x0ull; /* no ecc error bits should be set */

    if (data_read != exp_data)
      {
      eh.call_type = EH_DISP_TYP_INFO;
      eh.error_stop = ES0200;
      eh.sup_error_stop = SES0000;
      lwork = (uint32_t) llptr;
      fail_adrs = (uint64_t) lwork;
      eh.fail_adrs = fail_adrs;
      eh.exp_data = exp_data;
      eh.rec_data = data_read;
      eh.length = BYTES_8;
      eh.test_no = test_no;
      eh.exec_count = exec_count;

      p1_error_handler(&eh);        /* report the error to the system */
      //report_error(umsg, fail_adrs, exp_data, data_read, BYTES_8);
      test_results_flag = FAIL;
      clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */
      return;
      }

    tp++;                             /* inc pointer to next test pattern */
    } while (*tp != (u64) END_OF_TABLE);

  clear_and_enable_ecc(); /* clear all ECC errors & enable ECC */

  /* everything passed */
  if (test_results_flag == PASS)
    printf("Passed\n");

}

/*****************************************************************************
 **                   Clear ECC Failures & Enable ECC
 **
 **   This function clears all ECC failure bits in all the appropriate
 ** registers and enables ECC.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - All ECC error registers and error status bits are cleared
 **          or set as follows:
 **          - clear LMC_MEM_CFG0[DED_ERR]
 **          - clear LMC_MEM_CFG0[SEC_ERR]
 **          - clear LMC_FADR
 **          - set LMC_MEM_CFG0[ECC_ENA]
 **
 ** RETURN - Nothing
 **/
void clear_and_enable_ecc(void)
{
  uint64_t llwork;              /* 64-bit working reg */

  /* clear all ECC errors and enable ECC */
  llwork = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); /* read DDR CFG 0 reg */
  llwork &= ~LMC_MEM_CFG0_DED_ERR;  /* clear any double-bit ECC errores */
  llwork &= ~LMC_MEM_CFG0_SEC_ERR;  /* clear any single-bit ECC errores */
  llwork |= LMC_MEM_CFG0_ECC_ENA;
  cvmx_write_csr(CVMX_LMCX_MEM_CFG0(0), llwork); /* clr all ECC errors */

}

/*****************************************************************************
 **                             Display TLBs
 **
 **   This is a debug function to display all the available TLBs in the Octeon.
 ** This function was needed because the emulator could only display 32 of the
 ** 64 possible TLBs.
 **
 ** Input - Nothing
 **
 ** Output - All TLBs will be read from processor and displayed on the screen.
 **
 ** Return - Nothing
 **
 ****************************************************************************/
void disp_tlbs(void)
{
  uint64_t tlb[TLB_ARRAY_LEN];         /* stack space for TLB array */
  union b64_data b64;           /* union to manage a 64-bit test pattern */
  int i;

  printf("\nDump of TLBs...\n");
  for (i = 0; i < MAX_TLBS; i++)
    {
    tlb[TLB_INDEX] = (u64) i;         /* set up index of TLB to read */
    ll_read_tlv(&tlb[0]);              /* get tlb entry */
    printf("tlb: %02X, Mask = %08lX\n",i,(u32) tlb[TLB_MASK_REG]);

    b64.llwork = tlb[TLB_ENTRY_HI_REG];
    printf("EntryHi (Virtual adrs) = %08lX %08lX\n",b64.ul.up_work,
           b64.ul.lo_work);

    b64.llwork = tlb[TLB_ENTRY_LO_0];
    printf("EntryLo 0 (physical adrs) = %08lX %08lX\n",b64.ul.up_work,
           b64.ul.lo_work);

    b64.llwork = tlb[TLB_ENTRY_LO_1];
    printf("EntryLo 1 (physical adrs) = %08lX %08lX\n",b64.ul.up_work,
           b64.ul.lo_work);
    }

}

/*****************************************************************************
 **                    Restore TLB Zero To Original Values
 **
 **    This function restore TLB 0 to its original values before the RAM
 ** test were executed.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - The TLB entry 0 will be set to the values it had after reset but
 **          before the RAM test were executed.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void ll_restore_tlb_entry_0(void)
{
  uint64_t tlb[TLB_ARRAY_LEN];  /* space for creating tlb */

  tlb[TLB_INDEX] = (u64) 0;  /* index of TLB to be written */

  tlb[TLB_MASK_REG] = 0; /* power up value */

  /* set up physical adrs of region */
  tlb[TLB_ENTRY_HI_REG] = 0xC001FFFF9007E000ull;

  tlb[TLB_ENTRY_LO_0] = (u64) 0;
    
  tlb[TLB_ENTRY_LO_1] = (u64) 0;

  ll_write_tlv(&tlb[0]);      /* restore the TLB */

}

#if 0 /* moved to "mem_tests.c" */
/*****************************************************************************
 **                             Set Up TLB
 **
 **    This function sets up and enables a TLB entry as specified by the 
 ** calling code
 **
 ** INPUT - "index" = index of TLB to be written.
 **       - "phy_adrs" = actual physical address of region to be mapped.
 **       - "vadrs" = virtual address of region to be mapped.
 **       - "page_length" = total size, in bytes, of the region to be mapped.
 **        - "attrib" = Region attributes.  This value is written to bits 5-0 of
 **          registers "EntryLo0" & "EntryLo1".
 **
 **       NOTE: There are two registers that set up the virtual address of the 
 **             region: "EntryLo0" & "EntryLo1".  "EntryLo0" is always set up 
 **             to the beginning of the virtual region (the even page).  
 **             "EntryLo1" is set to "EntryLo0" + 1/2 the value of the 
 **             "page_length" parameter (the odd page).
 **
 ** OUTPUT - The TLB entry specified by the "index" parameter is set up to
 **          the values set up by the calling code.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void ll_write_tlb_entry(u64 index, u64 phy_adrs, u64 vadrs, u64 page_length, 
                        u64 attrib)
{
  uint64_t llwork;              /* 64-bit working reg */
  uint64_t llwork2;             /* 2nd 64-bit working reg */
  uint64_t tlb[TLB_ARRAY_LEN];  /* space for creating tlb */
  u32 i;

  tlb[TLB_INDEX] = index;  /* index of TLB to be written */

  /* convert the length into a page mask */
  llwork = 0;
  if (page_length > MEM_4KB_LENGTH)
    {
    llwork2 = (page_length/2); /* calc len of each page */
    i = 0;
 
    do
      {
      llwork |= (u64) (1 << i);
      i++;
      llwork2 = (llwork2 >> 1);
      } while (llwork2 > 0);
    }

  llwork = (llwork & MASK_REG_256MB); /* clear the bits we don't use */
  tlb[TLB_MASK_REG] = llwork; /* set up mask reg (size of each page) */

  /* set up physical adrs of region */
  tlb[TLB_ENTRY_HI_REG] = phy_adrs;

  tlb[TLB_ENTRY_LO_0] =            /* set up virtual adrs of even page */
    (u64) (((vadrs >> 6) & ~0x03Full) | attrib);
    
  llwork = (vadrs + (page_length / 2)); /* calc odd page virtual adrs */
  tlb[TLB_ENTRY_LO_1] =             /* set up virtual adrs of odd page */
    (u64) (((llwork >> 6) & ~0x03Full) | attrib);

#if 0
  printf("\nindex = %016qx",tlb[TLB_INDEX]);
  printf("\nmask = %016qx\n",tlb[TLB_MASK_REG]);
  printf("\nEntryHi = %016qx\n",tlb[TLB_ENTRY_HI_REG]);
  printf("\nEntryLo0 = %016qx\n",tlb[TLB_ENTRY_LO_0]);
  printf("\nEntryLo1 = %016qx\n",tlb[TLB_ENTRY_LO_1]);
#endif

  ll_write_tlv(&tlb[0]);      /* write the TLB */

}
#endif

/*****************************************************************************
 **                         Flush L2 Cache
 **
 **    This function Flushes all sets and ways of the entire L2 Cache thereby
 ** forcing all dirty data to be written to RAM.
 **
 ** NOTE:  This function is a copy of function "cvmx_l2c_flush()" from module
 **        "cvmx-l2c.c" and has been renamed and modified slightly here to
 **        work with the diagnostics code.
 **
 ** INPUT - Nothing
 ** 
 ** OUTPUT - L2 cache will be flushed and completely invalid.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void ll_flush_l2c(void)
{
    uint64_t assoc, set;
    uint64_t n_assoc, n_set;
    cvmx_l2c_dbg_t l2cdbg;

    //cvmx_spinlock_lock(&cvmx_l2c_spinlock);

    l2cdbg.u64 = 0;
    //if (!OCTEON_IS_MODEL(OCTEON_CN30XX))
    //    l2cdbg.s.ppnum = cvmx_get_core_num();
    l2cdbg.s.finv = 1;
    //n_set = CVMX_L2_SETS;
    n_set = 0x800;
    //n_assoc = l2_size_half() ? (CVMX_L2_ASSOC/2) : CVMX_L2_ASSOC ;
    n_assoc = 8;
    for(set=0; set < n_set; set++)
    {
        for(assoc = 0; assoc < n_assoc; assoc++)
        {
            l2cdbg.s.set = assoc;
            /* Enter debug mode, and make sure all other writes complete before we
            ** enter debug mode */
            CVMX_SYNCW;
            cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
            cvmx_read_csr(CVMX_L2C_DBG);

            CVMX_PREPARE_FOR_STORE (CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 
                                                 set*CVMX_CACHE_LINE_SIZE), 0);
            CVMX_SYNCW; /* Push STF out to L2 */
            /* Exit debug mode */
            CVMX_SYNC;
            cvmx_write_csr(CVMX_L2C_DBG, 0);
            cvmx_read_csr(CVMX_L2C_DBG);
        }
    }

    //cvmx_spinlock_unlock(&cvmx_l2c_spinlock);

}


#if 0
/*****************************************************************************
 **                    Display DDR Controller registers
 **
 **    This functiondiaplays all the configuration registers for both DDR 
 ** controllers (LMC0 & LMC1).  To do this a TLB must be set up then the
 ** registers can be dumped.
 **
 ** NOTE:  This code hangs when executed but the TLBs do work.  So This code
 **        was left in in case we need it again some day.
 **
 ** INPUT - Nothing
 ** 
 ** OUTPUT - Both DDR controller registers are displayed on the console.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void disp_lmcx_regs(void)
{
  uint64_t * reg_ptr;                /* pointer to DDR controller regs */
  uint64_t data;                     /* data read */
  uint64_t cur_ptr;                  /* current pointer value */

  int i;

#if 1
  /* this TLB set up works */
  ll_write_tlb_entry(0, 0x0001180088000000ull, 
                     0x0001180088000000ull, 0x0000000000010000ull,
                     TLB_DVG_BITS);

  /* this TLB set up works */
  ll_write_tlb_entry(1, 0x00011800E8000000ull, 
                     0x00011800E8000000ull, 0x0000000000010000ull,
                     TLB_DVG_BITS);

  /* this TLB set up works */
  ll_write_tlb_entry(2, 0x0001180080000000ull, 
                     0x0001180080000000ull, 0x0000000000001000ull,
                     TLB_DVG_BITS);
#endif

  //reg_ptr = (uint64_t *) 0x0001180088000000ull; /* beg of LMC0 regs */
  reg_ptr = (uint64_t *) 0x8001180088000000ull; /* beg of LMC0 regs */

  printf("\n");
  for (i = 0; i < 27; i++)
    {
    data = *reg_ptr;
    cur_ptr = reg_ptr;
    printf("%016qx = %016qx\n",cur_ptr,data);
    reg_ptr++;
    }

  printf("\n");
  //reg_ptr = (uint64_t *) 0x00011800E8000000ull; /* beg of LMC1 regs */
  reg_ptr = (uint64_t *) 0x80011800E8000000ull; /* beg of LMC1 regs */

  printf("\n");
  for (i = 0; i < 27; i++)
    {
    data = *reg_ptr;
    cur_ptr = reg_ptr;
    printf("%016qx = %016qx\n",cur_ptr,data);
    reg_ptr++;
    }

}
#endif /* end if 0 */
