bios/sdram: check for optimal read window before doing read leveling, increment bitslip if not optimal.

This commit is contained in:
Florent Kermarrec 2018-07-02 13:46:48 +02:00
parent 9e737d3c57
commit 477d224921
1 changed files with 44 additions and 18 deletions

View File

@ -336,6 +336,19 @@ static int write_level(int *delay, int *high_skew)
#endif /* CSR_DDRPHY_WLEVEL_EN_ADDR */ #endif /* CSR_DDRPHY_WLEVEL_EN_ADDR */
static void read_bitslip_inc(char m)
{
ddrphy_dly_sel_write(1 << m);
#ifdef KUSDDRPHY
ddrphy_rdly_dq_bitslip_write(1);
#else
/* 7-series SERDES in DDR mode needs 3 pulses for 1 bitslip */
ddrphy_rdly_dq_bitslip_write(1);
ddrphy_rdly_dq_bitslip_write(1);
ddrphy_rdly_dq_bitslip_write(1);
#endif
}
static void read_bitslip(int *delay, int *high_skew) static void read_bitslip(int *delay, int *high_skew)
{ {
int bitslip_thr; int bitslip_thr;
@ -352,28 +365,22 @@ static void read_bitslip(int *delay, int *high_skew)
printf("Read bitslip: "); printf("Read bitslip: ");
for(i=DFII_PIX_DATA_SIZE/2-1;i>=0;i--) for(i=DFII_PIX_DATA_SIZE/2-1;i>=0;i--)
if(delay[i] > bitslip_thr) { if(delay[i] > bitslip_thr) {
ddrphy_dly_sel_write(1 << i); read_bitslip_inc(i);
#ifdef KUSDDRPHY
ddrphy_rdly_dq_bitslip_write(1);
#else
/* 7-series SERDES in DDR mode needs 3 pulses for 1 bitslip */
ddrphy_rdly_dq_bitslip_write(1);
ddrphy_rdly_dq_bitslip_write(1);
ddrphy_rdly_dq_bitslip_write(1);
#endif
printf("%d ", i); printf("%d ", i);
} }
printf("\n"); printf("\n");
} }
static void read_delays_scan(void) static int read_level_scan(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 working; int working;
int optimal;
printf("Read delays scan:\n"); if (!silent)
printf("Read delays scan:\n");
/* Generate pseudo-random sequence */ /* Generate pseudo-random sequence */
prv = 42; prv = 42;
@ -399,8 +406,10 @@ static void read_delays_scan(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);
optimal = 1;
for(i=DFII_PIX_DATA_SIZE/2-1;i>=0;i--) { for(i=DFII_PIX_DATA_SIZE/2-1;i>=0;i--) {
printf("m%d: ", (DFII_PIX_DATA_SIZE/2-i-1)); if (!silent)
printf("m%d: ", (DFII_PIX_DATA_SIZE/2-i-1));
ddrphy_dly_sel_write(1 << (DFII_PIX_DATA_SIZE/2-i-1)); ddrphy_dly_sel_write(1 << (DFII_PIX_DATA_SIZE/2-i-1));
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++) {
@ -413,10 +422,15 @@ static void read_delays_scan(void)
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*(i+DFII_PIX_DATA_SIZE/2)) != prs[DFII_PIX_DATA_SIZE*p+i+DFII_PIX_DATA_SIZE/2])
working = 0; working = 0;
} }
printf("%d", working); if (j == 0)
/* to have an optimal scan, first tap should not be working */
optimal &= (working == 0);
if (!silent)
printf("%d", working);
ddrphy_rdly_dq_inc_write(1); ddrphy_rdly_dq_inc_write(1);
} }
printf("\n"); if (!silent)
printf("\n");
} }
/* Precharge */ /* Precharge */
@ -424,9 +438,11 @@ static void read_delays_scan(void)
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);
return optimal;
} }
static void read_delays(void) static void read_level(void)
{ {
unsigned int prv; unsigned int prv;
unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE]; unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE];
@ -732,6 +748,7 @@ int sdrlevel(void) /* automatic */
{ {
int delay[DFII_PIX_DATA_SIZE/2]; int delay[DFII_PIX_DATA_SIZE/2];
int high_skew[DFII_PIX_DATA_SIZE/2]; int high_skew[DFII_PIX_DATA_SIZE/2];
int i;
#ifndef CSR_DDRPHY_WLEVEL_EN_ADDR #ifndef CSR_DDRPHY_WLEVEL_EN_ADDR
int i; int i;
@ -744,9 +761,18 @@ int sdrlevel(void) /* automatic */
if(!write_level(delay, high_skew)) if(!write_level(delay, high_skew))
return 0; return 0;
#endif #endif
read_bitslip(delay, high_skew); /* check for optimal read leveling window */
read_delays_scan(); if (read_level_scan(1)) {
read_delays(); /* if optimal, show scan */
read_level_scan(0);
} else {
/* else increment bitslip and re-scan */
printf("Read bitslip for optimal window\n");
for(i=0; i<DFII_PIX_DATA_SIZE/2; i++)
read_bitslip_inc(i);
read_level_scan(0);
}
read_level();
return 1; return 1;
} }