Add the AMD Family10 Agesa code
[coreboot.git] / src / vendorcode / amd / agesa / f10 / Proc / Recovery / Mem / Tech / DDR3 / mrtspd3.c
diff --git a/src/vendorcode/amd/agesa/f10/Proc/Recovery/Mem/Tech/DDR3/mrtspd3.c b/src/vendorcode/amd/agesa/f10/Proc/Recovery/Mem/Tech/DDR3/mrtspd3.c
new file mode 100755 (executable)
index 0000000..f39655d
--- /dev/null
@@ -0,0 +1,269 @@
+/**
+ * @file
+ *
+ * mrtspd3.c
+ *
+ * Technology SPD supporting functions for DDR3 Recovery
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Proc/Recovery/Mem)
+ * @e \$Revision: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
+ *
+ **/
+/*****************************************************************************
+*
+* Copyright (c) 2011, Advanced Micro Devices, Inc.
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of Advanced Micro Devices, Inc. nor the names of 
+*       its contributors may be used to endorse or promote products derived 
+*       from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+* 
+* ***************************************************************************
+*
+*/
+
+/*
+ *----------------------------------------------------------------------------
+ *                                MODULES USED
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+
+#include "AGESA.h"
+#include "amdlib.h"
+#include "Ids.h"
+#include "mm.h"
+#include "mn.h"
+#include "mt.h"
+#include "mrtspd3.h"
+#include "Filecode.h"
+#define FILECODE PROC_RECOVERY_MEM_TECH_DDR3_MRTSPD3_FILECODE
+
+/*----------------------------------------------------------------------------
+ *                          DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+#define _UNDEF_ 0xFF
+#define MAX_DIES_PER_SOCKET     2   ///< Set to largest of any CPU
+
+/*----------------------------------------------------------------------------
+ *                           TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *                        PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *                            EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *   This function sets the DRAM mode
+ *
+ *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
+ *
+ *     @return  TRUE - indicates that the DRAM mode is set to DDR2
+ */
+
+BOOLEAN
+MemRecTSetDramMode3 (
+  IN OUT   MEM_TECH_BLOCK *TechPtr
+  )
+{
+  TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFLegacyBiosMode, 0);
+  TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFDdr3Mode, 1);
+  return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *   This function determines if DIMMs are present. It checks checksum and interrogates the SPDs
+ *
+ *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
+ *
+ *     @return  TRUE - indicates that a FATAL error has not occurred
+ *     @return  FALL - indicates that a FATAL error has not occurred
+ */
+
+BOOLEAN
+MemRecTDIMMPresence3 (
+  IN OUT   MEM_TECH_BLOCK *TechPtr
+  )
+{
+  UINT8 Node;
+  UINT8 Dct;
+  UINT8 Channel;
+  UINT8 i;
+  SPD_DEF_STRUCT *SPDPtr;
+  UINT8 *SpdBufferPtr;
+  DIE_STRUCT *MCTPtr;
+  DCT_STRUCT *DCTPtr;
+  CH_DEF_STRUCT *ChannelPtr;
+  MEM_NB_BLOCK *NBPtr;
+  UINT16 MaxDimms;
+  UINT16 Value16;
+  UINT8 Devwidth;
+  UINT8 Value8;
+  UINT16 DimmMask;
+
+  NBPtr = TechPtr->NBPtr;
+  MCTPtr = NBPtr->MCTPtr;
+
+  NBPtr->DimmToBeUsed = _UNDEF_;
+  for (Node = 0; Node < MAX_DIES_PER_SOCKET; Node++) {
+    NBPtr->SwitchNodeRec (NBPtr, Node);
+    for (Dct = 0; Dct < NBPtr->MCTPtr->DctCount; Dct++) {
+      NBPtr->SwitchDCT (NBPtr, Dct);
+      DCTPtr = NBPtr->DCTPtr;
+      for (Channel = 0; Channel < DCTPtr->ChannelCount; Channel++) {
+        NBPtr->SwitchChannel (NBPtr, Channel);
+        ChannelPtr = NBPtr->ChannelPtr;
+        SPDPtr = NBPtr->SPDPtr;
+
+        // Get the maximum number of DIMMs
+        MaxDimms = MAX_DIMMS_PER_CHANNEL;
+        for (i = 0; i < MaxDimms; i++) {
+          //  Bitmask representing dimm #i.
+          DimmMask = (UINT16) 1 << i;
+
+          if (SPDPtr[i].DimmPresent) {
+            SpdBufferPtr = (UINT8 *)&(SPDPtr[i].Data);
+
+            MCTPtr->DimmPresent |= DimmMask;
+            if (SpdBufferPtr[SPD_TYPE] == JED_DDR3SDRAM) {
+              ChannelPtr->ChDimmValid |= DimmMask;
+              if (NBPtr->DimmToBeUsed == _UNDEF_) {
+                NBPtr->DimmToBeUsed = i;
+              }
+            }
+
+            //  Check module type information.
+            if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_RDIMM || SpdBufferPtr[SPD_DIMM_TYPE] == JED_MINIRDIMM) {
+              ChannelPtr->RegDimmPresent |= DimmMask;
+            }
+
+            if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_SODIMM) {
+              ChannelPtr->SODimmPresent |= DimmMask;
+            }
+
+            //  Get the Dimm width data
+            Devwidth = SpdBufferPtr[SPD_DEV_WIDTH] & 0x7;
+            switch (Devwidth) {
+            case 0:
+              ChannelPtr->Dimmx4Present |= DimmMask;
+              Devwidth = 4;
+              break;
+            case 1:
+              ChannelPtr->Dimmx8Present |= DimmMask;
+              Devwidth = 8;
+              break;
+            case 2:
+              ChannelPtr->Dimmx16Present |= DimmMask;
+              Devwidth = 16;
+              break;
+            default:
+              IDS_ERROR_TRAP;
+            }
+
+            //  Determine the page size.
+            //       page_size = 2^COLBITS * Devwidth/8
+            //
+            Value16 = (((UINT16) 1 << (SpdBufferPtr[SPD_COL_SZ]&7)) * Devwidth) / 8;
+            if ((Value16 >> 11) == 0) {
+              DCTPtr->Timings.DIMM1KPage |= DimmMask;
+            }
+
+            //  Calculate bus loading per Channel
+            if (Devwidth == 16) {
+              Devwidth = 4;
+            } else if (Devwidth == 4) {
+              Devwidth = 16;
+            }
+
+            //  specify the number of ranks
+            Value8 = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
+            if (Value8 > 2) {
+              ChannelPtr->DimmQrPresent |= DimmMask;
+              Devwidth = Devwidth << 2;
+            } else if (Value8 == 2) {
+              ChannelPtr->DimmDrPresent |= DimmMask;   //  Dual rank dimms
+              Devwidth = Devwidth << 1;
+            }
+
+            ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
+            ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
+            ChannelPtr->Dimms++;
+
+            // Check address mirror support for Unbuffered Dimms only
+            if ((ChannelPtr->RegDimmPresent & DimmMask) == 0) {
+              if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) {
+                ChannelPtr->DimmMirrorPresent |= DimmMask;
+              }
+            }
+
+            // Get control word values for RC3, RC4 and RC5
+            ChannelPtr->CtrlWrd03[i] = SpdBufferPtr[SPD_CTLWRD03] >> 4;
+            ChannelPtr->CtrlWrd04[i] = SpdBufferPtr[SPD_CTLWRD04] & 0x0F;
+            ChannelPtr->CtrlWrd05[i] = SpdBufferPtr[SPD_CTLWRD05] >> 4;
+          } // if DIMM present
+        } // Dimm loop
+
+        if (ChannelPtr->ChDimmValid != 0) {
+          // exit loops
+          Channel = DCTPtr->ChannelCount;
+          Dct = NBPtr->MCTPtr->DctCount;
+          Node = MAX_DIES_PER_SOCKET;
+        }
+      } // Channel loop
+    } // DCT loop
+  }
+
+  //  If we have DIMMs, some further general characteristics checking
+  if (NBPtr->DimmToBeUsed == _UNDEF_) {
+    //  Leave with an error - no dimms on this DCT
+    // LibAmdEventLog (AGESA_FATAL, MEM_ERROR_NO_DIMM_FOUND, 0, NBPtr->Dct, NBPtr->Channel, 0);   //@attention commented out since it is not defined in recovery code
+    SetMemRecError (AGESA_FATAL, MCTPtr);
+  }
+
+  return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
+}
+
+/*----------------------------------------------------------------------------
+ *                              LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */