Skip to content

Commit

Permalink
DDR5: Improve CS/CA training
Browse files Browse the repository at this point in the history
DDR5: Improve device enumeration

Signed-off-by: Maciej Dudek <[email protected]>
  • Loading branch information
mtdudek committed Sep 26, 2023
1 parent 904dad3 commit e8e5e59
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 18 deletions.
32 changes: 32 additions & 0 deletions litex/soc/software/liblitedram/ddr5_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1550,8 +1550,21 @@ void setup_enumerate(int channel, int rank, int module, int width, int verbose)
printf("\n");
}
}
// Start DQS toggling before Enter PDA Enum MPC
cmd_injector(channel, 0xf, 0, 0xf, 1, 0, 0, 0);
store_continuous(channel);
// Enter PDA Enumerate Programming Mode
send_mpc(channel, rank, 0xB, 1);
busy_wait_us(1);
send_mpc(channel, rank, (0x60 | (module & 0xf)), 1);
busy_wait_us(1);
// Exit PDA Enumerate Programming Mode
send_mpc(channel, rank, 0xA, 1);
busy_wait_us(1);
// Stop DQS toggling after Exit PDA Enum MPC
cmd_injector(channel, 0xf, 0, 0, 0, 0, 0, 0);
store_continuous(channel);

for (module_ = 0; module_ < SDRAM_PHY_MODULES/CHANNELS; module_++) {
for (i = 0; i < 8; ++i)
set_data_module_phase(channel, module_, width, i, 0xffff);
Expand Down Expand Up @@ -1610,6 +1623,23 @@ void send_mrw_rcd(int channel, int rank, int reg, int value) {
cmd_injector(channel, 0xff, 0, 0, 0, 0, 0, 1);
}

void send_mrw_no_mpc(int channel, int rank, int reg, int value) {
cmd_injector(channel, 1<<0, 1<<rank, 0x5 | (reg<<5), 0, 0, 0, 1);
if (N2_mode)
cmd_injector(channel, 1<<1, 0, 0x5 | (reg<<5), 0, 0, 0, 1);
else
cmd_injector(channel, 1<<1, 0, value, 0, 0, 0, 1);
cmd_injector(channel, 1<<2, 0, value, 0, 0, 0, 1);
cmd_injector(channel, 1<<3, 0, value, 0, 0, 0, 1);
cmd_injector(channel, 1<<4, 0, 0, 0, 0, 0, 1);
cmd_injector(channel, 1<<5, 0, 0, 0, 0, 0, 1);
cmd_injector(channel, 1<<6, 0, 0, 0, 0, 0, 1);
cmd_injector(channel, 1<<7, 0, 0, 0, 0, 0, 1);
issue_single(channel);
busy_wait_us(5);
cmd_injector(channel, 0xff, 0, 0, 0, 0, 0, 1);
}

void send_mrw(int channel, int rank, int module, int reg, int value) {
send_mpc(channel, rank, 0x70 | (module&0xF), 0);
cmd_injector(channel, 1<<0, 1<<rank, 0x5 | (reg<<5), 0, 0, 0, 1);
Expand Down Expand Up @@ -1897,6 +1927,8 @@ void exit_catm(int channel, int rank) {
cmd_injector(channel, 0xff, 1<<rank, 0x1f, 0, 0, 0, 1);
issue_single(channel);
busy_wait_us(1);
cmd_injector(channel, 0xf, 0, 0, 0, 0, 0, 0);
store_continuous(channel);
cmd_injector(channel, 0xff, 0, 0, 0, 0, 0, 1);
}

Expand Down
1 change: 1 addition & 0 deletions litex/soc/software/liblitedram/ddr5_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ void setup_enumerate(int channel, int rank, int module, int width, int verbose);
bool check_enumerate(int channel, int rank, int module, int width, int verbose);
void send_mpc(int channel, int rank, int cmd, int wrdata_active);
void send_mrw_rcd(int channel, int rank, int reg, int value);
void send_mrw_no_mpc(int channel, int rank, int reg, int value);
void send_mrw(int channel, int rank, int module, int reg, int value);
void send_mrr(int channel, int rank, int reg);
void send_wleveling_write(int channel, int rank);
Expand Down
60 changes: 42 additions & 18 deletions litex/soc/software/liblitedram/ddr5_training.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ static void CS_training(training_ctx_t *const ctx, int32_t channel, uint8_t *suc
*success = 0;
return;
}
if ((right_side + left_side) / 2 >= ctx->max_delay_taps) {
// When delay is around 0 delay, allow for small negative bias
if ((right_side + left_side) / 2 >= ctx->max_delay_taps - (ctx->max_delay_taps/32)) {
right_side -= ctx->max_delay_taps;
left_side -= ctx->max_delay_taps;
}
Expand Down Expand Up @@ -293,10 +294,12 @@ static void CA_training(training_ctx_t *const ctx , int32_t channel, uint8_t *su
*success = 0;
return;
}
if ((right_side + left_side) / 2 >= ctx->max_delay_taps) {
right_side -= ctx->max_delay_taps;
left_side -= ctx->max_delay_taps;
}
// First ctx->max_delay_taps taps are in previous cs_n,
// so we need to always subtract ctx->max_delay_taps from
// answare
right_side -= ctx->max_delay_taps;
left_side -= ctx->max_delay_taps;
printf("CA[%"PRId32"] %d:%d\n", address, right_side, left_side);

if (right_side > ctx->ca.delays[channel][address][0])
ctx->ca.delays[channel][address][0] = right_side;
Expand Down Expand Up @@ -585,8 +588,6 @@ static void sdram_ddr5_module_enumerate(int rank, int width, int channels, int m
printf("Enumerating rank:%2d\n", rank);
for (channel = 0; channel < channels; channel++) {
printf("\tEnumerating subchannel:%c\n", (char)('A'+channel));
// Enter PDA Enumerate Programming Mode
send_mpc(channel, rank, 0xB, 1);
for (module = 0; module < modules; module++) {
printf("\t\tmodule:%2d\n", module);
#ifndef CA_INFO_DDR5
Expand All @@ -595,11 +596,6 @@ static void sdram_ddr5_module_enumerate(int rank, int width, int channels, int m
setup_enumerate(channel, rank, module, width, 1);
#endif // CA_INFO_DDR5
}
// Exit PDA Enumerate Programming Mode
send_mpc(channel, rank, 0xA, 1);
busy_wait_us(1);
send_mpc(channel, rank, 0xA, 0);
busy_wait_us(1);
}
enumerated = 1;
}
Expand Down Expand Up @@ -2154,6 +2150,7 @@ static void rcd_init(training_ctx_t *const ctx ) {
* training context.
*/
void sdram_ddr5_flow(void) {
int use_1n_mode = 0;
single_cycle_MPC = 0;
use_internal_write_timing = 0;
enumerated = 0;
Expand Down Expand Up @@ -2242,21 +2239,43 @@ void sdram_ddr5_flow(void) {
sdram_ddr5_cs_ca_training(base_ctx, -1);
#endif // SKIP_CSCA_TRAINING
}

#ifdef SKIP_CSCA_TRAINING
disable_dfi_2n_mode();
disable_dfi_2n_mode();
#endif // SKIP_CSCA_TRAINING

#ifndef KEEP_GOING_ON_DRAM_ERROR
if(!base_ctx->CS_CA_successful)
return;
#endif // KEEP_GOING_ON_DRAM_ERROR

for (int channel = 0; channel < base_ctx->channels; channel++) {
use_1n_mode = 1<<2;
if(is_rdimm) {
enter_ca_pass(0);
for (int rank = 0; rank < base_ctx->ranks; rank++) {
if (base_ctx->CS_CA_successful && base_ctx->rate == DDR) {
disable_dram_2n_mode(channel, rank);
select_ca_pass(rank);
for (int channel = 0; channel < base_ctx->channels; channel++) {
if (base_ctx->CS_CA_successful && base_ctx->rate == DDR) {
disable_dram_2n_mode(channel, rank);
}
}
}
exit_ca_pass(0);
} else {
for (int rank = 0; rank < base_ctx->ranks; rank++) {
for (int channel = 0; channel < base_ctx->channels; channel++) {
if (base_ctx->CS_CA_successful && base_ctx->rate == DDR) {
disable_dram_2n_mode(channel, rank);
}
}
}
}

single_cycle_MPC = 1<<4;
for (int rank = 0; rank < base_ctx->ranks; rank++) {
for (int channel = 0; channel < base_ctx->channels; channel++) {
send_mrw_no_mpc(channel, rank, 2, 0|use_internal_write_timing|single_cycle_MPC|use_1n_mode);
}
}

if (in_2n_mode()) {
Expand All @@ -2267,10 +2286,10 @@ void sdram_ddr5_flow(void) {
init_sequence_1n(base_ctx->ranks);
}

single_cycle_MPC = 1<<4;
// Disable DQ RTT during enumerate
for (int channel = 0; channel < base_ctx->channels; channel++)
for (int rank = 0; rank < base_ctx->ranks; rank++)
send_mrw(channel, rank, MODULE_BROADCAST, 2, 0|use_internal_write_timing|single_cycle_MPC);
send_mpc(channel, rank, 0x58, 0);

for (int rank = 0; rank < base_ctx->ranks; ++rank) {
if(dram_enumerate(base_ctx, rank))
Expand All @@ -2280,6 +2299,11 @@ void sdram_ddr5_flow(void) {
#endif // KEEP_GOING_ON_DRAM_ERROR
}

// Enable DQ RTT after enumerate
for (int channel = 0; channel < base_ctx->channels; channel++)
for (int rank = 1; rank < base_ctx->ranks; rank++)
send_mpc(channel, rank, 0x58, 0x4);

// Disable RTT on unused rank
if (base_ctx->ranks > 1) {
for (int channel = 0; channel < base_ctx->channels; channel++)
Expand Down

0 comments on commit e8e5e59

Please sign in to comment.