AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Main / mmflow.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mmflow.c
6  *
7  * Main Memory Flow Entrypoint file
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/Main)
12  * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
13  *
14  **/
15 /*****************************************************************************
16 *
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 *     * Redistributions of source code must retain the above copyright
23 *       notice, this list of conditions and the following disclaimer.
24 *     * Redistributions in binary form must reproduce the above copyright
25 *       notice, this list of conditions and the following disclaimer in the
26 *       documentation and/or other materials provided with the distribution.
27 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 *       its contributors may be used to endorse or promote products derived
29 *       from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * ***************************************************************************
43 *
44 */
45
46 /*
47  *----------------------------------------------------------------------------
48  *                                MODULES USED
49  *
50  *----------------------------------------------------------------------------
51  */
52
53
54 #include "AGESA.h"
55 #include "amdlib.h"
56 #include "AdvancedApi.h"
57 #include "Ids.h"
58 #include "cpuRegisters.h"
59 #include "cpuServices.h"
60 #include "GeneralServices.h"
61 #include "cpuFamilyTranslation.h"
62 #include "OptionMemory.h"
63 #include "mm.h"
64 #include "mn.h"
65 #include "mt.h"
66 #include "mu.h"
67 #include "heapManager.h"
68 #include "Filecode.h"
69 CODE_GROUP (G1_PEICC)
70 RDATA_GROUP (G2_PEI)
71
72 #define FILECODE PROC_MEM_MAIN_MMFLOW_FILECODE
73 /* features */
74
75 extern MEM_NB_SUPPORT memNBInstalled[];
76 extern MEM_TECH_CONSTRUCTOR* memTechInstalled[];
77 extern MEM_FEAT_BLOCK_MAIN MemFeatMain;
78 extern MEM_FLOW_CFG* memFlowControlInstalled[];
79
80 /*----------------------------------------------------------------------------
81  *                          DEFINITIONS AND MACROS
82  *
83  *----------------------------------------------------------------------------
84  */
85
86 /*----------------------------------------------------------------------------
87  *                           TYPEDEFS AND STRUCTURES
88  *
89  *----------------------------------------------------------------------------
90  */
91
92 /*----------------------------------------------------------------------------
93  *                        PROTOTYPES OF LOCAL FUNCTIONS
94  *
95  *----------------------------------------------------------------------------
96  */
97 VOID
98 STATIC
99 MemSPDDataProcess (
100   IN OUT   MEM_DATA_STRUCT *MemPtr
101   );
102
103 /*----------------------------------------------------------------------------
104  *                            EXPORTED FUNCTIONS
105  *
106  *----------------------------------------------------------------------------
107  */
108 /* -----------------------------------------------------------------------------*/
109 /**
110  *
111  *
112  *      This function is the main memory configuration function for DR DDR3
113  *
114  *      Requirements:
115  *
116  *      Run-Time Requirements:
117  *      1. Complete Hypertransport Bus Configuration
118  *      2. AmdMemInitDataStructDef must be run to set default values
119  *      3. MSR bit to allow access to high PCI regs set on all nodes
120  *      4. BSP in Big Real Mode
121  *      5. Stack available
122  *      6. MCG_CTL=-1, MC4_EN=0 for all CPUs
123  *      7. MCi_STS from shutdown/warm reset recorded (if desired) prior to entry
124  *      8. All var MTRRs reset to zero
125  *      9. State of NB_CFG.DisDatMsk set properly on all CPUs
126  *
127  *     @param[in,out]   *MemPtr   - Pointer to the MEM_DATA_STRUCT
128  *
129  *     @return          AGESA_STATUS
130  *                          - AGESA_ALERT
131  *                          - AGESA_FATAL
132  *                          - AGESA_SUCCESS
133  *                          - AGESA_WARNING
134  */
135 AGESA_STATUS
136 AmdMemAuto (
137   IN OUT   MEM_DATA_STRUCT *MemPtr
138   )
139 {
140   MEM_SHARED_DATA  mmSharedData;
141   MEM_MAIN_DATA_BLOCK mmData;
142   MEM_NB_BLOCK *NBPtr;
143   MEM_TECH_BLOCK *TechPtr;
144   ALLOCATE_HEAP_PARAMS AllocHeapParams;
145   AGESA_STATUS Retval;
146   UINT8 i;
147   UINT8 Die;
148   UINT8 DieCount;
149   UINT8 Tab;
150   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
151
152   ASSERT (MemPtr != NULL);
153
154   AGESA_TESTPOINT (TpProcMemAmdMemAuto, &MemPtr->StdHeader);
155
156   IDS_HDT_CONSOLE (MEM_FLOW, "MEM PARAMS:\n");
157   IDS_HDT_CONSOLE (MEM_FLOW, "\tBottomIo : %04x\n", MemPtr->ParameterListPtr->BottomIo);
158   IDS_HDT_CONSOLE (MEM_FLOW, "\tMemHoleRemap : %d\n", MemPtr->ParameterListPtr->MemHoleRemapping);
159   IDS_HDT_CONSOLE (MEM_FLOW, "\tLimitBelow1TB : %d\n", MemPtr->ParameterListPtr->LimitMemoryToBelow1Tb);
160   IDS_HDT_CONSOLE (MEM_FLOW, "\tUserTimingMode : %d\n", MemPtr->ParameterListPtr->UserTimingMode);
161   IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClockValue : %d\n", MemPtr->ParameterListPtr->MemClockValue);
162   IDS_HDT_CONSOLE (MEM_FLOW, "\tBankIntlv : %d\n", MemPtr->ParameterListPtr->EnableBankIntlv);
163   IDS_HDT_CONSOLE (MEM_FLOW, "\tNodeIntlv : %d\n", MemPtr->ParameterListPtr->EnableNodeIntlv);
164   IDS_HDT_CONSOLE (MEM_FLOW, "\tChannelIntlv : %d\n", MemPtr->ParameterListPtr->EnableChannelIntlv);
165   IDS_HDT_CONSOLE (MEM_FLOW, "\tEccFeature : %d\n", MemPtr->ParameterListPtr->EnableEccFeature);
166   IDS_HDT_CONSOLE (MEM_FLOW, "\tPowerDown : %d\n", MemPtr->ParameterListPtr->EnablePowerDown);
167   IDS_HDT_CONSOLE (MEM_FLOW, "\tOnLineSpare : %d\n", MemPtr->ParameterListPtr->EnableOnLineSpareCtl);
168   IDS_HDT_CONSOLE (MEM_FLOW, "\tParity : %d\n", MemPtr->ParameterListPtr->EnableParity);
169   IDS_HDT_CONSOLE (MEM_FLOW, "\tBankSwizzle : %d\n", MemPtr->ParameterListPtr->EnableBankSwizzle);
170   IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClr : %d\n", MemPtr->ParameterListPtr->EnableMemClr);
171   IDS_HDT_CONSOLE (MEM_FLOW, "\tUmaMode : %d\n", MemPtr->ParameterListPtr->UmaMode);
172   IDS_HDT_CONSOLE (MEM_FLOW, "\tUmaSize : %d\n", MemPtr->ParameterListPtr->UmaSize);
173   IDS_HDT_CONSOLE (MEM_FLOW, "\tMemRestoreCtl : %d\n", MemPtr->ParameterListPtr->MemRestoreCtl);
174   IDS_HDT_CONSOLE (MEM_FLOW, "\tSaveMemContextCtl : %d\n", MemPtr->ParameterListPtr->SaveMemContextCtl);
175   IDS_HDT_CONSOLE (MEM_FLOW, "\tExternalVrefCtl : %d\n", MemPtr->ParameterListPtr->ExternalVrefCtl );
176   IDS_HDT_CONSOLE (MEM_FLOW, "\tForceTrainMode : %d\n\n", MemPtr->ParameterListPtr->ForceTrainMode );
177
178   //----------------------------------------------------------------------------
179   // Get TSC rate, which will be used later in Wait10ns routine
180   //----------------------------------------------------------------------------
181   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &MemPtr->StdHeader);
182   FamilySpecificServices->GetTscRate (FamilySpecificServices, &MemPtr->TscRate, &MemPtr->StdHeader);
183
184   //----------------------------------------------------------------------------
185   // Read In SPD Data
186   //----------------------------------------------------------------------------
187   AGESA_TESTPOINT (TpProcMemBeforeSpdProcessing, &MemPtr->StdHeader);
188   MemSPDDataProcess (MemPtr);
189
190   //----------------------------------------------------------------
191   // Initialize Main Data Block
192   //----------------------------------------------------------------
193   mmData.MemPtr = MemPtr;
194   mmData.mmSharedPtr = &mmSharedData;
195   LibAmdMemFill (&mmSharedData, 0, sizeof (mmSharedData), &MemPtr->StdHeader);
196   mmSharedData.DimmExcludeFlag = NORMAL;
197   mmSharedData.NodeIntlv.IsValid = FALSE;
198   //----------------------------------------------------------------
199   // Discover populated CPUs
200   //
201   //----------------------------------------------------------------
202   Retval = MemSocketScan (&mmData);
203   if (Retval == AGESA_FATAL) {
204     return Retval;
205   }
206   DieCount = mmData.DieCount;
207   //----------------------------------------------------------------
208   //
209   // Allocate Memory for NB and Tech Blocks
210   //
211   //  NBPtr[Die]----+
212   //                |
213   //                V
214   //  +---+---+---+---+---+---+---+---+
215   //  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |   NB Blocks
216   //  +---+---+---+---+---+---+---+---+
217   //    |   |   |   |   |   |   |   |
218   //    |   |   |   |   |   |   |   |
219   //    v   v   v   v   v   v   v   v
220   //  +---+---+---+---+---+---+---+---+
221   //  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |   Tech Blocks
222   //  +---+---+---+---+---+---+---+---+
223   //
224   //
225   //----------------------------------------------------------------
226   AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (MEM_NB_BLOCK) + sizeof (MEM_TECH_BLOCK)));
227   AllocHeapParams.BufferHandle = AMD_MEM_AUTO_HANDLE;
228   AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
229   if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
230     ASSERT(FALSE); // NB and Tech Block Heap allocate error
231     return AGESA_FATAL;
232   }
233   NBPtr = (MEM_NB_BLOCK *)AllocHeapParams.BufferPtr;
234   TechPtr = (MEM_TECH_BLOCK *) (&NBPtr[DieCount]);
235   mmData.NBPtr = NBPtr;
236   mmData.TechPtr = TechPtr;
237
238   //----------------------------------------------------------------
239   // Create NB Blocks
240   //
241   //----------------------------------------------------------------
242   for (Die = 0 ; Die < DieCount ; Die++ ) {
243     i = 0;
244     while (memNBInstalled[i].MemConstructNBBlock != 0) {
245       if (memNBInstalled[i].MemConstructNBBlock (&NBPtr[Die], MemPtr, memNBInstalled[i].MemFeatBlock, &mmSharedData, Die) == TRUE) {
246         break;
247       }
248       i++;
249     }
250     // Couldn't find a NB which supported this family
251     if (memNBInstalled[i].MemConstructNBBlock == 0) {
252       return AGESA_FATAL;
253     }
254   }
255   //----------------------------------------------------------------
256   // Create Technology Blocks
257   //
258   //----------------------------------------------------------------
259   for (Die = 0 ; Die < DieCount ; Die++ ) {
260     i = 0;
261     while (memTechInstalled[i] != NULL) {
262       if (memTechInstalled[i] (&TechPtr[Die], &NBPtr[Die])) {
263         NBPtr[Die].TechPtr = &TechPtr[Die];
264         break;
265       }
266       i++;
267     }
268     // Couldn't find a Tech block which supported this family
269     if (memTechInstalled[i] == NULL) {
270       return AGESA_FATAL;
271     }
272   }
273   //----------------------------------------------------------------
274   //
275   //                 MEMORY INITIALIZATION TASKS
276   //
277   //----------------------------------------------------------------
278   i = 0;
279   while (memFlowControlInstalled[i] != NULL) {
280     Retval = memFlowControlInstalled[i] (&mmData);
281     if (MemPtr->IsFlowControlSupported == TRUE) {
282       break;
283     }
284     i++;
285   }
286
287   //----------------------------------------------------------------
288   // Deallocate NB register tables
289   //----------------------------------------------------------------
290   for (Tab = 0; Tab < NumberOfNbRegTables; Tab++) {
291     HeapDeallocateBuffer (GENERATE_MEM_HANDLE (ALLOC_NB_REG_TABLE, Tab, 0, 0), &MemPtr->StdHeader);
292   }
293
294   //----------------------------------------------------------------
295   // Check for errors and return
296   //----------------------------------------------------------------
297   AGESA_TESTPOINT (TpProcMemEnd, &MemPtr->StdHeader);
298   for (Die = 0; Die < DieCount; Die++) {
299     if (NBPtr[Die].MCTPtr->ErrCode > Retval) {
300       Retval = NBPtr[Die].MCTPtr->ErrCode;
301     }
302   }
303   return Retval;
304 }
305
306
307 /* -----------------------------------------------------------------------------*/
308 /**
309  *
310  *
311  *  This function fills a default SPD buffer with SPD values for all DIMMs installed in the system
312  *
313  *    The SPD Buffer is populated with a Socket-Channel-Dimm centric view of the Dimms.  At this
314  *  point, the Memory controller type is not known, and the platform BIOS does not know the anything
315  *  about which DIMM is on which DCT.  So the DCT relationship is abstracted from the arrangement
316  *  of SPD information here.  We use the utility functions GetSpdSocketIndex(), GetMaxChannelsPerSocket(),
317  *  and GetMaxDimmsPerChannel() to Map the SPD data according to which Socket-relative channel the DIMMs
318  *  are connected to.  The functions rely on either the maximum values in the
319  *  PlatformSpecificOverridingTable or if unspecified, the absolute maximums in AGESA.H.
320  *
321  *  This mapping is translated in the Northbridge object Constructor and the Technology block constructor.
322  *
323  *     @param[in,out]   *MemPtr   - Pointer to the MEM_DATA_STRUCT
324  *
325  */
326
327 VOID
328 STATIC
329 MemSPDDataProcess (
330   IN OUT   MEM_DATA_STRUCT *MemPtr
331   )
332 {
333   UINT8 Socket;
334   UINT8 Channel;
335   UINT8 Dimm;
336   UINT8 DimmIndex;
337   UINT32 AgesaStatus;
338   UINT8 MaxSockets;
339   UINT8 MaxChannelsPerSocket;
340   UINT8 MaxDimmsPerChannel;
341   SPD_DEF_STRUCT *DimmSPDPtr;
342   PSO_TABLE *PsoTable;
343   ALLOCATE_HEAP_PARAMS AllocHeapParams;
344   AGESA_READ_SPD_PARAMS SpdParam;
345
346   ASSERT (MemPtr != NULL);
347   MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
348   PsoTable = MemPtr->ParameterListPtr->PlatformMemoryConfiguration;
349   //
350   // Allocate heap for the table
351   //
352   AllocHeapParams.RequestedBufferSize = (GetSpdSocketIndex (PsoTable, MaxSockets, &MemPtr->StdHeader) * sizeof (SPD_DEF_STRUCT));
353   AllocHeapParams.BufferHandle = AMD_MEM_SPD_HANDLE;
354   AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
355   if (HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader) == AGESA_SUCCESS) {
356     MemPtr->SpdDataStructure = (SPD_DEF_STRUCT *) AllocHeapParams.BufferPtr;
357     //
358     // Initialize SpdParam Structure
359     //
360     LibAmdMemCopy ((VOID *)&SpdParam, (VOID *)MemPtr, (UINTN)sizeof (SpdParam.StdHeader), &MemPtr->StdHeader);
361     //
362     // Populate SPDDataBuffer
363     //
364     SpdParam.MemData = MemPtr;
365     DimmIndex = 0;
366     for (Socket = 0; Socket < (UINT16)MaxSockets; Socket++) {
367       MaxChannelsPerSocket = GetMaxChannelsPerSocket (PsoTable, Socket, &MemPtr->StdHeader);
368       SpdParam.SocketId = Socket;
369       for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
370         SpdParam.MemChannelId = Channel;
371         MaxDimmsPerChannel = GetMaxDimmsPerChannel (PsoTable, Socket, Channel);
372         for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++) {
373           SpdParam.DimmId = Dimm;
374           DimmSPDPtr = &(MemPtr->SpdDataStructure[DimmIndex++]);
375           SpdParam.Buffer = DimmSPDPtr->Data;
376           AGESA_TESTPOINT (TpProcMemBeforeAgesaReadSpd, &MemPtr->StdHeader);
377           AgesaStatus = AgesaReadSpd (0, &SpdParam);
378           AGESA_TESTPOINT (TpProcMemAfterAgesaReadSpd, &MemPtr->StdHeader);
379           if (AgesaStatus == AGESA_SUCCESS) {
380             DimmSPDPtr->DimmPresent = TRUE;
381             IDS_HDT_CONSOLE (MEM_FLOW, "SPD Socket %d Channel %d Dimm %d: %08x\n", Socket, Channel, Dimm, SpdParam.Buffer);
382           } else {
383             DimmSPDPtr->DimmPresent = FALSE;
384           }
385         }
386       }
387     }
388   } else {
389     PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_SPD, 0, 0, 0, 0, &MemPtr->StdHeader);
390     //
391     // Assert here if unable to allocate heap for SPDs
392     //
393     IDS_ERROR_TRAP;
394   }
395 }