/**   mem_tests.c
 **
 **   This module includes all the low-level DDR2 RAM tests for the 
 ** appropriate platform based on system flags set at the time of compile.
 **
 **   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
 **
 **   Date   INTLS Comments
 ** -------- ----- --------------------------------------------
 ** 06-29-09  TMS  Added support for TNPA-5651x board.
 **
 **/
#include <common.h>
#include <config.h>
#include "common_mem_test.h"
#include "asm_utils.h"

/*  Common patterns used to verify the 128-bit data lines to the DIMMs.
    Note:  Last pattern is zero to leave RAM cleared.
 */
uint64_t data_test_pats_64b[] =
  { 
    0x5555555555555555ull, 0xAAAAAAAAAAAAAAAAull, 
    0x0F0F0F0F0F0F0F0Full, 0xF0F0F0F0F0F0F0F0ull,
    0xDDDDDDDDDDDDDDDDull, 0x3333333333333333ull,
    0xD3D3D3D3D3D3D3D3ull, 0x3D3D3D3D3D3D3D3Dull,
    0xFFFFFFFFFFFFFFFFull, 0x0000000000000000ull,
    END_OF_TABLE
  };

/*  Common patterns used to verify the data lines to the DIMM's ECC cells.
    Note:  Last pattern is zero to leave RAM cleared.
 */
uint64_t ecc_data_test_pats_64b[] =
  { 
    0x1111111111111111ull, 0xEEEEEEEEEEEEEEEEull, 
    0x8888888888888888ull, 0x7777777777777777ull,
    0x1234567887654321ull, 0x8765432112345678ull,
    0x4242424242424242ull, 0xBDBDBDBDBDBDBDBDull,
    0xFFFFFFFFFFFFFFFFull, 0x0000000000000000ull,
    END_OF_TABLE
  };

/* compile for NPA-56x4 AMC board */
#ifdef octeon_tnpa56x4
#include "mem_test_npa56x4.c"    /* ddr RAM tests */
#include "pm_mem_test_npa56x4.c" /* presistent memory tests */
#endif

/* compile for NPA-5651x AMC board */
#ifdef octeon_tnpa5651x
#include "mem_test_npa56x4.c"    /* ddr RAM tests */
#include "pm_mem_test_npa56x4.c" /* presistent memory tests */
#endif

/* files to compile tests for AT2 5810 blade */
#ifdef octeon_at5810
#include "mem_test_at5810.c"
#endif

/*****************************************************************************
 **                         Flush Data Cache
 **
 **    This function forces the core's Dcache and the L2cache to flush its
 ** contents to RAM.  To do this we simply read a length of data equal to the
 ** largest Dcache we need to flush from a location at least as far away.  
 ** Since we do not know what that address might be, we must use the location 
 ** specified by the calling code.
 **
 ** INPUT - "read_address" = location of RAM to read to flush all Dcaches.
 **
 ** OUTPUT - Both the core Dcache and the L2Cache will be flushed to RAM and 
 **          Dcache will end up filled with "don't care" data.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void diag_flush_cache(uint64_t * read_address)
{
  uint64_t * llptr;             /* 64-bit data pointer */
  uint64_t llwork;              /* 64-bit working register */
  unsigned long i;

  llptr = read_address; /* set up data read pointer */
  llwork = 0ull;

  /* read it quickly and leave */
  for (i = 0; i < CACHE_FLUSH_READ_LENGTH; i++)
#if 0 /* read option */
    llwork = *llptr++;
#else /* write option */
    *llptr++ = llwork++;
#endif

}

#if 1
/*****************************************************************************
 **                             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" = vitrual 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 */

}

/*****************************************************************************
 **                   Restore All TLB(s) To Original Values
 **
 **    This function restores all TLB entries to their original values 
 ** that were set up in the "start.S" module.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - All TLBs will be reset to their original values.
 **
 ** RETURN - Nothing
 **
 *****************************************************************************/
void ll_restore_all_tlb_entrys(void)
{
  uint64_t tlb[TLB_ARRAY_LEN];  /* space for creating tlb */
  uint64_t llwork;              /* 64-bit working var */
  uint64_t i;

  /**   Reset the TLBs from largest to smallest index.  This is how it is done
   ** in "start.S" and it works much better this way. 
   **/
  for (i = 0; i <= MAX_TLB_INDEX; i++)
    {
    tlb[TLB_INDEX] = (u64) (MAX_TLB_INDEX - i);  /* index of TLB to be written */

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

    /**
     ** set up physical adrs of region 
     **/
    /* calc Entry Hi (thx) register value */
    llwork = (TLB_ENTRY_HI_REG_DEF | (i * TLB_ENTRY_HI_INC));
    tlb[TLB_ENTRY_HI_REG] = llwork;
#if 0
    printf ("\nIndex = %016qx, ENTRY HI reg = %016qx\n",
            (MAX_TLB_INDEX - i), llwork);
#endif

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

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

}


#endif
 
