Fix ECC disable option for AMD Fam10 DDR2 and DDR3.
[coreboot.git] / src / northbridge / amd / amdmct / mct / mct_d.c
index b4a5fdcf1fedede6d53661119fc36c0dc751bda0..36b473a55fdd921c5aa23a27bdf809f0432fb270 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * This file is part of the LinuxBIOS project.
+ * This file is part of the coreboot project.
  *
- * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@
  * ordinarily in 64-bit mode.
  *
  * Trc precision does not use extra Jedec defined fractional component.
- * InsteadTrc (course) is rounded up to nearest 1 ns.
+ * Instead Trc (course) is rounded up to nearest 1 ns.
  *
  * Mini and Micro DIMM not supported. Only RDIMM, UDIMM, SO-DIMM defined types
  * supported.
@@ -42,8 +42,6 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
                                struct DCTStatStruc *pDCTstatA);
 static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
                                        struct DCTStatStruc *pDCTstatA);
-static void ResetNBECCstat_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstatA);
 static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
                                struct DCTStatStruc *pDCTstatA);
 static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
@@ -156,7 +154,10 @@ static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
 static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct);
 static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
                                        struct DCTStatStruc *pDCTstat, u8 dct);
-
+static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct);
+static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
 
 /*See mctAutoInitMCT header for index relationships to CL and T*/
 static const u16 Table_F_k[]   = {00,200,266,333,400,533 };
@@ -177,7 +178,7 @@ static const u8 Table_Comp_Rise_Slew_15x[] = {7, 7, 3, 2, 0xFF};
 static const u8 Table_Comp_Fall_Slew_20x[] = {7, 5, 3, 2, 0xFF};
 static const u8 Table_Comp_Fall_Slew_15x[] = {7, 7, 5, 3, 0xFF};
 
-void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
                        struct DCTStatStruc *pDCTstatA)
 {
        /*
@@ -185,7 +186,7 @@ void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
         * on setup options). It is the responsibility of PCI subsystem to
         * create an uncacheable IO region below 4GB and to adjust TOP_MEM
         * downward prior to any IO mapping or accesses. It is the same
-        * responsibility of the CPU sub-system prior toaccessing LAPIC.
+        * responsibility of the CPU sub-system prior to accessing LAPIC.
         *
         * Slot Number is an external convention, and is determined by OEM with
         * accompanying silk screening.  OEM may choose to use Slot number
@@ -279,6 +280,9 @@ restartinit:
        print_t("mctAutoInitMCT_D: DQSTiming_D\n");
        DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable and DQS signal timing*/
 
+       print_t("mctAutoInitMCT_D: UMAMemTyping_D\n");
+       UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA sizing */
+
        print_t("mctAutoInitMCT_D: :OtherTiming\n");
        mct_OtherTiming(pMCTstat, pDCTstatA);
 
@@ -296,7 +300,7 @@ restartinit:
        }
 
        mct_FinalMCT_D(pMCTstat, (pDCTstatA + 0) );     // Node 0
-       print_t("All Done\n");
+       print_tx("mctAutoInitMCT_D Done: Global Status: ", pMCTstat->GStatus);
        return;
 
 fatalexit:
@@ -348,11 +352,12 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
        /* FIXME: BOZO- DQS training every time*/
        nv_DQSTrainCTL = 1;
 
+       print_t("DQSTiming_D: mct_BeforeDQSTrain_D:\n");
+       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
+       phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
+
        if (nv_DQSTrainCTL) {
-               print_t("DQSTiming_D: mct_BeforeDQSTrain_D:\n");
-               mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);;
-               phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
-               mctHookBeforeAnyTraining();
+               mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
 
                print_t("DQSTiming_D: TrainReceiverEn_D FirstPass:\n");
                TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
@@ -472,7 +477,9 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
        }
 }
 
-
+#ifdef UNUSED_CODE
+static void ResetNBECCstat_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
 static void ResetNBECCstat_D(struct MCTStatStruc *pMCTstat,
                                struct DCTStatStruc *pDCTstatA)
 {
@@ -499,7 +506,7 @@ static void ResetNBECCstat_D(struct MCTStatStruc *pMCTstat,
                }
        }
 }
-
+#endif
 
 static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
                                struct DCTStatStruc *pDCTstatA)
@@ -512,7 +519,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
        u32 val;
        u32 base;
        u32 limit;
-       u32 dev;
+       u32 dev, devx;
        struct DCTStatStruc *pDCTstat;
 
        _MemHoleRemap = mctGet_NVbits(NV_MemHole);
