AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Main / mmMemRestore.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mmMemRestore.c
6  *
7  * Main Memory Feature implementation file for Node Interleaving
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 #include "AGESA.h"
54 #include "amdlib.h"
55 #include "OptionMemory.h"
56 #include "mm.h"
57 #include "mn.h"
58 #include "Ids.h"
59 #include "S3.h"
60 #include "mfs3.h"
61 #include "heapManager.h"
62 #include "Filecode.h"
63 CODE_GROUP (G1_PEICC)
64 RDATA_GROUP (G2_PEI)
65
66 #define FILECODE PROC_MEM_MAIN_MMMEMRESTORE_FILECODE
67
68 #define ST_PRE_ESR  0
69 #define ST_POST_ESR 1
70 #define ST_DONE     2
71
72 /*----------------------------------------------------------------------------
73  *                        PROTOTYPES OF LOCAL FUNCTIONS
74  *
75  *----------------------------------------------------------------------------
76  */
77 BOOLEAN
78 STATIC
79 MemMRestoreDqsTimings (
80   IN       VOID                *Storage,
81   IN       MEM_MAIN_DATA_BLOCK *MemMainPtr
82   );
83
84 BOOLEAN
85 STATIC
86 MemMSetCSRNb (
87   IN OUT   MEM_NB_BLOCK *NBPtr,
88   IN       PCI_SPECIAL_CASE *SpecialCases,
89   IN       PCI_ADDR PciAddr,
90   IN       UINT32 Value
91   );
92
93 VOID
94 STATIC
95 MemMCreateS3NbBlock (
96   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr,
97      OUT   S3_MEM_NB_BLOCK **S3NBPtr
98   );
99
100 VOID
101 MemMContextSave (
102   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
103   );
104
105 BOOLEAN
106 MemMContextRestore (
107   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
108   );
109
110 /*-----------------------------------------------------------------------------
111 *                                EXPORTED FUNCTIONS
112 *
113 *-----------------------------------------------------------------------------
114 */
115 extern MEM_NB_SUPPORT memNBInstalled[];
116
117 /* -----------------------------------------------------------------------------*/
118 /**
119  *
120  *  Check and save memory context if possible.
121  *
122  *     @param[in,out]   *MemMainPtr   - Pointer to the MEM_MAIN_DATA_BLOCK
123  *
124  */
125 VOID
126 MemMContextSave (
127   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
128   )
129 {
130   UINT8 Node;
131   UINT8 i;
132   MEM_PARAMETER_STRUCT *RefPtr;
133   LOCATE_HEAP_PTR LocHeap;
134   ALLOCATE_HEAP_PARAMS AllocHeapParams;
135   DEVICE_BLOCK_HEADER *DeviceList;
136   AMD_CONFIG_PARAMS *StdHeader;
137   UINT32 BufferSize;
138   VOID *BufferOffset;
139   MEM_NB_BLOCK  *NBArray;
140   S3_MEM_NB_BLOCK *S3NBPtr;
141   DESCRIPTOR_GROUP DeviceDescript[MAX_NODES_SUPPORTED];
142
143   NBArray = MemMainPtr->NBPtr;
144   RefPtr = NBArray[BSP_DIE].RefPtr;
145
146   if (RefPtr->SaveMemContextCtl) {
147     RefPtr->MemContext.NvStorage = NULL;
148     RefPtr->MemContext.NvStorageSize = 0;
149
150     // Make sure DQS training has occurred before saving memory context
151     if (!RefPtr->MemRestoreCtl) {
152       StdHeader = &MemMainPtr->MemPtr->StdHeader;
153
154       MemMCreateS3NbBlock (MemMainPtr, &S3NBPtr);
155       if (S3NBPtr != NULL) {
156         // Get the mask bit and the register list for node that presents
157         BufferSize = 0;
158         for (Node = 0; Node < MemMainPtr->DieCount; Node ++) {
159           S3NBPtr->MemS3GetConPCIMask (&NBArray[Node], (VOID *)&DeviceDescript[Node]);
160           S3NBPtr->MemS3GetConMSRMask (&NBArray[Node], (VOID *)&DeviceDescript[Node]);
161           BufferSize += S3NBPtr->MemS3GetRegLstPtr (&NBArray[Node], (VOID *)&DeviceDescript[Node]);
162         }
163
164         // Base on the size of the device list, apply for a buffer for it.
165         AllocHeapParams.RequestedBufferSize = (UINT32) (BufferSize + sizeof (DEVICE_BLOCK_HEADER));
166         AllocHeapParams.BufferHandle = AMD_MEM_S3_DATA_HANDLE;
167         AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
168         if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) {
169           DeviceList = (DEVICE_BLOCK_HEADER *) AllocHeapParams.BufferPtr;
170           DeviceList->RelativeOrMaskOffset = (UINT16) AllocHeapParams.RequestedBufferSize;
171
172           // Copy device list on the stack to the heap.
173           BufferOffset = sizeof (DEVICE_BLOCK_HEADER) + AllocHeapParams.BufferPtr;
174           for (Node = 0; Node < MemMainPtr->DieCount; Node ++) {
175             for (i = PRESELFREF; i <= POSTSELFREF; i ++) {
176               // Copy PCI device descriptor to the heap if it exists.
177               if (DeviceDescript[Node].PCIDevice[i].RegisterListID != 0xFFFFFFFF) {
178                 LibAmdMemCopy (BufferOffset, &(DeviceDescript[Node].PCIDevice[i]), sizeof (PCI_DEVICE_DESCRIPTOR), StdHeader);
179                 DeviceList->NumDevices ++;
180                 BufferOffset = sizeof (PCI_DEVICE_DESCRIPTOR) + (UINT8 *)BufferOffset;
181               }
182               // Copy conditional PCI device descriptor to the heap if it exists.
183               if (DeviceDescript[Node].CPCIDevice[i].RegisterListID != 0xFFFFFFFF) {
184                 LibAmdMemCopy (BufferOffset, &(DeviceDescript[Node].CPCIDevice[i]), sizeof (CONDITIONAL_PCI_DEVICE_DESCRIPTOR), StdHeader);
185                 DeviceList->NumDevices ++;
186                 BufferOffset = sizeof (CONDITIONAL_PCI_DEVICE_DESCRIPTOR) + (UINT8 *)BufferOffset;
187               }
188               // Copy MSR device descriptor to the heap if it exists.
189               if (DeviceDescript[Node].MSRDevice[i].RegisterListID != 0xFFFFFFFF) {
190                 LibAmdMemCopy (BufferOffset, &(DeviceDescript[Node].MSRDevice[i]), sizeof (MSR_DEVICE_DESCRIPTOR), StdHeader);
191                 DeviceList->NumDevices ++;
192                 BufferOffset = sizeof (MSR_DEVICE_DESCRIPTOR) + (UINT8 *)BufferOffset;
193               }
194               // Copy conditional MSR device descriptor to the heap if it exists.
195               if (DeviceDescript[Node].CMSRDevice[i].RegisterListID != 0xFFFFFFFF) {
196                 LibAmdMemCopy (BufferOffset, &(DeviceDescript[Node].PCIDevice[i]), sizeof (CONDITIONAL_MSR_DEVICE_DESCRIPTOR), StdHeader);
197                 DeviceList->NumDevices ++;
198                 BufferOffset = sizeof (CONDITIONAL_MSR_DEVICE_DESCRIPTOR) + (UINT8 *)BufferOffset;
199               }
200             }
201           }
202
203           // Determine size needed
204           BufferSize = GetWorstCaseContextSize (DeviceList, INIT_RESUME, StdHeader);
205           AllocHeapParams.RequestedBufferSize = BufferSize;
206           AllocHeapParams.BufferHandle = AMD_S3_SAVE_HANDLE;
207           AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
208           if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) {
209             // Save memory context
210             SaveDeviceListContext (DeviceList, AllocHeapParams.BufferPtr, INIT_RESUME, &BufferSize, StdHeader);
211             RefPtr->MemContext.NvStorageSize = BufferSize;
212           }
213
214           HeapDeallocateBuffer (AMD_MEM_S3_DATA_HANDLE, StdHeader);
215         }
216       }
217       HeapDeallocateBuffer (AMD_MEM_S3_NB_HANDLE, StdHeader);
218
219       // Locate MemContext since it might have been shifted after deallocating
220       LocHeap.BufferHandle = AMD_S3_SAVE_HANDLE;
221       if (HeapLocateBuffer (&LocHeap, StdHeader) == AGESA_SUCCESS) {
222         RefPtr->MemContext.NvStorage = LocHeap.BufferPtr;
223       }
224     }
225   }
226
227   for (Node = 0; Node < MemMainPtr->DieCount; Node++) {
228     NBArray[Node].FamilySpecificHook[AfterSaveRestore] (&NBArray[Node], &NBArray[Node]);
229   }
230 }
231
232 /* -----------------------------------------------------------------------------*/
233 /**
234  *
235  *  Check and restore memory context if possible.
236  *
237  *     @param[in,out]   *MemMainPtr   - Pointer to the MEM_MAIN_DATA_BLOCK
238  *
239  *     @return          TRUE -  DQS timing restore succeeds.
240  *     @return          FALSE - DQS timing restore fails.
241  */
242 BOOLEAN
243 MemMContextRestore (
244   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
245   )
246 {
247   UINT8 Node;
248   MEM_NB_BLOCK  *NBArray;
249   MEM_PARAMETER_STRUCT *RefPtr;
250   S3_MEM_NB_BLOCK *S3NBPtr;
251
252   NBArray = MemMainPtr->NBPtr;
253   RefPtr = NBArray[BSP_DIE].RefPtr;
254
255   IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Mem Restore\n");
256   if (RefPtr->MemRestoreCtl) {
257     if (RefPtr->MemContext.NvStorage != NULL) {
258       MemMCreateS3NbBlock (MemMainPtr, &S3NBPtr);
259       if (S3NBPtr != NULL) {
260         // Check DIMM config and restore DQS timings if possible
261         if (!MemMRestoreDqsTimings (RefPtr->MemContext.NvStorage, MemMainPtr)) {
262           RefPtr->MemRestoreCtl = FALSE;
263         }
264       } else {
265         RefPtr->MemRestoreCtl = FALSE;
266       }
267       HeapDeallocateBuffer (AMD_MEM_S3_NB_HANDLE, &(MemMainPtr->MemPtr->StdHeader));
268     } else {
269       RefPtr->MemRestoreCtl = FALSE;
270     }
271   }
272
273   for (Node = 0; Node < MemMainPtr->DieCount; Node++) {
274     NBArray[Node].FamilySpecificHook[AfterSaveRestore] (&NBArray[Node], &NBArray[Node]);
275   }
276   IDS_HDT_CONSOLE (MEM_FLOW, RefPtr->MemRestoreCtl ? "Mem Restore Succeeds!\n" : "Mem Restore Fails!\n");
277   return RefPtr->MemRestoreCtl;
278 }
279
280 /*----------------------------------------------------------------------------
281  *                              LOCAL FUNCTIONS
282  *
283  *----------------------------------------------------------------------------
284  */
285
286 /*---------------------------------------------------------------------------------------*/
287 /**
288  * Restores all devices that contains DQS timings
289  *
290  *     @param[in]     Storage        Beginning of the device list.
291  *     @param[in,out]   MemMainPtr   - Pointer to the MEM_MAIN_DATA_BLOCK
292  *
293  *     @return          TRUE -  No fatal error occurs.
294  *     @return          FALSE - Fatal error occurs.
295  *
296  */
297 BOOLEAN
298 STATIC
299 MemMRestoreDqsTimings (
300   IN       VOID                *Storage,
301   IN       MEM_MAIN_DATA_BLOCK *MemMainPtr
302   )
303 {
304   AMD_CONFIG_PARAMS *StdHeader;
305   UINT8 *OrMask;
306   DEVICE_DESCRIPTORS Device;
307   INT16 i;
308   INT16 j;
309   DEVICE_BLOCK_HEADER *DeviceList;
310   PCI_REGISTER_BLOCK_HEADER *Reg;
311   CPCI_REGISTER_BLOCK_HEADER *CReg;
312   MSR_REGISTER_BLOCK_HEADER *MsrReg;
313   CMSR_REGISTER_BLOCK_HEADER *CMsrReg;
314   PCI_ADDR PciAddress;
315   MEM_NB_BLOCK  *NBArray;
316   UINT8 State;
317   UINT8 Node;
318   UINT8 Dct;
319   UINT8 MaxNode;
320
321   NBArray = MemMainPtr->NBPtr;
322   StdHeader = &(MemMainPtr->MemPtr->StdHeader);
323   DeviceList = (DEVICE_BLOCK_HEADER *) Storage;
324   Device.CommonDeviceHeader = (DEVICE_DESCRIPTOR *) &DeviceList[1];
325   OrMask = (UINT8 *) DeviceList + DeviceList->RelativeOrMaskOffset;
326
327   if (DeviceList->NumDevices == 0) {
328     return FALSE;
329   }
330
331   MaxNode = 0;
332   State = ST_PRE_ESR;
333   for (i = 0; State != ST_DONE; i++) {
334     if (((State == ST_PRE_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_PCI_PRE_ESR)) ||
335         ((State == ST_POST_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_PCI))) {
336       MemFS3GetPciDeviceRegisterList (Device.PciDevice, &Reg, StdHeader);
337       Node = Device.PciDevice->Node;
338       IDS_HDT_CONSOLE (MEM_STATUS, "Node %d\n", Node);
339       PciAddress = NBArray[Node].PciAddr;
340       for (j = 0; j < Reg->NumRegisters; j++) {
341         PciAddress.Address.Function = Reg->RegisterList[j].Function;
342         PciAddress.Address.Register = Reg->RegisterList[j].Offset;
343         PciAddress.Address.Segment = (Reg->RegisterList[j].Type.SpecialCaseFlag != 0) ?
344                                      0xF - Reg->RegisterList[j].Type.SpecialCaseIndex : 0;
345         if (!MemMSetCSRNb (&NBArray[Node], Reg->SpecialCases, PciAddress, *((UINT32 *) OrMask) & Reg->RegisterList[j].AndMask)) {
346           return FALSE;   // Restore fails
347         }
348         OrMask += (Reg->RegisterList[j].Type.RegisterSize == 0) ? 4 : Reg->RegisterList[j].Type.RegisterSize;
349       }
350
351       if (MaxNode < Node) {
352         MaxNode = Node;
353       }
354
355     } else if (((State == ST_PRE_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_CPCI_PRE_ESR)) ||
356                ((State == ST_POST_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_CPCI))) {
357       MemFS3GetCPciDeviceRegisterList (Device.CPciDevice, &CReg, StdHeader);
358       Node = Device.CPciDevice->Node;
359       IDS_HDT_CONSOLE (MEM_STATUS, "Node %d\n", Node);
360       PciAddress = NBArray[Node].PciAddr;
361       for (j = 0; j < CReg->NumRegisters; j++) {
362         if (((Device.CPciDevice->Mask1 & CReg->RegisterList[j].Mask1) != 0) &&
363             ((Device.CPciDevice->Mask2 & CReg->RegisterList[j].Mask2) != 0)) {
364           PciAddress.Address.Function = CReg->RegisterList[j].Function;
365           PciAddress.Address.Register = CReg->RegisterList[j].Offset;
366           PciAddress.Address.Segment = (CReg->RegisterList[j].Type.SpecialCaseFlag != 0) ?
367                                        0xF - CReg->RegisterList[j].Type.SpecialCaseIndex : 0;
368           if (!MemMSetCSRNb (&NBArray[Node], CReg->SpecialCases, PciAddress, *((UINT32 *) OrMask) & CReg->RegisterList[j].AndMask)) {
369             return FALSE;   // Restore fails
370           }
371           OrMask += (CReg->RegisterList[j].Type.RegisterSize == 0) ? 4 : CReg->RegisterList[j].Type.RegisterSize;
372         }
373       }
374     } else if (((State == ST_PRE_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_MSR_PRE_ESR)) ||
375                ((State == ST_POST_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_MSR))) {
376       MemFS3GetMsrDeviceRegisterList (Device.MsrDevice, &MsrReg, StdHeader);
377       for (j = 0; j < MsrReg->NumRegisters; j++) {
378         OrMask += 8;
379       }
380     } else if (((State == ST_PRE_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_CMSR_PRE_ESR)) ||
381                ((State == ST_POST_ESR) && (Device.CommonDeviceHeader->Type == DEV_TYPE_CMSR))) {
382       MemFS3GetCMsrDeviceRegisterList (Device.CMsrDevice, &CMsrReg, StdHeader);
383       for (j = 0; j < CMsrReg->NumRegisters; j++) {
384         if (((Device.CMsrDevice->Mask1 & CMsrReg->RegisterList[j].Mask1) != 0) &&
385             ((Device.CMsrDevice->Mask2 & CMsrReg->RegisterList[j].Mask2) != 0)) {
386           OrMask += 8;
387         }
388       }
389     }
390
391     switch (Device.CommonDeviceHeader->Type) {
392     case DEV_TYPE_PCI_PRE_ESR:
393       // Fall through to advance the pointer after restoring context
394     case DEV_TYPE_PCI:
395       Device.PciDevice++;
396       break;
397     case DEV_TYPE_CPCI_PRE_ESR:
398       // Fall through to advance the pointer after restoring context
399     case DEV_TYPE_CPCI:
400       Device.CPciDevice++;
401       break;
402     case DEV_TYPE_MSR_PRE_ESR:
403       // Fall through to advance the pointer after restoring context
404     case DEV_TYPE_MSR:
405       Device.MsrDevice++;
406       break;
407     case DEV_TYPE_CMSR_PRE_ESR:
408       // Fall through to advance the pointer after restoring context
409     case DEV_TYPE_CMSR:
410       Device.CMsrDevice++;
411       break;
412     default:
413       ASSERT (FALSE);
414       break;
415     }
416
417     if (i == (DeviceList->NumDevices - 1)) {
418       // Go to next state
419       State++;
420       i = -1;
421       Device.CommonDeviceHeader = (DEVICE_DESCRIPTOR *) &DeviceList[1];
422
423       // Check to see if processor or DIMM population has changed
424       if ((MaxNode + 1) != MemMainPtr->DieCount) {
425         IDS_HDT_CONSOLE (MEM_FLOW, "\tSTOP: Population changed\n");
426         return FALSE;
427       }
428
429       // Perform MemClk frequency change
430       for (Node = 0; Node < MemMainPtr->DieCount; Node ++) {
431         if (NBArray[Node].MCTPtr->NodeMemSize != 0) {
432           NBArray[Node].BeforeDqsTraining (&NBArray[Node]);
433           if (NBArray[Node].DCTPtr->Timings.Speed < NBArray[Node].DCTPtr->Timings.TargetSpeed) {
434             for (Dct = 0; Dct < NBArray[Node].DctCount; Dct++) {
435               NBArray[Node].SwitchDCT (&NBArray[Node], Dct);
436               NBArray[Node].DCTPtr->Timings.Speed = NBArray[Node].DCTPtr->Timings.TargetSpeed;
437             }
438             IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, &NBArray[Node], &(MemMainPtr->MemPtr->StdHeader));
439             NBArray[Node].ChangeFrequency (&NBArray[Node]);
440           }
441         }
442       }
443     }
444   }
445
446   return TRUE;
447 }
448
449 /* -----------------------------------------------------------------------------*/
450 /**
451  *
452  *   This function filters out other settings and only restores DQS timings.
453  *
454  *     @param[in,out]   NBPtr   - Pointer to the MEM_NB_BLOCK
455  *     @param[in]   SpecialCases - Pointer to special cases array handlers
456  *     @param[in]   PciAddr - address of the CSR register in PCI_ADDR format.
457  *     @param[in]   Value - Value to be programmed
458  *
459  *     @return          TRUE -  No fatal error occurs.
460  *     @return          FALSE - Fatal error occurs.
461  *
462  */
463
464 BOOLEAN
465 STATIC
466 MemMSetCSRNb (
467   IN OUT   MEM_NB_BLOCK *NBPtr,
468   IN       PCI_SPECIAL_CASE *SpecialCases,
469   IN       PCI_ADDR PciAddr,
470   IN       UINT32 Value
471   )
472 {
473   UINT32 Offset;
474   UINT8  Dct;
475   UINT32 Temp;
476   BOOLEAN RetVal;
477   UINT32 BOffset;
478
479   RetVal = TRUE;
480   if (PciAddr.Address.Segment != 0) {
481     if (PciAddr.Address.Segment == 0xF) {
482       PciAddr.Address.Segment = 0;
483       Dct = (UINT8) ((PciAddr.Address.Register >> 10) & 1);
484       Offset = PciAddr.Address.Register & 0x3FF;
485       BOffset = PciAddr.Address.Register & 0xFF;
486       if ((PciAddr.Address.Register & 0x800) == 0) {
487         if (((BOffset >= 1) && (BOffset <= 3)) ||
488             ((BOffset >= 5) && (BOffset <= 7)) ||
489             ((Offset >= 0x10) && (Offset <= 0x2B)) ||
490             ((Offset >= 0x30) && (Offset <= 0x4A))) {
491           IDS_HDT_CONSOLE (MEM_FLOW, "\t\tF2_%d9C_%03x = %08x\n", Dct, Offset, Value);
492           //MemNS3SetCSR
493           SpecialCases[0].Restore (AccessS3SaveWidth32, PciAddr, &Value, &NBPtr->MemPtr->StdHeader);
494         }
495       }
496     }
497   } else {
498     Dct = (UINT8) ((PciAddr.Address.Register >> 8) & 1);
499     Offset = PciAddr.Address.Register & 0xFF;
500
501     if (PciAddr.Address.Function == 2) {
502       if ((Offset >= 0x40) && (Offset < 0x60) && ((Value & 4) != 0)) {
503         // If TestFail bit is set, set CsTestFail
504         NBPtr->SwitchDCT (NBPtr, Dct);
505         NBPtr->DCTPtr->Timings.CsTrainFail |= (UINT16)1 << ((Offset - 0x40) >> 2);
506         IDS_HDT_CONSOLE (MEM_FLOW, "\tBad CS:%d\n", ((Offset - 0x40) >> 2));
507       } else if (Offset == 0x80) {
508         LibAmdPciRead (AccessWidth32, PciAddr, &Temp, &NBPtr->MemPtr->StdHeader);
509         if (Temp != Value) {
510           IDS_HDT_CONSOLE (MEM_FLOW, "\tSTOP: DIMM config changed\n");
511           RetVal = FALSE;
512         }
513       } else if (Offset == 0x90) {
514         LibAmdPciRead (AccessWidth32, PciAddr, &Temp, &NBPtr->MemPtr->StdHeader);
515         if ((Temp & 0x0001F000) != (Value & 0x0001F000)) {
516           IDS_HDT_CONSOLE (MEM_FLOW, "\tSTOP: DIMM config changed\n");
517           RetVal = FALSE;
518         }
519       } else if (Offset == 0x94) {
520         LibAmdPciRead (AccessWidth32, PciAddr, &Temp, &NBPtr->MemPtr->StdHeader);
521         if ((Temp & 0x00061000) != (Value & 0x00061000)) {
522           IDS_HDT_CONSOLE (MEM_FLOW, "\tSTOP: DIMM config changed\n");
523           RetVal = FALSE;
524         }
525         if (((Value & 0x4000) == 0) && (NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.TargetSpeed) != ((Value & 7) + 1))) {
526           IDS_HDT_CONSOLE (MEM_FLOW, "\tSTOP: MemClk has changed\n");
527           RetVal = FALSE;
528         }
529         // Restore ZqcsInterval
530         Temp &= 0xFFFFF3FF;
531         Temp |= (Value & 0x00000C00);
532         LibAmdPciWrite (AccessWidth32, PciAddr, &Temp, &NBPtr->MemPtr->StdHeader);
533       } else if (Offset == 0x78) {
534         // Program MaxRdLat
535         LibAmdPciRead (AccessWidth32, PciAddr, &Temp, &NBPtr->MemPtr->StdHeader);
536         Temp &= 0x0009BF0F;
537         Temp |= (Value & 0xFFC00000);
538         LibAmdPciWrite (AccessWidth32, PciAddr, &Temp, &NBPtr->MemPtr->StdHeader);
539       } else if (PciAddr.Address.Register == 0x110) {
540         if ((NBPtr->MCTPtr->NodeMemSize != 0) && (Value == 0x00000100)) {
541           IDS_HDT_CONSOLE (MEM_FLOW, "\tSTOP: DIMM config changed\n");
542           RetVal = FALSE;
543         }
544       }
545     }
546   }
547
548   if (RetVal == FALSE) {
549     NBPtr->SwitchDCT (NBPtr, 0);
550     NBPtr->DCTPtr->Timings.CsTrainFail = 0;
551     NBPtr->SwitchDCT (NBPtr, 1);
552     NBPtr->DCTPtr->Timings.CsTrainFail = 0;
553   }
554
555   return RetVal;
556 }
557
558 /* -----------------------------------------------------------------------------*/
559 /**
560  *
561  *  Create S3 NB Block.
562  *
563  *     @param[in,out]   MemMainPtr   - Pointer to the MEM_MAIN_DATA_BLOCK
564  *     @param[out]      S3NBPtr   - Pointer to the S3 NB Block pointer
565  *
566  */
567 VOID
568 STATIC
569 MemMCreateS3NbBlock (
570   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr,
571      OUT   S3_MEM_NB_BLOCK **S3NBPtr
572   )
573 {
574   UINT8 Node;
575   UINT8 i;
576   MEM_NB_BLOCK  *NBArray;
577   MEM_NB_BLOCK  *DummyNBs;
578   ALLOCATE_HEAP_PARAMS AllocHeapParams;
579
580   NBArray = MemMainPtr->NBPtr;
581
582   *S3NBPtr = NULL;
583
584   // Allocate heap for S3 NB Blocks
585   AllocHeapParams.RequestedBufferSize = (MemMainPtr->DieCount * (sizeof (S3_MEM_NB_BLOCK) + sizeof (MEM_NB_BLOCK)));
586   AllocHeapParams.BufferHandle = AMD_MEM_S3_NB_HANDLE;
587   AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
588   if (HeapAllocateBuffer (&AllocHeapParams, &(MemMainPtr->MemPtr->StdHeader)) == AGESA_SUCCESS) {
589     *S3NBPtr = (S3_MEM_NB_BLOCK *) AllocHeapParams.BufferPtr;
590     DummyNBs = (MEM_NB_BLOCK *) (AllocHeapParams.BufferPtr + MemMainPtr->DieCount * sizeof (S3_MEM_NB_BLOCK));
591
592     // Initialize S3 NB Blocks
593     for (Node = 0; Node < MemMainPtr->DieCount; Node ++) {
594       (*S3NBPtr)[Node].NBPtr = &DummyNBs[Node];
595
596       for (i = 0; memNBInstalled[i].MemS3ResumeConstructNBBlock != 0; i++) {
597         if (memNBInstalled[i].MemS3ResumeConstructNBBlock (&(*S3NBPtr)[Node], NBArray[BSP_DIE].MemPtr, Node)) {
598           break;
599         }
600       };
601       if (memNBInstalled[i].MemS3ResumeConstructNBBlock == 0) {
602         *S3NBPtr = NULL;
603         break;
604       }
605     }
606   }
607 }