aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineeringinc.com>2015-07-28 15:16:46 -0500
committerMartin Roth <martinroth@google.com>2015-11-16 18:04:59 +0100
commit29016ea3b4350d8c9ed5fad8dff7707ecbb21127 (patch)
tree86e3d67b447c903d58b6a53fb539101672f01b1a /src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
parentf682d0028cb33fc4a085af83344f4a7b9c0e78f2 (diff)
northbridge/amd/mct_ddr3: Add registered and x4 DIMM support to Fam15h
The existing MCT support code did not perform any of the requisite configuration to support registered or x4 DIMMs. Add the needed configuration per the BKDG for Family 15h. Change-Id: I9ee0bb7346aa35f564fe535cdd337ec7f6148f2b Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/12019 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mctrci.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctrci.c191
1 files changed, 132 insertions, 59 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
index 3f6c39d2c5..01061a7335 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
@@ -14,6 +14,78 @@
* GNU General Public License for more details.
*/
+static uint8_t fam15h_rdimm_rc2_control_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+ uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+
+ uint8_t package_type;
+ uint8_t control_code = 0;
+
+ package_type = mctGet_NVbits(NV_PACK_TYPE);
+ uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+
+ /* Obtain number of DIMMs on channel */
+ uint8_t dimm_count = pDCTstat->MAdimms[dct];
+
+ /* FIXME
+ * Assume there is only one register on the RDIMM for now
+ */
+ uint8_t num_registers = 1;
+
+ if (package_type == PT_GR) {
+ /* Socket G34 */
+ /* Fam15h BKDG Rev. 3.14 section 2.10.5.7.1.2.1 Table 85 */
+ if (MaxDimmsInstallable == 1) {
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ control_code = 0x1;
+ } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
+ /* DDR3-1066 - DDR3-1333 */
+ if (num_registers == 1) {
+ control_code = 0x0;
+ } else {
+ control_code = 0x1;
+ }
+ } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
+ /* DDR3-1600 - DDR3-1866 */
+ control_code = 0x0;
+ }
+ } else if (MaxDimmsInstallable == 2) {
+ if (dimm_count == 1) {
+ /* 1 DIMM detected */
+ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+ /* DDR3-667 - DDR3-800 */
+ control_code = 0x1;
+ } else if ((MemClkFreq >= 0xa) && (MemClkFreq <= 0x12)) {
+ /* DDR3-1066 - DDR3-1600 */
+ if (num_registers == 1) {
+ control_code = 0x0;
+ } else {
+ control_code = 0x1;
+ }
+ }
+ } else if (dimm_count == 2) {
+ /* 2 DIMMs detected */
+ if (num_registers == 1) {
+ control_code = 0x1;
+ } else {
+ control_code = 0x8;
+ }
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ /* TODO
+ * 3 DIMM/channel support unimplemented
+ */
+ }
+ } else {
+ /* TODO
+ * Other socket support unimplemented
+ */
+ }
+
+ return control_code;
+}
+
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};
@@ -33,36 +105,46 @@ static uint16_t memclk_to_freq(uint16_t memclk) {
return mem_freq;
}
+static uint8_t rc_word_chip_select_lower_bit(void) {
+ if (is_fam15h()) {
+ return 21;
+ } else {
+ return 20;
+ }
+}
+
+static uint32_t rc_word_address_to_ctl_bits(uint32_t address) {
+ if (is_fam15h()) {
+ return (((address >> 3) & 0x1) << 2) << 18 | (address & 0x7);
+ } else {
+ return (((address >> 3) & 0x1) << 2) << 16 | (address & 0x7);
+ }
+}
+
static uint32_t rc_word_value_to_ctl_bits(uint32_t value) {
- return ((value >> 2) & 3) << 16 | ((value & 3) << 3);
+ if (is_fam15h()) {
+ return ((value >> 2) & 0x3) << 18 | ((value & 0x3) << 3);
+ } else {
+ return ((value >> 2) & 0x3) << 16 | ((value & 0x3) << 3);
+ }
}
static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum)
+ struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MrsChipSel, u32 CtrlWordNum)
{
u8 Dimms, DimmNum;
u32 val;
- 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 >> rc_word_chip_select_lower_bit()) & 0xfe;
- /* assume dct=0; */
- /* if (dct == 1) */
- /* DimmNum ++; */
- /* cl +=8; */
+ if (dct == 1)
+ DimmNum++;
mem_freq = memclk_to_freq(pDCTstat->DIMMAutoSpeed);
-
- if (pDCTstat->CSPresent_DCT[0] > 0) {
- dct = 0;
- } else if (pDCTstat->CSPresent_DCT[1] > 0 ) {
- dct = 1;
- DimmNum++;
- }
Dimms = pDCTstat->MAdimms[dct];
ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
@@ -72,21 +154,25 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
val = 0x2;
else if (CtrlWordNum == 1) {
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) {
- if (package_type == PT_GR) {
- /* Socket G34 */
- if (MaxDimmsInstallable == 2) {
- if (Dimms > 1)
- val = 0x4;
+ if (is_fam15h()) {
+ val = fam15h_rdimm_rc2_control_code(pDCTstat, dct);
+ } else {
+ if (package_type == PT_GR) {
+ /* Socket G34 */
+ if (MaxDimmsInstallable == 2) {
+ if (Dimms > 1)
+ val = 0x4;
+ }
}
}
} else if (CtrlWordNum == 3) {
- val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
+ val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xff;
} else if (CtrlWordNum == 4) {
- val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
+ val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xff;
} else if (CtrlWordNum == 5) {
- val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
+ val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xff;
} else if (CtrlWordNum == 8) {
if (package_type == PT_GR) {
/* Socket G34 */
@@ -95,7 +181,7 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
}
}
} 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) {
@@ -110,43 +196,30 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
}
val &= 0xf;
- printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", CtrlWordNum, val);
+ printk(BIOS_SPEW, "Preparing to send DCT %d DIMM RC%d: %02x\n", dct, CtrlWordNum, val);
val = MrsChipSel | rc_word_value_to_ctl_bits(val);
-
- /* transfer Control word number to address [BA2,A2,A1,A0] */
- if (CtrlWordNum > 7) {
- val |= 1 << 18;
- CtrlWordNum &= 7;
- }
- val |= CtrlWordNum;
+ val |= rc_word_address_to_ctl_bits(CtrlWordNum);
return val;
}
static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u32 val)
+ struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t val)
{
- uint8_t dct = 0;
u32 dev = pDCTstat->dev_dct;
- if (pDCTstat->CSPresent_DCT[0] > 0) {
- dct = 0;
- } else if (pDCTstat->CSPresent_DCT[1] > 0 ){
- dct = 1;
- }
-
- val |= Get_NB32_DCT(dev, dct, 0x7C) & ~0xFFFFFF;
+ val |= Get_NB32_DCT(dev, dct, 0x7c) & ~0xffffff;
val |= 1 << SendControlWord;
- Set_NB32_DCT(dev, dct, 0x7C, val);
+ Set_NB32_DCT(dev, dct, 0x7c, val);
do {
- val = Get_NB32_DCT(dev, dct, 0x7C);
+ val = Get_NB32_DCT(dev, dct, 0x7c);
} while (val & (1 << SendControlWord));
}
void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u8 dct)
+ struct DCTStatStruc *pDCTstat, uint8_t dct)
{
u8 MrsChipSel;
u32 dev = pDCTstat->dev_dct;
@@ -159,7 +232,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
val = Get_NB32_DCT(dev, dct, 0xa8);
- val &= ~(0xF << 8);
+ val &= ~(0xf << 8);
switch (MrsChipSel) {
case 0:
@@ -180,8 +253,8 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
for (cw=0; cw <=15; cw ++) {
mct_Wait(1600);
if (!(cw==6 || cw==7)) {
- val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, cw);
- mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
+ val = mct_ControlRC(pMCTstat, pDCTstat, dct, MrsChipSel << rc_word_chip_select_lower_bit(), cw);
+ mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, val);
}
}
}
@@ -191,7 +264,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
}
void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat)
+ struct DCTStatStruc *pDCTstat, uint8_t dct)
{
u32 SaveSpeed = pDCTstat->DIMMAutoSpeed;
u32 MrsChipSel;
@@ -204,10 +277,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
/* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects. */
- val = Get_NB32_DCT(dev, 0, 0xA8); /* TODO: dct 0 / 1 select */
- val &= ~(0xFF << 8);
- val |= (0x3 << (MrsChipSel & 0xFE)) << 8;
- Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 select */
+ val = Get_NB32_DCT(dev, dct, 0xa8);
+ val &= ~(0xff << 8);
+ val |= (0x3 << (MrsChipSel & 0xfe)) << 8;
+ Set_NB32_DCT(dev, dct, 0xa8, val);
/* Resend control word 10 */
uint8_t freq_ctl_val = 0;
@@ -231,21 +304,21 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
break;
}
- printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", 10, freq_ctl_val);
+ printk(BIOS_SPEW, "Preparing to send DCT %d DIMM RC%d: %02x\n", dct, 10, freq_ctl_val);
- mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40002 | rc_word_value_to_ctl_bits(freq_ctl_val));
+ mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, MrsChipSel << rc_word_chip_select_lower_bit() | rc_word_address_to_ctl_bits(10) | rc_word_value_to_ctl_bits(freq_ctl_val));
mct_Wait(1600);
/* Resend control word 2 */
- val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 2);
- mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
+ val = mct_ControlRC(pMCTstat, pDCTstat, dct, MrsChipSel << rc_word_chip_select_lower_bit(), 2);
+ mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, val);
mct_Wait(1600);
/* Resend control word 8 */
- val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 8);
- mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
+ val = mct_ControlRC(pMCTstat, pDCTstat, dct, MrsChipSel << rc_word_chip_select_lower_bit(), 8);
+ mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, val);
mct_Wait(1600);
}