software/liblitedram: add support for dynamic read/write phase and add command to BIOS to force them.

This commit is contained in:
Florent Kermarrec 2020-09-30 17:09:19 +02:00
parent 96976941b4
commit c154f1cbb2
2 changed files with 176 additions and 1 deletions

View file

@ -40,6 +40,58 @@ static void sdram_cal_handler(int nb_params, char **params)
define_command(sdram_cal, sdram_cal_handler, "Calibrate SDRAM", LITEDRAM_CMDS);
#endif
#ifdef CSR_DDRPHY_RDPHASE_ADDR
/**
* Command "sdram_force_rdphase"
*
* Force read phase
*
*/
static void sdram_force_rdphase_handler(int nb_params, char **params)
{
char *c;
int phase;
if (nb_params < 1) {
printf("sdram_force_rdphase <phase>");
return;
}
phase = strtoul(params[0], &c, 0);
if (*c != 0) {
printf("Incorrect phase");
return;
}
printf("Forcing read phase to %d\n", phase);
ddrphy_rdphase_write(phase);
}
define_command(sdram_force_rdphase, sdram_force_rdphase_handler, "Force read phase", LITEDRAM_CMDS);
#endif
#ifdef CSR_DDRPHY_WRPHASE_ADDR
/**
* Command "sdram_force_wrphase"
*
* Force write phase
*
*/
static void sdram_force_wrphase_handler(int nb_params, char **params)
{
char *c;
int phase;
if (nb_params < 1) {
printf("sdram_force_wrphase <phase>");
return;
}
phase = strtoul(params[0], &c, 0);
if (*c != 0) {
printf("Incorrect phase");
return;
}
printf("Forcing write phase to %d\n", phase);
ddrphy_wrphase_write(phase);
}
define_command(sdram_force_wrphase, sdram_force_wrphase_handler, "Force write phase", LITEDRAM_CMDS);
#endif
#ifdef CSR_DDRPHY_CDLY_RST_ADDR
/**
@ -113,7 +165,7 @@ static void sdram_rst_dat_delay_handler(int nb_params, char **params)
sdram_write_leveling_rst_dat_delay(module, 1);
sdram_software_control_off();
}
define_command(sdram_rst_dat_delay, sdram_rst_dat_delay_handler, "Reset write leveling Dat delay", LITEDRAM_CMDS);
define_command(sdram_rst_dat_delay, sdram_rst_dat_delay_handler, "Force write leveling Dat delay", LITEDRAM_CMDS);
#endif
/**

View file

@ -50,6 +50,120 @@ int sdram_get_freq(void) {
return SDRAM_PHY_XDR*SDRAM_PHY_PHASES*CONFIG_CLOCK_FREQUENCY;
}
/*-----------------------------------------------------------------------*/
/* DFII */
/*-----------------------------------------------------------------------*/
#ifdef CSR_DDRPHY_BASE
static unsigned char sdram_dfii_get_rdphase(void) {
#ifdef CSR_DDRPHY_RDPHASE_ADDR
return ddrphy_rdphase_read();
#else
return SDRAM_PHY_RDPHASE;
#endif
}
static unsigned char sdram_dfii_get_wrphase(void) {
#ifdef CSR_DDRPHY_WRPHASE_ADDR
return ddrphy_wrphase_read();
#else
return SDRAM_PHY_WRPHASE;
#endif
}
static void sdram_dfii_pix_address_write(unsigned char phase, unsigned int value) {
switch (phase) {
#if (SDRAM_PHY_PHASES > 2)
case 3:
sdram_dfii_pi3_address_write(value);
break;
case 2:
sdram_dfii_pi2_address_write(value);
break;
#endif
#if (SDRAM_PHY_PHASES > 1)
case 1:
sdram_dfii_pi1_address_write(value);
break;
#endif
default:
sdram_dfii_pi0_address_write(value);
}
}
static void sdram_dfii_pird_address_write(unsigned int value) {
unsigned char rdphase = sdram_dfii_get_rdphase();
sdram_dfii_pix_address_write(rdphase, value);
}
static void sdram_dfii_piwr_address_write(unsigned int value) {
unsigned char wrphase = sdram_dfii_get_wrphase();
sdram_dfii_pix_address_write(wrphase, value);
}
static void sdram_dfii_pix_baddress_write(unsigned char phase, unsigned int value) {
switch (phase) {
#if (SDRAM_PHY_PHASES > 2)
case 3:
sdram_dfii_pi3_baddress_write(value);
break;
case 2:
sdram_dfii_pi2_baddress_write(value);
break;
#endif
#if (SDRAM_PHY_PHASES > 1)
case 1:
sdram_dfii_pi1_baddress_write(value);
break;
#endif
default:
sdram_dfii_pi0_baddress_write(value);
}
}
static void sdram_dfii_pird_baddress_write(unsigned int value) {
unsigned char rdphase = sdram_dfii_get_rdphase();
sdram_dfii_pix_baddress_write(rdphase, value);
}
static void sdram_dfii_piwr_baddress_write(unsigned int value) {
unsigned char wrphase = sdram_dfii_get_wrphase();
sdram_dfii_pix_baddress_write(wrphase, value);
}
static void command_px(unsigned char phase, unsigned int value) {
switch (phase) {
#if (SDRAM_PHY_PHASES > 2)
case 3:
command_p3(value);
break;
case 2:
command_p2(value);
break;
#endif
#if (SDRAM_PHY_PHASES > 1)
case 1:
command_p1(value);
break;
#endif
default:
command_p0(value);
}
}
static void command_prd(unsigned int value) {
unsigned char rdphase = sdram_dfii_get_rdphase();
command_px(rdphase, value);
}
static void command_pwr(unsigned int value) {
unsigned char wrphase = sdram_dfii_get_wrphase();
command_px(wrphase, value);
}
#endif
/*-----------------------------------------------------------------------*/
/* Software/Hardware Control */
/*-----------------------------------------------------------------------*/
@ -778,11 +892,20 @@ int sdram_leveling(void)
int sdram_init(void)
{
/* Reset Cmd/Dat delays */
#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
int i;
sdram_write_leveling_rst_cmd_delay(0);
for (i=0; i<16; i++) sdram_write_leveling_rst_dat_delay(i, 0);
#endif
/* Reset Read/Write phases */
#ifdef CSR_DDRPHY_RDPHASE_ADDR
ddrphy_rdphase_write(SDRAM_PHY_RDPHASE);
#endif
#ifdef CSR_DDRPHY_WRPHASE_ADDR
ddrphy_wrphase_write(SDRAM_PHY_WRPHASE);
#endif
/* Set Cmd delay if enforced at build time */
#ifdef SDRAM_PHY_CMD_DELAY
_sdram_write_leveling_cmd_scan = 0;
_sdram_write_leveling_cmd_delay = SDRAM_PHY_CMD_DELAY;