@@ -531,6 +538,8 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
 
 
        for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               devx = pDCTstat->dev_map;
                DramSelBaseAddr = 0;
                pDCTstat = pDCTstatA + Node;
                if (!pDCTstat->GangedMode) {
@@ -550,7 +559,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
                        base  += NextBase;
                        limit += NextBase;
                        DramSelBaseAddr += NextBase;
-                       printk_debug(" Node: %02x  base: %02x  limit: %02x  BottomIO: %02x\n", Node, base, limit, BottomIO);
+                       printk(BIOS_DEBUG, " Node: %02x  base: %02x  limit: %02x  BottomIO: %02x\n", Node, base, limit, BottomIO);
 
                        if (_MemHoleRemap) {
                                if ((base < BottomIO) && (limit >= BottomIO)) {
@@ -569,7 +578,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
                                        val <<= 8; /* shl 16, rol 24 */
                                        val |= DramHoleBase << 24;
                                        val |= 1  << DramHoleValid;
-                                       Set_NB32(dev, 0xF0, val); /*Dram Hole Address Register*/
+                                       Set_NB32(devx, 0xF0, val); /* Dram Hole Address Reg */
                                        pDCTstat->DCTSysLimit += HoleSize;
                                        base = pDCTstat->DCTSysBase;
                                        limit = pDCTstat->DCTSysLimit;
@@ -598,24 +607,36 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
                        pMCTstat->SysLimit = limit;
                }
                Set_NB32(dev, 0x40 + (Node << 3), base); /* [Node] + Dram Base 0 */
-               val = limit & 0xffff0000;
-               val |= Node;                            /* set DstNode*/
+
+               /* if Node limit > 1GB then set it to 1GB boundary for each node */
+               if ((mctSetNodeBoundary_D()) && (limit > 0x00400000)) {
+                       limit++;
+                       limit &= 0xFFC00000;
+                       limit--;
+               }
+               val = limit & 0xFFFF0000;
+               val |= Node;
                Set_NB32(dev, 0x44 + (Node << 3), val); /* set DstNode */
 
                limit = pDCTstat->DCTSysLimit;
                if (limit) {
-                       NextBase = (limit & 0xffff0000) + 0x10000;
+                       NextBase = (limit & 0xFFFF0000) + 0x10000;
+                       if ((mctSetNodeBoundary_D()) && (NextBase > 0x00400000)) {
+                               NextBase++;
+                               NextBase &= 0xFFC00000;
+                               NextBase--;
+                       }
                }
        }
 
        /* Copy dram map from Node 0 to Node 1-7 */
        for (Node = 1; Node < MAX_NODES_SUPPORTED; Node++) {
-               pDCTstat = pDCTstatA + Node;
                u32 reg;
-               u32 devx = pDCTstat->dev_map;
+               pDCTstat = pDCTstatA + Node;
+               devx = pDCTstat->dev_map;
 
                if (pDCTstat->NodePresent) {
-               printk_debug(" Copy dram map from Node 0 to Node %02x \n", Node);
+                       printk(BIOS_DEBUG, " Copy dram map from Node 0 to Node %02x \n", Node);
                        reg = 0x40;             /*Dram Base 0*/
                        do {
                                val = Get_NB32(dev, reg);
@@ -637,7 +658,7 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
 {
 
        /* Initiates a memory clear operation for all node. The mem clr
-        * is done in paralel. After the memclr is complete, all processors
+        * is done in parallel. After the memclr is complete, all processors
         * status are checked to ensure that memclr has completed.
         */
        u8 Node;
@@ -758,7 +779,7 @@ static u8 NodePresent_D(u8 Node)
                if (val  == dword)      /* current nodeID = requested nodeID ? */
                        ret = 1;
 finish:
-       ;
+               ;
        }
 
        return ret;
@@ -804,6 +825,8 @@ static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTst
                  all of the MemClkDis bits should also be set.*/
                val = 0xFF000000;
                Set_NB32(pDCTstat->dev_dct, reg_off+0x88, val);
+       } else {
+               mct_EnDllShutdownSR(pMCTstat, pDCTstat, dct);
        }
 }
 
@@ -838,7 +861,7 @@ static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
         * HW memory clear process that the chip is capable of. The sooner
         * that dram init is set for all nodes, the faster the memory system
         * initialization can complete. Thus, the init loop is unrolled into
-        * two loops so as to start the processeses for non BSP nodes sooner.
+        * two loops so as to start the processes for non BSP nodes sooner.
         * This procedure will not wait for the process to finish.
         * Synchronization is handled elsewhere.
         */
@@ -860,7 +883,7 @@ static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
                        reg = 0x78 + reg_off;
                        val = Get_NB32(dev, reg);
                        /* Setting this bit forces a 1T window with hard left
-                        * pass/fail edge and a probabalistic right pass/fail
+                        * pass/fail edge and a probabilistic right pass/fail
                         * edge.  LEFT edge is referenced for final
                         * receiver enable position.*/
                        val |= 1 << DqsRcvEnTrain;
@@ -964,8 +987,8 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
                if ( mctGet_NVbits(NV_MCTUSRTMGMODE) == 2)
                        pDCTstat->Speed = mctGet_NVbits(NV_MemCkVal) + 1;
 
-               mct_AfterGetCLT(pMCTstat, pDCTstat, dct);
        }
+       mct_AfterGetCLT(pMCTstat, pDCTstat, dct);
 
        /* Gather all DIMM mini-max values for cycle timing data */
        Rows = 0;
@@ -983,7 +1006,7 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
        for ( i = 0; i< MAX_DIMMS_SUPPORTED; i++) {
                LDIMM = i >> 1;
                if (pDCTstat->DIMMValid & (1 << i)) {
-                       smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, dct + i);
                        byte = mctRead_SPD(smbaddr, SPD_ROWSZ);
                        if (Rows < byte)
                                Rows = byte;    /* keep track of largest row sz */
@@ -1016,45 +1039,45 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
                        if ((val == 0) || (val == 0xFF)) {
                                pDCTstat->ErrStatus |= 1<<SB_NoTrcTrfc;
                                pDCTstat->ErrCode = SC_VarianceErr;
-                               val = Get_DefTrc_k_D(pDCTstat->DIMMAutoSpeed);
+                               val = Get_DefTrc_k_D(pDCTstat->Speed);
                        } else {
                                byte = mctRead_SPD(smbaddr, SPD_TRCRFC);
                                if (byte & 0xF0) {
-                                       val++;  /* round up in case fractional extention is non-zero.*/
+                                       val++;  /* round up in case fractional extension is non-zero.*/
                                }
-               }
-               if (Trc < val)
-                       Trc = val;
-
-               /* dev density=rank size/#devs per rank */
-               byte = mctRead_SPD(smbaddr, SPD_BANKSZ);
-
-               val = ((byte >> 5) | (byte << 3)) & 0xFF;
-               val <<= 2;
-
-               byte = mctRead_SPD(smbaddr, SPD_DEVWIDTH) & 0xFE;     /* dev density=2^(rows+columns+banks) */
-               if (byte == 4) {
-                       val >>= 4;
-               } else if (byte == 8) {
-                       val >>= 3;
-               } else if (byte == 16) {
-                       val >>= 2;
-               }
+                       }
+                       if (Trc < val)
+                               Trc = val;
 
-               byte = bsr(val);
+                       /* dev density=rank size/#devs per rank */
+                       byte = mctRead_SPD(smbaddr, SPD_BANKSZ);
+
+                       val = ((byte >> 5) | (byte << 3)) & 0xFF;
+                       val <<= 2;
+
+                       byte = mctRead_SPD(smbaddr, SPD_DEVWIDTH) & 0xFE;     /* dev density=2^(rows+columns+banks) */
+                       if (byte == 4) {
+                               val >>= 4;
+                       } else if (byte == 8) {
+                               val >>= 3;
+                       } else if (byte == 16) {
+                               val >>= 2;
+                       }
 
-               if (Trfc[LDIMM] < byte)
-                       Trfc[LDIMM] = byte;
+                       byte = bsr(val);
 
-               byte = mctRead_SPD(smbaddr, SPD_TRAS);
-               if (Tras < byte)
-                       Tras = byte;
+                       if (Trfc[LDIMM] < byte)
+                               Trfc[LDIMM] = byte;
+
+                       byte = mctRead_SPD(smbaddr, SPD_TRAS);
+                       if (Tras < byte)
+                               Tras = byte;
                }       /* Dimm Present */
        }
 
        /* Convert  DRAM CycleTiming values and store into DCT structure */
        DDR2_1066 = 0;
