summaryrefslogtreecommitdiffstats
path: root/resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch')
-rw-r--r--resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch602
1 files changed, 602 insertions, 0 deletions
diff --git a/resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch b/resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
new file mode 100644
index 0000000..4dcf7c5
--- /dev/null
+++ b/resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
@@ -0,0 +1,602 @@
+From d9d10881a0841481d8df2e357adb870ce52f9387 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <tpearson@raptorengineeringinc.com>
+Date: Thu, 27 Aug 2015 23:37:38 -0500
+Subject: [PATCH 129/143] northbridge/amd/amdmct/mct_ddr3: Fix broken support
+ for multiple DIMMs on single channel
+
+Change-Id: I0278656e98461882d0a64519dfde54a6cf28ab0f
+Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 336 +++++++++++++++++++-----
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h | 8 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 2 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctrci.c | 26 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c | 4 +
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 8 +-
+ 6 files changed, 310 insertions(+), 74 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index a11b227..5bc80f4 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1360,6 +1360,224 @@ static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t dc
+ return slow_access;
+ }
+
++static uint8_t fam15h_odt_tristate_enable_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
++{
++ uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
++
++ uint8_t package_type;
++ uint8_t odt_tristate_code = 0;
++
++ package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++ /* 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 */
++ /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 */
++ if (MaxDimmsInstallable == 1) {
++ rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm0 == 1)
++ odt_tristate_code = 0xe;
++ else
++ odt_tristate_code = 0xa;
++ } else if (MaxDimmsInstallable == 2) {
++ if (dimm_count == 1) {
++ /* 1 DIMM detected */
++ rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm1 == 1)
++ odt_tristate_code = 0xd;
++ else
++ odt_tristate_code = 0x5;
++ } 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 ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
++ odt_tristate_code = 0xc;
++ else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 >= 2))
++ odt_tristate_code = 0x4;
++ else if ((rank_count_dimm0 >= 2) && (rank_count_dimm1 == 1))
++ odt_tristate_code = 0x8;
++ else
++ odt_tristate_code = 0x0;
++ }
++ } else if (MaxDimmsInstallable == 3) {
++ /* TODO
++ * 3 DIMM/channel support unimplemented
++ */
++ }
++ } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++ /* LRDIMM */
++
++ /* TODO
++ * Implement LRDIMM support
++ * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 105
++ */
++ } else {
++ /* UDIMM */
++ /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 */
++ if (MaxDimmsInstallable == 1) {
++ rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm0 == 1)
++ odt_tristate_code = 0xe;
++ else
++ odt_tristate_code = 0xa;
++ } else if (MaxDimmsInstallable == 2) {
++ if (dimm_count == 1) {
++ /* 1 DIMM detected */
++ rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm0 == 1)
++ odt_tristate_code = 0xd;
++ else
++ odt_tristate_code = 0x5;
++ } 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 ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
++ odt_tristate_code = 0xc;
++ else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2))
++ odt_tristate_code = 0x4;
++ else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1))
++ odt_tristate_code = 0x8;
++ else
++ odt_tristate_code = 0x0;
++ }
++ } else if (MaxDimmsInstallable == 3) {
++ /* TODO
++ * 3 DIMM/channel support unimplemented
++ */
++ }
++ }
++ } else {
++ /* TODO
++ * Other socket support unimplemented
++ */
++ }
++
++ return odt_tristate_code;
++}
++
++static uint8_t fam15h_cs_tristate_enable_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
++{
++ uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
++
++ uint8_t package_type;
++ uint8_t cs_tristate_code = 0;
++
++ package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++ /* 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 */
++ /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 */
++ if (MaxDimmsInstallable == 1) {
++ rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm0 < 4)
++ cs_tristate_code = 0xfc;
++ else
++ cs_tristate_code = 0xcc;
++ } else if (MaxDimmsInstallable == 2) {
++ if (dimm_count == 1) {
++ /* 1 DIMM detected */
++ rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm1 < 4)
++ cs_tristate_code = 0xf3;
++ else
++ cs_tristate_code = 0x33;
++ } 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 ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4))
++ cs_tristate_code = 0xf0;
++ else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4))
++ cs_tristate_code = 0x30;
++ else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4))
++ cs_tristate_code = 0xc0;
++ else
++ cs_tristate_code = 0x0;
++ }
++ } else if (MaxDimmsInstallable == 3) {
++ /* TODO
++ * 3 DIMM/channel support unimplemented
++ */
++ }
++ } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++ /* LRDIMM */
++
++ /* TODO
++ * Implement LRDIMM support
++ * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 105
++ */
++ } else {
++ /* UDIMM */
++ /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 */
++ if (MaxDimmsInstallable == 1) {
++ rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm0 == 1)
++ cs_tristate_code = 0xfe;
++ else
++ cs_tristate_code = 0xfc;
++ } else if (MaxDimmsInstallable == 2) {
++ if (dimm_count == 1) {
++ /* 1 DIMM detected */
++ rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
++
++ if (rank_count_dimm0 == 1)
++ cs_tristate_code = 0xfb;
++ else
++ cs_tristate_code = 0xf3;
++ } 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 ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
++ cs_tristate_code = 0xfa;
++ else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2))
++ cs_tristate_code = 0xf2;
++ else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1))
++ cs_tristate_code = 0xf8;
++ else
++ cs_tristate_code = 0xf0;
++ }
++ } else if (MaxDimmsInstallable == 3) {
++ /* TODO
++ * 3 DIMM/channel support unimplemented
++ */
++ }
++ }
++ } else {
++ /* TODO
++ * Other socket support unimplemented
++ */
++ }
++
++ return cs_tristate_code;
++}
++
+ static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+@@ -2299,20 +2517,16 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
+ if (memclk_index <= 0x6) {
+ delay = 0x5;
+ delay2 = 0x3;
+- }
+- else if (memclk_index == 0xa) {
++ } else if (memclk_index == 0xa) {
+ delay = 0x6;
+ delay2 = 0x3;
+- }
+- else if (memclk_index == 0xe) {
++ } else if (memclk_index == 0xe) {
+ delay = 0x7;
+ delay2 = 0x4;
+- }
+- else if (memclk_index == 0x12) {
++ } else if (memclk_index == 0x12) {
+ delay = 0x8;
+ delay2 = 0x4;
+- }
+- else if (memclk_index == 0x16) {
++ } else if (memclk_index == 0x16) {
+ delay = 0xa;
+ delay2 = 0x5;
+ }
+@@ -3329,8 +3543,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ tCK16x = 40;
+ else
+ tCK16x = 48;
+- }
+- else {
++ } else {
+ if (byte == 7)
+ tCK16x = 20;
+ else if (byte == 6)
+@@ -4657,13 +4870,13 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ else
+ pDCTstat->RegMan1Present |= 1 << i;
+ }
+- /* Get Control word values for RC3. We dont need it. */
++ /* Get control word value for RC3 */
+ byte = pDCTstat->spd_data.spd_bytes[i][70];
+- pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); /* C3 = SPD byte 70 [7:4] */
+- /* Get Control word values for RC4, and RC5 */
++ pDCTstat->CtrlWrd3 |= ((byte >> 4) & 0xf) << (i << 2); /* RC3 = SPD byte 70 [7:4] */
++ /* Get control word values for RC4 and RC5 */
+ byte = pDCTstat->spd_data.spd_bytes[i][71];
+- pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 2); /* RC4 = SPD byte 71 [3:0] */
+- pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); /* RC5 = SPD byte 71 [7:4] */
++ pDCTstat->CtrlWrd4 |= (byte & 0xf) << (i << 2); /* RC4 = SPD byte 71 [3:0] */
++ pDCTstat->CtrlWrd5 |= ((byte >> 4) & 0xf) << (i << 2); /* RC5 = SPD byte 71 [7:4] */
+ }
+ }
+ }
+@@ -5849,23 +6062,27 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+ u32 index_reg = 0x98;
+- u32 index;
+ u16 word;
+
+- /* Tri-state unused chipselects when motherboard
+- termination is available */
++ if (is_fam15h()) {
++ word = fam15h_cs_tristate_enable_code(pDCTstat, dct);
++ } else {
++ /* Tri-state unused chipselects when motherboard
++ termination is available */
+
+- /* FIXME: skip for Ax */
++ /* FIXME: skip for Ax */
+
+- word = pDCTstat->CSPresent;
+- if (pDCTstat->Status & (1 << SB_Registered)) {
+- word |= (word & 0x55) << 1;
++ word = pDCTstat->CSPresent;
++ if (pDCTstat->Status & (1 << SB_Registered)) {
++ word |= (word & 0x55) << 1;
++ }
++ word = (~word) & 0xff;
+ }
+- word = (~word) & 0xFF;
+- index = 0x0c;
+- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
++
++ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
++ val &= ~0xff;
+ val |= word;
+- Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
++ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
+ }
+
+ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+@@ -5874,7 +6091,6 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+ u32 val;
+ u32 dev;
+ u32 index_reg = 0x98;
+- u32 index;
+ u16 word;
+
+ /* Tri-state unused CKEs when motherboard termination is available */
+@@ -5884,15 +6100,13 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+ dev = pDCTstat->dev_dct;
+ word = pDCTstat->CSPresent;
+
+- index = 0x0c;
+- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
++ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
++ val &= ~(0x3 << 12);
+ if ((word & 0x55) == 0)
+ val |= 1 << 12;
+-
+- if ((word & 0xAA) == 0)
++ if ((word & 0xaa) == 0)
+ val |= 1 << 13;
+-
+- Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
++ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
+ }
+
+ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+@@ -5902,42 +6116,44 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+ u32 dev;
+ u32 index_reg = 0x98;
+ u8 cs;
+- u32 index;
+ u8 odt;
+ u8 max_dimms;
+
+- /* FIXME: skip for Ax */
+-
+ dev = pDCTstat->dev_dct;
+
+- /* Tri-state unused ODTs when motherboard termination is available */
+- max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
+- odt = 0x0F; /* ODT tri-state setting */
+-
+- if (pDCTstat->Status & (1 <<SB_Registered)) {
+- for (cs = 0; cs < 8; cs += 2) {
+- if (pDCTstat->CSPresent & (1 << cs)) {
+- odt &= ~(1 << (cs / 2));
+- if (mctGet_NVbits(NV_4RANKType) != 0) { /* quad-rank capable platform */
+- if (pDCTstat->CSPresent & (1 << (cs + 1)))
+- odt &= ~(4 << (cs / 2));
++ if (is_fam15h()) {
++ odt = fam15h_odt_tristate_enable_code(pDCTstat, dct);
++ } else {
++ /* FIXME: skip for Ax */
++
++ /* Tri-state unused ODTs when motherboard termination is available */
++ max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
++ odt = 0x0f; /* ODT tri-state setting */
++
++ if (pDCTstat->Status & (1 <<SB_Registered)) {
++ for (cs = 0; cs < 8; cs += 2) {
++ if (pDCTstat->CSPresent & (1 << cs)) {
++ odt &= ~(1 << (cs / 2));
++ if (mctGet_NVbits(NV_4RANKType) != 0) { /* quad-rank capable platform */
++ if (pDCTstat->CSPresent & (1 << (cs + 1)))
++ odt &= ~(4 << (cs / 2));
++ }
+ }
+ }
++ } else { /* AM3 package */
++ val = ~(pDCTstat->CSPresent);
++ odt = val & 9; /* swap bits 1 and 2 */
++ if (val & (1 << 1))
++ odt |= 1 << 2;
++ if (val & (1 << 2))
++ odt |= 1 << 1;
+ }
+- } else { /* AM3 package */
+- val = ~(pDCTstat->CSPresent);
+- odt = val & 9; /* swap bits 1 and 2 */
+- if (val & (1 << 1))
+- odt |= 1 << 2;
+- if (val & (1 << 2))
+- odt |= 1 << 1;
+ }
+
+- index = 0x0C;
+- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+- val |= ((odt & 0xFF) << 8); /* set bits 11:8 ODTTriState[3:0] */
+- Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+-
++ val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
++ val &= ~(0xf << 8); /* ODTTri = odt */
++ val |= (odt & 0xf) << 8;
++ Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
+ }
+
+ /* Family 15h */
+@@ -6507,7 +6723,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
+ dword |= (read_odt_delay & 0xf);
+ 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);
++ printk(BIOS_SPEW, "Programmed DCT %d ODT pattern %08x %08x %08x %08x\n", dct, odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
+ } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+ if (pDCTstat->Speed == 3)
+ dword = 0x00000800;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index ec5658e..8bc4ec2 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -582,7 +582,7 @@ struct DCTStatStruc { /* A per Node structure*/
+ uint8_t NbPstateThreshold;
+ uint8_t NbPstateHi;
+
+-/* New for LB Support */
++ /* New for LB Support */
+ u8 NodePresent;
+ u32 dev_host;
+ u32 dev_map;
+@@ -592,9 +592,9 @@ struct DCTStatStruc { /* A per Node structure*/
+ u32 dev_nbctl;
+ u8 TargetFreq;
+ u8 TargetCASL;
+- u8 CtrlWrd3;
+- u8 CtrlWrd4;
+- u8 CtrlWrd5;
++ uint32_t CtrlWrd3;
++ uint32_t CtrlWrd4;
++ uint32_t CtrlWrd5;
+ u8 DqsRdWrPos_Saved;
+ u8 DqsRcvEnGrossMax;
+ u8 DqsRcvEnGrossMin;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index d870f17..553a54a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -1021,7 +1021,7 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
+ pDCTstat->CH_MaxRdLat[dct] = n - 1;
+
+ #if DQS_TRAIN_DEBUG > 0
+- printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, pDCTstat->CH_MaxRdLat[dct]);
++ printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, pDCTstat->CH_MaxRdLat[dct]);
+ #endif
+ }
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+index 8fd2523..dec2bf8 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+@@ -18,7 +18,7 @@
+ * Foundation, Inc.
+ */
+
+-static uint8_t fam15h_rdimm_rc2_control_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
++static uint8_t fam15h_rdimm_rc2_ibt_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
+ {
+ uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+
+@@ -161,7 +161,7 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+ val = 0xc; /* if single rank, set DBA1 and DBA0 */
+ } else if (CtrlWordNum == 2) {
+ if (is_fam15h()) {
+- val = fam15h_rdimm_rc2_control_code(pDCTstat, dct);
++ val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0x1) << 2;
+ } else {
+ if (package_type == PT_GR) {
+ /* Socket G34 */
+@@ -178,10 +178,14 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+ } else if (CtrlWordNum == 5) {
+ val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xff;
+ } else if (CtrlWordNum == 8) {
+- if (package_type == PT_GR) {
+- /* Socket G34 */
+- if (MaxDimmsInstallable == 2) {
+- val = 0x0;
++ if (is_fam15h()) {
++ val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0xe) >> 1;
++ } else {
++ if (package_type == PT_GR) {
++ /* Socket G34 */
++ if (MaxDimmsInstallable == 2) {
++ val = 0x0;
++ }
+ }
+ }
+ } else if (CtrlWordNum == 9) {
+@@ -233,7 +237,11 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
+
+ mct_Wait(1200);
+
+- for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
++ pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
++ if (pDCTstat->GangedMode & 1)
++ pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
++
++ for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel += 2) {
+ if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+ val = Get_NB32_DCT(dev, dct, 0xa8);
+ val &= ~(0xff << 8);
+@@ -276,6 +284,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+ u32 val;
+ uint16_t mem_freq;
+
++ pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
++ if (pDCTstat->GangedMode & 1)
++ pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
++
+ pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
+ mem_freq = memclk_to_freq(pDCTstat->TargetFreq);
+ for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 7804a38..5019faa 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -845,6 +845,10 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+ */
+ }
+
++ pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
++ if (pDCTstat->GangedMode & 1)
++ pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
++
+ /* The following steps are performed once for unbuffered DIMMs and once for each
+ * chip select on registered DIMMs: */
+ for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 73b231e..5cbadc3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -925,7 +925,7 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
+ * OUT
+ * ----------------------------------------------------------------------------
+ */
+-void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm)
++void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm)
+ {
+ sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+@@ -933,6 +933,10 @@ void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
+ u8 WrLvOdt1=0;
+
+ if (is_fam15h()) {
++ /* On Family15h processors, the value for the specific CS being targetted
++ * is taken from F2x238 / F2x23C as appropriate, then loaded into F2x9C_x0000_0008
++ */
++
+ /* Convert DIMM number to CS */
+ uint32_t dword;
+ uint8_t cs;
+@@ -967,7 +971,7 @@ void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
+ set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+ DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
+
+- printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x\n", dct, WrLvOdt1);
++ printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x from DIMM %d data\n", dct, WrLvOdt1, dimm);
+
+ }
+
+--
+1.7.9.5
+