remove trailing whitespace
[coreboot.git] / src / mainboard / asrock / e350m1 / BiosCallOuts.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2011 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include "agesawrapper.h"
21 #include "amdlib.h"
22 #include "BiosCallOuts.h"
23 #include "heapManager.h"
24 #include "SB800.h"
25
26 AGESA_STATUS GetBiosCallout (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
27 {
28   UINTN i;
29   AGESA_STATUS CalloutStatus;
30
31 CONST BIOS_CALLOUT_STRUCT BiosCallouts[REQUIRED_CALLOUTS] =
32 {
33   {AGESA_ALLOCATE_BUFFER,
34    BiosAllocateBuffer
35   },
36
37   {AGESA_DEALLOCATE_BUFFER,
38    BiosDeallocateBuffer
39   },
40
41   {AGESA_DO_RESET,
42    BiosReset
43   },
44
45   {AGESA_LOCATE_BUFFER,
46    BiosLocateBuffer
47   },
48
49   {AGESA_READ_SPD,
50    BiosReadSpd
51   },
52
53   {AGESA_READ_SPD_RECOVERY,
54    BiosDefaultRet
55   },
56
57   {AGESA_RUNFUNC_ONAP,
58    BiosRunFuncOnAp
59   },
60
61   {AGESA_HOOKBEFORE_DQS_TRAINING,
62    BiosHookBeforeDQSTraining
63   },
64
65   {AGESA_HOOKBEFORE_DRAM_INIT,
66    BiosHookBeforeDramInit
67   },
68   {AGESA_HOOKBEFORE_EXIT_SELF_REF,
69    BiosHookBeforeExitSelfRefresh
70   },
71   {AGESA_GNB_PCIE_SLOT_RESET,
72    BiosGnbPcieSlotReset
73   },
74 };
75
76   for (i = 0; i < REQUIRED_CALLOUTS; i++)
77   {
78     if (BiosCallouts[i].CalloutName == Func)
79     {
80       break;
81     }
82   }
83
84   if(i >= REQUIRED_CALLOUTS)
85   {
86     return AGESA_UNSUPPORTED;
87   }
88
89   CalloutStatus = BiosCallouts[i].CalloutPtr (Func, Data, ConfigPtr);
90
91   return CalloutStatus;
92 }
93
94 AGESA_STATUS BiosAllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
95 {
96   UINT32              AvailableHeapSize;
97   UINT8               *BiosHeapBaseAddr;
98   UINT32              CurrNodeOffset;
99   UINT32              PrevNodeOffset;
100   UINT32              FreedNodeOffset;
101   UINT32              BestFitNodeOffset;
102   UINT32              BestFitPrevNodeOffset;
103   UINT32              NextFreeOffset;
104   BIOS_BUFFER_NODE   *CurrNodePtr;
105   BIOS_BUFFER_NODE   *FreedNodePtr;
106   BIOS_BUFFER_NODE   *BestFitNodePtr;
107   BIOS_BUFFER_NODE   *BestFitPrevNodePtr;
108   BIOS_BUFFER_NODE   *NextFreePtr;
109   BIOS_HEAP_MANAGER  *BiosHeapBasePtr;
110   AGESA_BUFFER_PARAMS *AllocParams;
111
112   AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr);
113   AllocParams->BufferPointer = NULL;
114
115   AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER);
116   BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
117   BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
118
119   if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) {
120     /* First allocation */
121     CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER);
122     CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
123     CurrNodePtr->BufferHandle = AllocParams->BufferHandle;
124     CurrNodePtr->BufferSize = AllocParams->BufferLength;
125     CurrNodePtr->NextNodeOffset = 0;
126     AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE);
127
128     /* Update the remaining free space */
129     FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE);
130     FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
131     FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize;
132     FreedNodePtr->NextNodeOffset = 0;
133
134     /* Update the offsets for Allocated and Freed nodes */
135     BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset;
136     BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset;
137   } else {
138     /* Find out whether BufferHandle has been allocated on the heap. */
139     /* If it has, return AGESA_BOUNDS_CHK */
140     CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
141     CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
142
143     while (CurrNodeOffset != 0) {
144       CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
145       if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) {
146         return AGESA_BOUNDS_CHK;
147       }
148       CurrNodeOffset = CurrNodePtr->NextNodeOffset;
149       /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points
150        to the end of the allocated nodes list.
151       */
152
153     }
154     /* Find the node that best fits the requested buffer size */
155     FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
156     PrevNodeOffset = FreedNodeOffset;
157     BestFitNodeOffset = 0;
158     BestFitPrevNodeOffset = 0;
159     while (FreedNodeOffset != 0) {
160       FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
161       if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
162         if (BestFitNodeOffset == 0) {
163           /* First node that fits the requested buffer size */
164           BestFitNodeOffset = FreedNodeOffset;
165           BestFitPrevNodeOffset = PrevNodeOffset;
166         } else {
167           /* Find out whether current node is a better fit than the previous nodes */
168           BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
169           if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) {
170             BestFitNodeOffset = FreedNodeOffset;
171             BestFitPrevNodeOffset = PrevNodeOffset;
172           }
173         }
174       }
175       PrevNodeOffset = FreedNodeOffset;
176       FreedNodeOffset = FreedNodePtr->NextNodeOffset;
177     } /* end of while loop */
178
179
180     if (BestFitNodeOffset == 0) {
181       /* If we could not find a node that fits the requested buffer */
182       /* size, return AGESA_BOUNDS_CHK */
183       return AGESA_BOUNDS_CHK;
184     } else {
185       BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
186       BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset);
187
188       /* If BestFitNode is larger than the requested buffer, fragment the node further */
189       if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
190         NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE);
191
192         NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset);
193         NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE));
194         NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset;
195       } else {
196         /* Otherwise, next free node is NextNodeOffset of BestFitNode */
197         NextFreeOffset = BestFitNodePtr->NextNodeOffset;
198       }
199
200       /* If BestFitNode is the first buffer in the list, then update
201          StartOfFreedNodes to reflect the new free node
202       */
203       if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) {
204         BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset;
205       } else {
206         BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset;
207       }
208
209       /* Add BestFitNode to the list of Allocated nodes */
210       CurrNodePtr->NextNodeOffset = BestFitNodeOffset;
211       BestFitNodePtr->BufferSize = AllocParams->BufferLength;
212       BestFitNodePtr->BufferHandle = AllocParams->BufferHandle;
213       BestFitNodePtr->NextNodeOffset = 0;
214
215       /* Remove BestFitNode from list of Freed nodes */
216       AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE);
217     }
218   }
219
220   return AGESA_SUCCESS;
221 }
222
223 AGESA_STATUS BiosDeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
224 {
225
226   UINT8               *BiosHeapBaseAddr;
227   UINT32              AllocNodeOffset;
228   UINT32              PrevNodeOffset;
229   UINT32              NextNodeOffset;
230   UINT32              FreedNodeOffset;
231   UINT32              EndNodeOffset;
232   BIOS_BUFFER_NODE   *AllocNodePtr;
233   BIOS_BUFFER_NODE   *PrevNodePtr;
234   BIOS_BUFFER_NODE   *FreedNodePtr;
235   BIOS_BUFFER_NODE   *NextNodePtr;
236   BIOS_HEAP_MANAGER  *BiosHeapBasePtr;
237   AGESA_BUFFER_PARAMS *AllocParams;
238
239   BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
240   BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
241
242   AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
243
244   /* Find target node to deallocate in list of allocated nodes.
245      Return AGESA_BOUNDS_CHK if the BufferHandle is not found
246   */
247   AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
248   AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
249   PrevNodeOffset = AllocNodeOffset;
250
251   while (AllocNodePtr->BufferHandle !=  AllocParams->BufferHandle) {
252     if (AllocNodePtr->NextNodeOffset == 0) {
253       return AGESA_BOUNDS_CHK;
254     }
255     PrevNodeOffset = AllocNodeOffset;
256     AllocNodeOffset = AllocNodePtr->NextNodeOffset;
257     AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
258   }
259
260   /* Remove target node from list of allocated nodes */
261   PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
262   PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
263
264   /* Zero out the buffer, and clear the BufferHandle */
265   LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader));
266   AllocNodePtr->BufferHandle = 0;
267   AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE);
268
269   /* Add deallocated node in order to the list of freed nodes */
270   FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
271   FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
272
273   EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize;
274
275   if (AllocNodeOffset < FreedNodeOffset) {
276     /* Add to the start of the freed list */
277     if (EndNodeOffset == FreedNodeOffset) {
278       /* If the freed node is adjacent to the first node in the list, concatenate both nodes */
279       AllocNodePtr->BufferSize += FreedNodePtr->BufferSize;
280       AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset;
281
282       /* Clear the BufferSize and NextNodeOffset of the previous first node */
283       FreedNodePtr->BufferSize = 0;
284       FreedNodePtr->NextNodeOffset = 0;
285
286     } else {
287       /* Otherwise, add freed node to the start of the list
288          Update NextNodeOffset and BufferSize to include the
289          size of BIOS_BUFFER_NODE
290       */
291       AllocNodePtr->NextNodeOffset = FreedNodeOffset;
292     }
293     /* Update StartOfFreedNodes to the new first node */
294     BiosHeapBasePtr->StartOfFreedNodes = AllocNodeOffset;
295   } else {
296     /* Traverse list of freed nodes to find where the deallocated node
297        should be place
298     */
299     NextNodeOffset = FreedNodeOffset;
300     NextNodePtr = FreedNodePtr;
301     while (AllocNodeOffset > NextNodeOffset) {
302       PrevNodeOffset = NextNodeOffset;
303       if (NextNodePtr->NextNodeOffset == 0) {
304         break;
305       }
306       NextNodeOffset = NextNodePtr->NextNodeOffset;
307       NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
308     }
309
310     /* If deallocated node is adjacent to the next node,
311        concatenate both nodes
312     */
313     if (NextNodeOffset == EndNodeOffset) {
314       NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
315       AllocNodePtr->BufferSize += NextNodePtr->BufferSize;
316       AllocNodePtr->NextNodeOffset = NextNodePtr->NextNodeOffset;
317
318       NextNodePtr->BufferSize = 0;
319       NextNodePtr->NextNodeOffset = 0;
320     } else {
321       /*AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; */
322       AllocNodePtr->NextNodeOffset = NextNodeOffset;
323     }
324     /* If deallocated node is adjacent to the previous node,
325        concatenate both nodes
326     */
327     PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
328     EndNodeOffset = PrevNodeOffset + PrevNodePtr->BufferSize;
329     if (AllocNodeOffset == EndNodeOffset) {
330       PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
331       PrevNodePtr->BufferSize += AllocNodePtr->BufferSize;
332
333       AllocNodePtr->BufferSize = 0;
334       AllocNodePtr->NextNodeOffset = 0;
335     } else {
336       PrevNodePtr->NextNodeOffset = AllocNodeOffset;
337     }
338   }
339   return AGESA_SUCCESS;
340 }
341
342 AGESA_STATUS BiosLocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
343 {
344   UINT32              AllocNodeOffset;
345   UINT8               *BiosHeapBaseAddr;
346   BIOS_BUFFER_NODE   *AllocNodePtr;
347   BIOS_HEAP_MANAGER  *BiosHeapBasePtr;
348   AGESA_BUFFER_PARAMS *AllocParams;
349
350   AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
351
352   BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
353   BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
354
355   AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
356   AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
357
358   while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) {
359     if (AllocNodePtr->NextNodeOffset == 0) {
360       AllocParams->BufferPointer = NULL;
361       AllocParams->BufferLength = 0;
362       return AGESA_BOUNDS_CHK;
363     } else {
364       AllocNodeOffset = AllocNodePtr->NextNodeOffset;
365       AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
366     }
367   }
368
369   AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE));
370   AllocParams->BufferLength = AllocNodePtr->BufferSize;
371
372   return AGESA_SUCCESS;
373
374 }
375
376 AGESA_STATUS BiosRunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
377 {
378   AGESA_STATUS        Status;
379
380   Status = agesawrapper_amdlaterunaptask (Func, Data, ConfigPtr);
381   return Status;
382 }
383
384 AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
385 {
386   AGESA_STATUS        Status;
387   UINT8                 Value;
388   UINTN               ResetType;
389   AMD_CONFIG_PARAMS   *StdHeader;
390
391   ResetType = Data;
392   StdHeader = ConfigPtr;
393
394   //
395   // Perform the RESET based upon the ResetType. In case of
396   // WARM_RESET_WHENVER and COLD_RESET_WHENEVER, the request will go to
397   // AmdResetManager. During the critical condition, where reset is required
398   // immediately, the reset will be invoked directly by writing 0x04 to port
399   // 0xCF9 (Reset Port).
400   //
401   switch (ResetType) {
402   case WARM_RESET_WHENEVER:
403   case COLD_RESET_WHENEVER:
404     break;
405
406   case WARM_RESET_IMMEDIATELY:
407   case COLD_RESET_IMMEDIATELY:
408       Value = 0x06;
409       LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
410     break;
411
412   default:
413     break;
414   }
415
416   Status = 0;
417   return Status;
418 }
419
420 AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
421 {
422   AGESA_STATUS Status;
423   Status = AmdMemoryReadSPD (Func, Data, ConfigPtr);
424
425   return Status;
426 }
427
428 AGESA_STATUS BiosDefaultRet (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
429 {
430   return AGESA_UNSUPPORTED;
431 }
432 /*  Call the host environment interface to provide a user hook opportunity. */
433 AGESA_STATUS BiosHookBeforeDQSTraining (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
434 {
435   return AGESA_SUCCESS;
436 }
437 /*  Call the host environment interface to provide a user hook opportunity. */
438 AGESA_STATUS BiosHookBeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
439 {
440   AGESA_STATUS      Status;
441   UINTN             FcnData;
442   MEM_DATA_STRUCT   *MemData;
443   UINT32            AcpiMmioAddr;
444   UINT32            GpioMmioAddr;
445   UINT8             Data8;
446   UINT16            Data16;
447   UINT8             TempData8;
448
449   FcnData = Data;
450   MemData = ConfigPtr;
451
452   Status  = AGESA_SUCCESS;
453   /* Get SB800 MMIO Base (AcpiMmioAddr) */
454   WriteIo8 (0xCD6, 0x27);
455   Data8   = ReadIo8(0xCD7);
456   Data16  = Data8<<8;
457   WriteIo8 (0xCD6, 0x26);
458   Data8   = ReadIo8(0xCD7);
459   Data16  |= Data8;
460   AcpiMmioAddr = (UINT32)Data16 << 16;
461   GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
462
463   Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG178);
464   Data8 &= ~BIT5;
465   TempData8  = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
466   TempData8 &= 0x03;
467   TempData8 |= Data8;
468   Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
469
470   Data8 |= BIT2+BIT3;
471   Data8 &= ~BIT4;
472   TempData8  = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
473   TempData8 &= 0x23;
474   TempData8 |= Data8;
475   Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
476   Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG179);
477   Data8 &= ~BIT5;
478   TempData8  = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
479   TempData8 &= 0x03;
480   TempData8 |= Data8;
481   Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, TempData8);
482   Data8 |= BIT2+BIT3;
483   Data8 &= ~BIT4;
484   TempData8  = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
485   TempData8 &= 0x23;
486   TempData8 |= Data8;
487   Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, TempData8);
488
489   switch(MemData->ParameterListPtr->DDR3Voltage){
490     case VOLT1_35:
491       Data8 =  Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
492       Data8 &= ~(UINT8)BIT6;
493       Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
494       Data8 =  Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
495       Data8 |= (UINT8)BIT6;
496       Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
497       break;
498     case VOLT1_25:
499       Data8 =  Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
500       Data8 &= ~(UINT8)BIT6;
501       Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
502       Data8 =  Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
503       Data8 &= ~(UINT8)BIT6;
504       Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
505       break;
506     case VOLT1_5:
507     default:
508       Data8 =  Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
509       Data8 |= (UINT8)BIT6;
510       Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
511       Data8 =  Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
512       Data8 &= ~(UINT8)BIT6;
513       Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
514   }
515   // disable memory clear for boot time reduction
516   MemData->ParameterListPtr->EnableMemClr = FALSE;
517   return Status;
518 }
519 /*  Call the host environment interface to provide a user hook opportunity. */
520 AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
521 {
522   return AGESA_SUCCESS;
523 }
524 /* PCIE slot reset control */
525 AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
526 {
527   AGESA_STATUS Status;
528   UINTN                 FcnData;
529   PCIe_SLOT_RESET_INFO  *ResetInfo;
530
531   UINT32  GpioMmioAddr;
532   UINT32  AcpiMmioAddr;
533   UINT8   Data8;
534   UINT16  Data16;
535
536   FcnData   = Data;
537   ResetInfo = ConfigPtr;
538   // Get SB800 MMIO Base (AcpiMmioAddr)
539   WriteIo8(0xCD6, 0x27);
540   Data8 = ReadIo8(0xCD7);
541   Data16=Data8<<8;
542   WriteIo8(0xCD6, 0x26);
543   Data8 = ReadIo8(0xCD7);
544   Data16|=Data8;
545   AcpiMmioAddr = (UINT32)Data16 << 16;
546   Status = AGESA_UNSUPPORTED;
547   GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
548   switch (ResetInfo->ResetId)
549   {
550   case 4:
551       switch (ResetInfo->ResetControl)
552       {
553       case AssertSlotReset:
554         Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
555         Data8 &= ~(UINT8)BIT6 ;
556         Write64Mem8(GpioMmioAddr+SB_GPIO_REG21, Data8);   // MXM_GPIO0. GPIO21
557         Status = AGESA_SUCCESS;
558         break;
559       case DeassertSlotReset:
560         Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
561         Data8 |= BIT6 ;
562         Write64Mem8 (GpioMmioAddr+SB_GPIO_REG21, Data8);       // MXM_GPIO0. GPIO21
563         Status = AGESA_SUCCESS;
564         break;
565       }
566       break;
567   case 6:
568       switch (ResetInfo->ResetControl)
569       {
570       case AssertSlotReset:
571         Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
572         Data8 &= ~(UINT8)BIT6 ;
573         Write64Mem8(GpioMmioAddr+SB_GPIO_REG25, Data8);   // PCIE_RST#_LAN, GPIO25
574         Status = AGESA_SUCCESS;
575         break;
576       case DeassertSlotReset:
577         Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
578         Data8 |= BIT6 ;
579         Write64Mem8 (GpioMmioAddr+SB_GPIO_REG25, Data8);       // PCIE_RST#_LAN, GPIO25
580         Status = AGESA_SUCCESS;
581         break;
582       }
583       break;
584   case 7:
585       switch (ResetInfo->ResetControl)
586       {
587       case AssertSlotReset:
588         Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG02);
589         Data8 &= ~(UINT8)BIT6 ;
590         Write64Mem8(GpioMmioAddr+SB_GPIO_REG02, Data8);   // MPCIE_RST0, GPIO02
591         Status = AGESA_SUCCESS;
592         break;
593       case DeassertSlotReset:
594         Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
595         Data8 |= BIT6 ;
596         Write64Mem8 (GpioMmioAddr+SB_GPIO_REG02, Data8);       // MPCIE_RST0, GPIO02
597         Status = AGESA_SUCCESS;
598         break;
599       }
600       break;
601   }
602   return  Status;
603 }