-       byte = pDCTstat->DIMMAutoSpeed;
+       byte = pDCTstat->Speed;
        if (byte == 5)
                DDR2_1066 = 1;
        Tk40 = Get_40Tk_D(byte);
@@ -1111,7 +1134,7 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
        }
        pDCTstat->Trp = val;
 
-        /*Trrd*/
+       /*Trrd*/
        dword = Trrd * 10;
        pDCTstat->DIMMTrrd = dword;
        val = dword / Tk40;
@@ -1175,12 +1198,10 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
        dword = Trtp * 10;
        pDCTstat->DIMMTrtp = dword;
        val = pDCTstat->Speed;
-       if (val <= 2) {
-               val = 2;        /* Calculate by 7.75ns / Speed in ns to get clock # */
-       } else if (val == 4) {  /* Note a speed of 3 will be a Trtp of 3 */
-               val = 3;
-       } else if (val == 5){
-               val = 2;
+       if (val <= 2) {         /* 7.75ns / Speed in ns to get clock # */
+               val = 2;        /* for DDR400/DDR533 */
+       } else {                /* Note a speed of 3 will be a Trtp of 3 */
+               val = 3;        /* for DDR667/DDR800/DDR1066 */
        }
        pDCTstat->Trtp = val;
 
@@ -1480,7 +1501,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
        DramConfigMisc = 0;
        DramConfigMisc2 = 0;
 
-       /* set bank addessing and Masks, plus CS pops */
+       /* set bank addressing and Masks, plus CS pops */
        SPDSetBanks_D(pMCTstat, pDCTstat, dct);
        if (pDCTstat->ErrCode == SC_StopError)
                goto AutoConfig_exit;
@@ -1566,14 +1587,14 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
        }
 
        if (!(Status & (1 << SB_Registered)))
