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