From 93f357d8530b6ec952faffffb438a1d97c2c8bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Mon, 17 May 2021 14:53:04 +0200 Subject: [PATCH] soc/software/liblitedram: make leveling scores more robust by counting number of bitslips --- litex/soc/software/liblitedram/sdram.c | 96 ++++++++++++++++++-------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index 6d2219981..80884b149 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -28,6 +28,7 @@ //#define SDRAM_TEST_DISABLE //#define SDRAM_WRITE_LEVELING_CMD_DELAY_DEBUG //#define SDRAM_WRITE_LATENCY_CALIBRATION_DEBUG +//#define SDRAM_LEVELING_SCAN_DISPLAY_HEX_DIV 10 #ifdef CSR_SDRAM_BASE @@ -272,8 +273,37 @@ static void sdram_precharge_test_row(void) { cdelay(15); } -static int sdram_write_read_check_test_pattern(int module, unsigned int seed) { +// Count number of bits in a 32-bit word, faster version than a while loop +// see: https://www.johndcook.com/blog/2020/02/21/popcount/ +static unsigned int popcount(unsigned int x) { + x -= ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += (x >> 8); + x += (x >> 16); + return x & 0x0000003F; +} + +static void print_scan_errors(unsigned int errors) { +#ifdef SDRAM_LEVELING_SCAN_DISPLAY_HEX_DIV + // Display '.' for no errors, errors/div in hex if it is a single char, else show 'X' + errors = errors / SDRAM_LEVELING_SCAN_DISPLAY_HEX_DIV; + if (errors == 0) + printf("."); + else if (errors > 0xf) + printf("X"); + else + printf("%x", errors); +#else + printf("%d", errors == 0); +#endif +} + +#define READ_CHECK_TEST_PATTERN_MAX_ERRORS (SDRAM_PHY_PHASES*2*32) + +static unsigned int sdram_write_read_check_test_pattern(int module, unsigned int seed) { int p, i; + unsigned int errors; unsigned int prv; unsigned char tst[DFII_PIX_DATA_BYTES]; unsigned char prs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES]; @@ -311,13 +341,13 @@ static int sdram_write_read_check_test_pattern(int module, unsigned int seed) { /* Precharge */ sdram_precharge_test_row(); + errors = 0; for(p=0;p 32 show = show && (delay%16 == 0); #endif if (show) - printf(working ? "1" : "0"); + print_scan_errors(errors); if(working && delay_min < 0) { delay_min = delay; break; @@ -375,14 +407,15 @@ static void sdram_leveling_center_module( /* Find largest working delay */ while(1) { - working = sdram_write_read_check_test_pattern(module, 42); - working &= sdram_write_read_check_test_pattern(module, 84); + errors = sdram_write_read_check_test_pattern(module, 42); + errors += sdram_write_read_check_test_pattern(module, 84); + working = errors == 0; show = show_long; #if SDRAM_PHY_DELAYS > 32 show = show && (delay%16 == 0); #endif if (show) - printf(working ? "1" : "0"); + print_scan_errors(errors); if(!working && delay_max < 0) { delay_max = delay; } @@ -874,15 +907,17 @@ static void sdram_read_leveling_inc_bitslip(char m) ddrphy_dly_sel_write(0); } -static int sdram_read_leveling_scan_module(int module, int bitslip, int show) +static unsigned int sdram_read_leveling_scan_module(int module, int bitslip, int show) { + const unsigned int max_errors = 2*READ_CHECK_TEST_PATTERN_MAX_ERRORS; int i; - int score; + unsigned int score; + unsigned int errors; - /* Check test pattern for each delay value */ + /* Check test pattern for each delay value */ score = 0; if (show) - printf(" m%d, b%d: |", module, bitslip); + printf(" m%d, b%02d: |", module, bitslip); sdram_read_leveling_rst_delay(module); for(i=0;i 32 _show = (i%16 == 0) & show; #endif - working = sdram_write_read_check_test_pattern(module, 42); - working &= sdram_write_read_check_test_pattern(module, 84); - if (_show) - printf("%d", working); - score += working; + errors = sdram_write_read_check_test_pattern(module, 42); + errors += sdram_write_read_check_test_pattern(module, 84); + working = errors == 0; + /* When any scan is working then the final score will always be higher then if no scan was working */ + score += (working * max_errors*SDRAM_PHY_DELAYS) + (max_errors - errors); + if (_show) { + print_scan_errors(errors); + } sdram_read_leveling_inc_delay(module); } if (show) @@ -915,8 +953,8 @@ void sdram_read_leveling(void) { int module; int bitslip; - int score; - int best_score; + unsigned int score; + unsigned int best_score; int best_bitslip; for(module=0; module score ? subscore : score; /* Increment bitslip */ sdram_read_leveling_inc_bitslip(module); } @@ -1073,10 +1113,10 @@ static void sdram_write_dq_dqs_training_inc_delay(int module) { static void sdram_read_leveling_best_bitslip(int module) { - int score; + unsigned int score; int bitslip; int best_bitslip = 0; - int best_score = 0; + unsigned int best_score = 0; sdram_read_leveling_rst_bitslip(module); for(bitslip=0; bitslip