-               DramConfigLo |= 1 << UnBuffDimm;        /* Unbufferd DIMMs */
+               DramConfigLo |= 1 << UnBuffDimm;        /* Unbuffered DIMMs */
 
        if (mctGet_NVbits(NV_ECC_CAP))
                if (Status & (1 << SB_ECCDIMMs))
                        if ( mctGet_NVbits(NV_ECC))
                                DramConfigLo |= 1 << DimmEcEn;
 
-
+       DramConfigLo = mct_DisDllShutdownSR(pMCTstat, pDCTstat, DramConfigLo, dct);
 
        /* Build Dram Config Hi Register Value */
        dword = pDCTstat->Speed;
@@ -1810,7 +1831,7 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
        /* SetCKETriState */
        SetODTTriState(pMCTstat, pDCTstat, dct);
 
-       if ( pDCTstat->Status & 1<<SB_128bitmode) {
+       if (pDCTstat->Status & (1 << SB_128bitmode)) {
                SetCSTriState(pMCTstat, pDCTstat, 1); /* force dct1) */
                SetODTTriState(pMCTstat, pDCTstat, 1); /* force dct1) */
        }
@@ -1954,7 +1975,7 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
                                reg  = 0x40 + (q << 2) + reg_off;  /* Base[q] reg.*/
                                val = Get_NB32(dev, reg);
                                if (!(val & 3)) {       /* (CSEnable|Spare==1)bank is enabled already? */
-                                       reg = 0x60 + (q << 1) + reg_off; /*Mask[q] reg.*/
+                                       reg = 0x60 + ((q << 1) & 0xc) + reg_off; /*Mask[q] reg.*/
                                        val = Get_NB32(dev, reg);
                                        val >>= 19;
                                        val++;
@@ -2167,8 +2188,8 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
                                                pDCTstat->DimmECCPresent |= 1 << i;
                                        }
                                        if (byte & JED_ADRCPAR) {
-                                       /* DIMM is ECC capable */
-                                       pDCTstat->DimmPARPresent |= 1 << i;
+                                               /* DIMM is ECC capable */
+                                               pDCTstat->DimmPARPresent |= 1 << i;
                                        }
                                        /* Check if x4 device */
                                        devwidth = mctRead_SPD(smbaddr, SPD_DEVWIDTH) & 0xFE;
@@ -2385,30 +2406,37 @@ static void mct_DramInit(struct MCTStatStruc *pMCTstat,
        mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat);
        // FIXME: for rev A: mct_BeforeDramInit_D(pDCTstat, dct);
 
-       /* Disable auto refresh before Dram init when in ganged mode */
-       if (pDCTstat->GangedMode) {
-               val = Get_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct));
-               val |= 1 << DisAutoRefresh;
-               Set_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct), val);
+       /* Disable auto refresh before Dram init when in ganged mode (Erratum 278) */
+       if (pDCTstat->LogicalCPUID & (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)) {
+               if (pDCTstat->GangedMode) {
+                       val = Get_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct));
+                       val |= 1 << DisAutoRefresh;
+                       Set_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct), val);
+               }
        }
 
        mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct);
 
        /* Re-enable auto refresh after Dram init when in ganged mode
-        * to ensure both DCTs are in sync
+        * to ensure both DCTs are in sync (Erratum 278)
         */
 
-       if (pDCTstat->GangedMode) {
-               do {
-                       val = Get_NB32(pDCTstat->dev_dct, 0x90 + (0x100 * dct));
-               } while (!(val & (1 << InitDram)));
-
-               WaitRoutine_D(50);
-
-               val = Get_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct));
-               val &= ~(1 << DisAutoRefresh);
-               val |= 1 << DisAutoRefresh;
-               val &= ~(1 << DisAutoRefresh);
+       if (pDCTstat->LogicalCPUID & (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)) {
+               if (pDCTstat->GangedMode) {
+                       do {
+                               val = Get_NB32(pDCTstat->dev_dct, 0x90 + (0x100 * dct));
+                       } while (!(val & (1 << InitDram)));
+
+                       WaitRoutine_D(50);
+
+                       val = Get_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct));
+                       val &= ~(1 << DisAutoRefresh);
+                       Set_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct), val);
+                       val |= 1 << DisAutoRefresh;
+                       Set_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct), val);
+                       val &= ~(1 << DisAutoRefresh);
+                       Set_NB32(pDCTstat->dev_dct, 0x8C + (0x100 * dct), val);
+               }
        }
 }
 
