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