mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
Merge pull request #918 from antmicro/jboc/sdram-leveling
Attempt to improve DRAM leveling robustness
This commit is contained in:
commit
beac24b796
1 changed files with 79 additions and 27 deletions
|
@ -27,6 +27,8 @@
|
|||
|
||||
//#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
|
||||
|
||||
|
@ -271,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];
|
||||
|
@ -310,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<SDRAM_PHY_PHASES;p++) {
|
||||
/* Read back test pattern */
|
||||
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr(p), tst, DFII_PIX_DATA_BYTES);
|
||||
/* Verify bytes matching current 'module' */
|
||||
if (prs[p][ SDRAM_PHY_MODULES-1-module] != tst[ SDRAM_PHY_MODULES-1-module] ||
|
||||
prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
|
||||
return 0;
|
||||
errors += popcount(prs[p][ SDRAM_PHY_MODULES-1-module] ^ tst[ SDRAM_PHY_MODULES-1-module]);
|
||||
errors += popcount(prs[p][2*SDRAM_PHY_MODULES-1-module] ^ tst[2*SDRAM_PHY_MODULES-1-module]);
|
||||
}
|
||||
|
||||
#ifdef SDRAM_PHY_ECP5DDRPHY
|
||||
|
@ -324,7 +355,7 @@ static int sdram_write_read_check_test_pattern(int module, unsigned int seed) {
|
|||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
return errors;
|
||||
}
|
||||
|
||||
static void sdram_leveling_center_module(
|
||||
|
@ -333,6 +364,7 @@ static void sdram_leveling_center_module(
|
|||
int i;
|
||||
int show;
|
||||
int working;
|
||||
unsigned int errors;
|
||||
int delay, delay_mid, delay_range;
|
||||
int delay_min = -1, delay_max = -1;
|
||||
|
||||
|
@ -343,14 +375,15 @@ static void sdram_leveling_center_module(
|
|||
delay = 0;
|
||||
rst_delay(module);
|
||||
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_min < 0) {
|
||||
delay_min = delay;
|
||||
break;
|
||||
|
@ -374,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;
|
||||
}
|
||||
|
@ -873,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<SDRAM_PHY_DELAYS;i++) {
|
||||
int working;
|
||||
|
@ -889,11 +925,14 @@ static int sdram_read_leveling_scan_module(int module, int bitslip, int show)
|
|||
#if SDRAM_PHY_DELAYS > 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)
|
||||
|
@ -914,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<SDRAM_PHY_MODULES; module++) {
|
||||
|
@ -963,8 +1002,9 @@ static void sdram_write_latency_calibration(void) {
|
|||
int i;
|
||||
int module;
|
||||
int bitslip;
|
||||
int score;
|
||||
int best_score;
|
||||
unsigned int score;
|
||||
unsigned int subscore;
|
||||
unsigned int best_score;
|
||||
int best_bitslip;
|
||||
|
||||
for(module=0; module<SDRAM_PHY_MODULES; module++) {
|
||||
|
@ -972,6 +1012,9 @@ static void sdram_write_latency_calibration(void) {
|
|||
best_score = 0;
|
||||
best_bitslip = -1;
|
||||
for(bitslip=0; bitslip<SDRAM_PHY_BITSLIPS; bitslip+=2) { /* +2 for tCK steps */
|
||||
#ifdef SDRAM_WRITE_LATENCY_CALIBRATION_DEBUG
|
||||
printf("m%d wb%02d:\n", module, bitslip);
|
||||
#endif
|
||||
score = 0;
|
||||
/* Select module */
|
||||
ddrphy_dly_sel_write(1 << module);
|
||||
|
@ -986,7 +1029,13 @@ static void sdram_write_latency_calibration(void) {
|
|||
sdram_read_leveling_rst_bitslip(module);
|
||||
for(i=0; i<SDRAM_PHY_BITSLIPS; i++) {
|
||||
/* Compute score */
|
||||
score += sdram_read_leveling_scan_module(module, i, 0);
|
||||
#ifdef SDRAM_WRITE_LATENCY_CALIBRATION_DEBUG
|
||||
subscore = sdram_read_leveling_scan_module(module, i, 1);
|
||||
printf("\n");
|
||||
#else
|
||||
subscore = sdram_read_leveling_scan_module(module, i, 0);
|
||||
#endif
|
||||
score = subscore > score ? subscore : score;
|
||||
/* Increment bitslip */
|
||||
sdram_read_leveling_inc_bitslip(module);
|
||||
}
|
||||
|
@ -1004,6 +1053,9 @@ static void sdram_write_latency_calibration(void) {
|
|||
printf("m%d:- ", module);
|
||||
else
|
||||
printf("m%d:%d ", module, bitslip);
|
||||
#ifdef SDRAM_WRITE_LATENCY_CALIBRATION_DEBUG
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* Select best write window */
|
||||
ddrphy_dly_sel_write(1 << module);
|
||||
|
@ -1061,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<SDRAM_PHY_BITSLIPS; bitslip++) {
|
||||
|
|
Loading…
Reference in a new issue