@@ -2432,8 +2460,8 @@ static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
        if (byte != bytex) {
                pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO);
        } else {
-       if ( mctGet_NVbits(NV_Unganged) )
-               pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO);
+               if ( mctGet_NVbits(NV_Unganged) )
+                       pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO);
 
                if (!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) {
                        pDCTstat->GangedMode = 1;
@@ -2452,22 +2480,13 @@ static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
 
 u32 Get_NB32(u32 dev, u32 reg)
 {
-       u32 addr;
-
-       addr = (dev>>4) | (reg & 0xFF) | ((reg & 0xf00)<<16);
-       outl((1<<31) | (addr & ~3), 0xcf8);
-
-       return inl(0xcfc);
+       return pci_read_config32(dev, reg);
 }
 
 
 void Set_NB32(u32 dev, u32 reg, u32 val)
 {
-       u32 addr;
-
-       addr = (dev>>4) | (reg & 0xFF) | ((reg & 0xf00)<<16);
-       outl((1<<31) | (addr & ~3), 0xcf8);
-       outl(val, 0xcfc);
+       pci_write_config32(dev, reg, val);
 }
 
 
@@ -2631,7 +2650,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
        if (!pDCTstat->GangedMode) {
                dev = pDCTstat->dev_dct;
                pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit;
-               /* if DCT0 and DCT1 exist both, set DctSelBaseAddr[47:27] */
+               /* if DCT0 and DCT1 both exist, set DctSelBaseAddr[47:27] to the top of DCT0 */
                if (dct == 0) {
                        if (pDCTstat->DIMMValidDCT[1] > 0) {
                                dword = pDCTstat->DCTSysLimit + 1;
@@ -2641,8 +2660,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
                                        pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
                                        val = pMCTstat->HoleBase;
                                        val >>= 16;
-                                       val &= ~(0xFF);
-                                       val |= (((~val) & 0xFF) + 1);
+                                       val = (((~val) & 0xFF) + 1);
                                        val <<= 8;
                                        dword += val;
                                }
@@ -2653,6 +2671,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
                                val |= 3;  /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */
                                Set_NB32(dev, reg, val);
                                print_tx("AfterStitch DCT0 and DCT1: DRAM Controller Select Low Register = ", val);
+                               print_tx("AfterStitch DCT0 and DCT1: DRAM Controller Select High Register = ", dword);
 
                                reg = 0x114;
                                val = dword;
@@ -2664,7 +2683,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
                        if (pDCTstat->DIMMValidDCT[0] == 0) {
                                dword = pDCTstat->NodeSysBase;
                                dword >>= 8;
-                               if (dword >= DramHoleBase) {
+                               if ((dword >= DramHoleBase) && _MemHoleRemap) {
                                        pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
                                        val = pMCTstat->HoleBase;
                                        val >>= 8;
@@ -2680,6 +2699,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
                                val |= 3;       /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */
                                Set_NB32(dev, reg, val);
                                print_tx("AfterStitch DCT1 only: DRAM Controller Select Low Register = ", val);
+                               print_tx("AfterStitch DCT1 only: DRAM Controller Select High Register = ", dword);
                        }
                }
        } else {
@@ -2857,7 +2877,7 @@ static void Get_Twrwr(struct MCTStatStruc *pMCTstat,
                dword = bsr(pDCTstat->DIMMValid);
                if (dword != val && dword != 0)  {
                        /*the largest WrDatGrossDlyByte of any DIMM minus the
-                       WrDatGrossDlyByte of any other DIMM is equal to CGDD */
+                         WrDatGrossDlyByte of any other DIMM is equal to CGDD */
                        val = Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg);
                }
                if (val == 0)
@@ -2872,16 +2892,25 @@ static void Get_Twrwr(struct MCTStatStruc *pMCTstat,
 static void Get_Twrrd(struct MCTStatStruc *pMCTstat,
                        struct DCTStatStruc *pDCTstat, u8 dct)
 {
-       u8 byte, bytex;
+       u8 byte, bytex, val;
        u32 index_reg = 0x98 + 0x100 * dct;
        u32 dev = pDCTstat->dev_dct;
 
        /* On any given byte lane, the largest WrDatGrossDlyByte delay of
           any DIMM minus the DqsRcvEnGrossDelay delay of any other DIMM is
           equal to the Critical Gross Delay Difference (CGDD) for Twrrd.*/
-       pDCTstat->Twrrd = 0;
+
+       /* WrDatGrossDlyByte only use one set register when DDR400~DDR667
+          DDR800 have two set register for DIMM0 and DIMM1 */
+       if (pDCTstat->Speed > 3) {
+               val = Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg);
+       } else {
+               val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 1);  /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM0 */
+               pDCTstat->WrDatGrossH = (u8) val; /* low byte = max value */
+       }
+
        Get_DqsRcvEnGross_Diff(pDCTstat, dev, index_reg);
-       Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg);
+
        bytex = pDCTstat->DqsRcvEnGrossL;
        byte = pDCTstat->WrDatGrossH;
        if (byte > bytex) {
@@ -2946,12 +2975,16 @@ static u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat,
        u8 i;
        u32 val;
        u8 byte;
+       u8 ecc_reg = 0;
 
        Smallest_0 = 0xFF;
        Smallest_1 = 0xFF;
        Largest_0 = 0;
        Largest_1 = 0;
 
+       if (index == 0x12)
+               ecc_reg = 1;
+
        for (i=0; i < 8; i+=2) {
                if ( pDCTstat->DIMMValid & (1 << i)) {
                        val = Get_NB32_index_wait(dev, index_reg, index);
@@ -2960,11 +2993,13 @@ static u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat,
                                Smallest_0 = byte;
                        if (byte > Largest_0)
                                Largest_0 = byte;
-                       byte = (val >> 16) & 0xFF;
-                       if (byte < Smallest_1)
-                               Smallest_1 = byte;
-                       if (byte > Largest_1)
-                               Largest_1 = byte;
+                       if (!(ecc_reg)) {
+                               byte = (val >> 16) & 0xFF;
+                               if (byte < Smallest_1)
+                                       Smallest_1 = byte;
+                               if (byte > Largest_1)
+                                       Largest_1 = byte;
+                       }
                }
                index += 3;
        }       /* while ++i */
@@ -2973,8 +3008,9 @@ static u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat,
           two DIMMs is less than half of a MEMCLK */
        if ((Largest_0 - Smallest_0) > 31)
                return 1;
-       if ((Largest_1 - Smallest_1) > 31)
-               return 1;
+       if (!(ecc_reg))
+               if ((Largest_1 - Smallest_1) > 31)
+                       return 1;
        return 0;
 }
 
@@ -3072,10 +3108,14 @@ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
        u8 byte;
        u32 val;
        u16 word;
+       u8 ecc_reg = 0;
 
        Smallest = 7;
        Largest = 0;
 
+       if (index == 0x12)
+               ecc_reg = 1;
+
        for (i=0; i < 8; i+=2) {
                if ( pDCTstat->DIMMValid & (1 << i)) {
                        val = Get_NB32_index_wait(dev, index_reg, index);
@@ -3085,13 +3125,15 @@ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
                                Smallest = byte;
                        if (byte > Largest)
                                Largest = byte;
-                       byte = (val >> (16 + 5)) & 0xFF;
-                       if (byte < Smallest)
-                               Smallest = byte;
-                       if (byte > Largest)
-                               Largest = byte;
+                       if (!(ecc_reg)) {
+                               byte = (val >> (16 + 5)) & 0xFF;
+                               if (byte < Smallest)
+                                       Smallest = byte;
+                               if (byte > Largest)
+                                       Largest = byte;
+                       }
                }
-       index += 3;
+               index += 3;
        }       /* while ++i */
 
        word = Smallest;
@@ -3155,7 +3197,7 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
        print_t("\tmct_FinalMCT_D: Clr Cl, Wb\n");
 
 
-       mct_ClrClToNB_D(pMCTstat, pDCTstat);
+       /* ClrClToNB_D postponed until we're done executing from ROM */
        mct_ClrWbEnhWsbDis_D(pMCTstat, pDCTstat);
 }
 
@@ -3228,7 +3270,7 @@ static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
        dev = pDCTstat->dev_map;
 
        /* Copy dram map from F1x40/44,F1x48/4c,
-         to F1x120/124(Node0),F1x120/124(Node1),...*/
+          to F1x120/124(Node0),F1x120/124(Node1),...*/
        for (Node=0; Node < MAX_NODES_SUPPORTED; Node++) {
                pDCTstat = pDCTstatA + Node;
                devx = pDCTstat->dev_map;
@@ -3303,7 +3345,7 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
 }
 
 
-
+#ifdef UNUSED_CODE
 static void SetCKETriState(struct MCTStatStruc *pMCTstat,
                                struct DCTStatStruc *pDCTstat, u8 dct)
 {
@@ -3343,7 +3385,7 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
 
        Set_NB32_index_wait(dev, index_reg, index, val);
 }
-
+#endif
 
 static void SetODTTriState(struct MCTStatStruc *pMCTstat,
                                struct DCTStatStruc *pDCTstat, u8 dct)
@@ -3353,25 +3395,34 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
        u32 index_reg = 0x98 + 0x100 * dct;
        u8 cs;
        u32 index;
-       u16 word;
-
-       /* Tri-state unused ODTs when motherboard termination is available */
+       u8 odt;
+       u8 max_dimms;
 
        // FIXME: skip for Ax
 
        dev = pDCTstat->dev_dct;
-       word = 0;
+
+       /* Tri-state unused ODTs when motherboard termination is available */
+       max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
+       odt = 0x0F;     /* tristate all the pins then clear the used ones. */
+
        for (cs = 0; cs < 8; cs += 2) {
-               if (!(pDCTstat->CSPresent & (1 << cs))) {
-                       if (!(pDCTstat->CSPresent & (1 << (cs + 1))))
-                               word |= (1 << (cs >> 1));
+               if (pDCTstat->CSPresent & (1 << cs)) {
+                       odt &= ~(1 << (cs / 2));
+
+                       /* if quad-rank capable platform clear additional pins */
+                       if (max_dimms != MAX_CS_SUPPORTED) {
+                               if (pDCTstat->CSPresent & (1 << (cs + 1)))
+                                       odt &= ~(4 << (cs / 2));
+                       }
                }
        }
 
        index  = 0x0C;
        val = Get_NB32_index_wait(dev, index_reg, index);
-       val |= (word << 8);
+       val |= (odt << 8);
        Set_NB32_index_wait(dev, index_reg, index, val);
+
 }
 
 
@@ -3414,8 +3465,15 @@ static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
        }
 
        /* Override/Exception */
-       if ((pDCTstat->Speed == 2) && (pDCTstat->MAdimms[dct] == 4))
-               dword &= 0xF18FFF18;
+       if (!pDCTstat->GangedMode) {
+               i = 0; /* use i for the dct setting required */
+               if (pDCTstat->MAdimms[0] < 4)
+                       i = 1;
+               if (((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) && (pDCTstat->MAdimms[i] == 4)) {
+                       dword &= 0xF18FFF18;
+                       index_reg = 0x98;       /* force dct = 0 */
+               }
+       }
 
        Set_NB32_index_wait(dev, index_reg, 0x0a, dword);
 }
@@ -3516,7 +3574,7 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
        u8 Node;
        u32 i;
        struct DCTStatStruc *pDCTstat;
-       u16 start, stop;
+       u32 start, stop;
        u8 *p;
        u16 host_serv1, host_serv2;
 
@@ -3533,12 +3591,12 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
 
                p = (u8 *) pDCTstat;
                start = 0;
-               stop = ((u16) &((struct DCTStatStruc *)0)->CH_MaxRdLat[2]);
+               stop = (u32)(&((struct DCTStatStruc *)0)->CH_MaxRdLat[2]);
                for (i = start; i < stop ; i++) {
                        p[i] = 0;
                }
 
-               start = ((u16) &((struct DCTStatStruc *)0)->CH_D_BC_RCVRDLY[2][4]);
+               start = (u32)(&((struct DCTStatStruc *)0)->CH_D_BC_RCVRDLY[2][4]);
                stop = sizeof(struct DCTStatStruc);
                for (i = start; i < stop; i++) {
                        p[i] = 0;
@@ -3568,7 +3626,7 @@ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
 }
 
 
-void mct_AdjustDelayRange_D(struct MCTStatStruc *pMCTstat,
+static void mct_AdjustDelayRange_D(struct MCTStatStruc *pMCTstat,
                        struct DCTStatStruc *pDCTstat, u8 *dqs_pos)
 {
        // FIXME: Skip for Ax
@@ -3577,6 +3635,41 @@ void mct_AdjustDelayRange_D(struct MCTStatStruc *pMCTstat,
        }
 }
 
+static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+
+       /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
+       if (pDCTstat->LogicalCPUID & (AMD_DA_C2 | AMD_RB_C3)) {
+               Set_NB32(dev,  0x9C + reg_off, 0x7D0);
+               Set_NB32(dev,  0x98 + reg_off, 0x4D0FE006);
+               Set_NB32(dev,  0x9C + reg_off, 0x190);
+               Set_NB32(dev,  0x98 + reg_off, 0x4D0FE007);
+       }
+
+       return DramConfigLo | /* DisDllShutdownSR */ 1 << 27;
+}
+
+static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+{
+       u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct, val;
+
+       /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
+       if (pDCTstat->LogicalCPUID & (AMD_DA_C2 | AMD_RB_C3)) {
+               Set_NB32(dev,  0x9C + reg_off, 0x1C);
+               Set_NB32(dev,  0x98 + reg_off, 0x4D0FE006);
+               Set_NB32(dev,  0x9C + reg_off, 0x13D);
+               Set_NB32(dev,  0x98 + reg_off, 0x4D0FE007);
+
+               val = Get_NB32(dev, 0x90 + reg_off);
+               val &= ~(1 << 27/* DisDllShutdownSR */);
+               Set_NB32(dev, 0x90 + reg_off, val);
+       }
+}
 
 void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat,
                        struct DCTStatStruc *pDCTstat)
