#include <common.h>
#include "cvmx.h"
#include "cvmx-fau.h"
#include "cvmx-llm.h"

#include <octeon_eeprom_types.h>

#if defined(CONFIG_OCTEON_W3860)
static void tWriteRldram(cvmx_llm_address_t addr, uint32_t size, int display);
#endif
static inline uint32_t tReadRldram(cvmx_llm_address_t addr, uint32_t size);
static inline cvmx_llm_address_t createAddr(uint32_t addr, int replType);
extern int octeon_post_error_store(uint8_t);

#define bs(x)				\
{							\
	int i;					\
	for (i=0; i<x; i++) {	\
		printf("\b");		\
	}						\
}
#if defined(CONFIG_OCTEON_W3860)
int testLlm(uint32_t addr, uint32_t size, int replType, int display)
{
	uint32_t correct = (uint32_t)size * (size - 1) / 2;
	uint32_t total;
	
	printf("rldram test: ");
	if (!display) { printf( "running without display\n" ); }

	cvmx_fau_atomic_write32(CVMX_FAU_REG_AVAIL_BASE, 0 );
	tWriteRldram(createAddr(addr, replType), size, display);

	total = tReadRldram(createAddr(addr, replType), size);
	int error = (total != correct);

    if (error) {
        printf("Data ERROR: read 0x%08ld expected 0x%08ld\n", (unsigned long)total, (unsigned long)correct);
        cvmx_fau_atomic_add32(CVMX_FAU_REG_AVAIL_BASE, 1);
		octeon_post_error_store(RLDRAM_FAILURE); /* add failure code */
    }

	if(cvmx_fau_fetch_and_add32(CVMX_FAU_REG_AVAIL_BASE, 0)) {		
		return -1;
	}
	printf("\n");
	return 1;

}
#endif
#if defined(CONFIG_OCTEON_W3860)
static void tWriteRldram(cvmx_llm_address_t addr, uint32_t size, int display)
{
    uint32_t i;
    cvmx_llm_data_t data;

    for (i=0; i<size; i++)
    {
        data.u64 = i;
        data.cn38xx_par.par = cvmx_llm_parity(i);
        cvmx_llm_write36(addr, data.u64, 0);
        addr.u64 += 4; 		
		if(display) { printf("0x%08x", addr.u64); bs(10); }
	}
}
#endif
static inline uint32_t tReadRldram(cvmx_llm_address_t addr, uint32_t size)
{
    uint32_t sum = 0;
    uint32_t i;
    cvmx_llm_data_t data;

    for (i=0; i<size; i++)
    {
        CVMX_MT_LLM_READ_ADDR(0,addr.u64);   
        addr.u64 += 4;             
        CVMX_MF_LLM_DATA(0,data.u64); 
        if (data.s.xxor)
        {
            printf("Parity ERROR: addr=0x%08ld data=0x%08ld\n", (unsigned long)addr.u64, (unsigned long)data.u64);
            return 0;
        }
        sum += data.cn38xx_par.dat;
    }
    return sum;
}

static inline cvmx_llm_address_t createAddr(uint32_t addr, int replType)
{
    cvmx_llm_address_t newAddr;

    newAddr.u64 = 0;
    newAddr.s.address = addr;
    newAddr.s.repl = replType;

    return newAddr;
}


