bios/sdram: improve write/read leveling

write_leveling: select last 0 to 1 transition.
read_leveling: do it by module (select best bitslip for each module)
This commit is contained in:
Florent Kermarrec 2018-10-10 10:42:56 +02:00
parent deffa60324
commit 915c2f417a
1 changed files with 119 additions and 144 deletions

View File

@ -207,6 +207,8 @@ void sdrwr(char *startaddr)
#endif #endif
#define ERR_DDRPHY_BITSLIP 8 #define ERR_DDRPHY_BITSLIP 8
#define NBMODULES DFII_PIX_DATA_SIZE/2
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR #ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
void sdrwlon(void) void sdrwlon(void)
@ -238,22 +240,20 @@ int write_level(void)
int one_window_active; int one_window_active;
int one_window_start; int one_window_start;
int one_window_len;
int best_one_window_len;
int delays[DFII_PIX_DATA_SIZE/2]; int delays[NBMODULES];
int ok; int ok;
err_ddrphy_wdly = ERR_DDRPHY_DELAY - ddrphy_half_sys8x_taps_read(); err_ddrphy_wdly = ERR_DDRPHY_DELAY - ddrphy_half_sys8x_taps_read();
printf("Write leveling scan:\n"); printf("Write leveling:\n");
sdrwlon(); sdrwlon();
cdelay(100); cdelay(100);
for(i=0;i<DFII_PIX_DATA_SIZE/2;i++) { for(i=0;i<NBMODULES;i++) {
printf("m%d: ", i); printf("m%d: |", i);
dq_address = sdram_dfii_pix_rddata_addr[0]+4*(DFII_PIX_DATA_SIZE/2-1-i); dq_address = sdram_dfii_pix_rddata_addr[0]+4*(NBMODULES-1-i);
/* reset delay */ /* reset delay */
ddrphy_dly_sel_write(1 << i); ddrphy_dly_sel_write(1 << i);
@ -274,24 +274,16 @@ int write_level(void)
ddrphy_wdly_dqs_inc_write(1); ddrphy_wdly_dqs_inc_write(1);
cdelay(10); cdelay(10);
} }
printf("\n"); printf("|");
/* find best delay */ /* select last 0/1 transition */
one_window_active = 0; one_window_active = 0;
one_window_start = 0; one_window_start = 0;
one_window_len = 0;
best_one_window_len = 0;
delays[i] = -1; delays[i] = -1;
for(j=0;j<err_ddrphy_wdly;j++) { for(j=0;j<err_ddrphy_wdly;j++) {
if (one_window_active) { if (one_window_active) {
if ((taps_scan[j] == 0) || (j == err_ddrphy_wdly-1)) { if (taps_scan[j] == 0)
one_window_len = j - one_window_start;
if (one_window_len > best_one_window_len) {
delays[i] = one_window_start;
best_one_window_len = one_window_len;
}
one_window_active = 0; one_window_active = 0;
}
} else { } else {
if (taps_scan[j]) { if (taps_scan[j]) {
one_window_active = 1; one_window_active = 1;
@ -299,6 +291,7 @@ int write_level(void)
} }
} }
} }
delays[i] = one_window_start;
/* configure delays */ /* configure delays */
ddrphy_wdly_dq_rst_write(1); ddrphy_wdly_dq_rst_write(1);
@ -311,23 +304,18 @@ int write_level(void)
ddrphy_wdly_dq_inc_write(1); ddrphy_wdly_dq_inc_write(1);
ddrphy_wdly_dqs_inc_write(1); ddrphy_wdly_dqs_inc_write(1);
} }
printf(" delay: %02d\n", delays[i]);
} }
sdrwloff(); sdrwloff();
ok = 1; ok = 1;
printf("Write leveling: "); for(i=NBMODULES-1;i>=0;i--) {
for(i=DFII_PIX_DATA_SIZE/2-1;i>=0;i--) {
printf("%2d ", delays[i]);
if(delays[i] < 0) if(delays[i] < 0)
ok = 0; ok = 0;
} }
if(ok)
printf("completed\n");
else
printf("failed\n");
return ok; return ok;
} }
@ -346,16 +334,13 @@ static void read_bitslip_inc(char m)
#endif #endif
} }
static int read_level_scan(int silent) static int read_level_scan(int module, int silent)
{ {
unsigned int prv; unsigned int prv;
unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE]; unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE];
int p, i, j; int p, i, j;
int score; int score;
if (!silent)
printf("Read delays scan:\n");
/* Generate pseudo-random sequence */ /* Generate pseudo-random sequence */
prv = 42; prv = 42;
for(i=0;i<DFII_NPHASES*DFII_PIX_DATA_SIZE;i++) { for(i=0;i<DFII_NPHASES*DFII_PIX_DATA_SIZE;i++) {
@ -381,10 +366,10 @@ static int read_level_scan(int silent)
sdram_dfii_pird_address_write(0); sdram_dfii_pird_address_write(0);
sdram_dfii_pird_baddress_write(0); sdram_dfii_pird_baddress_write(0);
score = 0; score = 0;
for(i=DFII_PIX_DATA_SIZE/2-1;i>=0;i--) {
if (!silent) if (!silent)
printf("m%d: ", (DFII_PIX_DATA_SIZE/2-i-1)); printf("m%d: |", module);
ddrphy_dly_sel_write(1 << (DFII_PIX_DATA_SIZE/2-i-1)); ddrphy_dly_sel_write(1 << module);
ddrphy_rdly_dq_rst_write(1); ddrphy_rdly_dq_rst_write(1);
for(j=0; j<ERR_DDRPHY_DELAY;j++) { for(j=0; j<ERR_DDRPHY_DELAY;j++) {
int working; int working;
@ -392,9 +377,9 @@ static int read_level_scan(int silent)
cdelay(15); cdelay(15);
working = 1; working = 1;
for(p=0;p<DFII_NPHASES;p++) { for(p=0;p<DFII_NPHASES;p++) {
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*i) != prs[DFII_PIX_DATA_SIZE*p+i]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+(NBMODULES-module-1)])
working = 0; working = 0;
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(i+DFII_PIX_DATA_SIZE/2)) != prs[DFII_PIX_DATA_SIZE*p+i+DFII_PIX_DATA_SIZE/2]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1])
working = 0; working = 0;
} }
if (!silent) if (!silent)
@ -403,8 +388,7 @@ static int read_level_scan(int silent)
ddrphy_rdly_dq_inc_write(1); ddrphy_rdly_dq_inc_write(1);
} }
if (!silent) if (!silent)
printf("\n"); printf("|");
}
/* Precharge */ /* Precharge */
sdram_dfii_pi0_address_write(0); sdram_dfii_pi0_address_write(0);
@ -415,7 +399,7 @@ static int read_level_scan(int silent)
return score; return score;
} }
static void read_level(void) static void read_level(int module)
{ {
unsigned int prv; unsigned int prv;
unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE]; unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE];
@ -423,7 +407,7 @@ static void read_level(void)
int working; int working;
int delay, delay_min, delay_max; int delay, delay_min, delay_max;
printf("Read delays: "); printf("delays: ");
/* Generate pseudo-random sequence */ /* Generate pseudo-random sequence */
prv = 42; prv = 42;
@ -449,8 +433,8 @@ static void read_level(void)
/* Calibrate each DQ in turn */ /* Calibrate each DQ in turn */
sdram_dfii_pird_address_write(0); sdram_dfii_pird_address_write(0);
sdram_dfii_pird_baddress_write(0); sdram_dfii_pird_baddress_write(0);
for(i=0;i<DFII_PIX_DATA_SIZE/2;i++) {
ddrphy_dly_sel_write(1 << (DFII_PIX_DATA_SIZE/2-i-1)); ddrphy_dly_sel_write(1 << module);
delay = 0; delay = 0;
/* Find smallest working delay */ /* Find smallest working delay */
@ -460,9 +444,9 @@ static void read_level(void)
cdelay(15); cdelay(15);
working = 1; working = 1;
for(p=0;p<DFII_NPHASES;p++) { for(p=0;p<DFII_NPHASES;p++) {
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*i) != prs[DFII_PIX_DATA_SIZE*p+i]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+(NBMODULES-module-1)])
working = 0; working = 0;
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(i+DFII_PIX_DATA_SIZE/2)) != prs[DFII_PIX_DATA_SIZE*p+i+DFII_PIX_DATA_SIZE/2]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1])
working = 0; working = 0;
} }
if(working) if(working)
@ -491,9 +475,9 @@ static void read_level(void)
cdelay(15); cdelay(15);
working = 1; working = 1;
for(p=0;p<DFII_NPHASES;p++) { for(p=0;p<DFII_NPHASES;p++) {
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*i) != prs[DFII_PIX_DATA_SIZE*p+i]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+(NBMODULES-module-1)])
working = 0; working = 0;
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(i+DFII_PIX_DATA_SIZE/2)) != prs[DFII_PIX_DATA_SIZE*p+i+DFII_PIX_DATA_SIZE/2]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1])
working = 0; working = 0;
} }
if(!working) if(!working)
@ -505,21 +489,18 @@ static void read_level(void)
} }
delay_max = delay; delay_max = delay;
printf("%d:%02d-%02d ", DFII_PIX_DATA_SIZE/2-i-1, delay_min, delay_max); printf("%02d+-%02d", (delay_min+delay_max)/2, (delay_max-delay_min)/2);
/* Set delay to the middle */ /* Set delay to the middle */
ddrphy_rdly_dq_rst_write(1); ddrphy_rdly_dq_rst_write(1);
for(j=0;j<(delay_min+delay_max)/2;j++) for(j=0;j<(delay_min+delay_max)/2;j++)
ddrphy_rdly_dq_inc_write(1); ddrphy_rdly_dq_inc_write(1);
}
/* Precharge */ /* Precharge */
sdram_dfii_pi0_address_write(0); sdram_dfii_pi0_address_write(0);
sdram_dfii_pi0_baddress_write(0); sdram_dfii_pi0_baddress_write(0);
command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
cdelay(15); cdelay(15);
printf("completed\n");
} }
#endif /* CSR_DDRPHY_BASE */ #endif /* CSR_DDRPHY_BASE */
@ -566,7 +547,7 @@ static int memtest_bus(void)
if(rdata != ONEZERO) { if(rdata != ONEZERO) {
errors++; errors++;
#ifdef MEMTEST_BUS_DEBUG #ifdef MEMTEST_BUS_DEBUG
printf("[bus: %0x]: %08x vs %08x\n", i, rdata, ONEZERO); printf("[bus: 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ONEZERO);
#endif #endif
} }
} }
@ -581,7 +562,7 @@ static int memtest_bus(void)
if(rdata != ZEROONE) { if(rdata != ZEROONE) {
errors++; errors++;
#ifdef MEMTEST_BUS_DEBUG #ifdef MEMTEST_BUS_DEBUG
printf("[bus %0x]: %08x vs %08x\n", i, rdata, ZEROONE); printf("[bus 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ZEROONE);
#endif #endif
} }
} }
@ -620,7 +601,7 @@ static int memtest_data(void)
if(rdata != seed_32) { if(rdata != seed_32) {
errors++; errors++;
#ifdef MEMTEST_DATA_DEBUG #ifdef MEMTEST_DATA_DEBUG
printf("[data %0x]: %08x vs %08x\n", i, rdata, seed_32); printf("[data 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, seed_32);
#endif #endif
} }
} }
@ -658,7 +639,7 @@ static int memtest_addr(void)
if(rdata != i) { if(rdata != i) {
errors++; errors++;
#ifdef MEMTEST_ADDR_DEBUG #ifdef MEMTEST_ADDR_DEBUG
printf("[addr %0x]: %08x vs %08x\n", i, rdata, i); printf("[addr 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, i);
#endif #endif
} }
} }
@ -701,7 +682,7 @@ int sdrlevel(int silent)
sdrsw(); sdrsw();
for(i=0; i<DFII_PIX_DATA_SIZE/2; i++) { for(i=0; i<NBMODULES; i++) {
ddrphy_dly_sel_write(1<<i); ddrphy_dly_sel_write(1<<i);
ddrphy_rdly_dq_rst_write(1); ddrphy_rdly_dq_rst_write(1);
ddrphy_rdly_dq_bitslip_rst_write(1); ddrphy_rdly_dq_bitslip_rst_write(1);
@ -712,14 +693,14 @@ int sdrlevel(int silent)
return 0; return 0;
#endif #endif
printf("Read leveling:\n");
for(i=0; i<NBMODULES; i++) {
/* scan possible read windows */ /* scan possible read windows */
best_score = 0; best_score = 0;
best_bitslip = 0; best_bitslip = 0;
for(bitslip=0; bitslip<ERR_DDRPHY_BITSLIP; bitslip++) { for(bitslip=0; bitslip<ERR_DDRPHY_BITSLIP; bitslip++) {
if (!silent)
printf("Read bitslip: %d\n", bitslip);
/* compute score */ /* compute score */
score = read_level_scan(silent); score = read_level_scan(i, silent);
if (score > best_score) { if (score > best_score) {
best_bitslip = bitslip; best_bitslip = bitslip;
best_score = score; best_score = score;
@ -728,22 +709,20 @@ int sdrlevel(int silent)
if (bitslip == ERR_DDRPHY_BITSLIP-1) if (bitslip == ERR_DDRPHY_BITSLIP-1)
break; break;
/* increment bitslip */ /* increment bitslip */
for(i=0; i<DFII_PIX_DATA_SIZE/2; i++)
read_bitslip_inc(i); read_bitslip_inc(i);
} }
/* select best read window */ /* select best read window */
printf("Best read bitslip: %d\n", best_bitslip);
for(i=0; i<DFII_PIX_DATA_SIZE/2; i++) {
ddrphy_dly_sel_write(1<<i);
ddrphy_rdly_dq_bitslip_rst_write(1); ddrphy_rdly_dq_bitslip_rst_write(1);
for (j=0; j<best_bitslip; j++) for (j=0; j<best_bitslip; j++)
read_bitslip_inc(i); read_bitslip_inc(i);
}
/* show scan and do leveling */ /* show scan and do leveling */
read_level_scan(0); read_level_scan(i, 0);
read_level(); printf(" bitslip:%d ", best_bitslip);
read_level(i);
printf("\n");
}
return 1; return 1;
} }
@ -765,10 +744,6 @@ int sdrinit(void)
#endif #endif
sdrhw(); sdrhw();
if(!memtest()) { if(!memtest()) {
#ifdef CSR_DDRPHY_BASE
/* show scans */
sdrlevel(0);
#endif
return 0; return 0;
} }