@@ -3685,7 +3778,7 @@ void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct,
        Set_NB32_index_wait(dev, index_reg, index, val | (1 << DisAutoComp));
 
        //FIXME: check for Bx Cx CPU
-         // if Ax mct_SetDramConfigHi_Samp_D
+       // if Ax mct_SetDramConfigHi_Samp_D
 
        /* errata#177 */
        index = 0x4D014F00;     /* F2x[1, 0]9C_x[D0FFFFF:D000000] DRAM Phy Debug Registers */
@@ -3715,17 +3808,17 @@ static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
         * Silicon Status: Fixed In Rev B0
         *
         * Bug#15880: Determine validity of reset settings for DDR PHY timing.
-        * Solutiuon: At least, set WrDqs fine delay to be 0 for DDR2 training.
+        * Solution: At least, set WrDqs fine delay to be 0 for DDR2 training.
         */
 
        for (Node = 0; Node < 8; Node++) {
                pDCTstat = pDCTstatA + Node;
 
-               if (pDCTstat->NodePresent)
+               if (pDCTstat->NodePresent) {
                        mct_BeforeDQSTrain_Samp_D(pMCTstat, pDCTstat);
                        mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
                        mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
-
+               }
        }
 }
 
@@ -3733,12 +3826,29 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
                                        struct DCTStatStruc *pDCTstat, u8 dct)
 {
        u8 Receiver;
-       u32 val;
        u32 dev = pDCTstat->dev_dct;
        u32 reg_off = 0x100 * dct;
        u32 addr;
+       u32 lo, hi;
+       u8 wrap32dis = 0;
        u8 valid = 0;
 
+       /* Skip reset DLL for B3 */
+       if (pDCTstat->LogicalCPUID & AMD_DR_B3) {
+               return;
+       }
+
+       addr = HWCR;
+       _RDMSR(addr, &lo, &hi);
+       if(lo & (1<<17)) {              /* save the old value */
+               wrap32dis = 1;
+       }
+       lo |= (1<<17);                  /* HWCR.wrap32dis */
+       lo &= ~(1<<15);                 /* SSEDIS */
+       /* Setting wrap32dis allows 64-bit memory references in 32bit mode */
+       _WRMSR(addr, lo, hi);
+
+
        pDCTstat->Channel = dct;
        Receiver = mct_InitReceiver_D(pDCTstat, dct);
        /* there are four receiver pairs, loosely associated with chipselects.*/
@@ -3747,23 +3857,24 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
                        addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, dct, Receiver, &valid);
                        if (valid) {
                                mct_Read1LTestPattern_D(pMCTstat, pDCTstat, addr);      /* cache fills */
-                               Set_NB32(dev, 0x98 + reg_off, 0x0D00000C);
-                               val = Get_NB32(dev, 0x9C + reg_off);
-                               val |= 1 << 15;
-                               Set_NB32(dev, 0x9C + reg_off, val);
-                               Set_NB32(dev, 0x98 + reg_off, 0x4D0F0F0C);
-                               mct_Wait_10ns(60); /* wait >= 300ns */
-
-                               Set_NB32(dev, 0x98 + reg_off, 0x0D00000C);
-                               val = Get_NB32(dev, 0x9C + reg_off);
-                               val &= ~(1 << 15);
-                               Set_NB32(dev, 0x9C + reg_off, val);
-                               Set_NB32(dev, 0x98 + reg_off, 0x4D0F0F0C);
-                               mct_Wait_10ns(400); /* wait >= 2us */
+
+                               /* Write 0000_8000h to register F2x[1,0]9C_xD080F0C */
+                               Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00008000);
+                               mct_Wait(80); /* wait >= 300ns */
+
+                               /* Write 0000_0000h to register F2x[1,0]9C_xD080F0C */
+                               Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00000000);
+                               mct_Wait(800); /* wait >= 2us */
                                break;
                        }
                }
        }
