nb/amd/amdmct: Select max_lanes based on ECC presence or absence

Change-Id: Ic5482dc13ab7b53ec4df408bbe32d20888ae2e12
Signed-off-by: Damien Zammit <damien@zamaudio.com>
Reviewed-on: https://review.coreboot.org/13725
Tested-by: build bot (Jenkins)
Tested-by: Raptor Engineering Automated Test Stand <noreply@raptorengineeringinc.com>
Reviewed-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
Damien Zammit 2016-02-17 14:14:47 +11:00 committed by Martin Roth
parent 4cd9a11477
commit ec38c3d956
4 changed files with 151 additions and 88 deletions

View File

@ -183,6 +183,9 @@ static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat); static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
static void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat); static void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat);
uint8_t is_ecc_enabled(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
uint8_t get_available_lane_count(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
static void read_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, 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);
@ -329,6 +332,31 @@ static inline uint8_t is_model10_1f(void)
return model101f; return model101f;
} }
uint8_t is_ecc_enabled(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
{
uint8_t ecc_enabled = 1;
if (!mctGet_NVbits(NV_ECC_CAP) || !mctGet_NVbits(NV_ECC)) {
return 0;
}
if (pDCTstat->NodePresent && pDCTstat->DIMMValid) {
if (!(pDCTstat->Status & (1 << SB_ECCDIMMs))) {
ecc_enabled = 0;
}
}
return !!ecc_enabled;
}
uint8_t get_available_lane_count(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
{
if (is_ecc_enabled(pMCTstat, pDCTstat))
return 9;
else
return 8;
}
static uint16_t mhz_to_memclk_config(uint16_t freq) static uint16_t mhz_to_memclk_config(uint16_t freq)
{ {
if (is_fam15h()) if (is_fam15h())
@ -2625,6 +2653,7 @@ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
uint8_t dimm; uint8_t dimm;
uint8_t nvram; uint8_t nvram;
uint8_t enable_cc6; uint8_t enable_cc6;
uint8_t ecc_enabled;
uint8_t allow_config_restore; uint8_t allow_config_restore;
uint8_t s3resume = acpi_is_wakeup_s3(); uint8_t s3resume = acpi_is_wakeup_s3();
@ -2827,6 +2856,17 @@ restartinit:
InterleaveNodes_D(pMCTstat, pDCTstatA); InterleaveNodes_D(pMCTstat, pDCTstatA);
InterleaveChannels_D(pMCTstat, pDCTstatA); InterleaveChannels_D(pMCTstat, pDCTstatA);
ecc_enabled = 1;
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
struct DCTStatStruc *pDCTstat;
pDCTstat = pDCTstatA + Node;
if (pDCTstat->NodePresent)
if (!is_ecc_enabled(pMCTstat, pDCTstat))
ecc_enabled = 0;
}
if (ecc_enabled) {
printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n"); printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
if (!ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/ if (!ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/
/* Memory was not cleared during ECC setup */ /* Memory was not cleared during ECC setup */
@ -2834,6 +2874,7 @@ restartinit:
printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n"); printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
MCTMemClr_D(pMCTstat,pDCTstatA); MCTMemClr_D(pMCTstat,pDCTstatA);
} }
}
if (is_fam15h()) { if (is_fam15h()) {
printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n"); printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
@ -3030,8 +3071,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
uint16_t max_cdd_we_delta; uint16_t max_cdd_we_delta;
uint16_t cdd_trwtto_we_delta; uint16_t cdd_trwtto_we_delta;
uint8_t receiver; uint8_t receiver;
uint8_t max_lane; uint8_t lane_count;
uint8_t ecc_enabled;
uint8_t x4_present = 0; uint8_t x4_present = 0;
uint8_t x8_present = 0; uint8_t x8_present = 0;
uint8_t memclk_index; uint8_t memclk_index;
@ -3074,11 +3114,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
max_dimms_installable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); max_dimms_installable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); lane_count = get_available_lane_count(pMCTstat, pDCTstat);
if (ecc_enabled)
max_lane = 9;
else
max_lane = 8;
if (pDCTstat->Dimmx4Present & ((dct)?0xaa:0x55)) if (pDCTstat->Dimmx4Present & ((dct)?0xaa:0x55))
x4_present = 1; x4_present = 1;
@ -3148,7 +3184,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
first_dimm = 0; first_dimm = 0;
} }
for (lane = 0; lane < max_lane; lane++) { for (lane = 0; lane < lane_count; lane++) {
if (current_total_delay_1[lane] > current_total_delay_2[lane]) if (current_total_delay_1[lane] > current_total_delay_2[lane])
difference = current_total_delay_1[lane] - current_total_delay_2[lane]; difference = current_total_delay_1[lane] - current_total_delay_2[lane];
else else
@ -3194,7 +3230,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
first_dimm = 0; first_dimm = 0;
} }
for (lane = 0; lane < max_lane; lane++) { for (lane = 0; lane < lane_count; lane++) {
if (current_total_delay_1[lane] > current_total_delay_2[lane]) if (current_total_delay_1[lane] > current_total_delay_2[lane])
difference = current_total_delay_1[lane] - current_total_delay_2[lane]; difference = current_total_delay_1[lane] - current_total_delay_2[lane];
else else
@ -3385,7 +3421,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
read_dqs_write_timing_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); 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_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg);
for (lane = 0; lane < max_lane; lane++) { for (lane = 0; lane < lane_count; lane++) {
if (current_total_delay_1[lane] > current_total_delay_2[lane]) if (current_total_delay_1[lane] > current_total_delay_2[lane])
difference = current_total_delay_1[lane] - current_total_delay_2[lane]; difference = current_total_delay_1[lane] - current_total_delay_2[lane];
else else
@ -3439,7 +3475,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
read_dqs_receiver_enable_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); 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_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg);
for (lane = 0; lane < max_lane; lane++) { for (lane = 0; lane < lane_count; lane++) {
if (current_total_delay_1[lane] > current_total_delay_2[lane]) if (current_total_delay_1[lane] > current_total_delay_2[lane])
difference = current_total_delay_1[lane] - current_total_delay_2[lane]; difference = current_total_delay_1[lane] - current_total_delay_2[lane];
else else

View File

@ -875,6 +875,9 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
printk(BIOS_DEBUG, "%s: Start\n", __func__); printk(BIOS_DEBUG, "%s: Start\n", __func__);
#endif #endif
uint8_t lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f; mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
if (fam15h_freq_tab[mem_clk] == 0) { if (fam15h_freq_tab[mem_clk] == 0) {
pDCTstat->CH_MaxRdLat[dct][0] = 0x55; pDCTstat->CH_MaxRdLat[dct][0] = 0x55;
@ -917,7 +920,7 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg); read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg);
read_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, index_reg); read_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, index_reg);
for (lane = 0; lane < MAX_BYTE_LANES; lane++) for (lane = 0; lane < lane_count; lane++)
if ((current_phy_phase_delay[lane] + current_read_dqs_delay[lane]) > max_delay) 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]); max_delay = (current_phy_phase_delay[lane] + current_read_dqs_delay[lane]);
} }
@ -1271,6 +1274,9 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat,
uint32_t index_reg = 0x98; uint32_t index_reg = 0x98;
uint32_t dev = pDCTstat->dev_dct; uint32_t dev = pDCTstat->dev_dct;
uint8_t lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
/* Calculate and program MaxRdLatency */ /* Calculate and program MaxRdLatency */
Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0); Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0);
@ -1621,6 +1627,9 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
uint32_t index_reg = 0x98; uint32_t index_reg = 0x98;
uint32_t dev = pDCTstat->dev_dct; uint32_t dev = pDCTstat->dev_dct;
uint8_t lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
print_debug_dqs("\nTrainDQSReceiverEnCyc: Node_ID ", pDCTstat->Node_ID, 0); print_debug_dqs("\nTrainDQSReceiverEnCyc: Node_ID ", pDCTstat->Node_ID, 0);
cr4 = read_cr4(); cr4 = read_cr4();
if (cr4 & (1<<9)) { if (cr4 & (1<<9)) {
@ -1678,7 +1687,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
/* 2.10.5.8.3 (2) */ /* 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);
for (lane = 0; lane < MAX_BYTE_LANES; lane++) { for (lane = 0; lane < lane_count; lane++) {
/* Initialize variables */ /* Initialize variables */
memset(dqs_results_array, 0, sizeof(dqs_results_array)); memset(dqs_results_array, 0, sizeof(dqs_results_array));
@ -1780,7 +1789,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
#if DQS_TRAIN_DEBUG > 0 #if DQS_TRAIN_DEBUG > 0
printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc_D_Fam15 DQS receiver enable timing: "); printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc_D_Fam15 DQS receiver enable timing: ");
for (lane = 0; lane < MAX_BYTE_LANES; lane++) { for (lane = 0; lane < lane_count; lane++) {
printk(BIOS_DEBUG, " %03x", current_phy_phase_delay[lane]); printk(BIOS_DEBUG, " %03x", current_phy_phase_delay[lane]);
} }
printk(BIOS_DEBUG, "\n"); printk(BIOS_DEBUG, "\n");

View File

@ -1205,6 +1205,9 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE); 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}; 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 lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0); print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
print_debug_dqs("TrainRcvEn: Pass", Pass, 0); print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
@ -1323,7 +1326,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
initial_seed = (uint16_t) (((((uint64_t) initial_seed) * initial_seed = (uint16_t) (((((uint64_t) initial_seed) *
fam15h_freq_tab[mem_clk] * 100) / (min_mem_clk * 100))); fam15h_freq_tab[mem_clk] * 100) / (min_mem_clk * 100)));
for (lane = 0; lane < MAX_BYTE_LANES; lane++) { for (lane = 0; lane < lane_count; lane++) {
uint16_t wl_pass1_delay; uint16_t wl_pass1_delay;
wl_pass1_delay = current_total_delay[lane]; wl_pass1_delay = current_total_delay[lane];
@ -1349,13 +1352,13 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
register_delay = 0x0; register_delay = 0x0;
} }
for (lane = 0; lane < MAX_BYTE_LANES; lane++) { for (lane = 0; lane < lane_count; lane++) {
seed_prescaling = current_total_delay[lane] - register_delay - 0x20; 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) / (min_mem_clk * 100))); seed[lane] = (uint16_t) (register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 100) / (min_mem_clk * 100)));
} }
} }
for (lane = 0; lane < MAX_BYTE_LANES; lane++) { for (lane = 0; lane < lane_count; lane++) {
seed_gross[lane] = (seed[lane] >> 5) & 0x1f; seed_gross[lane] = (seed[lane] >> 5) & 0x1f;
seed_fine[lane] = seed[lane] & 0x1f; seed_fine[lane] = seed[lane] & 0x1f;
@ -1413,7 +1416,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
/* 2.10.5.8.2 (7) /* 2.10.5.8.2 (7)
* Calculate and program the DQS Receiver Enable delay values * Calculate and program the DQS Receiver Enable delay values
*/ */
for (lane = 0; lane < MAX_BYTE_LANES; lane++) { for (lane = 0; lane < lane_count; lane++) {
current_total_delay[lane] = (phase_recovery_delays[lane] & 0x1f); 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); current_total_delay[lane] |= ((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - seed_pre_gross[lane] + 1) << 5);
if (nibble == 0) { if (nibble == 0) {
@ -1450,7 +1453,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
* Compute the average delay across both ranks and program the result into * Compute the average delay across both ranks and program the result into
* the DQS Receiver Enable delay registers * the DQS Receiver Enable delay registers
*/ */
for (lane = 0; lane < MAX_BYTE_LANES; lane++) { for (lane = 0; lane < lane_count; lane++) {
current_total_delay[lane] = (rank0_current_total_delay[lane] + current_total_delay[lane]) / 2; current_total_delay[lane] = (rank0_current_total_delay[lane] + current_total_delay[lane]) / 2;
if (lane == 8) if (lane == 8)
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane]; pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
@ -1577,6 +1580,9 @@ static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat,
uint8_t current_worst_case_total_delay_dimm; uint8_t current_worst_case_total_delay_dimm;
uint16_t current_worst_case_total_delay_value; uint16_t current_worst_case_total_delay_value;
uint8_t lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
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}; 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); print_debug_dqs("\nTrainMaxRdLatency: Node", pDCTstat->Node_ID, 0);

View File

@ -32,8 +32,8 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
u8 dct, u8 dimm, BOOL wl); u8 dct, u8 dimm, BOOL wl);
void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm); 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 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 setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass, uint8_t lane_count);
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, uint8_t lane_count);
static int32_t abs(int32_t val) { static int32_t abs(int32_t val) {
if (val < 0) if (val < 0)
@ -77,6 +77,9 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
u16 Addl_Data_Offset, Addl_Data_Port; u16 Addl_Data_Offset, Addl_Data_Port;
sMCTStruct *pMCTData = pDCTstat->C_MCTPtr; sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
uint8_t lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
pDCTData->WLPass = pass; pDCTData->WLPass = pass;
/* 1. Specify the target DIMM that is to be trained by programming /* 1. Specify the target DIMM that is to be trained by programming
@ -176,8 +179,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 /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
* to get the gross and fine delay settings * to get the gross and fine delay settings
* for the target DIMM and save these values. */ * for the target DIMM and save these values. */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, nibble); getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, nibble, lane_count);
} }
pDCTData->WLCriticalGrossDelayPrevPass = 0x0; pDCTData->WLCriticalGrossDelayPrevPass = 0x0;
@ -192,11 +195,14 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
u8 ByteLane; u8 ByteLane;
uint8_t status = 0; uint8_t status = 0;
sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
uint8_t lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
if (is_fam15h()) { if (is_fam15h()) {
int32_t gross_diff[MAX_BYTE_LANES]; int32_t gross_diff[lane_count];
int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass; int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm); uint8_t index = (uint8_t)(lane_count * dimm);
printk(BIOS_SPEW, "\toriginal critical gross delay: %d\n", cgd); printk(BIOS_SPEW, "\toriginal critical gross delay: %d\n", cgd);
@ -205,7 +211,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
*/ */
/* Calculate the Critical Gross Delay */ /* Calculate the Critical Gross Delay */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
/* Calculate the gross delay differential for this lane */ /* Calculate the gross delay differential for this lane */
gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane]; gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane];
gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane]; gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane];
@ -231,7 +237,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
* Figure out why this is and fix it, then remove the bypass code below... * Figure out why this is and fix it, then remove the bypass code below...
*/ */
if (pass == FirstPass) { if (pass == FirstPass) {
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane]; pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane];
pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane]; pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane];
} }
@ -240,7 +246,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
} }
/* Compensate for occasional noise/instability causing sporadic training failure */ /* Compensate for occasional noise/instability causing sporadic training failure */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
uint8_t faulty_value_detected = 0; 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_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); uint16_t total_delay_phy = ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
@ -278,12 +284,15 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
u8 ByteLane; u8 ByteLane;
sMCTStruct *pMCTData = pDCTstat->C_MCTPtr; sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
uint8_t lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
if (is_fam15h()) { if (is_fam15h()) {
uint32_t dword; uint32_t dword;
int32_t gross_diff[MAX_BYTE_LANES]; int32_t gross_diff[lane_count];
int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass; int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm); uint8_t index = (uint8_t)(lane_count * dimm);
/* Apply offset(s) if needed */ /* Apply offset(s) if needed */
if (cgd < 0) { if (cgd < 0) {
@ -292,7 +301,7 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
dword |= ((abs(cgd) & 0x3) << 24); dword |= ((abs(cgd) & 0x3) << 24);
Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword); Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
/* Calculate the gross delay differential for this lane */ /* Calculate the gross delay differential for this lane */
gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane]; gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane];
gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane]; gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane];
@ -313,8 +322,8 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
/* Write the adjusted gross and fine delay settings /* Write the adjusted gross and fine delay settings
* to the target DIMM. */ * to the target DIMM. */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass); setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass, lane_count);
} }
/* 6. Configure DRAM Phy Control Register so that the phy stops driving /* 6. Configure DRAM Phy Control Register so that the phy stops driving
@ -1006,6 +1015,9 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800}; 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}; 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 lane_count;
lane_count = get_available_lane_count(pMCTstat, pDCTstat);
if (is_fam15h()) { if (is_fam15h()) {
/* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 667MHz; 0x12: 800MHz; 0x16: 933MHz */ /* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 667MHz; 0x12: 800MHz; 0x16: 933MHz */
@ -1113,9 +1125,9 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
Seed_Fine = Seed_Total & 0x1f; Seed_Fine = Seed_Total & 0x1f;
/* Save seed values for later use */ /* Save seed values for later use */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; pDCTData->WLSeedGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; pDCTData->WLSeedFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
if (Seed_Gross == 0) if (Seed_Gross == 0)
Seed_PreGross = 0; Seed_PreGross = 0;
@ -1124,7 +1136,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
else else
Seed_PreGross = 2; Seed_PreGross = 2;
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross; pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane] = Seed_PreGross;
} }
} else { } else {
if (pDCTData->Status[DCT_STATUS_REGISTERED]) { if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
@ -1150,7 +1162,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
} }
} }
} }
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) for (ByteLane = 0; ByteLane < lane_count; ByteLane++)
{ {
/* Program an initialization value to registers F2x[1, 0]9C_x[51:50] and /* 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 * F2x[1, 0]9C_x52 to set the gross and fine delay for all the byte lane fields
@ -1160,8 +1172,8 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
* of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined * of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined
* by design. * by design.
*/ */
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f)); printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
} }
} else { } else {
@ -1170,8 +1182,8 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
/* From BKDG, Write Leveling Seed Value. */ /* From BKDG, Write Leveling Seed Value. */
if (is_fam15h()) { if (is_fam15h()) {
uint32_t RegisterDelay; uint32_t RegisterDelay;
int32_t SeedTotal[MAX_BYTE_LANES]; int32_t SeedTotal[lane_count];
int32_t SeedTotalPreScaling[MAX_BYTE_LANES]; int32_t SeedTotalPreScaling[lane_count];
uint32_t WrDqDqsEarly; uint32_t WrDqDqsEarly;
uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */ uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
@ -1194,17 +1206,17 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
WrDqDqsEarly = 0; WrDqDqsEarly = 0;
/* Generate new seed values */ /* Generate new seed values */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
/* Calculate adjusted seed values */ /* Calculate adjusted seed values */
SeedTotal[ByteLane] = (pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) | SeedTotal[ByteLane] = (pDCTData->WLFineDelayPrevPass[lane_count*dimm+ByteLane] & 0x1f) |
((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5); ((pDCTData->WLGrossDelayPrevPass[lane_count*dimm+ByteLane] & 0x1f) << 5);
SeedTotalPreScaling[ByteLane] = (SeedTotal[ByteLane] - RegisterDelay - (0x20 * WrDqDqsEarly)); SeedTotalPreScaling[ByteLane] = (SeedTotal[ByteLane] - RegisterDelay - (0x20 * WrDqDqsEarly));
SeedTotal[ByteLane] = (int32_t) (RegisterDelay + ((((int64_t) SeedTotalPreScaling[ByteLane]) * SeedTotal[ByteLane] = (int32_t) (RegisterDelay + ((((int64_t) SeedTotalPreScaling[ByteLane]) *
fam15h_freq_tab[MemClkFreq] * 100) / (fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100))); fam15h_freq_tab[MemClkFreq] * 100) / (fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
} }
/* Generate register values from seeds */ /* Generate register values from seeds */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
printk(BIOS_SPEW, "\tLane %02x scaled delay: %04x\n", ByteLane, SeedTotal[ByteLane]); printk(BIOS_SPEW, "\tLane %02x scaled delay: %04x\n", ByteLane, SeedTotal[ByteLane]);
if (SeedTotal[ByteLane] >= 0) { if (SeedTotal[ByteLane] >= 0) {
@ -1229,21 +1241,21 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
Seed_PreGross = Seed_Gross; Seed_PreGross = Seed_Gross;
/* Save seed values for later use */ /* Save seed values for later use */
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; pDCTData->WLSeedGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; pDCTData->WLSeedFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross; pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane] = Seed_PreGross;
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross; pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = Seed_PreGross;
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; pDCTData->WLFineDelay[lane_count*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[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
} }
} else { } else {
uint32_t RegisterDelay; uint32_t RegisterDelay;
uint32_t SeedTotalPreScaling; uint32_t SeedTotalPreScaling;
uint32_t SeedTotal; uint32_t SeedTotal;
uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */ uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) for (ByteLane = 0; ByteLane < lane_count; ByteLane++)
{ {
if (pDCTData->Status[DCT_STATUS_REGISTERED]) { if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
if (AddrCmdPrelaunch == 0) if (AddrCmdPrelaunch == 0)
@ -1253,8 +1265,8 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
} else { } else {
RegisterDelay = 0; RegisterDelay = 0;
} }
SeedTotalPreScaling = ((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) | SeedTotalPreScaling = ((pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f) |
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay; (pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] << 5)) - RegisterDelay;
/* SeedTotalPreScaling = (the total delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization /* SeedTotalPreScaling = (the total delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
training) - RegisterDelay. */ training) - RegisterDelay. */
SeedTotal = (uint16_t) ((((uint64_t) SeedTotalPreScaling) * SeedTotal = (uint16_t) ((((uint64_t) SeedTotalPreScaling) *
@ -1277,49 +1289,49 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
Seed_Gross = SeedTotal / 32; Seed_Gross = SeedTotal / 32;
Seed_Fine = SeedTotal & 0x1f; Seed_Fine = SeedTotal & 0x1f;
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; pDCTData->WLFineDelay[lane_count*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[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
} }
} }
/* Save initial seeds for upper nibble pass */ /* Save initial seeds for upper nibble pass */
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedPreGrossPrevNibble[lane_count*dimm+ByteLane] = pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane];
pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedGrossPrevNibble[lane_count*dimm+ByteLane] = pDCTData->WLGrossDelay[lane_count*dimm+ByteLane];
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedFinePrevNibble[lane_count*dimm+ByteLane] = pDCTData->WLFineDelay[lane_count*dimm+ByteLane];
} }
} else { } else {
/* Restore seed values from lower nibble pass */ /* Restore seed values from lower nibble pass */
if (is_fam15h()) { if (is_fam15h()) {
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[lane_count*dimm+ByteLane];
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedFineDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[lane_count*dimm+ByteLane];
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[lane_count*dimm+ByteLane];
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[lane_count*dimm+ByteLane];
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[lane_count*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[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
} }
} else { } else {
for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[lane_count*dimm+ByteLane];
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[lane_count*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[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
} }
} }
} }
} }
pDCTData->WLPrevMemclkFreq = MemClkFreq; pDCTData->WLPrevMemclkFreq = MemClkFreq;
setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass); setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass, lane_count);
} }
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm){ * void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm, uint8_t lane_count){
* *
* Description: * Description:
* This function writes the write levelization byte delay for the Phase * This function writes the write levelization byte delay for the Phase
@ -1339,7 +1351,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, uint8_t lane_count)
{ {
sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr; u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr;
@ -1347,12 +1359,12 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
if (targetAddr == 0) if (targetAddr == 0)
{ {
index = (u8)(MAX_BYTE_LANES * dimm); index = (u8)(lane_count * dimm);
ValueLow = 0; ValueLow = 0;
ValueHigh = 0; ValueHigh = 0;
ByteLane = 0; ByteLane = 0;
EccValue = 0; EccValue = 0;
while (ByteLane < MAX_BYTE_LANES) while (ByteLane < lane_count)
{ {
if (is_fam15h()) { if (is_fam15h()) {
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane]; grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
@ -1394,7 +1406,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
else else
{ {
/* Fam10h BKDG Rev. 3.62 2.8.9.9.1 (6) */ /* Fam10h BKDG Rev. 3.62 2.8.9.9.1 (6) */
index = (u8)(MAX_BYTE_LANES * dimm); index = (u8)(lane_count * dimm);
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane]; grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
fineDelayValue = pDCTData->WLFineDelay[index+ByteLane]; fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
@ -1440,7 +1452,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, uint8_t lane_count)
* *
* Description: * Description:
* This function reads the write levelization byte delay from the Phase * This function reads the write levelization byte delay from the Phase
@ -1458,13 +1470,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, uint8_t lane_count)
{ {
sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index; u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index;
u32 addr, fine, gross; u32 addr, fine, gross;
tempB = 0; tempB = 0;
index = (u8)(MAX_BYTE_LANES*dimm); index = (u8)(lane_count*dimm);
if (ByteLane < 4) { if (ByteLane < 4) {
tempB = (u8)(8 * ByteLane); tempB = (u8)(8 * ByteLane);
addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW; addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;