summaryrefslogtreecommitdiffstats
path: root/resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
diff options
context:
space:
mode:
authorFrancis Rowe <info@gluglug.org.uk>2016-01-02 17:10:32 (EST)
committer Francis Rowe <info@gluglug.org.uk>2016-01-04 15:28:39 (EST)
commitd1f408f3725aa02bc1d76c4c6aadb4697bd073c0 (patch)
tree7eed036543ae1f8c57b56825880a722a8efbedf1 /resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
parent91aec7e72005dcda72d19f2d024a02d8c0f86590 (diff)
downloadlibreboot-d1f408f3725aa02bc1d76c4c6aadb4697bd073c0.zip
libreboot-d1f408f3725aa02bc1d76c4c6aadb4697bd073c0.tar.gz
libreboot-d1f408f3725aa02bc1d76c4c6aadb4697bd073c0.tar.bz2
Use different coreboot revisions and patches per board
The release archives will be bigger, but this is a necessary change that makes libreboot development easier. At present, there are boards maintained in libreboot by different people. By doing it this way, that becomes much easier. This is in contrast to the present situation, where a change to one board potentially affects all other boards, especially when updating to a new version of coreboot. Coreboot-libre scripts, download scripts, build scripts - everything. The entire build system has been modified to reflect this change of development. For reasons of consistency, cbfstool and nvramtool are no longer included in the util archives.
Diffstat (limited to 'resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch')
-rw-r--r--resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/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/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch b/resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/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/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/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
+