amd/amdmct/mct_ddr3: Partially fix up registered DIMMs on Fam10h
Sufficient support has been added to allow booting with registered DIMMs on the KGPE-D16 in certain slots. ECC support needs additional work; the ECC data lanes appear to cause boot failures in some slots. Change-Id: Ieaf4cbf351908e5a89760be49a6667dc55dbc575 Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/12017 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
This commit is contained in:
parent
474ff3dee5
commit
f682d0028c
|
@ -311,6 +311,120 @@ static uint16_t mhz_to_memclk_config(uint16_t freq)
|
||||||
return fam10h_mhz_to_memclk_config(freq) + 1;
|
return fam10h_mhz_to_memclk_config(freq) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t fam10h_address_timing_compensation_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
|
||||||
|
{
|
||||||
|
uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
|
||||||
|
|
||||||
|
uint8_t package_type;
|
||||||
|
uint32_t calibration_code = 0;
|
||||||
|
|
||||||
|
package_type = mctGet_NVbits(NV_PACK_TYPE);
|
||||||
|
uint16_t MemClkFreq = (Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7) + 1;
|
||||||
|
|
||||||
|
/* Obtain number of DIMMs on channel */
|
||||||
|
uint8_t dimm_count = pDCTstat->MAdimms[dct];
|
||||||
|
uint8_t rank_count_dimm0;
|
||||||
|
uint8_t rank_count_dimm1;
|
||||||
|
|
||||||
|
if (package_type == PT_GR) {
|
||||||
|
/* Socket G34 */
|
||||||
|
if (pDCTstat->Status & (1 << SB_Registered)) {
|
||||||
|
/* RDIMM */
|
||||||
|
/* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Tables 60 - 61 */
|
||||||
|
if (MaxDimmsInstallable == 1) {
|
||||||
|
if (MemClkFreq == 0x4) {
|
||||||
|
/* DDR3-800 */
|
||||||
|
calibration_code = 0x00000000;
|
||||||
|
} else if (MemClkFreq == 0x5) {
|
||||||
|
/* DDR3-1066 */
|
||||||
|
calibration_code = 0x003c3c3c;
|
||||||
|
} else if (MemClkFreq == 0x6) {
|
||||||
|
/* DDR3-1333 */
|
||||||
|
calibration_code = 0x003a3a3a;
|
||||||
|
}
|
||||||
|
} else if (MaxDimmsInstallable == 2) {
|
||||||
|
if (dimm_count == 1) {
|
||||||
|
/* 1 DIMM detected */
|
||||||
|
if (MemClkFreq == 0x4) {
|
||||||
|
/* DDR3-800 */
|
||||||
|
calibration_code = 0x00000000;
|
||||||
|
} else if (MemClkFreq == 0x5) {
|
||||||
|
/* DDR3-1066 */
|
||||||
|
calibration_code = 0x003c3c3c;
|
||||||
|
} else if (MemClkFreq == 0x6) {
|
||||||
|
/* DDR3-1333 */
|
||||||
|
calibration_code = 0x003a3a3a;
|
||||||
|
}
|
||||||
|
} else if (dimm_count == 2) {
|
||||||
|
/* 2 DIMMs detected */
|
||||||
|
if (MemClkFreq == 0x4) {
|
||||||
|
/* DDR3-800 */
|
||||||
|
calibration_code = 0x00000000;
|
||||||
|
} else if (MemClkFreq == 0x5) {
|
||||||
|
/* DDR3-1066 */
|
||||||
|
calibration_code = 0x003a3c3a;
|
||||||
|
} else if (MemClkFreq == 0x6) {
|
||||||
|
/* DDR3-1333 */
|
||||||
|
calibration_code = 0x00383a38;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (MaxDimmsInstallable == 3) {
|
||||||
|
/* TODO
|
||||||
|
* 3 DIMM/channel support unimplemented
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* UDIMM */
|
||||||
|
/* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Table 56 */
|
||||||
|
if (dimm_count == 1) {
|
||||||
|
/* 1 DIMM detected */
|
||||||
|
rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
|
||||||
|
|
||||||
|
if (MemClkFreq == 0x4) {
|
||||||
|
/* DDR3-800 */
|
||||||
|
if (rank_count_dimm0 == 1)
|
||||||
|
calibration_code = 0x00000000;
|
||||||
|
else
|
||||||
|
calibration_code = 0x003b0000;
|
||||||
|
} else if (MemClkFreq == 0x5) {
|
||||||
|
/* DDR3-1066 */
|
||||||
|
if (rank_count_dimm0 == 1)
|
||||||
|
calibration_code = 0x00000000;
|
||||||
|
else
|
||||||
|
calibration_code = 0x00380000;
|
||||||
|
} else if (MemClkFreq == 0x6) {
|
||||||
|
/* DDR3-1333 */
|
||||||
|
if (rank_count_dimm0 == 1)
|
||||||
|
calibration_code = 0x00000000;
|
||||||
|
else
|
||||||
|
calibration_code = 0x00360000;
|
||||||
|
}
|
||||||
|
} else if (dimm_count == 2) {
|
||||||
|
/* 2 DIMMs detected */
|
||||||
|
rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct];
|
||||||
|
rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
|
||||||
|
|
||||||
|
if (MemClkFreq == 0x4) {
|
||||||
|
/* DDR3-800 */
|
||||||
|
calibration_code = 0x00390039;
|
||||||
|
} else if (MemClkFreq == 0x5) {
|
||||||
|
/* DDR3-1066 */
|
||||||
|
calibration_code = 0x00350037;
|
||||||
|
} else if (MemClkFreq == 0x6) {
|
||||||
|
/* DDR3-1333 */
|
||||||
|
calibration_code = 0x00000035;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* TODO
|
||||||
|
* Other socket support unimplemented
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return calibration_code;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength)
|
static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength)
|
||||||
{
|
{
|
||||||
uint8_t lrdimm = 0;
|
uint8_t lrdimm = 0;
|
||||||
|
@ -1005,7 +1119,7 @@ static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
|
||||||
/* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
|
/* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
|
||||||
if (MaxDimmsInstallable == 1) {
|
if (MaxDimmsInstallable == 1) {
|
||||||
if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
|
if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
|
||||||
/* DDR3-667 - DDR3-800*/
|
/* DDR3-667 - DDR3-800 */
|
||||||
calibration_code = 0x00000000;
|
calibration_code = 0x00000000;
|
||||||
} else if (MemClkFreq == 0xa) {
|
} else if (MemClkFreq == 0xa) {
|
||||||
/* DDR3-1066 */
|
/* DDR3-1066 */
|
||||||
|
@ -1021,7 +1135,7 @@ static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
|
||||||
if (dimm_count == 1) {
|
if (dimm_count == 1) {
|
||||||
/* 1 DIMM detected */
|
/* 1 DIMM detected */
|
||||||
if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
|
if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
|
||||||
/* DDR3-667 - DDR3-800*/
|
/* DDR3-667 - DDR3-800 */
|
||||||
calibration_code = 0x00000000;
|
calibration_code = 0x00000000;
|
||||||
} else if (MemClkFreq == 0xa) {
|
} else if (MemClkFreq == 0xa) {
|
||||||
/* DDR3-1066 */
|
/* DDR3-1066 */
|
||||||
|
@ -1036,7 +1150,7 @@ static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
|
||||||
} else if (dimm_count == 2) {
|
} else if (dimm_count == 2) {
|
||||||
/* 2 DIMMs detected */
|
/* 2 DIMMs detected */
|
||||||
if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
|
if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
|
||||||
/* DDR3-667 - DDR3-800*/
|
/* DDR3-667 - DDR3-800 */
|
||||||
calibration_code = 0x00000000;
|
calibration_code = 0x00000000;
|
||||||
} else if (MemClkFreq == 0xa) {
|
} else if (MemClkFreq == 0xa) {
|
||||||
/* DDR3-1066 */
|
/* DDR3-1066 */
|
||||||
|
@ -1314,6 +1428,26 @@ static void read_spd_bytes(struct MCTStatStruc *pMCTstat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_DIMM_SPD
|
||||||
|
static void dump_spd_bytes(struct MCTStatStruc *pMCTstat,
|
||||||
|
struct DCTStatStruc *pDCTstat, uint8_t dimm)
|
||||||
|
{
|
||||||
|
uint16_t byte;
|
||||||
|
|
||||||
|
printk(BIOS_DEBUG, "SPD dump for DIMM %d\n ", dimm);
|
||||||
|
for (byte = 0; byte < 16; byte++) {
|
||||||
|
printk(BIOS_DEBUG, "%02x ", byte);
|
||||||
|
}
|
||||||
|
for (byte = 0; byte < 256; byte++) {
|
||||||
|
if ((byte & 0xf) == 0x0) {
|
||||||
|
printk(BIOS_DEBUG, "\n%02x ", byte >> 4);
|
||||||
|
}
|
||||||
|
printk(BIOS_DEBUG, "%02x ", pDCTstat->spd_data.spd_bytes[dimm][byte]);
|
||||||
|
}
|
||||||
|
printk(BIOS_DEBUG, "\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
|
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
|
||||||
static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
|
static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
|
||||||
struct DCTStatStruc *pDCTstat)
|
struct DCTStatStruc *pDCTstat)
|
||||||
|
@ -1515,12 +1649,14 @@ restartinit:
|
||||||
pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
|
pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
|
if (is_fam15h()) {
|
||||||
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
|
||||||
struct DCTStatStruc *pDCTstat;
|
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
||||||
pDCTstat = pDCTstatA + Node;
|
struct DCTStatStruc *pDCTstat;
|
||||||
|
pDCTstat = pDCTstatA + Node;
|
||||||
|
|
||||||
mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
|
mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NodesWmem = 0;
|
NodesWmem = 0;
|
||||||
|
@ -1682,14 +1818,14 @@ restartinit:
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
|
printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
|
||||||
UMAMemTyping_D(pMCTstat, pDCTstatA); /* Fix up for UMA sizing */
|
UMAMemTyping_D(pMCTstat, pDCTstatA); /* Fix up for UMA sizing */
|
||||||
}
|
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
|
printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
|
||||||
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
||||||
struct DCTStatStruc *pDCTstat;
|
struct DCTStatStruc *pDCTstat;
|
||||||
pDCTstat = pDCTstatA + Node;
|
pDCTstat = pDCTstatA + Node;
|
||||||
|
|
||||||
mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
|
mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_fam15h()) {
|
if (is_fam15h()) {
|
||||||
|
@ -2727,6 +2863,10 @@ static void DCTFinalInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *p
|
||||||
dword = 1 << DisDramInterface;
|
dword = 1 << DisDramInterface;
|
||||||
Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
|
Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
|
||||||
|
|
||||||
|
dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x90);
|
||||||
|
dword &= ~(1 << ParEn);
|
||||||
|
Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x90, dword);
|
||||||
|
|
||||||
/* To maximize power savings when DisDramInterface=1b,
|
/* To maximize power savings when DisDramInterface=1b,
|
||||||
* all of the MemClkDis bits should also be set.
|
* all of the MemClkDis bits should also be set.
|
||||||
*/
|
*/
|
||||||
|
@ -3610,7 +3750,9 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
|
||||||
dword++;
|
dword++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(Status & (1 << SB_Registered)))
|
if (Status & (1 << SB_Registered))
|
||||||
|
DramConfigLo |= 1 << ParEn; /* Registered DIMMs */
|
||||||
|
else
|
||||||
DramConfigLo |= 1 << UnBuffDimm; /* Unbuffered DIMMs */
|
DramConfigLo |= 1 << UnBuffDimm; /* Unbuffered DIMMs */
|
||||||
|
|
||||||
if (mctGet_NVbits(NV_ECC_CAP))
|
if (mctGet_NVbits(NV_ECC_CAP))
|
||||||
|
@ -4099,6 +4241,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
|
||||||
if (status >= 0) { /* SPD access is ok */
|
if (status >= 0) { /* SPD access is ok */
|
||||||
pDCTstat->DIMMPresent |= 1 << i;
|
pDCTstat->DIMMPresent |= 1 << i;
|
||||||
read_spd_bytes(pMCTstat, pDCTstat, i);
|
read_spd_bytes(pMCTstat, pDCTstat, i);
|
||||||
|
#ifdef DEBUG_DIMM_SPD
|
||||||
|
dump_spd_bytes(pMCTstat, pDCTstat, i);
|
||||||
|
#endif
|
||||||
crc_status = crcCheck(pDCTstat, i);
|
crc_status = crcCheck(pDCTstat, i);
|
||||||
if (!crc_status) {
|
if (!crc_status) {
|
||||||
/* Try again in case there was a transient glitch */
|
/* Try again in case there was a transient glitch */
|
||||||
|
@ -4398,6 +4543,10 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
|
||||||
val = 1 << DisDramInterface;
|
val = 1 << DisDramInterface;
|
||||||
Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
|
Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
|
||||||
|
|
||||||
|
val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
|
||||||
|
val &= ~(1 << ParEn);
|
||||||
|
Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
|
||||||
|
|
||||||
/* To maximize power savings when DisDramInterface=1b,
|
/* To maximize power savings when DisDramInterface=1b,
|
||||||
* all of the MemClkDis bits should also be set.
|
* all of the MemClkDis bits should also be set.
|
||||||
*/
|
*/
|
||||||
|
@ -4550,8 +4699,9 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
|
||||||
}
|
}
|
||||||
for (i=i_start; i<i_end; i++) {
|
for (i=i_start; i<i_end; i++) {
|
||||||
index_reg = 0x98;
|
index_reg = 0x98;
|
||||||
Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */
|
Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */
|
||||||
Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */
|
Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */
|
||||||
|
printk(BIOS_SPEW, "Programmed DCT %d timing/termination pattern %08x %08x\n", dct, pDCTstat->CH_ADDR_TMG[i], pDCTstat->CH_ODC_CTL[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pDCTstat->ErrCode;
|
return pDCTstat->ErrCode;
|
||||||
|
@ -4608,11 +4758,19 @@ static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat,
|
||||||
val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
|
val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
|
||||||
val |= 1 << DisDramInterface;
|
val |= 1 << DisDramInterface;
|
||||||
Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
|
Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
|
||||||
|
|
||||||
|
val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
|
||||||
|
val &= ~(1 << ParEn);
|
||||||
|
Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
|
||||||
}
|
}
|
||||||
if (pDCTstat->DIMMValidDCT[1] == 0) {
|
if (pDCTstat->DIMMValidDCT[1] == 0) {
|
||||||
val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
|
val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
|
||||||
val |= 1 << DisDramInterface;
|
val |= 1 << DisDramInterface;
|
||||||
Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
|
Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
|
||||||
|
|
||||||
|
val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
|
||||||
|
val &= ~(1 << ParEn);
|
||||||
|
Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
|
printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
|
||||||
|
@ -6043,6 +6201,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
|
||||||
dword &= ~(0xf); /* RdOdtTrnOnDly = read_odt_delay */
|
dword &= ~(0xf); /* RdOdtTrnOnDly = read_odt_delay */
|
||||||
dword |= (read_odt_delay & 0xf);
|
dword |= (read_odt_delay & 0xf);
|
||||||
Set_NB32_DCT(dev, dct, 0x240, dword);
|
Set_NB32_DCT(dev, dct, 0x240, dword);
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x %08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
|
||||||
} else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
|
} else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
|
||||||
if (pDCTstat->Speed == 3)
|
if (pDCTstat->Speed == 3)
|
||||||
dword = 0x00000800;
|
dword = 0x00000800;
|
||||||
|
@ -6178,6 +6338,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
|
||||||
Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, odt_pattern_0);
|
Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, odt_pattern_0);
|
||||||
Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, odt_pattern_3);
|
Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, odt_pattern_3);
|
||||||
Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, odt_pattern_2);
|
Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, odt_pattern_2);
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x %08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
/* AM3/ASB2/C32/G34 DDR3 */
|
/* AM3/ASB2/C32/G34 DDR3 */
|
||||||
|
|
||||||
static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
|
static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
|
||||||
u32 *AddrTmgCTL, u32 *ODC_CTL,
|
u32 *ODC_CTL,
|
||||||
u8 *CMDmode);
|
u8 *CMDmode);
|
||||||
|
|
||||||
void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
|
void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
|
||||||
|
@ -30,9 +30,14 @@ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
|
||||||
} else {
|
} else {
|
||||||
Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
|
Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
|
||||||
pDCTstat->MAload[dct],
|
pDCTstat->MAload[dct],
|
||||||
&(pDCTstat->CH_ADDR_TMG[dct]), &(pDCTstat->CH_ODC_CTL[dct]),
|
&(pDCTstat->CH_ODC_CTL[dct]),
|
||||||
&pDCTstat->_2Tmode);
|
&pDCTstat->_2Tmode);
|
||||||
|
|
||||||
|
if (pDCTstat->Status & (1 << SB_Registered)) {
|
||||||
|
pDCTstat->_2Tmode = 1; /* Disable slow access mode */
|
||||||
|
}
|
||||||
|
pDCTstat->CH_ADDR_TMG[dct] = fam10h_address_timing_compensation_code(pDCTstat, dct);
|
||||||
|
|
||||||
pDCTstat->CH_ODC_CTL[dct] |= 0x20000000; /* 60ohms */
|
pDCTstat->CH_ODC_CTL[dct] |= 0x20000000; /* 60ohms */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,42 +55,25 @@ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
|
||||||
* : ODC_CTL - Output Driver Compensation Control Register Value
|
* : ODC_CTL - Output Driver Compensation Control Register Value
|
||||||
* : CMDmode - CMD mode
|
* : CMDmode - CMD mode
|
||||||
*/
|
*/
|
||||||
static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
|
static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
|
||||||
u32 *AddrTmgCTL, u32 *ODC_CTL,
|
u32 *ODC_CTL,
|
||||||
u8 *CMDmode)
|
u8 *CMDmode)
|
||||||
{
|
{
|
||||||
*AddrTmgCTL = 0;
|
|
||||||
*ODC_CTL = 0;
|
*ODC_CTL = 0;
|
||||||
*CMDmode = 1;
|
*CMDmode = 1;
|
||||||
|
|
||||||
if(MAAdimms == 1) {
|
if (MAAdimms == 1) {
|
||||||
if(MAAload >= 16) {
|
|
||||||
if(Speed == 4)
|
|
||||||
*AddrTmgCTL = 0x003B0000;
|
|
||||||
else if (Speed == 5)
|
|
||||||
*AddrTmgCTL = 0x00380000;
|
|
||||||
else if (Speed == 6)
|
|
||||||
*AddrTmgCTL = 0x00360000;
|
|
||||||
else
|
|
||||||
*AddrTmgCTL = 0x00340000;
|
|
||||||
} else {
|
|
||||||
*AddrTmgCTL = 0x00000000;
|
|
||||||
}
|
|
||||||
*ODC_CTL = 0x00113222;
|
*ODC_CTL = 0x00113222;
|
||||||
*CMDmode = 1;
|
*CMDmode = 1;
|
||||||
} else /* if(MAAdimms == 0) */ {
|
} else /* if(MAAdimms == 0) */ {
|
||||||
if(Speed == 4) {
|
if(Speed == 4) {
|
||||||
*CMDmode = 1;
|
*CMDmode = 1;
|
||||||
*AddrTmgCTL = 0x00390039;
|
|
||||||
} else if(Speed == 5) {
|
} else if(Speed == 5) {
|
||||||
*CMDmode = 1;
|
*CMDmode = 1;
|
||||||
*AddrTmgCTL = 0x00350037;
|
|
||||||
} else if(Speed == 6) {
|
} else if(Speed == 6) {
|
||||||
*CMDmode = 2;
|
*CMDmode = 2;
|
||||||
*AddrTmgCTL = 0x00000035;
|
|
||||||
} else {
|
} else {
|
||||||
*CMDmode = 2;
|
*CMDmode = 2;
|
||||||
*AddrTmgCTL = 0x00000033;
|
|
||||||
}
|
}
|
||||||
*ODC_CTL = 0x00223323;
|
*ODC_CTL = 0x00223323;
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,37 +237,53 @@ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
|
||||||
struct DCTStatStruc *pDCTstat,
|
struct DCTStatStruc *pDCTstat,
|
||||||
u16 like, u8 scale, u8 ChipSel)
|
u16 like, u8 scale, u8 ChipSel)
|
||||||
{
|
{
|
||||||
u8 DQSDelay0, DQSDelay1;
|
uint8_t DQSDelay0, DQSDelay1;
|
||||||
u16 DQSDelay;
|
int16_t delay_differential;
|
||||||
|
uint16_t DQSDelay;
|
||||||
|
|
||||||
if (pDCTstat->Status & (1 << SB_Registered)) {
|
if (pDCTstat->Status & (1 << SB_Registered)) {
|
||||||
return;
|
pDCTstat->ByteLane = 0x2;
|
||||||
}
|
GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
|
||||||
|
DQSDelay0 = pDCTstat->DQSDelay;
|
||||||
|
|
||||||
pDCTstat->ByteLane = like & 0xff;
|
pDCTstat->ByteLane = 0x3;
|
||||||
GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
|
GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
|
||||||
DQSDelay0 = pDCTstat->DQSDelay;
|
DQSDelay1 = pDCTstat->DQSDelay;
|
||||||
|
|
||||||
pDCTstat->ByteLane = (like >> 8) & 0xff;
|
if (pDCTstat->Direction == DQS_READDIR) {
|
||||||
GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
|
DQSDelay = DQSDelay1;
|
||||||
DQSDelay1 = pDCTstat->DQSDelay;
|
} else {
|
||||||
|
delay_differential = (int16_t)DQSDelay1 - (int16_t)DQSDelay0;
|
||||||
|
delay_differential += (int16_t)DQSDelay1;
|
||||||
|
|
||||||
if (DQSDelay0>DQSDelay1) {
|
DQSDelay = delay_differential;
|
||||||
DQSDelay = DQSDelay0 - DQSDelay1;
|
}
|
||||||
} else {
|
} else {
|
||||||
DQSDelay = DQSDelay1 - DQSDelay0;
|
pDCTstat->ByteLane = like & 0xff;
|
||||||
}
|
GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
|
||||||
|
DQSDelay0 = pDCTstat->DQSDelay;
|
||||||
|
|
||||||
DQSDelay = DQSDelay * (~scale);
|
pDCTstat->ByteLane = (like >> 8) & 0xff;
|
||||||
|
GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
|
||||||
|
DQSDelay1 = pDCTstat->DQSDelay;
|
||||||
|
|
||||||
DQSDelay += 0x80; /* round it */
|
if (DQSDelay0>DQSDelay1) {
|
||||||
|
DQSDelay = DQSDelay0 - DQSDelay1;
|
||||||
|
} else {
|
||||||
|
DQSDelay = DQSDelay1 - DQSDelay0;
|
||||||
|
}
|
||||||
|
|
||||||
DQSDelay >>= 8; /* 256 */
|
DQSDelay = DQSDelay * (~scale);
|
||||||
|
|
||||||
if (DQSDelay0>DQSDelay1) {
|
DQSDelay += 0x80; /* round it */
|
||||||
DQSDelay = DQSDelay1 - DQSDelay;
|
|
||||||
} else {
|
DQSDelay >>= 8; /* 256 */
|
||||||
DQSDelay += DQSDelay1;
|
|
||||||
|
if (DQSDelay0>DQSDelay1) {
|
||||||
|
DQSDelay = DQSDelay1 - DQSDelay;
|
||||||
|
} else {
|
||||||
|
DQSDelay += DQSDelay1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pDCTstat->DQSDelay = (u8)DQSDelay;
|
pDCTstat->DQSDelay = (u8)DQSDelay;
|
||||||
|
|
|
@ -14,12 +14,39 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static uint16_t memclk_to_freq(uint16_t memclk) {
|
||||||
|
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 mem_freq = 0;
|
||||||
|
|
||||||
|
if (is_fam15h()) {
|
||||||
|
if (memclk < 0x17) {
|
||||||
|
mem_freq = fam15h_freq_tab[memclk];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((memclk > 0x0) && (memclk < 0x8)) {
|
||||||
|
mem_freq = fam10h_freq_tab[memclk - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t rc_word_value_to_ctl_bits(uint32_t value) {
|
||||||
|
return ((value >> 2) & 3) << 16 | ((value & 3) << 3);
|
||||||
|
}
|
||||||
|
|
||||||
static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
|
static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
|
||||||
struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum)
|
struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum)
|
||||||
{
|
{
|
||||||
u8 Dimms, DimmNum, MaxDimm, Speed;
|
u8 Dimms, DimmNum;
|
||||||
u32 val;
|
u32 val;
|
||||||
u32 dct = 0;
|
u32 dct = 0;
|
||||||
|
uint8_t ddr_voltage_index;
|
||||||
|
uint16_t mem_freq;
|
||||||
|
uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
|
||||||
|
uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
|
||||||
|
|
||||||
DimmNum = (MrsChipSel >> 20) & 0xFE;
|
DimmNum = (MrsChipSel >> 20) & 0xFE;
|
||||||
|
|
||||||
|
@ -28,54 +55,64 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
|
||||||
/* DimmNum ++; */
|
/* DimmNum ++; */
|
||||||
/* cl +=8; */
|
/* cl +=8; */
|
||||||
|
|
||||||
MaxDimm = mctGet_NVbits(NV_MAX_DIMMS);
|
mem_freq = memclk_to_freq(pDCTstat->DIMMAutoSpeed);
|
||||||
Speed = pDCTstat->DIMMAutoSpeed;
|
|
||||||
|
|
||||||
if (pDCTstat->CSPresent_DCT[0] > 0) {
|
if (pDCTstat->CSPresent_DCT[0] > 0) {
|
||||||
dct = 0;
|
dct = 0;
|
||||||
} else if (pDCTstat->CSPresent_DCT[1] > 0 ){
|
} else if (pDCTstat->CSPresent_DCT[1] > 0 ) {
|
||||||
dct = 1;
|
dct = 1;
|
||||||
DimmNum ++;
|
DimmNum++;
|
||||||
}
|
}
|
||||||
Dimms = pDCTstat->MAdimms[dct];
|
Dimms = pDCTstat->MAdimms[dct];
|
||||||
|
|
||||||
|
ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
|
||||||
|
|
||||||
val = 0;
|
val = 0;
|
||||||
if (CtrlWordNum == 0)
|
if (CtrlWordNum == 0)
|
||||||
val |= 1 << 1;
|
val = 0x2;
|
||||||
else if (CtrlWordNum == 1) {
|
else if (CtrlWordNum == 1) {
|
||||||
if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 << DimmNum)))
|
if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 << DimmNum)))
|
||||||
val |= 0xC; /* if single rank, set DBA1 and DBA0 */
|
val = 0xC; /* if single rank, set DBA1 and DBA0 */
|
||||||
} else if (CtrlWordNum == 2) {
|
} else if (CtrlWordNum == 2) {
|
||||||
if (MaxDimm == 4) {
|
if (package_type == PT_GR) {
|
||||||
if (Speed == 4) {
|
/* Socket G34 */
|
||||||
if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) && (Dimms == 1)) || (Dimms == 2))
|
if (MaxDimmsInstallable == 2) {
|
||||||
if (!(pDCTstat->MirrPresU_NumRegR & (1 << DimmNum)))
|
if (Dimms > 1)
|
||||||
val |= 1 << 2;
|
val = 0x4;
|
||||||
} else {
|
|
||||||
if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
|
|
||||||
val |= 1 << 2;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (Dimms > 1)
|
|
||||||
val |= 1 << 2;
|
|
||||||
}
|
}
|
||||||
} else if (CtrlWordNum == 3) {
|
} else if (CtrlWordNum == 3) {
|
||||||
val |= (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
|
val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
|
||||||
} else if (CtrlWordNum == 4) {
|
} else if (CtrlWordNum == 4) {
|
||||||
val |= (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
|
val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
|
||||||
} else if (CtrlWordNum == 5) {
|
} else if (CtrlWordNum == 5) {
|
||||||
val |= (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
|
val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
|
||||||
} else if (CtrlWordNum == 8) {
|
} else if (CtrlWordNum == 8) {
|
||||||
if (MaxDimm == 4)
|
if (package_type == PT_GR) {
|
||||||
if (Speed == 4)
|
/* Socket G34 */
|
||||||
if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
|
if (MaxDimmsInstallable == 2) {
|
||||||
val |= 1 << 2;
|
val = 0x0;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (CtrlWordNum == 9) {
|
} else if (CtrlWordNum == 9) {
|
||||||
val |= 0xD; /* DBA1, DBA0, DA3 = 0 */
|
val = 0xD; /* DBA1, DBA0, DA3 = 0 */
|
||||||
|
} else if (CtrlWordNum == 10) {
|
||||||
|
val = 0x0; /* Lowest operating frequency */
|
||||||
|
} else if (CtrlWordNum == 11) {
|
||||||
|
if (ddr_voltage_index & 0x4)
|
||||||
|
val = 0x2; /* 1.25V */
|
||||||
|
else if (ddr_voltage_index & 0x2)
|
||||||
|
val = 0x1; /* 1.35V */
|
||||||
|
else
|
||||||
|
val = 0x0; /* 1.5V */
|
||||||
|
} else if (CtrlWordNum >= 12) {
|
||||||
|
val = 0x0; /* Unset */
|
||||||
}
|
}
|
||||||
val &= 0xffffff0f;
|
val &= 0xf;
|
||||||
|
|
||||||
val = MrsChipSel | ((val >> 2) & 3) << 16 | ((val & 3) << 3);
|
printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", CtrlWordNum, val);
|
||||||
|
|
||||||
|
val = MrsChipSel | rc_word_value_to_ctl_bits(val);
|
||||||
|
|
||||||
/* transfer Control word number to address [BA2,A2,A1,A0] */
|
/* transfer Control word number to address [BA2,A2,A1,A0] */
|
||||||
if (CtrlWordNum > 7) {
|
if (CtrlWordNum > 7) {
|
||||||
|
@ -125,18 +162,18 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
|
||||||
val &= ~(0xF << 8);
|
val &= ~(0xF << 8);
|
||||||
|
|
||||||
switch (MrsChipSel) {
|
switch (MrsChipSel) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
val |= 3 << 8;
|
val |= 3 << 8;
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
val |= (3 << 2) << 8;
|
val |= (3 << 2) << 8;
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
val |= (3 << 4) << 8;
|
val |= (3 << 4) << 8;
|
||||||
case 6:
|
case 6:
|
||||||
case 7:
|
case 7:
|
||||||
val |= (3 << 6) << 8;
|
val |= (3 << 6) << 8;
|
||||||
}
|
}
|
||||||
Set_NB32_DCT(dev, dct, 0xa8, val);
|
Set_NB32_DCT(dev, dct, 0xa8, val);
|
||||||
|
|
||||||
|
@ -160,8 +197,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
|
||||||
u32 MrsChipSel;
|
u32 MrsChipSel;
|
||||||
u32 dev = pDCTstat->dev_dct;
|
u32 dev = pDCTstat->dev_dct;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
uint16_t mem_freq;
|
||||||
|
|
||||||
pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
|
pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
|
||||||
|
mem_freq = memclk_to_freq(pDCTstat->TargetFreq);
|
||||||
for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
|
for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
|
||||||
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
|
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
|
||||||
/* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects. */
|
/* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects. */
|
||||||
|
@ -171,19 +210,31 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
|
||||||
Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 select */
|
Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 select */
|
||||||
|
|
||||||
/* Resend control word 10 */
|
/* Resend control word 10 */
|
||||||
|
uint8_t freq_ctl_val = 0;
|
||||||
mct_Wait(1600);
|
mct_Wait(1600);
|
||||||
switch (pDCTstat->TargetFreq) {
|
switch (mem_freq) {
|
||||||
case 5:
|
case 333:
|
||||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4000A);
|
case 400:
|
||||||
break;
|
freq_ctl_val = 0x0;
|
||||||
case 6:
|
break;
|
||||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40012);
|
case 533:
|
||||||
break;
|
freq_ctl_val = 0x1;
|
||||||
case 7:
|
break;
|
||||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4001A);
|
case 667:
|
||||||
break;
|
freq_ctl_val = 0x2;
|
||||||
|
break;
|
||||||
|
case 800:
|
||||||
|
freq_ctl_val = 0x3;
|
||||||
|
break;
|
||||||
|
case 933:
|
||||||
|
freq_ctl_val = 0x4;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", 10, freq_ctl_val);
|
||||||
|
|
||||||
|
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40002 | rc_word_value_to_ctl_bits(freq_ctl_val));
|
||||||
|
|
||||||
mct_Wait(1600);
|
mct_Wait(1600);
|
||||||
|
|
||||||
/* Resend control word 2 */
|
/* Resend control word 2 */
|
||||||
|
|
|
@ -492,6 +492,8 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
|
||||||
ret |= ((dword >> 10) & 3) << 9;
|
ret |= ((dword >> 10) & 3) << 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Going to send MR2 control word %08x\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,6 +523,8 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
|
||||||
ret |= (dword >> 24) & 7;
|
ret |= (dword >> 24) & 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Going to send MR3 control word %08x\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,6 +619,8 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
|
||||||
ret |= 1 << 12;
|
ret |= 1 << 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Going to send MR1 control word %08x\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,6 +740,8 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
|
||||||
ret |= 1 << 8;
|
ret |= 1 << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Going to send MR0 control word %08x\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1740,6 +1740,7 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
|
||||||
u16 EccDQSLike;
|
u16 EccDQSLike;
|
||||||
u8 EccDQSScale;
|
u8 EccDQSScale;
|
||||||
u32 val, val0, val1;
|
u32 val, val0, val1;
|
||||||
|
int16_t delay_differential;
|
||||||
|
|
||||||
EccDQSLike = pDCTstat->CH_EccDQSLike[Channel];
|
EccDQSLike = pDCTstat->CH_EccDQSLike[Channel];
|
||||||
EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
|
EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
|
||||||
|
@ -1749,14 +1750,22 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
|
||||||
u16 *p;
|
u16 *p;
|
||||||
p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
|
p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
|
||||||
|
|
||||||
/* DQS Delay Value of Data Bytelane
|
if (pDCTstat->Status & (1 << SB_Registered)) {
|
||||||
* most like ECC byte lane */
|
val0 = p[0x2];
|
||||||
val0 = p[EccDQSLike & 0x07];
|
val1 = p[0x3];
|
||||||
/* DQS Delay Value of Data Bytelane
|
|
||||||
* 2nd most like ECC byte lane */
|
delay_differential = (int16_t)val1 - (int16_t)val0;
|
||||||
val1 = p[(EccDQSLike>>8) & 0x07];
|
delay_differential += (int16_t)val1;
|
||||||
|
|
||||||
|
val = delay_differential;
|
||||||
|
} else {
|
||||||
|
/* DQS Delay Value of Data Bytelane
|
||||||
|
* most like ECC byte lane */
|
||||||
|
val0 = p[EccDQSLike & 0x07];
|
||||||
|
/* DQS Delay Value of Data Bytelane
|
||||||
|
* 2nd most like ECC byte lane */
|
||||||
|
val1 = p[(EccDQSLike>>8) & 0x07];
|
||||||
|
|
||||||
if (!(pDCTstat->Status & (1 << SB_Registered))) {
|
|
||||||
if(val0 > val1) {
|
if(val0 > val1) {
|
||||||
val = val0 - val1;
|
val = val0 - val1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1771,9 +1780,6 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
|
||||||
} else {
|
} else {
|
||||||
val += val0;
|
val += val0;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val = val1 - val0;
|
|
||||||
val += val1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pDCTstat->CH_D_BC_RCVRDLY[Channel][ChipSel>>1] = val;
|
pDCTstat->CH_D_BC_RCVRDLY[Channel][ChipSel>>1] = val;
|
||||||
|
|
|
@ -926,7 +926,9 @@ void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
|
||||||
else if ((cs == 4) || (cs == 0))
|
else if ((cs == 4) || (cs == 0))
|
||||||
WrLvOdt1 = (dword & 0xf);
|
WrLvOdt1 = (dword & 0xf);
|
||||||
} else {
|
} else {
|
||||||
if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
|
if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
|
||||||
|
WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
|
||||||
|
} else {
|
||||||
if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
|
if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
|
||||||
WrLvOdt1 = 0x03;
|
WrLvOdt1 = 0x03;
|
||||||
} else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
|
} else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
|
||||||
|
@ -934,14 +936,14 @@ void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
|
||||||
} else {
|
} else {
|
||||||
WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
|
WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
|
set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
|
||||||
DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
|
DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x\n", dct, WrLvOdt1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNUSED_CODE
|
#ifdef UNUSED_CODE
|
||||||
|
@ -976,7 +978,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
|
||||||
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];
|
||||||
u16 fam10h_freq_tab[] = {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};
|
||||||
|
|
||||||
if (is_fam15h()) {
|
if (is_fam15h()) {
|
||||||
|
@ -1089,21 +1091,18 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
|
||||||
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
|
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pDCTData->Status[DCT_STATUS_REGISTERED])
|
if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
|
||||||
{
|
uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
|
||||||
if(pDCTData->RegMan1Present & ((1<<(dimm*2+dct))))
|
|
||||||
{
|
/* The seed values below assume Pass 1 utilizes a 400MHz clock frequency (DDR3-800) */
|
||||||
|
if (AddrCmdPrelaunch == 0) {
|
||||||
Seed_Gross = 0x02;
|
Seed_Gross = 0x02;
|
||||||
Seed_Fine = 0x16;
|
Seed_Fine = 0x01;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Seed_Gross = 0x02;
|
Seed_Gross = 0x02;
|
||||||
Seed_Fine = 0x00;
|
Seed_Fine = 0x11;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
if (MemClkFreq == 6) {
|
if (MemClkFreq == 6) {
|
||||||
/* DDR-800 */
|
/* DDR-800 */
|
||||||
Seed_Gross = 0x00;
|
Seed_Gross = 0x00;
|
||||||
|
@ -1127,6 +1126,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
|
||||||
*/
|
*/
|
||||||
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
|
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
|
||||||
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
|
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
|
||||||
|
printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Pass 2 */
|
/* Pass 2 */
|
||||||
|
@ -1178,21 +1178,30 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
|
||||||
|
|
||||||
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
|
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
|
||||||
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
|
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
u32 RegisterDelay, SeedTotal;
|
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_BYTE_LANES; ByteLane++)
|
||||||
{
|
{
|
||||||
if (pDCTData->Status[DCT_STATUS_REGISTERED])
|
if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
|
||||||
RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) == 0) ? 0x20 : 0x30; */
|
if (AddrCmdPrelaunch == 0)
|
||||||
else
|
RegisterDelay = 0x20;
|
||||||
|
else
|
||||||
|
RegisterDelay = 0x30;
|
||||||
|
} else {
|
||||||
RegisterDelay = 0;
|
RegisterDelay = 0;
|
||||||
SeedTotal = (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
|
}
|
||||||
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
|
SeedTotalPreScaling = ((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
|
||||||
|
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*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) (RegisterDelay + ((((uint64_t) SeedTotal - RegisterDelay) *
|
SeedTotal = (uint16_t) ((((uint64_t) SeedTotalPreScaling) *
|
||||||
fam10h_freq_tab[MemClkFreq-3] * 100) / (fam10h_freq_tab[0] * 100)));
|
fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 100));
|
||||||
Seed_Gross = SeedTotal / 32;
|
Seed_Gross = SeedTotal / 32;
|
||||||
Seed_Fine = SeedTotal & 0x1f;
|
Seed_Fine = SeedTotal & 0x1f;
|
||||||
if (Seed_Gross == 0)
|
if (Seed_Gross == 0)
|
||||||
|
@ -1201,8 +1210,20 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
|
||||||
Seed_Gross = 1;
|
Seed_Gross = 1;
|
||||||
else
|
else
|
||||||
Seed_Gross = 2;
|
Seed_Gross = 2;
|
||||||
|
|
||||||
|
/* The BKDG-recommended algorithm causes problems with registered DIMMs on some systems
|
||||||
|
* due to the long register delays causing premature total delay wrap-around.
|
||||||
|
* Attempt to work around this...
|
||||||
|
*/
|
||||||
|
SeedTotal = ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f);
|
||||||
|
SeedTotal += RegisterDelay;
|
||||||
|
Seed_Gross = SeedTotal / 32;
|
||||||
|
Seed_Fine = SeedTotal & 0x1f;
|
||||||
|
|
||||||
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
|
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
|
||||||
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
|
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1379,6 +1400,8 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
|
||||||
gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
|
gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
|
||||||
FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
|
FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
|
||||||
|
|
||||||
|
printk(BIOS_SPEW, "\tLane %02x raw readback: %04x\n", ByteLane, ((gross & 0x1f) << 5) | (fine & 0x1f));
|
||||||
|
|
||||||
if (!is_fam15h()) {
|
if (!is_fam15h()) {
|
||||||
/* Adjust seed gross delay overflow (greater than 3):
|
/* Adjust seed gross delay overflow (greater than 3):
|
||||||
* - Adjust the trained gross delay to the original seed gross delay.
|
* - Adjust the trained gross delay to the original seed gross delay.
|
||||||
|
@ -1402,4 +1425,5 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
|
||||||
}
|
}
|
||||||
pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
|
pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
|
||||||
pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
|
pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
|
||||||
|
printk(BIOS_SPEW, "\tLane %02x final adjusted value: %04x\n", ByteLane, ((gross & 0x1f) << 5) | (fine & 0x1f));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue