diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-07-26 00:55:43 -0500 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2015-11-16 17:55:57 +0100 |
commit | f682d0028cb33fc4a085af83344f4a7b9c0e78f2 (patch) | |
tree | 84c2289b2ca976c728f2fb42ded31c9f79c7a275 /src/northbridge/amd/amdmct/mct_ddr3/mctrci.c | |
parent | 474ff3dee54e81017587f53ce644307e4f655333 (diff) | |
download | coreboot-f682d0028cb33fc4a085af83344f4a7b9c0e78f2.tar.xz |
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>
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mctrci.c')
-rw-r--r-- | src/northbridge/amd/amdmct/mct_ddr3/mctrci.c | 151 |
1 files changed, 101 insertions, 50 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c index d7bd3a7cdc..3f6c39d2c5 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c @@ -14,12 +14,39 @@ * 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, struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum) { - u8 Dimms, DimmNum, MaxDimm, Speed; + 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; @@ -28,54 +55,64 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat, /* DimmNum ++; */ /* cl +=8; */ - MaxDimm = mctGet_NVbits(NV_MAX_DIMMS); - Speed = pDCTstat->DIMMAutoSpeed; + mem_freq = memclk_to_freq(pDCTstat->DIMMAutoSpeed); if (pDCTstat->CSPresent_DCT[0] > 0) { dct = 0; - } else if (pDCTstat->CSPresent_DCT[1] > 0 ){ + } else if (pDCTstat->CSPresent_DCT[1] > 0 ) { dct = 1; - DimmNum ++; + DimmNum++; } Dimms = pDCTstat->MAdimms[dct]; + ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); + val = 0; if (CtrlWordNum == 0) - val |= 1 << 1; + 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 (MaxDimm == 4) { - if (Speed == 4) { - if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) && (Dimms == 1)) || (Dimms == 2)) - if (!(pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))) - val |= 1 << 2; - } else { - if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum)) - val |= 1 << 2; + if (package_type == PT_GR) { + /* Socket G34 */ + if (MaxDimmsInstallable == 2) { + if (Dimms > 1) + val = 0x4; } - } else { - if (Dimms > 1) - val |= 1 << 2; } } 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 (MaxDimm == 4) - if (Speed == 4) - if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum)) - val |= 1 << 2; + if (package_type == PT_GR) { + /* Socket G34 */ + if (MaxDimmsInstallable == 2) { + val = 0x0; + } + } } 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; + + printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", CtrlWordNum, val); - val = MrsChipSel | ((val >> 2) & 3) << 16 | ((val & 3) << 3); + val = MrsChipSel | rc_word_value_to_ctl_bits(val); /* transfer Control word number to address [BA2,A2,A1,A0] */ if (CtrlWordNum > 7) { @@ -125,18 +162,18 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat, val &= ~(0xF << 8); switch (MrsChipSel) { - case 0: - case 1: - val |= 3 << 8; - case 2: - case 3: - val |= (3 << 2) << 8; - case 4: - case 5: - val |= (3 << 4) << 8; - case 6: - case 7: - val |= (3 << 6) << 8; + case 0: + case 1: + val |= 3 << 8; + case 2: + case 3: + val |= (3 << 2) << 8; + case 4: + case 5: + val |= (3 << 4) << 8; + case 6: + case 7: + val |= (3 << 6) << 8; } Set_NB32_DCT(dev, dct, 0xa8, val); @@ -160,8 +197,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat, u32 MrsChipSel; u32 dev = pDCTstat->dev_dct; u32 val; + uint16_t mem_freq; pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq; + mem_freq = memclk_to_freq(pDCTstat->TargetFreq); 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. */ @@ -171,19 +210,31 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat, Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 select */ /* Resend control word 10 */ + uint8_t freq_ctl_val = 0; mct_Wait(1600); - switch (pDCTstat->TargetFreq) { - case 5: - mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4000A); - break; - case 6: - mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40012); - break; - case 7: - mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4001A); - break; + switch (mem_freq) { + case 333: + case 400: + freq_ctl_val = 0x0; + break; + case 533: + freq_ctl_val = 0x1; + break; + case 667: + 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); /* Resend control word 2 */ |