summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineeringinc.com>2015-08-27 13:19:34 -0500
committerMartin Roth <martinroth@google.com>2015-11-29 19:38:13 +0100
commit4502df12aa0d097bb5382d369eade2f578ac015a (patch)
treebf1c148de24ee54da22f4eab4c0d2b635ce8c861 /src
parentdf499b53c3ce8acbb4c303b2041d09cb526e252e (diff)
nb/amd/mct_ddr3: Fix odd rank data corruption
The odd rank of each DIMM could experience data corruption due to incorrect DQS training. Fix the DQS training algorithm by executing the relevant portions of the training algorithm on the odd ranks. Change-Id: Ibc51f5052d5189e45b3d9aa98ca8febbfe13f178 Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: https://review.coreboot.org/12058 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
index 06597e23bb..9362a60961 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
@@ -1320,9 +1320,9 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat,
Receiver = receiver_start;
/* There are four receiver pairs, loosely associated with chipselects.
- * This is essentially looping over each DIMM.
+ * This is essentially looping over each rank within each DIMM.
*/
- for (; Receiver < receiver_end; Receiver += 2) {
+ for (; Receiver < receiver_end; Receiver++) {
dimm = (Receiver >> 1);
if ((Receiver & 0x1) == 0) {
/* Even rank of DIMM */
@@ -1336,18 +1336,27 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat,
continue;
}
+#if DQS_TRAIN_DEBUG > 0
+ printk(BIOS_DEBUG, "TrainDQSRdWrPos: Training DQS read/write position for receiver %d (DIMM %d)\n", Receiver, dimm);
+#endif
+
/* Initialize variables */
for (lane = lane_start; lane < lane_end; lane++) {
passing_dqs_delay_found[lane] = 0;
}
- memset(dqs_results_array, 0, sizeof(dqs_results_array));
+ if ((Receiver & 0x1) == 0) {
+ /* Even rank of DIMM */
+ memset(dqs_results_array, 0, sizeof(dqs_results_array));
+
+ /* Read initial read / write DQS delays */
+ read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, dimm, index_reg);
+ read_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, index_reg);
- /* Read initial read / write DQS delays */
- read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, dimm, index_reg);
- read_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, index_reg);
+ /* Read current settings of other (previously trained) lanes */
+ read_dqs_write_data_timing_registers(initial_write_data_timing, dev, dct, dimm, index_reg);
+ }
- /* Read current settings of other (previously trained) lanes */
- read_dqs_write_data_timing_registers(initial_write_data_timing, dev, dct, dimm, index_reg);
+ /* Initialize iterators */
memcpy(current_write_data_delay, initial_write_data_timing, sizeof(current_write_data_delay));
for (lane = lane_start; lane < lane_end; lane++) {