bios: move memtest from liblitedram to libbase

This commit is contained in:
Jędrzej Boczar 2020-06-24 12:21:34 +02:00
parent 3a5aec6933
commit 3b084b284a
8 changed files with 422 additions and 234 deletions

View File

@ -216,16 +216,6 @@ define_command(sdrwloff, sdrwloff, "Disable write leveling", LITEDRAM_CMDS);
define_command(sdrlevel, sdrlevel, "Perform read/write leveling", LITEDRAM_CMDS); define_command(sdrlevel, sdrlevel, "Perform read/write leveling", LITEDRAM_CMDS);
#endif #endif
/**
* Command "memtest"
*
* Run a memory test
*
*/
#ifdef CSR_SDRAM_BASE
define_command(memtest, memtest, "Run a memory test", LITEDRAM_CMDS);
#endif
/** /**
* Command "spdread" * Command "spdread"
* *

View File

@ -2,6 +2,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <memtest.h>
#include <generated/csr.h> #include <generated/csr.h>
@ -137,3 +138,175 @@ static void mc(int nb_params, char **params)
} }
define_command(mc, mc, "Copy address space", MEM_CMDS); define_command(mc, mc, "Copy address space", MEM_CMDS);
/**
* Command "memtest"
*
* Run a memory test
*
*/
static void memtest_handler(int nb_params, char **params)
{
char *c;
unsigned int *addr;
unsigned long maxsize = ~0uL;
if (nb_params < 1) {
printf("memtest <addr> [<maxsize>]");
return;
}
addr = (unsigned int *)strtoul(params[0], &c, 0);
if (*c != 0) {
printf("Incorrect address");
return;
}
if (nb_params >= 2) {
maxsize = strtoul(params[1], &c, 0);
if (*c != 0) {
printf("Incorrect max size");
return;
}
}
memtest(addr, maxsize);
}
define_command(memtest, memtest_handler, "Run a memory test", MEM_CMDS);
/**
* Command "memspeed"
*
* Run a memory speed test
*
*/
static void memspeed_handler(int nb_params, char **params)
{
char *c;
unsigned int *addr;
unsigned long size;
bool read_only = false;
if (nb_params < 1) {
printf("memspeed <addr> <size> [<readonly>]");
return;
}
addr = (unsigned int *)strtoul(params[0], &c, 0);
if (*c != 0) {
printf("Incorrect address");
return;
}
size = strtoul(params[1], &c, 0);
if (*c != 0) {
printf("Incorrect size");
return;
}
if (nb_params >= 3) {
read_only = (bool) strtoul(params[2], &c, 0);
if (*c != 0) {
printf("Incorrect readonly value");
return;
}
}
memspeed(addr, size, read_only);
}
define_command(memspeed, memspeed_handler, "Run a memory speed test", MEM_CMDS);
#ifdef CSR_DEBUG_PRINTER
/**
* Command "csrprint"
*
* Print CSR values
*
*/
static void csrprint(int nb_params, char **params)
{
print_csrs();
}
define_command(csrprint, csrprint, "Print CSR values", MEM_CMDS);
#endif
#ifdef CSR_WB_SOFTCONTROL_BASE
static void wbr(int nb_params, char **params)
{
char *c;
unsigned int *addr;
unsigned int length;
unsigned int i;
if (nb_params < 1) {
printf("mr <address> [length]");
return;
}
addr = (unsigned int *)strtoul(params[0], &c, 0);
if (*c != 0) {
printf("Incorrect address");
return;
}
if (nb_params == 1) {
length = 4;
} else {
length = strtoul(params[1], &c, 0);
if(*c != 0) {
printf("\nIncorrect length");
return;
}
}
for (i = 0; i < length; ++i) {
wb_softcontrol_adr_write((unsigned long)(addr + i));
wb_softcontrol_read_write(1);
printf("0x%08x: 0x%08x\n", (unsigned long)(addr + i), wb_softcontrol_data_read());
}
}
define_command(wbr, wbr, "Read using softcontrol wishbone controller", MEM_CMDS);
static void wbw(int nb_params, char **params)
{
char *c;
unsigned int *addr;
unsigned int value;
unsigned int count;
unsigned int i;
if (nb_params < 2) {
printf("mw <address> <value> [count]");
return;
}
addr = (unsigned int *)strtoul(params[0], &c, 0);
if (*c != 0) {
printf("Incorrect address");
return;
}
value = strtoul(params[1], &c, 0);
if(*c != 0) {
printf("Incorrect value");
return;
}
if (nb_params == 2) {
count = 1;
} else {
count = strtoul(params[2], &c, 0);
if(*c != 0) {
printf("Incorrect count");
return;
}
}
wb_softcontrol_data_write(value);
for (i = 0; i < count; i++) {
wb_softcontrol_adr_write((unsigned long)(addr + i));
wb_softcontrol_write_write(1);
}
}
define_command(wbw, wbw, "Write using softcontrol wishbone controller", MEM_CMDS);
#endif

