aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineeringinc.com>2015-10-16 13:51:51 -0500
committerMartin Roth <martinroth@google.com>2015-11-02 23:45:19 +0100
commit730a043fb6cb4dd3cb5af8f8640365727b598648 (patch)
tree59afe45caca1a8e1682939c7e44e95344104533e /src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
parentd150006c4a4584bc9933c2d8ff580a54c4f0cc2a (diff)
cpu/amd: Add initial AMD Family 15h support
TEST: Booted ASUS KGPE-D16 with single Opteron 6380 * Unbuffered DDR3 DIMMs tested and working * Suspend to RAM (S3) tested and working Change-Id: Idffd2ce36ce183fbfa087e5ba69a9148f084b45e Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/11966 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c585
1 files changed, 461 insertions, 124 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
index a71bcbb56b..46a068414b 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
@@ -14,17 +14,182 @@
* GNU General Public License for more details.
*/
+static uint8_t fam15_dimm_dic(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
+{
+ uint8_t dic;
+
+ /* Calculate DIC based on recommendations in MR1_dct[1:0] */
+ if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+ /* TODO
+ * LRDIMM unimplemented
+ */
+ dic = 0x0;
+ } else {
+ dic = 0x1;
+ }
+
+ return dic;
+}
+
+static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
+{
+ uint8_t term = 0;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
+ uint8_t frequency_index;
+ uint8_t rank_count = pDCTData->DimmRanks[dimm];
+
+ if (is_fam15h())
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+ else
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7;
+
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ if (is_fam15h()) {
+ if (pDCTstat->Status & (1 << SB_Registered)) {
+ /* TODO
+ * RDIMM unimplemented
+ */
+ } else {
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 56 */
+ if (MaxDimmsInstallable == 1) {
+ term = 0x0;
+ } else if (MaxDimmsInstallable == 2) {
+ if ((number_of_dimms == 2) && (frequency_index == 0x12)) {
+ term = 0x1;
+ } else if (number_of_dimms == 1) {
+ term = 0x0;
+ } else {
+ term = 0x2;
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ if (number_of_dimms == 1) {
+ if (frequency_index <= 0xa) {
+ term = 0x2;
+ } else {
+ if (rank_count < 3) {
+ term = 0x1;
+ } else {
+ term = 0x2;
+ }
+ }
+ } else if (number_of_dimms == 2) {
+ term = 0x2;
+ }
+ }
+ } else {
+ /* TODO
+ * Other sockets unimplemented
+ */
+ }
+ }
+ }
+
+ return term;
+}
+
+static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
+{
+ uint8_t term = 0;
+ sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
+ uint8_t frequency_index;
+
+ if (is_fam15h())
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+ else
+ frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7;
+
+ /* FIXME
+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
+ * For now assume a maximum of 2 DIMMs per channel can be installed
+ */
+ uint8_t MaxDimmsInstallable = 2;
+
+ if (is_fam15h()) {
+ if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+ /* TODO
+ * LRDIMM unimplemented
+ */
+ } else if (pDCTstat->Status & (1 << SB_Registered)) {
+ /* TODO
+ * RDIMM unimplemented
+ */
+ } else {
+ if (package_type == PT_GR) {
+ /* Socket G34: Fam15h BKDG v3.14 Table 56 */
+ if (MaxDimmsInstallable == 1) {
+ if ((frequency_index == 0x4) || (frequency_index == 0x6))
+ term = 0x2;
+ else if ((frequency_index == 0xa) || (frequency_index == 0xe))
+ term = 0x1;
+ else
+ term = 0x3;
+ }
+ if (MaxDimmsInstallable == 2) {
+ if (number_of_dimms == 1) {
+ if (frequency_index <= 0x6) {
+ term = 0x2;
+ } else if (frequency_index <= 0xe) {
+ term = 0x1;
+ } else {
+ term = 0x3;
+ }
+ } else {
+ if (frequency_index <= 0xa) {
+ term = 0x3;
+ } else if (frequency_index <= 0xe) {
+ term = 0x5;
+ } else {
+ term = 0x4;
+ }
+ }
+ } else if (MaxDimmsInstallable == 3) {
+ if (number_of_dimms == 1) {
+ term = 0x0;
+ } else if (number_of_dimms == 2) {
+ if (frequency_index <= 0xa) {
+ if (rank == 1) {
+ term = 0x0;
+ } else {
+ term = 0x3;
+ }
+ } else if (frequency_index <= 0xe) {
+ if (rank == 1) {
+ term = 0x0;
+ } else {
+ term = 0x5;
+ }
+ }
+ }
+ }
+ } else {
+ /* TODO
+ * Other sockets unimplemented
+ */
+ }
+ }
+ }
+
+ return term;
+}
+
static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct);
static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 val;
do {
- val = Get_NB32(dev, reg_off + 0x98);
+ val = Get_NB32_DCT(dev, dct, 0x98);
} while (!(val & (1 << DctAccessDone)));
}
@@ -50,9 +215,15 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting,
if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
- if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
- if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
- MR_register_setting &= ~0x301f8;
+ if (is_fam15h()) {
+ if (MR_register_setting & (1 << 18)) ret |= 1 << 19;
+ if (MR_register_setting & (1 << 19)) ret |= 1 << 18;
+ MR_register_setting &= ~0x000c01f8;
+ } else {
+ if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
+ if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
+ MR_register_setting &= ~0x000301f8;
+ }
MR_register_setting |= ret;
}
}
@@ -61,47 +232,76 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting,
static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 val;
- val = Get_NB32(dev, reg_off + 0x7C);
- val &= ~0xFFFFFF;
+ val = Get_NB32_DCT(dev, dct, 0x7c);
+ val &= ~0x00ffffff;
val |= EMRS;
val |= 1 << SendMrsCmd;
- Set_NB32(dev, reg_off + 0x7C, val);
+ Set_NB32_DCT(dev, dct, 0x7c, val);
do {
- val = Get_NB32(dev, reg_off + 0x7C);
+ val = Get_NB32_DCT(dev, dct, 0x7c);
} while (val & (1 << SendMrsCmd));
}
static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret;
- ret = 0x20000;
- ret |= MrsChipSel;
+ if (is_fam15h()) {
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+ /* The formula for chip select number is: CS = dimm*2+rank */
+ uint8_t dimm = MrsChipSel / 2;
+ uint8_t rank = MrsChipSel % 2;
- /* program MrsAddress[5:3]=CAS write latency (CWL):
- * based on F2x[1,0]84[Tcwl] */
- dword = Get_NB32(dev, reg_off + 0x84);
- dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
+ /* FIXME: These parameters should be configurable
+ * For now, err on the side of caution and enable automatic 2x refresh
+ * when the DDR temperature rises above the internal limits
+ */
+ uint8_t force_2x_self_refresh = 0; /* ASR */
+ uint8_t auto_2x_self_refresh = 1; /* SRT */
- ret |= ((dword >> 20) & 7) << 3;
+ ret = 0x80000;
+ ret |= (MrsChipSel << 21);
- /* program MrsAddress[6]=auto self refresh method (ASR):
- based on F2x[1,0]84[ASR]
- program MrsAddress[7]=self refresh temperature range (SRT):
- based on F2x[1,0]84[ASR and SRT] */
- ret |= ((dword >> 18) & 3) << 6;
+ /* Set self refresh parameters */
+ ret |= (force_2x_self_refresh << 6);
+ ret |= (auto_2x_self_refresh << 7);
- /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
- based on F2x[1,0]84[DramTermDyn] */
- ret |= ((dword >> 10) & 3) << 9;
+ /* Obtain Tcwl, adjust, and set CWL with the adjusted value */
+ dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
+ ret |= ((dword - 5) << 3);
+
+ /* Obtain and set RttWr */
+ ret |= (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9);
+ } else {
+ ret = 0x20000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[5:3]=CAS write latency (CWL):
+ * based on F2x[1,0]84[Tcwl] */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
+
+ ret |= ((dword >> 20) & 7) << 3;
+
+ /* program MrsAddress[6]=auto self refresh method (ASR):
+ * based on F2x[1,0]84[ASR]
+ * program MrsAddress[7]=self refresh temperature range (SRT):
+ * based on F2x[1,0]84[ASR and SRT]
+ */
+ ret |= ((dword >> 18) & 3) << 6;
+
+ /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
+ * based on F2x[1,0]84[DramTermDyn]
+ */
+ ret |= ((dword >> 10) & 3) << 9;
+ }
return ret;
}
@@ -109,20 +309,28 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret;
- ret = 0x30000;
- ret |= MrsChipSel;
+ if (is_fam15h()) {
+ ret = 0xc0000;
+ ret |= (MrsChipSel << 21);
- /* program MrsAddress[1:0]=multi purpose register address location
- (MPR Location):based on F2x[1,0]84[MprLoc]
- program MrsAddress[2]=multi purpose register
- (MPR):based on F2x[1,0]84[MprEn]
- */
- dword = Get_NB32(dev, reg_off + 0x84);
- ret |= (dword >> 24) & 7;
+ /* Program MPR and MPRLoc to 0 */
+ // ret |= 0x0; /* MPR */
+ // ret |= (0x0 << 2); /* MPRLoc */
+ } else {
+ ret = 0x30000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[1:0]=multi purpose register address location
+ * (MPR Location):based on F2x[1,0]84[MprLoc]
+ * program MrsAddress[2]=multi purpose register
+ * (MPR):based on F2x[1,0]84[MprEn]
+ */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ ret |= (dword >> 24) & 7;
+ }
return ret;
}
@@ -130,48 +338,93 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret;
- ret = 0x10000;
- ret |= MrsChipSel;
-
- /* program MrsAddress[5,1]=output driver impedance control (DIC):
- * based on F2x[1,0]84[DrvImpCtrl] */
- dword = Get_NB32(dev, reg_off + 0x84);
- if (dword & (1 << 3))
- ret |= 1 << 5;
- if (dword & (1 << 2))
- ret |= 1 << 1;
-
- /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
- based on F2x[1,0]84[DramTerm] */
- if (!(pDCTstat->Status & (1 << SB_Registered))) {
- if (dword & (1 << 9))
- ret |= 1 << 9;
- if (dword & (1 << 8))
- ret |= 1 << 6;
- if (dword & (1 << 7))
- ret |= 1 << 2;
+ if (is_fam15h()) {
+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+ /* Set defaults */
+ uint8_t qoff = 0; /* Enable output buffers */
+ uint8_t wrlvl = 0; /* Disable write levelling */
+ uint8_t tqds = 0;
+ uint8_t rttnom = 0;
+ uint8_t dic = 0;
+ uint8_t additive_latency = 0;
+ uint8_t dll_enable = 0;
+
+ ret = 0x40000;
+ ret |= (MrsChipSel << 21);
+
+ /* The formula for chip select number is: CS = dimm*2+rank */
+ uint8_t dimm = MrsChipSel / 2;
+ uint8_t rank = MrsChipSel % 2;
+
+ /* Determine if TQDS should be set */
+ if ((pDCTstat->Dimmx8Present & (1 << dimm))
+ && (((dimm & 0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0)
+ && (pDCTstat->Status & (1 << SB_LoadReduced)))
+ tqds = 1;
+
+ /* Obtain RttNom */
+ rttnom = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
+
+ /* Obtain DIC */
+ dic = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
+
+ /* Load data into MRS word */
+ ret |= (qoff & 0x1) << 12;
+ ret |= (tqds & 0x1) << 11;
+ ret |= ((rttnom & 0x4) >> 2) << 9;
+ ret |= ((rttnom & 0x2) >> 1) << 6;
+ ret |= ((rttnom & 0x1) >> 0) << 2;
+ ret |= (wrlvl & 0x1) << 7;
+ ret |= ((dic & 0x2) >> 1) << 5;
+ ret |= ((dic & 0x1) >> 0) << 1;
+ ret |= (additive_latency & 0x3) << 3;
+ ret |= (dll_enable & 0x1);
} else {
- ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel);
- }
+ ret = 0x10000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[5,1]=output driver impedance control (DIC):
+ * based on F2x[1,0]84[DrvImpCtrl]
+ */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ if (dword & (1 << 3))
+ ret |= 1 << 5;
+ if (dword & (1 << 2))
+ ret |= 1 << 1;
+
+ /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
+ * based on F2x[1,0]84[DramTerm]
+ */
+ if (!(pDCTstat->Status & (1 << SB_Registered))) {
+ if (dword & (1 << 9))
+ ret |= 1 << 9;
+ if (dword & (1 << 8))
+ ret |= 1 << 6;
+ if (dword & (1 << 7))
+ ret |= 1 << 2;
+ } else {
+ ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel);
+ }
- /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
- if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
- u8 bit;
- /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
- bit = (ret >> 21) << 1;
- if ((dct & 1) != 0)
- bit ++;
- if (pDCTstat->Dimmx8Present & (1 << bit))
- ret |= 1 << 11;
- }
+ /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
+ if (Get_NB32_DCT(dev, dct, 0x94) & (1 << RDqsEn)) {
+ u8 bit;
+ /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
+ bit = (ret >> 21) << 1;
+ if ((dct & 1) != 0)
+ bit ++;
+ if (pDCTstat->Dimmx8Present & (1 << bit))
+ ret |= 1 << 11;
+ }
- /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
- if (dword & (1 << 13))
- ret |= 1 << 12;
+ /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
+ if (dword & (1 << 13))
+ ret |= 1 << 12;
+ }
return ret;
}
@@ -179,60 +432,139 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword, ret, dword2;
- ret = 0x00000;
- ret |= MrsChipSel;
-
- /* program MrsAddress[1:0]=burst length and control method
- (BL):based on F2x[1,0]84[BurstCtrl] */
- dword = Get_NB32(dev, reg_off + 0x84);
- ret |= dword & 3;
-
- /* program MrsAddress[3]=1 (BT):interleaved */
- ret |= 1 << 3;
-
- /* program MrsAddress[6:4,2]=read CAS latency
- (CL):based on F2x[1,0]88[Tcl] */
- dword2 = Get_NB32(dev, reg_off + 0x88);
- ret |= (dword2 & 0x7) << 4; /* F2x88[2:0] to MrsAddress[6:4] */
- ret |= ((dword2 & 0x8) >> 3) << 2; /* F2x88[3] to MrsAddress[2] */
-
- /* program MrsAddress[12]=0 (PPD):slow exit */
- if (dword & (1 << 23))
- ret |= 1 << 12;
-
- /* program MrsAddress[11:9]=write recovery for auto-precharge
- (WR):based on F2x[1,0]84[Twr] */
- ret |= ((dword >> 4) & 7) << 9;
-
- /* program MrsAddress[8]=1 (DLL):DLL reset
- just issue DLL reset at first time */
- ret |= 1 << 8;
+ if (is_fam15h()) {
+ ret = 0x00000;
+ ret |= (MrsChipSel << 21);
+
+ /* Set defaults */
+ uint8_t ppd = 0;
+ uint8_t wr_ap = 0;
+ uint8_t dll_reset = 1;
+ uint8_t test_mode = 0;
+ uint8_t cas_latency = 0;
+ uint8_t read_burst_type = 1;
+ uint8_t burst_length = 0;
+
+ /* Obtain PchgPDModeSel */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ ppd = (dword >> 23) & 0x1;
+
+ /* Obtain Twr */
+ dword = Get_NB32_DCT(dev, dct, 0x22c) & 0x1f;
+
+ /* Calculate wr_ap (Fam15h BKDG v3.14 Table 82) */
+ if (dword == 0x10)
+ wr_ap = 0x0;
+ else if (dword == 0x5)
+ wr_ap = 0x1;
+ else if (dword == 0x6)
+ wr_ap = 0x2;
+ else if (dword == 0x7)
+ wr_ap = 0x3;
+ else if (dword == 0x8)
+ wr_ap = 0x4;
+ else if (dword == 0xa)
+ wr_ap = 0x5;
+ else if (dword == 0xc)
+ wr_ap = 0x6;
+ else if (dword == 0xe)
+ wr_ap = 0x7;
+
+ /* Obtain Tcl */
+ dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
+
+ /* Calculate cas_latency (Fam15h BKDG v3.14 Table 83) */
+ if (dword == 0x5)
+ cas_latency = 0x2;
+ else if (dword == 0x6)
+ cas_latency = 0x4;
+ else if (dword == 0x7)
+ cas_latency = 0x6;
+ else if (dword == 0x8)
+ cas_latency = 0x8;
+ else if (dword == 0x9)
+ cas_latency = 0xa;
+ else if (dword == 0xa)
+ cas_latency = 0xc;
+ else if (dword == 0xb)
+ cas_latency = 0xe;
+ else if (dword == 0xc)
+ cas_latency = 0x1;
+ else if (dword == 0xd)
+ cas_latency = 0x3;
+ else if (dword == 0xe)
+ cas_latency = 0x5;
+ else if (dword == 0xf)
+ cas_latency = 0x7;
+ else if (dword == 0x10)
+ cas_latency = 0x9;
+
+ /* Obtain BurstCtrl */
+ burst_length = Get_NB32_DCT(dev, dct, 0x84) & 0x3;
+
+ /* Load data into MRS word */
+ ret |= (ppd & 0x1) << 12;
+ ret |= (wr_ap & 0x3) << 9;
+ ret |= (dll_reset & 0x1) << 8;
+ ret |= (test_mode & 0x1) << 7;
+ ret |= ((cas_latency & 0xe) >> 1) << 4;
+ ret |= ((cas_latency & 0x1) >> 0) << 2;
+ ret |= (read_burst_type & 0x1) << 3;
+ ret |= (burst_length & 0x3);
+ } else {
+ ret = 0x00000;
+ ret |= (MrsChipSel << 20);
+
+ /* program MrsAddress[1:0]=burst length and control method
+ (BL):based on F2x[1,0]84[BurstCtrl] */
+ dword = Get_NB32_DCT(dev, dct, 0x84);
+ ret |= dword & 3;
+
+ /* program MrsAddress[3]=1 (BT):interleaved */
+ ret |= 1 << 3;
+
+ /* program MrsAddress[6:4,2]=read CAS latency
+ (CL):based on F2x[1,0]88[Tcl] */
+ dword2 = Get_NB32_DCT(dev, dct, 0x88);
+ ret |= (dword2 & 0x7) << 4; /* F2x88[2:0] to MrsAddress[6:4] */
+ ret |= ((dword2 & 0x8) >> 3) << 2; /* F2x88[3] to MrsAddress[2] */
+
+ /* program MrsAddress[12]=0 (PPD):slow exit */
+ if (dword & (1 << 23))
+ ret |= 1 << 12;
+
+ /* program MrsAddress[11:9]=write recovery for auto-precharge
+ (WR):based on F2x[1,0]84[Twr] */
+ ret |= ((dword >> 4) & 7) << 9;
+
+ /* program MrsAddress[8]=1 (DLL):DLL reset
+ just issue DLL reset at first time */
+ ret |= 1 << 8;
+ }
return ret;
}
static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
{
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
u32 dword;
/*1.Program MrsAddress[10]=1
2.Set SendZQCmd=1
*/
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7C);
dword &= ~0xFFFFFF;
dword |= 1 << 10;
dword |= 1 << SendZQCmd;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7C, dword);
/* Wait for SendZQCmd=0 */
do {
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7C);
} while (dword & (1 << SendZQCmd));
/* 4.Wait 512 MEMCLKs */
@@ -244,31 +576,30 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
{
u8 MrsChipSel;
u32 dword;
- u32 reg_off = 0x100 * dct;
u32 dev = pDCTstat->dev_dct;
- if (pDCTstat->DIMMAutoSpeed == 4) {
+ if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
/* 3.Program F2x[1,0]7C[EnDramInit]=1 */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7c);
dword |= 1 << EnDramInit;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7c, dword);
mct_DCTAccessDone(pDCTstat, dct);
/* 4.wait 200us */
mct_Wait(40000);
- /* 5.On revision C processors, program F2x[1, 0]7C[DeassertMemRstX] = 1. */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ /* 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1. */
+ dword = Get_NB32_DCT(dev, dct, 0x7c);
dword |= 1 << DeassertMemRstX;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7c, dword);
/* 6.wait 500us */
mct_Wait(200000);
/* 7.Program F2x[1,0]7C[AssertCke]=1 */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7c);
dword |= 1 << AssertCke;
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7c, dword);
/* 8.wait 360ns */
mct_Wait(80);
@@ -277,6 +608,13 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
* must be done for each chip select pair */
if (pDCTstat->Status & (1 << SB_Registered))
mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
+
+ /* The following steps are performed with load reduced DIMMs only and
+ * must be done for each DIMM */
+ // if (pDCTstat->Status & (1 << SB_LoadReduced))
+ /* TODO
+ * Implement LRDIMM configuration
+ */
}
/* The following steps are performed once for unbuffered DIMMs and once for each
@@ -285,23 +623,23 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
u32 EMRS;
/* 13.Send EMRS(2) */
- EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
/* 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b */
- EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
/* 15.Send EMRS(1) */
- EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
/* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
- EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel);
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
mct_SendMrsCmd(pDCTstat, dct, EMRS);
- if (pDCTstat->DIMMAutoSpeed == 4)
+ if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
if (!(pDCTstat->Status & (1 << SB_Registered)))
break; /* For UDIMM, only send MR commands once per channel */
}
@@ -310,16 +648,15 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
MrsChipSel ++;
}
- mct_Wait(100000);
-
- if (pDCTstat->DIMMAutoSpeed == 4) {
+ if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
/* 17.Send two ZQCL commands */
mct_SendZQCmd(pDCTstat, dct);
mct_SendZQCmd(pDCTstat, dct);
+
/* 18.Program F2x[1,0]7C[EnDramInit]=0 */
- dword = Get_NB32(dev, reg_off + 0x7C);
+ dword = Get_NB32_DCT(dev, dct, 0x7C);
dword &= ~(1 << EnDramInit);
- Set_NB32(dev, reg_off + 0x7C, dword);
+ Set_NB32_DCT(dev, dct, 0x7C, dword);
mct_DCTAccessDone(pDCTstat, dct);
}
}