From 1f2b8621fec8cee607ebf8c88e35c75c23cd5f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Mon, 17 May 2021 14:38:35 +0200 Subject: [PATCH] soc/software/liblitedram: add sdram_debug command --- litex/soc/software/bios/cmds/cmd_litedram.c | 4 + litex/soc/software/liblitedram/sdram.c | 141 ++++++++++++++++++++ litex/soc/software/liblitedram/sdram.h | 5 + 3 files changed, 150 insertions(+) diff --git a/litex/soc/software/bios/cmds/cmd_litedram.c b/litex/soc/software/bios/cmds/cmd_litedram.c index 71a931321..e8c713f7f 100644 --- a/litex/soc/software/bios/cmds/cmd_litedram.c +++ b/litex/soc/software/bios/cmds/cmd_litedram.c @@ -409,3 +409,7 @@ static void sdram_spd_handler(int nb_params, char **params) } define_command(sdram_spd, sdram_spd_handler, "Read SDRAM SPD EEPROM", LITEDRAM_CMDS); #endif + +#ifdef SDRAM_DEBUG +define_command(sdram_debug, sdram_debug, "Run SDRAM debug tests", LITEDRAM_CMDS); +#endif diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index 72fbc9f34..884de3192 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -23,6 +23,7 @@ #include #include +#include //#define SDRAM_TEST_DISABLE //#define SDRAM_WRITE_LEVELING_CMD_DELAY_DEBUG @@ -1205,4 +1206,144 @@ int sdram_init(void) return 1; } +/*-----------------------------------------------------------------------*/ +/* Debugging */ +/*-----------------------------------------------------------------------*/ + +#ifdef SDRAM_DEBUG + +#define SDRAM_DEBUG_STATS_NUM_RUNS 10 +#define SDRAM_DEBUG_STATS_MEMTEST_SIZE MEMTEST_DATA_SIZE + +#ifdef SDRAM_DEBUG_READBACK_MEM_ADDR +#ifndef SDRAM_DEBUG_READBACK_MEM_SIZE +#error "Provide readback memory size via SDRAM_DEBUG_READBACK_MEM_SIZE" +#endif +#define SDRAM_DEBUG_READBACK_VERBOSE 1 + +#define SDRAM_DEBUG_READBACK_COUNT 3 +#define SDRAM_DEBUG_READBACK_MEMTEST_SIZE MEMTEST_DATA_SIZE + +#define _SINGLE_READBACK (SDRAM_DEBUG_READBACK_MEM_SIZE/SDRAM_DEBUG_READBACK_COUNT) +#define _READBACK_ERRORS_SIZE (_SINGLE_READBACK - sizeof(struct readback)) +#define SDRAM_DEBUG_READBACK_LEN (_READBACK_ERRORS_SIZE / sizeof(struct memory_error)) +#endif + +static int sdram_debug_error_stats_on_error( + unsigned int addr, unsigned int rdata, unsigned int refdata, void *arg) +{ + struct error_stats *stats = (struct error_stats *) arg; + struct memory_error error = { + .addr = addr, + .data = rdata, + .ref = refdata, + }; + error_stats_update(stats, error); + return 0; +} + +static void sdram_debug_error_stats(void) { + printf("Running initial memtest to fill memory ...\n"); + memtest_data((unsigned int *) MAIN_RAM_BASE, SDRAM_DEBUG_STATS_MEMTEST_SIZE, 1, NULL); + + struct error_stats stats; + error_stats_init(&stats); + + struct memtest_config config = { + .show_progress = 0, + .read_only = 1, + .on_error = sdram_debug_error_stats_on_error, + .arg = &stats, + }; + + printf("Running read-only memtests ... \n"); + for (int i = 0; i < SDRAM_DEBUG_STATS_NUM_RUNS; ++i) { + printf("Running read-only memtest %3d/%3d ... \r", i + 1, SDRAM_DEBUG_STATS_NUM_RUNS); + memtest_data((unsigned int *) MAIN_RAM_BASE, SDRAM_DEBUG_STATS_MEMTEST_SIZE, 1, &config); + } + + printf("\n"); + error_stats_print(&stats); +} + +#ifdef SDRAM_DEBUG_READBACK_MEM_ADDR +static int sdram_debug_readback_on_error( + unsigned int addr, unsigned int rdata, unsigned int refdata, void *arg) +{ + struct readback *readback = (struct readback *) arg; + struct memory_error error = { + .addr = addr, + .data = rdata, + .ref = refdata, + }; + // run only as long as we have space for new entries + return readback_add(readback, SDRAM_DEBUG_READBACK_LEN, error) != 1; +} + +static void sdram_debug_readback(void) +{ + printf("Using storage @0x%08x with size 0x%08x for %d readbacks.\n", + SDRAM_DEBUG_READBACK_MEM_ADDR, SDRAM_DEBUG_READBACK_MEM_SIZE, SDRAM_DEBUG_READBACK_COUNT); + + printf("Running initial memtest to fill memory ...\n"); + memtest_data((unsigned int *) MAIN_RAM_BASE, SDRAM_DEBUG_READBACK_MEMTEST_SIZE, 1, NULL); + + for (int i = 0; i < SDRAM_DEBUG_READBACK_COUNT; ++i) { + struct readback *readback = (struct readback *) + (SDRAM_DEBUG_READBACK_MEM_ADDR + i * READBACK_SIZE(SDRAM_DEBUG_READBACK_LEN)); + readback_init(readback); + + struct memtest_config config = { + .show_progress = 0, + .read_only = 1, + .on_error = sdram_debug_readback_on_error, + .arg = readback, + }; + + printf("Running readback %3d/%3d ... \r", i + 1, SDRAM_DEBUG_READBACK_COUNT); + memtest_data((unsigned int *) MAIN_RAM_BASE, SDRAM_DEBUG_READBACK_MEMTEST_SIZE, 1, &config); + } + printf("\n"); + + + // Iterate over all combinations + for (int i = 0; i < SDRAM_DEBUG_READBACK_COUNT; ++i) { + struct readback *first = (struct readback *) + (SDRAM_DEBUG_READBACK_MEM_ADDR + i * READBACK_SIZE(SDRAM_DEBUG_READBACK_LEN)); + + for (int j = i + 1; j < SDRAM_DEBUG_READBACK_COUNT; ++j) { + int nums[] = {i, j}; + struct readback *readbacks[] = { + (struct readback *) (SDRAM_DEBUG_READBACK_MEM_ADDR + i * READBACK_SIZE(SDRAM_DEBUG_READBACK_LEN)), + (struct readback *) (SDRAM_DEBUG_READBACK_MEM_ADDR + j * READBACK_SIZE(SDRAM_DEBUG_READBACK_LEN)), + }; + + // Compare i vs j and j vs i + for (int k = 0; k < 2; ++k) { + printf("Comparing readbacks %d vs %d:\n", nums[k], nums[1 - k]); + int missing = readback_compare(readbacks[k], readbacks[1 - k], SDRAM_DEBUG_READBACK_VERBOSE); + if (missing == 0) + printf(" OK\n"); + else + printf(" N missing = %d\n", missing); + } + } + } +} +#endif + +void sdram_debug(void) +{ +#if defined(SDRAM_DEBUG_STATS_NUM_RUNS) && SDRAM_DEBUG_STATS_NUM_RUNS > 0 + printf("\nError stats:\n"); + sdram_debug_error_stats(); +#endif + +#ifdef SDRAM_DEBUG_READBACK_MEM_ADDR + printf("\nReadback:\n"); + sdram_debug_readback(); +#endif +} +#endif + #endif diff --git a/litex/soc/software/liblitedram/sdram.h b/litex/soc/software/liblitedram/sdram.h index 417d890fb..d8df2b2c1 100644 --- a/litex/soc/software/liblitedram/sdram.h +++ b/litex/soc/software/liblitedram/sdram.h @@ -48,4 +48,9 @@ int sdram_leveling(void); /*-----------------------------------------------------------------------*/ int sdram_init(void); +/*-----------------------------------------------------------------------*/ +/* Debugging */ +/*-----------------------------------------------------------------------*/ +void sdram_debug(void); + #endif /* __SDRAM_H */