[coreboot-gerrit] New patch to review for coreboot: nb/amd/mct_ddr3: Fix x4 DIMM receiver enable training on Fam15h

Timothy Pearson (tpearson@raptorengineeringinc.com) gerrit at coreboot.org
Fri Apr 29 07:40:43 CEST 2016


Timothy Pearson (tpearson at raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14541

-gerrit

commit 52b2f2fe258558f2a8cd49d7ef4a54c3e7648bc6
Author: Timothy Pearson <tpearson at raptorengineeringinc.com>
Date:   Fri Apr 29 00:38:29 2016 -0500

    nb/amd/mct_ddr3: Fix x4 DIMM receiver enable training on Fam15h
    
    The existing Family 51h receiver enable training code stored
    temporary delay values in the wrong variables, leading to
    the requisite averaging of delays across nibbles not being
    applied.  This in turn made x4 DIMMs less stable than they
    should have been.
    
    Store temporary nibble delay values in a dedicated array.
    
    Change-Id: Ic5da898af7d689db4110211f89b886ccdbb5f78f
    Signed-off-by: Timothy Pearson <tpearson at raptorengineeringinc.com>
---
 src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c | 47 +++++++++++++++-------------
 1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
index c8c75e1..90c612d 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
@@ -1194,6 +1194,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
 	uint16_t initial_seed;
 	uint8_t train_both_nibbles;
 	uint16_t current_total_delay[MAX_BYTE_LANES];
+	uint16_t nibble0_current_total_delay[MAX_BYTE_LANES];
 	uint16_t dqs_ret_pass1_total_delay[MAX_BYTE_LANES];
 	uint16_t rank0_current_total_delay[MAX_BYTE_LANES];
 	uint16_t phase_recovery_delays[MAX_BYTE_LANES];
@@ -1419,19 +1420,11 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
 					for (lane = 0; lane < lane_count; lane++) {
 						current_total_delay[lane] = (phase_recovery_delays[lane] & 0x1f);
 						current_total_delay[lane] |= ((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - seed_pre_gross[lane] + 1) << 5);
-						if (nibble == 0) {
-							if (lane == 8)
-								pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
-							else
-								pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
-						} else {
+						if (nibble == 1) {
 							/* 2.10.5.8.2 (1)
 							 * Average the trained values of both nibbles on x4 DIMMs
 							 */
-							if (lane == 8)
-								pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = (pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] + current_total_delay[lane]) / 2;
-							else
-								pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = (pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] + current_total_delay[lane]) / 2;
+							current_total_delay[lane] = (nibble0_current_total_delay[lane] + current_total_delay[lane]) / 2;
 						}
 					}
 
@@ -1441,26 +1434,38 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
 							Channel, dimm, nibble, lane, current_total_delay[lane], pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane]);
 #endif
 					write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
-				}
 
-				if (rank == 0) {
-					/* Back up the Rank 0 delays for later use */
-					memcpy(rank0_current_total_delay, current_total_delay, sizeof(current_total_delay));
+					/* Back up the Nibble 0 delays for later use */
+					memcpy(nibble0_current_total_delay, current_total_delay, sizeof(current_total_delay));
 				}
 
-				if (rank == 1) {
-					/* 2.10.5.8.2 (8)
-					 * Compute the average delay across both ranks and program the result into
-					 * the DQS Receiver Enable delay registers
-					 */
+				if (_2Ranks) {
+					if (rank == 0) {
+						/* Back up the Rank 0 delays for later use */
+						memcpy(rank0_current_total_delay, current_total_delay, sizeof(current_total_delay));
+					}
+					if (rank == 1) {
+						/* 2.10.5.8.2 (8)
+						 * Compute the average delay across both ranks and program the result into
+						 * the DQS Receiver Enable delay registers
+						 */
+						for (lane = 0; lane < lane_count; lane++) {
+							current_total_delay[lane] = (rank0_current_total_delay[lane] + current_total_delay[lane]) / 2;
+							if (lane == 8)
+								pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
+							else
+								pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
+						}
+						write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
+					}
+				} else {
+					/* Save the current delay for later use by other routines */
 					for (lane = 0; lane < lane_count; lane++) {
-						current_total_delay[lane] = (rank0_current_total_delay[lane] + current_total_delay[lane]) / 2;
 						if (lane == 8)
 							pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
 						else
 							pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
 					}
-					write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
 				}
 			}
 



More information about the coreboot-gerrit mailing list