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