+       if(!wrap32dis) {
+               addr = HWCR;
+               _RDMSR(addr, &lo, &hi);
+               lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
+               _WRMSR(addr, lo, hi);
+       }
 }
 
 
@@ -3784,12 +3895,12 @@ static void mct_EnableDatIntlv_D(struct MCTStatStruc *pMCTstat,
                // FIXME Skip for Cx
                dev = pDCTstat->dev_nbmisc;
                val = Get_NB32(dev, 0x8C);      // NB Configuration Hi
-               val |= 36-32;                   // DisDatMask
+               val |= 1 << (36-32);            // DisDatMask
                Set_NB32(dev, 0x8C, val);
        }
 }
 
-
+#ifdef UNUSED_CODE
 static void mct_SetupSync_D(struct MCTStatStruc *pMCTstat,
                                        struct DCTStatStruc *pDCTstat)
 {
@@ -3811,6 +3922,7 @@ static void mct_SetupSync_D(struct MCTStatStruc *pMCTstat,
                Set_NB32(dev, 0x78, val);
        }
 }
+#endif
 
 static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
 
@@ -3818,8 +3930,8 @@ static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
        u32 reg_off = 0x100 * dct;
        u32 dev = pDCTstat->dev_dct;
 
-       if (pDCTstat->LogicalCPUID & AMD_DR_B2) {
-               mct_Wait_10ns(5000);    /* Wait 50 us*/
+       if (pDCTstat->LogicalCPUID & (AMD_DR_B2 | AMD_DR_B3)) {
+               mct_Wait(10000);        /* Wait 50 us*/
                val = Get_NB32(dev, 0x110);
                if ( val & (1 << DramEnabled)) {
                        /* If 50 us expires while DramEnable =0 then do the following */