View File

@ -0,0 +1,13 @@
#ifndef __MEMTEST_H
#define __MEMTEST_H
#include <stdbool.h>
int memtest(unsigned int *addr, unsigned long maxsize);
void memspeed(unsigned int *addr, unsigned long size, bool read_only);
int memtest_addr(unsigned int *addr, unsigned long size, int random);
int memtest_data(unsigned int *addr, unsigned long size, int random);
int memtest_bus(unsigned int *addr, unsigned long size);
#endif /* __MEMTEST_H */

View File

@ -17,7 +17,8 @@ OBJECTS = exception.o \
strcasecmp.o \ strcasecmp.o \
i2c.o \ i2c.o \
div64.o \ div64.o \
progress.o progress.o \
memtest.o
all: crt0.o libbase.a libbase-nofloat.a all: crt0.o libbase.a libbase-nofloat.a

View File

@ -0,0 +1,228 @@
#include "memtest.h"
#include <stdio.h>
#include <lfsr.h>
#include <system.h>
#include <generated/soc.h>
#include <generated/csr.h>
// #define MEMTEST_BUS_DEBUG
// #define MEMTEST_DATA_DEBUG
// #define MEMTEST_ADDR_DEBUG
#ifndef MEMTEST_BUS_SIZE
#define MEMTEST_BUS_SIZE (512)
#endif
#ifndef MEMTEST_DATA_SIZE
#define MEMTEST_DATA_SIZE (2*1024*1024)
#endif
#define MEMTEST_DATA_RANDOM 1
#ifndef MEMTEST_ADDR_SIZE
#define MEMTEST_ADDR_SIZE (32*1024)
#endif
#define MEMTEST_ADDR_RANDOM 0
#define ONEZERO 0xAAAAAAAA
#define ZEROONE 0x55555555
static unsigned int seed_to_data_32(unsigned int seed, int random)
{
return random ? lfsr(32, seed) : seed + 1;
}
static unsigned short seed_to_data_16(unsigned short seed, int random)
{
return random ? lfsr(16, seed) : seed + 1;
}
int memtest_bus(unsigned int *addr, unsigned long size)
{
volatile unsigned int *array = addr;
int i, errors;
unsigned int rdata;
errors = 0;
for(i = 0; i < size/4;i++) {
array[i] = ONEZERO;
}
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i = 0; i < size/4; i++) {
rdata = array[i];
if(rdata != ONEZERO) {
errors++;
#ifdef MEMTEST_BUS_DEBUG
printf("[bus: 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ONEZERO);
#endif
}
}
for(i = 0; i < size/4; i++) {
array[i] = ZEROONE;
}
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i = 0; i < size/4; i++) {
rdata = array[i];
if(rdata != ZEROONE) {
errors++;
#ifdef MEMTEST_BUS_DEBUG
printf("[bus 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ZEROONE);
#endif
}
}
return errors;
}
int memtest_data(unsigned int *addr, unsigned long size, int random)
{
volatile unsigned int *array = addr;
int i, errors;
unsigned int seed_32;
unsigned int rdata;
errors = 0;
seed_32 = 1;
for(i = 0; i < size/4; i++) {
seed_32 = seed_to_data_32(seed_32, random);
array[i] = seed_32;
}
seed_32 = 1;
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i = 0; i < size/4; i++) {
seed_32 = seed_to_data_32(seed_32, random);
rdata = array[i];
if(rdata != seed_32) {
errors++;
#ifdef MEMTEST_DATA_DEBUG
printf("[data 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, seed_32);
#endif
}
}
return errors;
}
int memtest_addr(unsigned int *addr, unsigned long size, int random)
{
volatile unsigned int *array = addr;
int i, errors;
unsigned short seed_16;
unsigned short rdata;
errors = 0;
seed_16 = 1;
for(i = 0; i < size/4; i++) {
seed_16 = seed_to_data_16(seed_16, random);
array[(unsigned int) seed_16] = i;
}
seed_16 = 1;
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i = 0; i < size/4; i++) {
seed_16 = seed_to_data_16(seed_16, random);
rdata = array[(unsigned int) seed_16];
if(rdata != i) {
errors++;
#ifdef MEMTEST_ADDR_DEBUG
printf("[addr 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, i);
#endif
}
}
return errors;
}
void memspeed(unsigned int *addr, unsigned long size, bool read_only)
{
volatile unsigned int *array = addr;
int i;
unsigned int start, end;
unsigned long write_speed = 0;
unsigned long read_speed;
__attribute__((unused)) unsigned long data;
const unsigned int sz = sizeof(unsigned long);
/* init timer */
timer0_en_write(0);
timer0_reload_write(0);
timer0_load_write(0xffffffff);
timer0_en_write(1);
/* write speed */
if (!read_only) {
timer0_update_value_write(1);
start = timer0_value_read();
for(i = 0; i < size/sz; i++) {
array[i] = i;
}
timer0_update_value_write(1);
end = timer0_value_read();
write_speed = (8*size*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
}
/* flush CPU and L2 caches */
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
/* read speed */
timer0_en_write(1);
timer0_update_value_write(1);
start = timer0_value_read();
for(i = 0; i < size/sz; i++) {
data = array[i];
}
timer0_update_value_write(1);
end = timer0_value_read();
read_speed = (8*size*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
printf("Memspeed Writes: %ldMbps Reads: %ldMbps\n", write_speed, read_speed);
}
int memtest(unsigned int *addr, unsigned long maxsize)
{
int bus_errors, data_errors, addr_errors;
unsigned long bus_size = MEMTEST_BUS_SIZE < maxsize ? MEMTEST_BUS_SIZE : maxsize;
unsigned long data_size = MEMTEST_DATA_SIZE < maxsize ? MEMTEST_DATA_SIZE : maxsize;
unsigned long addr_size = MEMTEST_ADDR_SIZE < maxsize ? MEMTEST_ADDR_SIZE : maxsize;
bus_errors = memtest_bus(addr, bus_size);
if(bus_errors != 0)
printf("Memtest bus failed: %d/%d errors\n", bus_errors, bus_size/4);
data_errors = memtest_data(addr, data_size, MEMTEST_DATA_RANDOM);
if(data_errors != 0)
printf("Memtest data failed: %d/%d errors\n", data_errors, data_size/4);
addr_errors = memtest_addr(addr, addr_size, MEMTEST_ADDR_RANDOM);
if(addr_errors != 0)
printf("Memtest addr failed: %d/%d errors\n", addr_errors, addr_size/4);
if(bus_errors + data_errors + addr_errors != 0)
return 0;
else {
printf("Memtest OK\n");
memspeed(addr, data_size, false);
return 1;
}
}

View File

@ -12,6 +12,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <memtest.h>
#include <lfsr.h>
#ifdef CSR_SDRAM_BASE #ifdef CSR_SDRAM_BASE
#include <generated/sdram_phy.h> #include <generated/sdram_phy.h>
@ -20,12 +22,14 @@
#include <system.h> #include <system.h>
#include "sdram.h" #include "sdram.h"
#include "lfsr.h"
// FIXME(hack): If we don't have main ram, just target the sram instead. // FIXME(hack): If we don't have main ram, just target the sram instead.
#ifndef MAIN_RAM_BASE #ifndef MAIN_RAM_BASE
#define MAIN_RAM_BASE SRAM_BASE #define MAIN_RAM_BASE SRAM_BASE
#endif #endif
#ifndef MAIN_RAM_SIZE
#define MAIN_RAM_SIZE SRAM_SIZE
#endif
__attribute__((unused)) static void cdelay(int i) __attribute__((unused)) static void cdelay(int i)
{ {
@ -725,227 +729,8 @@ static void read_level(int module)
#endif /* CSR_SDRAM_BASE */ #endif /* CSR_SDRAM_BASE */
static unsigned int seed_to_data_32(unsigned int seed, int random)
{
if (random)
return lfsr(32, seed);
else
return seed + 1;
}
static unsigned short seed_to_data_16(unsigned short seed, int random)
{
if (random)
return lfsr(16, seed);
else
return seed + 1;
}
#define ONEZERO 0xAAAAAAAA
#define ZEROONE 0x55555555
#ifndef MEMTEST_BUS_SIZE
#define MEMTEST_BUS_SIZE (512)
#endif
//#define MEMTEST_BUS_DEBUG
static int memtest_bus(void)
{
volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
int i, errors;
unsigned int rdata;
errors = 0;
for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
array[i] = ONEZERO;
}
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
rdata = array[i];
if(rdata != ONEZERO) {
errors++;
#ifdef MEMTEST_BUS_DEBUG
printf("[bus: 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ONEZERO);
#endif
}
}
for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
array[i] = ZEROONE;
}
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
rdata = array[i];
if(rdata != ZEROONE) {
errors++;
#ifdef MEMTEST_BUS_DEBUG
printf("[bus 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ZEROONE);
#endif
}
}
return errors;
}
#ifndef MEMTEST_DATA_SIZE
#define MEMTEST_DATA_SIZE (2*1024*1024)
#endif
#define MEMTEST_DATA_RANDOM 1
//#define MEMTEST_DATA_DEBUG
static int memtest_data(void)
{
volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
int i, errors;
unsigned int seed_32;
unsigned int rdata;
errors = 0;
seed_32 = 1;
for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
seed_32 = seed_to_data_32(seed_32, MEMTEST_DATA_RANDOM);
array[i] = seed_32;
}
seed_32 = 1;
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
seed_32 = seed_to_data_32(seed_32, MEMTEST_DATA_RANDOM);
rdata = array[i];
if(rdata != seed_32) {
errors++;
#ifdef MEMTEST_DATA_DEBUG
printf("[data 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, seed_32);
#endif
}
}
return errors;
}
#ifndef MEMTEST_ADDR_SIZE
#define MEMTEST_ADDR_SIZE (32*1024)
#endif
#define MEMTEST_ADDR_RANDOM 0
//#define MEMTEST_ADDR_DEBUG
static int memtest_addr(void)
{
volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
int i, errors;
unsigned short seed_16;
unsigned short rdata;
errors = 0;
seed_16 = 1;
for(i=0;i<MEMTEST_ADDR_SIZE/4;i++) {
seed_16 = seed_to_data_16(seed_16, MEMTEST_ADDR_RANDOM);
array[(unsigned int) seed_16] = i;
}
seed_16 = 1;
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
for(i=0;i<MEMTEST_ADDR_SIZE/4;i++) {
seed_16 = seed_to_data_16(seed_16, MEMTEST_ADDR_RANDOM);
rdata = array[(unsigned int) seed_16];
if(rdata != i) {
errors++;
#ifdef MEMTEST_ADDR_DEBUG
printf("[addr 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, i);
#endif
}
}
return errors;
}
static void memspeed(void)
{
volatile unsigned long *array = (unsigned long *)MAIN_RAM_BASE;
int i;
unsigned int start, end;
unsigned long write_speed;
unsigned long read_speed;
__attribute__((unused)) unsigned long data;
const unsigned int sz = sizeof(unsigned long);
/* init timer */
timer0_en_write(0);
timer0_reload_write(0);
timer0_load_write(0xffffffff);
timer0_en_write(1);
/* write speed */
timer0_update_value_write(1);
start = timer0_value_read();
for(i=0;i<MEMTEST_DATA_SIZE/sz;i++) {
array[i] = i;
}
timer0_update_value_write(1);
end = timer0_value_read();
write_speed = (8*MEMTEST_DATA_SIZE*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
/* flush CPU and L2 caches */
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
/* read speed */
timer0_en_write(1);
timer0_update_value_write(1);
start = timer0_value_read();
for(i=0;i<MEMTEST_DATA_SIZE/sz;i++) {
data = array[i];
}
timer0_update_value_write(1);
end = timer0_value_read();
read_speed = (8*MEMTEST_DATA_SIZE*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
printf("Memspeed Writes: %ldMbps Reads: %ldMbps\n", write_speed, read_speed);
}
int memtest(void)
{
int bus_errors, data_errors, addr_errors;
bus_errors = memtest_bus();
if(bus_errors != 0)
printf("Memtest bus failed: %d/%d errors\n", bus_errors, 2*128);
data_errors = memtest_data();
if(data_errors != 0)
printf("Memtest data failed: %d/%d errors\n", data_errors, MEMTEST_DATA_SIZE/4);
addr_errors = memtest_addr();
if(addr_errors != 0)
printf("Memtest addr failed: %d/%d errors\n", addr_errors, MEMTEST_ADDR_SIZE/4);
if(bus_errors + data_errors + addr_errors != 0)
return 0;
else {
printf("Memtest OK\n");
memspeed();
return 1;
}
}
#ifdef CSR_SDRAM_BASE #ifdef CSR_SDRAM_BASE
@ -1051,7 +836,7 @@ int sdrinit(void)
#endif #endif
#endif #endif
sdrhw(); sdrhw();
if(!memtest()) { if(!memtest((unsigned int *) MAIN_RAM_BASE, MAIN_RAM_SIZE)) {
#ifdef CSR_DDRCTRL_BASE #ifdef CSR_DDRCTRL_BASE
ddrctrl_init_done_write(1); ddrctrl_init_done_write(1);
ddrctrl_init_error_write(1); ddrctrl_init_error_write(1);

View File

@ -17,8 +17,6 @@ int write_level(void);
int sdrlevel(void); int sdrlevel(void);
int memtest_silent(void);
int memtest(void);
int sdrinit(void); int sdrinit(void);
#if defined(DDRPHY_CMD_DELAY) || defined(USDDRPHY_DEBUG) #if defined(DDRPHY_CMD_DELAY) || defined(USDDRPHY_DEBUG)