Damien Zammit (damien@zamaudio.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13725
-gerrit
commit a3d1837dd99ada2dbd7acc2e03801859e95d52f4 Author: Damien Zammit damien@zamaudio.com Date: Wed Feb 17 14:14:47 2016 +1100
nb/amd/amdmct: Select max_lanes based on ECC presence or absence
Change-Id: Ic5482dc13ab7b53ec4df408bbe32d20888ae2e12 Signed-off-by: Damien Zammit damien@zamaudio.com --- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 46 ++++---- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 69 ++++++++---- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c | 108 ++++++++++-------- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 150 ++++++++++++++----------- 4 files changed, 221 insertions(+), 152 deletions(-)
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c index 4615dd2..23c60b8 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c @@ -183,11 +183,13 @@ static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat); static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat); static void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat);
+uint8_t is_ecc_enabled(struct MCTStatStruc *pMCTstat); + static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, - uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg); + uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane);
static void read_dqs_write_timing_control_registers(uint16_t* current_total_delay, - uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg); + uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane);
/*See mctAutoInitMCT header for index relationships to CL and T*/ static const u16 Table_F_k[] = {00,200,266,333,400,533 }; @@ -329,6 +331,11 @@ static inline uint8_t is_model10_1f(void) return model101f; }
+uint8_t is_ecc_enabled(struct MCTStatStruc *pMCTstat) +{ + return !!(pMCTstat->GStatus & (1 << GSB_ECCDIMMs)); +} + static uint16_t mhz_to_memclk_config(uint16_t freq) { if (is_fam15h()) @@ -2827,12 +2834,14 @@ restartinit: InterleaveNodes_D(pMCTstat, pDCTstatA); InterleaveChannels_D(pMCTstat, pDCTstatA);
- printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n"); - if (!ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/ - /* Memory was not cleared during ECC setup */ - /* mctDoWarmResetMemClr_D(); */ - printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n"); - MCTMemClr_D(pMCTstat,pDCTstatA); + if (is_ecc_enabled(pMCTstat)) { + printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n"); + if (!ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/ + /* Memory was not cleared during ECC setup */ + /* mctDoWarmResetMemClr_D(); */ + printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n"); + MCTMemClr_D(pMCTstat,pDCTstatA); + } }
if (is_fam15h()) { @@ -3031,7 +3040,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, uint16_t cdd_trwtto_we_delta; uint8_t receiver; uint8_t max_lane; - uint8_t ecc_enabled; uint8_t x4_present = 0; uint8_t x8_present = 0; uint8_t memclk_index; @@ -3056,8 +3064,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, uint8_t buffer_data_delay; int16_t latency_difference; uint16_t difference; - uint16_t current_total_delay_1[MAX_BYTE_LANES]; - uint16_t current_total_delay_2[MAX_BYTE_LANES]; uint8_t ddr_voltage_index; uint8_t max_dimms_installable;
@@ -3074,12 +3080,14 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); max_dimms_installable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); - if (ecc_enabled) + if (is_ecc_enabled(pMCTstat)) max_lane = 9; else max_lane = 8;
+ uint16_t current_total_delay_1[max_lane]; + uint16_t current_total_delay_2[max_lane]; + if (pDCTstat->Dimmx4Present & ((dct)?0xaa:0x55)) x4_present = 1; if (pDCTstat->Dimmx8Present & ((dct)?0xaa:0x55)) @@ -3141,7 +3149,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) continue;
- read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); + read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg, max_lane);
if (first_dimm) { memcpy(current_total_delay_1, current_total_delay_2, sizeof(current_total_delay_1)); @@ -3187,7 +3195,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) continue;
- read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); + read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg, max_lane);
if (first_dimm) { memcpy(current_total_delay_1, current_total_delay_2, sizeof(current_total_delay_1)); @@ -3382,8 +3390,8 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) continue;
- read_dqs_write_timing_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); - read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); + read_dqs_write_timing_control_registers(current_total_delay_1, dev, dct, dimm, index_reg, max_lane); + read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg, max_lane);
for (lane = 0; lane < max_lane; lane++) { if (current_total_delay_1[lane] > current_total_delay_2[lane]) @@ -3436,8 +3444,8 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) continue;
- read_dqs_receiver_enable_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); - read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); + read_dqs_receiver_enable_control_registers(current_total_delay_1, dev, dct, dimm, index_reg, max_lane); + read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg, max_lane);
for (lane = 0; lane < max_lane; lane++) { if (current_total_delay_1[lane] > current_total_delay_2[lane]) diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c index 19a7acb..9f9d95f 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c @@ -15,10 +15,10 @@ */
static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, - uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg); + uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane);
static void read_read_dqs_timing_control_registers(uint16_t* current_total_delay, - uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg); + uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane);
static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat); @@ -931,8 +931,6 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, uint32_t p = 0; uint32_t n = 0; uint32_t t = 0; - uint16_t current_phy_phase_delay[MAX_BYTE_LANES]; - uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
uint32_t index_reg = 0x98; uint32_t dev = pDCTstat->dev_dct; @@ -942,6 +940,15 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, printk(BIOS_DEBUG, "%s: Start\n", __func__); #endif
+ u8 max_lane; + if (is_ecc_enabled(pMCTstat)) + max_lane = 9; + else + max_lane = 8; + + uint16_t current_phy_phase_delay[max_lane]; + uint16_t current_read_dqs_delay[max_lane]; + mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f; if (fam15h_freq_tab[mem_clk] == 0) { pDCTstat->CH_MaxRdLat[dct] = 0x55; @@ -981,9 +988,9 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, dimm * 2)) continue;
- read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg); - read_read_dqs_timing_control_registers(current_read_dqs_delay, dev, dct, dimm, index_reg); - for (lane = 0; lane < MAX_BYTE_LANES; lane++) + read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg, max_lane); + read_read_dqs_timing_control_registers(current_read_dqs_delay, dev, dct, dimm, index_reg, max_lane); + for (lane = 0; lane < max_lane; lane++) if ((current_phy_phase_delay[lane] + current_read_dqs_delay[lane]) > max_delay) max_delay = (current_phy_phase_delay[lane] + current_read_dqs_delay[lane]); } @@ -1318,13 +1325,6 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, uint8_t write_iter; uint8_t read_iter; uint8_t check_antiphase; - uint16_t initial_write_dqs_delay[MAX_BYTE_LANES]; - uint16_t initial_read_dqs_delay[MAX_BYTE_LANES]; - uint16_t initial_write_data_timing[MAX_BYTE_LANES]; - uint16_t current_write_data_delay[MAX_BYTE_LANES]; - 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][48]; /* [rank][lane][write step][read step + 16] */
uint8_t last_pos = 0; @@ -1335,6 +1335,20 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, uint32_t index_reg = 0x98; uint32_t dev = pDCTstat->dev_dct;
+ u8 max_lane; + if (is_ecc_enabled(pMCTstat)) + max_lane = 9; + else + max_lane = 8; + + uint16_t initial_write_dqs_delay[max_lane]; + uint16_t initial_read_dqs_delay[max_lane]; + uint16_t initial_write_data_timing[max_lane]; + uint16_t current_write_data_delay[max_lane]; + uint16_t current_read_dqs_delay[max_lane]; + uint16_t current_write_dqs_delay[max_lane]; + uint8_t passing_dqs_delay_found[max_lane]; + /* Calculate and program MaxRdLatency */ Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0);
@@ -1374,7 +1388,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, 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_write_timing_control_registers(initial_write_dqs_delay, dev, dct, dimm, index_reg, max_lane); read_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, index_reg);
/* Read current settings of other (previously trained) lanes */ @@ -1665,15 +1679,22 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, uint32_t dword; uint32_t rx_en_offset; uint8_t dct_training_success; - uint16_t initial_phy_phase_delay[MAX_BYTE_LANES]; - uint16_t current_phy_phase_delay[MAX_BYTE_LANES]; - uint8_t lane_training_success[MAX_BYTE_LANES]; uint8_t dqs_results_array[1024];
uint16_t ren_step = 0x40; uint32_t index_reg = 0x98; uint32_t dev = pDCTstat->dev_dct;
+ u8 max_lane; + if (is_ecc_enabled(pMCTstat)) + max_lane = 9; + else + max_lane = 8; + + uint16_t initial_phy_phase_delay[max_lane]; + uint16_t current_phy_phase_delay[max_lane]; + uint8_t lane_training_success[max_lane]; + print_debug_dqs("\nTrainDQSReceiverEnCyc: Node_ID ", pDCTstat->Node_ID, 0); cr4 = read_cr4(); if (cr4 & (1<<9)) { @@ -1723,13 +1744,13 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, continue; }
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) + for (lane = 0; lane < max_lane; lane++) lane_training_success[lane] = 0;
/* 2.10.5.8.3 (2) */ - read_dqs_receiver_enable_control_registers(initial_phy_phase_delay, dev, dct, dimm, index_reg); + read_dqs_receiver_enable_control_registers(initial_phy_phase_delay, dev, dct, dimm, index_reg, max_lane);
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { /* Initialize variables */ memset(dqs_results_array, 0, sizeof(dqs_results_array));
@@ -1751,7 +1772,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, #endif
/* 2.10.5.8.3 (4 A) */ - write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg, max_lane);
/* Calculate and program MaxRdLatency */ Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0); @@ -1796,7 +1817,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, current_phy_phase_delay[lane] -= 0x10;
/* Update hardware registers with final values */ - write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg, max_lane); break; } prev = dqs_results_array[current_phy_phase_delay[lane]]; @@ -1817,7 +1838,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
#if DQS_TRAIN_DEBUG > 0 printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc_D_Fam15 DQS receiver enable timing: "); - for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { printk(BIOS_DEBUG, " %03x", current_phy_phase_delay[lane]); } printk(BIOS_DEBUG, "\n"); diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c index b8d89fe..9e3bed8 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c @@ -236,12 +236,12 @@ static uint16_t fam15_receiver_enable_training_seed(struct DCTStatStruc *pDCTsta return seed; }
-static void read_dqs_write_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg) +static void read_dqs_write_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane) { uint8_t lane; uint32_t dword;
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint32_t wdt_reg; if ((lane == 0) || (lane == 1)) wdt_reg = 0x30; @@ -295,12 +295,12 @@ static void write_dqs_write_timing_control_registers(uint16_t* current_total_del } #endif
-static void write_write_data_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg) +static void write_write_data_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane) { uint8_t lane; uint32_t dword;
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint32_t wdt_reg;
/* Calculate Write Data Timing register location */ @@ -334,7 +334,7 @@ static void write_write_data_timing_control_registers(uint16_t* current_total_de } }
-static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg) +static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane) { uint8_t lane; uint32_t mask; @@ -345,7 +345,7 @@ static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_d else mask = 0x1ff;
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint32_t ret_reg; if ((lane == 0) || (lane == 1)) ret_reg = 0x10; @@ -368,7 +368,7 @@ static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_d } }
-static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg) +static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane) { uint8_t lane; uint32_t mask; @@ -379,7 +379,7 @@ static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_ else mask = 0x1ff;
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint32_t ret_reg; if ((lane == 0) || (lane == 1)) ret_reg = 0x10; @@ -405,12 +405,12 @@ static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_ } }
-static void read_dram_phase_recovery_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg) +static void read_dram_phase_recovery_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane) { uint8_t lane; uint32_t dword;
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint32_t prc_reg;
/* Calculate DRAM Phase Recovery Control register location */ @@ -437,12 +437,12 @@ static void read_dram_phase_recovery_control_registers(uint16_t* current_total_d } }
-static void write_dram_phase_recovery_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg) +static void write_dram_phase_recovery_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane) { uint8_t lane; uint32_t dword;
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint32_t prc_reg;
/* Calculate DRAM Phase Recovery Control register location */ @@ -475,12 +475,12 @@ static void write_dram_phase_recovery_control_registers(uint16_t* current_total_ } }
-static void read_read_dqs_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg) +static void read_read_dqs_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg, u8 max_lane) { uint8_t lane; uint32_t dword;
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint32_t rdt_reg;
/* Calculate DRAM Read DQS Timing register location */ @@ -646,14 +646,14 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat, /* 2.8.9.9.2 (1, 6) * Retrieve gross and fine timing fields from write DQS registers */ - read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES);
/* 2.8.9.9.2 (1) * Program the Write Data Timing and Write ECC Timing register to * the values stored in the DQS Write Timing Control register * for each lane */ - write_write_data_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_write_data_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES);
/* 2.8.9.9.2 (2) * Program the Read DQS Timing Control and the Read DQS ECC Timing Control registers @@ -721,7 +721,7 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat, /* 2.8.9.9.2 (6) * Write gross and fine timing fields to read DQS registers */ - write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES);
/* 2.8.9.9.2 (7) * Loop over all delay values up to 1 MEMCLK (0x40 delay steps) from the initial delay values @@ -765,17 +765,17 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat, */ proc_IOCLFLUSH_D((rank == 0)?TestAddr0B:TestAddr1B); result_qword2 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0B:TestAddr1B, Channel)); - write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES); proc_IOCLFLUSH_D((rank == 0)?TestAddr0:TestAddr1); result_qword1 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0:TestAddr1, Channel)); - write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES); } else { proc_IOCLFLUSH_D((rank == 0)?TestAddr0:TestAddr1); result_qword1 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0:TestAddr1, Channel)); - write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES); proc_IOCLFLUSH_D((rank == 0)?TestAddr0B:TestAddr1B); result_qword2 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0B:TestAddr1B, Channel)); - write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES); } /* 2.8.9.9.2 (7 A e) * Compare both read patterns and flag passing ranks/lanes @@ -864,7 +864,7 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat, }
/* Update delays in hardware */ - write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, MAX_BYTE_LANES);
/* Save previous results for comparison in the next iteration */ for (lane = 0; lane < 8; lane++) @@ -1148,18 +1148,26 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, uint8_t mem_clk; uint16_t initial_seed; uint8_t train_both_nibbles; - uint16_t 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]; - uint16_t seed[MAX_BYTE_LANES]; - uint16_t seed_gross[MAX_BYTE_LANES]; - uint16_t seed_fine[MAX_BYTE_LANES]; - uint16_t seed_pre_gross[MAX_BYTE_LANES];
uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE); uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+ u8 max_lane; + u8 ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8; + + uint16_t current_total_delay[max_lane]; + uint16_t dqs_ret_pass1_total_delay[max_lane]; + uint16_t rank0_current_total_delay[max_lane]; + uint16_t phase_recovery_delays[max_lane]; + uint16_t seed[max_lane]; + uint16_t seed_gross[max_lane]; + uint16_t seed_fine[max_lane]; + uint16_t seed_pre_gross[max_lane]; + print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0); print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
@@ -1239,7 +1247,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
/* Retrieve the total delay values from pass 1 of DQS receiver enable training */ if (Pass != FirstPass) { - read_dqs_receiver_enable_control_registers(dqs_ret_pass1_total_delay, dev, Channel, dimm, index_reg); + read_dqs_receiver_enable_control_registers(dqs_ret_pass1_total_delay, dev, Channel, dimm, index_reg, max_lane); }
/* 2.10.5.8.2 @@ -1264,7 +1272,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, /* 2.10.5.8.2 (2) * Retrieve gross and fine timing fields from write DQS registers */ - read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg, max_lane);
/* 2.10.5.8.2.1 * Generate the DQS Receiver Enable Training Seed Values @@ -1276,7 +1284,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, initial_seed = (uint16_t) (((((uint64_t) initial_seed) * fam15h_freq_tab[mem_clk] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { uint16_t wl_pass1_delay; wl_pass1_delay = current_total_delay[lane];
@@ -1302,13 +1310,13 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, register_delay = 0x0; }
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { seed_prescaling = current_total_delay[lane] - register_delay - 0x20; seed[lane] = (uint16_t) (register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100))); } }
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { seed_gross[lane] = (seed[lane] >> 5) & 0x1f; seed_fine[lane] = seed[lane] & 0x1f;
@@ -1332,12 +1340,12 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6) * Program PhRecFineDly and PhRecGrossDly */ - write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg); + write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg, max_lane);
/* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7) * Program the DQS Receiver Enable delay values for each lane */ - write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, max_lane);
/* 2.10.5.8.2 (3) * Program DqsRcvTrEn = 1 @@ -1361,12 +1369,12 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, /* 2.10.5.8.2 (6) * Read PhRecGrossDly, PhRecFineDly */ - read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg); + read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg, max_lane);
/* 2.10.5.8.2 (7) * Calculate and program the DQS Receiver Enable delay values */ - for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; 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) { @@ -1390,7 +1398,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, printk(BIOS_DEBUG, "\t\tTrainRcvEn55: Channel: %d dimm: %d nibble: %d lane %d current_total_delay: %04x CH_D_B_RCVRDLY: %04x\n", 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); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, max_lane); }
if (rank == 0) { @@ -1403,14 +1411,14 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, * Compute the average delay across both ranks and program the result into * the DQS Receiver Enable delay registers */ - for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; 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); + write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, max_lane); } }
@@ -1526,11 +1534,19 @@ static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat, uint8_t mem_clk; uint32_t nb_clk; uint8_t nb_pstate; - uint16_t current_total_delay[MAX_BYTE_LANES]; - uint16_t current_rdqs_total_delay[MAX_BYTE_LANES]; uint8_t current_worst_case_total_delay_dimm; uint16_t current_worst_case_total_delay_value;
+ u8 max_lane; + u8 ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8; + + uint16_t current_total_delay[max_lane]; + uint16_t current_rdqs_total_delay[max_lane]; + uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
print_debug_dqs("\nTrainMaxRdLatency: Node", pDCTstat->Node_ID, 0); @@ -1592,8 +1608,8 @@ static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat, }
/* Retrieve the total delay values from pass 1 of DQS receiver enable training */ - read_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); - read_read_dqs_timing_control_registers(current_rdqs_total_delay, dev, Channel, dimm, index_reg); + read_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg, max_lane); + read_read_dqs_timing_control_registers(current_rdqs_total_delay, dev, Channel, dimm, index_reg, max_lane);
for (lane = 0; lane < 8; lane++) { current_total_delay[lane] += current_rdqs_total_delay[lane]; diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c index 2b8a997..258da21 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c @@ -32,8 +32,8 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, BOOL wl); void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm); void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble); -void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass); -void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass, uint8_t nibble); +void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass, u8 max_lane); +void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass, uint8_t nibble, u8 max_lane);
static int32_t abs(int32_t val) { if (val < 0) @@ -77,6 +77,12 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT u16 Addl_Data_Offset, Addl_Data_Port; sMCTStruct *pMCTData = pDCTstat->C_MCTPtr; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; + uint8_t max_lane; + + if (is_ecc_enabled(pMCTstat)) + max_lane = 9; + else + max_lane = 8;
pDCTData->WLPass = pass; /* 1. Specify the target DIMM that is to be trained by programming @@ -176,8 +182,8 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 * to get the gross and fine delay settings * for the target DIMM and save these values. */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { - getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, nibble); + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { + getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, nibble, max_lane); }
pDCTData->WLCriticalGrossDelayPrevPass = 0x0; @@ -192,11 +198,17 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT u8 ByteLane; uint8_t status = 0; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; + uint8_t max_lane; + + if (is_ecc_enabled(pMCTstat)) + max_lane = 9; + else + max_lane = 8;
if (is_fam15h()) { - int32_t gross_diff[MAX_BYTE_LANES]; + int32_t gross_diff[max_lane]; int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass; - uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm); + uint8_t index = (uint8_t)(max_lane * dimm);
printk(BIOS_SPEW, "\toriginal critical gross delay: %d\n", cgd);
@@ -205,7 +217,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT */
/* Calculate the Critical Gross Delay */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Calculate the gross delay differential for this lane */ gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane]; gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane]; @@ -231,7 +243,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT * Figure out why this is and fix it, then remove the bypass code below... */ if (pass == FirstPass) { - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane]; pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane]; } @@ -240,7 +252,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT }
/* Compensate for occasional noise/instability causing sporadic training failure */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { uint8_t faulty_value_detected = 0; uint16_t total_delay_seed = ((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f); uint16_t total_delay_phy = ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f); @@ -278,12 +290,18 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT u8 ByteLane; sMCTStruct *pMCTData = pDCTstat->C_MCTPtr; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; + u8 max_lane; + + if (is_ecc_enabled(pMCTstat)) + max_lane = 9; + else + max_lane = 8;
if (is_fam15h()) { uint32_t dword; - int32_t gross_diff[MAX_BYTE_LANES]; + int32_t gross_diff[max_lane]; int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass; - uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm); + uint8_t index = (uint8_t)(max_lane * dimm);
/* Apply offset(s) if needed */ if (cgd < 0) { @@ -292,7 +310,7 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT dword |= ((abs(cgd) & 0x3) << 24); Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
- for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Calculate the gross delay differential for this lane */ gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane]; gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane]; @@ -313,8 +331,8 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
/* Write the adjusted gross and fine delay settings * to the target DIMM. */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { - setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass); + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { + setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass, max_lane); }
/* 6. Configure DRAM Phy Control Register so that the phy stops driving @@ -1006,6 +1024,12 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800}; uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933}; + uint8_t max_lane; + + if (is_ecc_enabled(pMCTstat)) + max_lane = 9; + else + max_lane = 8;
if (is_fam15h()) { /* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 667MHz; 0x12: 800MHz; 0x16: 933MHz */ @@ -1113,9 +1137,9 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui Seed_Fine = Seed_Total & 0x1f;
/* Save seed values for later use */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { - pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; - pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { + pDCTData->WLSeedGrossDelay[max_lane*dimm+ByteLane] = Seed_Gross; + pDCTData->WLSeedFineDelay[max_lane*dimm+ByteLane] = Seed_Fine;
if (Seed_Gross == 0) Seed_PreGross = 0; @@ -1124,7 +1148,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui else Seed_PreGross = 2;
- pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross; + pDCTData->WLSeedPreGrossDelay[max_lane*dimm+ByteLane] = Seed_PreGross; } } else { if (pDCTData->Status[DCT_STATUS_REGISTERED]) { @@ -1150,7 +1174,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui } } } - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Program an initialization value to registers F2x[1, 0]9C_x[51:50] and * F2x[1, 0]9C_x52 to set the gross and fine delay for all the byte lane fields @@ -1160,8 +1184,8 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui * of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined * by design. */ - pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; - pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; + pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] = Seed_Gross; + pDCTData->WLFineDelay[max_lane*dimm+ByteLane] = Seed_Fine; printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f)); } } else { @@ -1170,8 +1194,8 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui /* From BKDG, Write Leveling Seed Value. */ if (is_fam15h()) { uint32_t RegisterDelay; - int32_t SeedTotal[MAX_BYTE_LANES]; - int32_t SeedTotalPreScaling[MAX_BYTE_LANES]; + int32_t SeedTotal[max_lane]; + int32_t SeedTotalPreScaling[max_lane]; uint32_t WrDqDqsEarly; uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
@@ -1194,17 +1218,17 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui WrDqDqsEarly = 0;
/* Generate new seed values */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Calculate adjusted seed values */ - SeedTotal[ByteLane] = (pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) | - ((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5); + SeedTotal[ByteLane] = (pDCTData->WLFineDelayPrevPass[max_lane*dimm+ByteLane] & 0x1f) | + ((pDCTData->WLGrossDelayPrevPass[max_lane*dimm+ByteLane] & 0x1f) << 5); SeedTotalPreScaling[ByteLane] = (SeedTotal[ByteLane] - RegisterDelay - (0x20 * WrDqDqsEarly)); SeedTotal[ByteLane] = (int32_t) (RegisterDelay + ((((int64_t) SeedTotalPreScaling[ByteLane]) * fam15h_freq_tab[MemClkFreq] * 100) / (fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100))); }
/* Generate register values from seeds */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { printk(BIOS_SPEW, "\tLane %02x scaled delay: %04x\n", ByteLane, SeedTotal[ByteLane]);
if (SeedTotal[ByteLane] >= 0) { @@ -1229,21 +1253,21 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui Seed_PreGross = Seed_Gross;
/* Save seed values for later use */ - pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; - pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; - pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross; + pDCTData->WLSeedGrossDelay[max_lane*dimm+ByteLane] = Seed_Gross; + pDCTData->WLSeedFineDelay[max_lane*dimm+ByteLane] = Seed_Fine; + pDCTData->WLSeedPreGrossDelay[max_lane*dimm+ByteLane] = Seed_PreGross;
- pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross; - pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; + pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] = Seed_PreGross; + pDCTData->WLFineDelay[max_lane*dimm+ByteLane] = Seed_Fine;
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f)); + printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[max_lane*dimm+ByteLane] & 0x1f)); } } else { uint32_t RegisterDelay; uint32_t SeedTotalPreScaling; uint32_t SeedTotal; uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { if (pDCTData->Status[DCT_STATUS_REGISTERED]) { if (AddrCmdPrelaunch == 0) @@ -1253,8 +1277,8 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui } else { RegisterDelay = 0; } - SeedTotalPreScaling = ((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) | - (pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay; + SeedTotalPreScaling = ((pDCTData->WLFineDelay[max_lane*dimm+ByteLane] & 0x1f) | + (pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] << 5)) - RegisterDelay; /* SeedTotalPreScaling = (the total delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization training) - RegisterDelay. */ SeedTotal = (uint16_t) ((((uint64_t) SeedTotalPreScaling) * @@ -1277,49 +1301,49 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui Seed_Gross = SeedTotal / 32; Seed_Fine = SeedTotal & 0x1f;
- pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; - pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; + pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] = Seed_Gross; + pDCTData->WLFineDelay[max_lane*dimm+ByteLane] = Seed_Fine;
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f)); + printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[max_lane*dimm+ByteLane] & 0x1f)); } }
/* Save initial seeds for upper nibble pass */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { - pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane]; - pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane]; - pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane]; + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { + pDCTData->WLSeedPreGrossPrevNibble[max_lane*dimm+ByteLane] = pDCTData->WLSeedPreGrossDelay[max_lane*dimm+ByteLane]; + pDCTData->WLSeedGrossPrevNibble[max_lane*dimm+ByteLane] = pDCTData->WLGrossDelay[max_lane*dimm+ByteLane]; + pDCTData->WLSeedFinePrevNibble[max_lane*dimm+ByteLane] = pDCTData->WLFineDelay[max_lane*dimm+ByteLane]; } } else { /* Restore seed values from lower nibble pass */ if (is_fam15h()) { - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { - pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; - pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; - pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { + pDCTData->WLSeedGrossDelay[max_lane*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[max_lane*dimm+ByteLane]; + pDCTData->WLSeedFineDelay[max_lane*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[max_lane*dimm+ByteLane]; + pDCTData->WLSeedPreGrossDelay[max_lane*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[max_lane*dimm+ByteLane];
- pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; - pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; + pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[max_lane*dimm+ByteLane]; + pDCTData->WLFineDelay[max_lane*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[max_lane*dimm+ByteLane];
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f)); + printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[max_lane*dimm+ByteLane] & 0x1f)); } } else { - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { - pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; - pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { + pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[max_lane*dimm+ByteLane]; + pDCTData->WLFineDelay[max_lane*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[max_lane*dimm+ByteLane];
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f)); + printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[max_lane*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[max_lane*dimm+ByteLane] & 0x1f)); } } } }
pDCTData->WLPrevMemclkFreq = MemClkFreq; - setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass); + setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass, max_lane); }
/*----------------------------------------------------------------------------- - * void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm){ + * void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm, u8 max_lane){ * * Description: * This function writes the write levelization byte delay for the Phase @@ -1339,7 +1363,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui * *----------------------------------------------------------------------------- */ -void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass) +void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass, u8 max_lane) { sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr; @@ -1347,12 +1371,12 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
if (targetAddr == 0) { - index = (u8)(MAX_BYTE_LANES * dimm); + index = (u8)(max_lane * dimm); ValueLow = 0; ValueHigh = 0; ByteLane = 0; EccValue = 0; - while (ByteLane < MAX_BYTE_LANES) + while (ByteLane < max_lane) { if (is_fam15h()) { grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane]; @@ -1394,7 +1418,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 else { /* Fam10h BKDG Rev. 3.62 2.8.9.9.1 (6) */ - index = (u8)(MAX_BYTE_LANES * dimm); + index = (u8)(max_lane * dimm); grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane]; fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
@@ -1440,7 +1464,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 }
/*----------------------------------------------------------------------------- - * void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm, u8 Nibble) + * void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm, u8 Nibble, u8 max_lane) * * Description: * This function reads the write levelization byte delay from the Phase @@ -1458,13 +1482,13 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 * *----------------------------------------------------------------------------- */ -void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass, uint8_t nibble) +void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass, uint8_t nibble, u8 max_lane) { sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index; u32 addr, fine, gross; tempB = 0; - index = (u8)(MAX_BYTE_LANES*dimm); + index = (u8)(max_lane*dimm); if (ByteLane < 4) { tempB = (u8)(8 * ByteLane); addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;