Fix ECC disable option for AMD Fam10 DDR2 and DDR3.
[coreboot.git] / src / northbridge / amd / amdmct / mct / mctecc_d.c
index d8d37bad9964a9fd13091ef95dcd1bf094c1e2a7..58e61ae0ee6a66c0c4a4fbe3e2b20d626efaf766 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
@@ -22,7 +22,9 @@
 
 static void setSyncOnUnEccEn_D(struct MCTStatStruc *pMCTstat,
                                struct DCTStatStruc *pDCTstatA);
+#ifdef UNUSED_CODE
 static u32 GetScrubAddr_D(u32 Node);
+#endif
 static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat);
 
 
@@ -59,7 +61,7 @@ static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat);
  * guarantee that the NB scrubs the entire dram on its node. Do do this, we
  * simply sample the scrub ADDR once, for an initial value, then we sample and poll until the polled value of scrub ADDR
  * has wrapped around at least once: Scrub ADDRi+1 < Scrub ADDRi. Since we let all
- * Nodes run in parallel, we need to gaurantee that all nodes have wrapped. To do
+ * Nodes run in parallel, we need to guarantee that all nodes have wrapped. To do
  * this efficiently, we need only to sample one of the nodes, the node with the
  * largest ammount of dram populated is the one which will take the longest amount
  * of time (the scrub rate is set to max, the same rate, on all nodes).  So,
@@ -88,6 +90,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
        u32 dev;
        u32 reg;
        u32 val;
+       u16 nvbits;
 
        mctHookBeforeECC();
 
@@ -100,18 +103,18 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
        OB_ChipKill = mctGet_NVbits(NV_ChipKill);       /* ECC Chip-kill mode */
 
        OF_ScrubCTL = 0;                /* Scrub CTL for Dcache, L2, and dram */
-       val = mctGet_NVbits(NV_DCBKScrub);
-       mct_AdjustScrub_D(pDCTstatA, val);
-       OF_ScrubCTL |= val << 16;
-       val = mctGet_NVbits(NV_L2BKScrub);
-       OF_ScrubCTL |= val << 8;
+       nvbits = mctGet_NVbits(NV_DCBKScrub);
+       mct_AdjustScrub_D(pDCTstatA, &nvbits);
+       OF_ScrubCTL |= (u32) nvbits << 16;
 
-       val = mctGet_NVbits(NV_DramBKScrub);
-       OF_ScrubCTL |= val;
+       nvbits = mctGet_NVbits(NV_L2BKScrub);
+       OF_ScrubCTL |= (u32) nvbits << 8;
+
+       nvbits = mctGet_NVbits(NV_DramBKScrub);
+       OF_ScrubCTL |= nvbits;
 
        AllECC = 1;
        MemClrECC = 0;
-       print_t(" ECCInit 0 \n");
        for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
                struct DCTStatStruc *pDCTstat;
                pDCTstat = pDCTstatA + Node;
@@ -129,7 +132,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
                                        LDramECC = isDramECCEn_D(pDCTstat);
                                        if(pDCTstat->ErrCode != SC_RunningOK) {
                                                pDCTstat->Status &=  ~(1 << SB_ECCDIMMs);
-                                               if (OB_NBECC) {
+                                               if (!OB_NBECC) {
                                                        pDCTstat->ErrStatus |= (1 << SB_DramECCDis);
                                                }
                                                AllECC = 0;
@@ -160,15 +163,12 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
                        }
                }       /* if Node present */
        }
-       print_t(" ECCInit 1 \n");
 
        if(AllECC)
                pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
        else
                pMCTstat->GStatus &= ~(1<<GSB_ECCDIMMs);
 
-       print_t(" ECCInit 2 \n");
-
        /* Program the Dram BKScrub CTL to the proper (user selected) value.*/
        /* Reset MC4_STS. */
        for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
@@ -190,17 +190,40 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
                                        Set_NB32(dev, 0x5C, val); /* Dram Scrub Addr Low */
                                        val = curBase>>24;
                                        Set_NB32(dev, 0x60, val); /* Dram Scrub Addr High */
-                                       Set_NB32(dev, 0x58, OF_ScrubCTL);       /*Scrub Control */    /*set dram background scrubbing to setup value */
+                                       Set_NB32(dev, 0x58, OF_ScrubCTL);       /*Scrub Control */
+
+                                       /* Divisor should not be set deeper than
+                                        * divide by 16 when Dcache scrubber or
+                                        * L2 scrubber is enabled.
+                                        */
+                                       if ((OF_ScrubCTL & (0x1F << 16)) || (OF_ScrubCTL & (0x1F << 8))) {
+                                               val = Get_NB32(dev, 0x84);
+                                               if ((val & 0xE0000000) > 0x80000000) {  /* Get F3x84h[31:29]ClkDivisor for C1 */
+                                                       val &= 0x1FFFFFFF;      /* If ClkDivisor is deeper than divide-by-16 */
+                                                       val |= 0x80000000;      /* set it to divide-by-16 */
+                                                       Set_NB32(dev, 0x84, val);
+                                               }
+                                       }
                                }       /* this node has ECC enabled dram */
                        }       /*Node has Dram */
                }       /*if Node present */
        }
-       print_t(" ECCInit 3 \n");
 
        if(mctGet_NVbits(NV_SyncOnUnEccEn))
                setSyncOnUnEccEn_D(pMCTstat, pDCTstatA);
 
        mctHookAfterECC();
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
+               if (NodePresent_D(Node)) {
+                       print_tx("ECCInit: Node ", Node);
+                       print_tx("ECCInit: Status ", pDCTstat->Status);
+                       print_tx("ECCInit: ErrStatus ", pDCTstat->ErrStatus);
+                       print_tx("ECCInit: ErrCode ", pDCTstat->ErrCode);
+                       print_t("ECCInit: Done\n");
+               }
+       }
        return MemClrECC;
 }
 
@@ -234,7 +257,7 @@ static void setSyncOnUnEccEn_D(struct MCTStatStruc *pMCTstat,
        }
 }
 
-
+#ifdef UNUSED_CODE
 static u32 GetScrubAddr_D(u32 Node)
 {
        /* Get the current 40-bit Scrub ADDR address, scaled to 32-bits,
@@ -265,7 +288,7 @@ static u32 GetScrubAddr_D(u32 Node)
 
        return val;             /* ScrubAddr[39:8] */
 }
-
+#endif
 
 static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat)
 {