diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-08-27 15:10:19 -0500 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2015-11-30 05:19:19 +0100 |
commit | 01b9f8e4c221b3ae8167579ab81bb6c829fb8070 (patch) | |
tree | 767392be1d291058f56193b850f7303349047ffe /src | |
parent | 323c7db20441e5ee2ffc2c76c283e131ef9897cb (diff) |
nb/amd/mct_ddr3: Use antiphase to better center DQS window
The BKDG recommends the use of an antiphase window detection
algorithm to ensure that the DQS data eye is properly centered.
TEST: Booted both with DIMMs known to move the data eye into the
prior clock phase and DIMMs known to keep the data eye in the
current clock phase.
Change-Id: I1d85fddd45197ca82dcaa46fe863e64589712d1f
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
Reviewed-on: https://review.coreboot.org/12059
Tested-by: build bot (Jenkins)
Reviewed-by: Edward O'Callaghan <edward.ocallaghan@koparo.com>
Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c index 9362a60961..5edb22f61e 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c @@ -1300,7 +1300,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, uint16_t current_read_dqs_delay[MAX_BYTE_LANES]; uint16_t current_write_dqs_delay[MAX_BYTE_LANES]; uint8_t passing_dqs_delay_found[MAX_BYTE_LANES]; - uint8_t dqs_results_array[2][(lane_end - lane_start)][32][32]; /* [rank][lane][write step][read step] */ + uint8_t dqs_results_array[2][(lane_end - lane_start)][32][48]; /* [rank][lane][write step][read step + 16] */ uint8_t last_pos = 0; uint8_t cur_count = 0; @@ -1400,16 +1400,24 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, */ dword = Get_NB32_DCT(dev, dct, 0x268) & 0x3ffff; if (dword & (0x3 << (lane * 2))) - dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 0; /* Fail */ + dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 0; /* Fail */ else - dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 1; /* Pass */ + dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 1; /* Pass */ + if ((current_read_dqs_delay[lane] >> 1) >= (32 - 16)) { + /* Check antiphase results */ + dword = Get_NB32_DCT(dev, dct, 0x26c) & 0x3ffff; + if (dword & (0x3 << (lane * 2))) + dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][16 - (32 - (current_read_dqs_delay[lane] >> 1))] = 0; /* Fail */ + else + dqs_results_array[Receiver & 0x1][lane - lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][16 - (32 - (current_read_dqs_delay[lane] >> 1))] = 1; /* Pass */ + } } } if (dual_rank && (Receiver & 0x1)) { /* Overlay the previous rank test results with the current rank */ for (write_iter = 0; write_iter < 32; write_iter++) { - for (read_iter = 0; read_iter < 32; read_iter++) { + for (read_iter = 0; read_iter < 48; read_iter++) { if ((dqs_results_array[0][lane - lane_start][write_iter][read_iter]) && (dqs_results_array[1][lane - lane_start][write_iter][read_iter])) dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 1; @@ -1427,8 +1435,8 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, best_pos = 0; best_count = 0; for (write_iter = 0; write_iter < 32; write_iter++) { - for (read_iter = 0; read_iter < 32; read_iter++) { - if ((dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 31)) { + for (read_iter = 0; read_iter < 48; read_iter++) { + if ((dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 47)) { /* Pass */ cur_count++; } else { @@ -1438,18 +1446,28 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, best_pos = last_pos; } cur_count = 0; - last_pos = read_iter; + last_pos = read_iter + 1; } } last_pos = 0; } if (best_count > 2) { + uint16_t region_center = (best_pos + (best_count / 2)); + + if (region_center < 16) { + printk(BIOS_WARNING, "TrainDQSRdWrPos: negative DQS recovery delay detected!" + " Attempting to continue but your system may be unstable...\n"); + region_center = 0; + } else { + region_center -= 16; + } + /* Restore current settings of other (previously trained) lanes to the active array */ memcpy(current_read_dqs_delay, initial_read_dqs_delay, sizeof(current_read_dqs_delay)); /* Program the Read DQS Timing Control register with the center of the passing window */ - current_read_dqs_delay[lane] = ((best_pos << 1) + ((best_count << 1) / 2)); + current_read_dqs_delay[lane] = region_center << 1; passing_dqs_delay_found[lane] = 1; /* Commit the current Read DQS Timing Control settings to the hardware registers */ @@ -1460,6 +1478,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 largest read passing region ", best_count, 4); print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 largest read passing region start ", best_pos, 4); + print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 largest read passing region center (raw hardware value) ", region_center, 4); } else { /* Reprogram the Read DQS Timing Control register with the original settings */ write_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, index_reg); @@ -1472,7 +1491,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, cur_count = 0; best_pos = 0; best_count = 0; - for (read_iter = 0; read_iter < 32; read_iter++) { + for (read_iter = 0; read_iter < 48; read_iter++) { for (write_iter = 0; write_iter < 32; write_iter++) { if ((dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter]) && (write_iter < 31)) { /* Pass */ @@ -1484,7 +1503,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, best_pos = last_pos; } cur_count = 0; - last_pos = write_iter; + last_pos = write_iter + 1; } } last_pos = 0; @@ -1507,8 +1526,8 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, /* Save the final Write Data Timing settings for later use */ pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane]; - print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 largest write passing region ", best_count, 4); - print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 largest write passing region start ", best_pos, 4); + print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 largest write passing region ", best_count, 4); + print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 146 largest write passing region start ", best_pos, 4); } else { /* Reprogram the Write DQS Timing Control register with the original settings */ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, index_reg); @@ -1517,12 +1536,16 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, #ifdef PRINT_PASS_FAIL_BITMAPS for (lane = lane_start; lane < lane_end; lane++) { - for (read_iter = 0; read_iter < 32; read_iter++) { - for (write_iter = 0; write_iter < 32; write_iter++) { - if (dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter]) + for (write_iter = 0; write_iter < 32; write_iter++) { + for (read_iter = 0; read_iter < 48; read_iter++) { + if (dqs_results_array[Receiver & 0x1][lane - lane_start][write_iter][read_iter]) { printk(BIOS_DEBUG, "+"); - else - printk(BIOS_DEBUG, "."); + } else { + if (read_iter < 16) + printk(BIOS_DEBUG, "°"); + else + printk(BIOS_DEBUG, "."); + } } printk(BIOS_DEBUG, "\n"); } |