blob: f4a5cb672a2d59eba9f5bc69b712b4c9c95efd48 [file] [log] [blame]
Frank Vibrans69da1b62011-02-14 19:04:45 +00001/*
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
26AGESA_STATUS GetBiosCallout (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
27{
28 UINTN i;
29 AGESA_STATUS CalloutStatus;
30
31CONST 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
94AGESA_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
223AGESA_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
342AGESA_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
376AGESA_STATUS BiosRunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
377{
378 AGESA_STATUS Status;
379
380 Status = agesawrapper_amdlaterunaptask (Data, ConfigPtr);
381 return Status;
382}
383
384AGESA_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
420AGESA_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
428AGESA_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. */
433AGESA_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. */
438AGESA_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 return Status;
516}
517/* Call the host environment interface to provide a user hook opportunity. */
518AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
519{
520 return AGESA_SUCCESS;
521}
522/* PCIE slot reset control */
523AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
524{
525 AGESA_STATUS Status;
526 UINTN FcnData;
527 PCIe_SLOT_RESET_INFO *ResetInfo;
528
529 UINT32 GpioMmioAddr;
530 UINT32 AcpiMmioAddr;
531 UINT8 Data8;
532 UINT16 Data16;
533
534 FcnData = Data;
535 ResetInfo = ConfigPtr;
536 // Get SB800 MMIO Base (AcpiMmioAddr)
537 WriteIo8(0xCD6, 0x27);
538 Data8 = ReadIo8(0xCD7);
539 Data16=Data8<<8;
540 WriteIo8(0xCD6, 0x26);
541 Data8 = ReadIo8(0xCD7);
542 Data16|=Data8;
543 AcpiMmioAddr = (UINT32)Data16 << 16;
544 Status = AGESA_UNSUPPORTED;
545 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
546 switch (ResetInfo->ResetId)
547 {
548 case 4:
549 switch (ResetInfo->ResetControl)
550 {
551 case AssertSlotReset:
552 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
553 Data8 &= ~(UINT8)BIT6 ;
554 Write64Mem8(GpioMmioAddr+SB_GPIO_REG21, Data8); // MXM_GPIO0. GPIO21
555 Status = AGESA_SUCCESS;
556 break;
557 case DeassertSlotReset:
558 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
559 Data8 |= BIT6 ;
560 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG21, Data8); // MXM_GPIO0. GPIO21
561 Status = AGESA_SUCCESS;
562 break;
563 }
564 break;
565 case 6:
566 switch (ResetInfo->ResetControl)
567 {
568 case AssertSlotReset:
569 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
570 Data8 &= ~(UINT8)BIT6 ;
571 Write64Mem8(GpioMmioAddr+SB_GPIO_REG25, Data8); // PCIE_RST#_LAN, GPIO25
572 Status = AGESA_SUCCESS;
573 break;
574 case DeassertSlotReset:
575 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
576 Data8 |= BIT6 ;
577 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG25, Data8); // PCIE_RST#_LAN, GPIO25
578 Status = AGESA_SUCCESS;
579 break;
580 }
581 break;
582 case 7:
583 switch (ResetInfo->ResetControl)
584 {
585 case AssertSlotReset:
586 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG02);
587 Data8 &= ~(UINT8)BIT6 ;
588 Write64Mem8(GpioMmioAddr+SB_GPIO_REG02, Data8); // MPCIE_RST0, GPIO02
589 Status = AGESA_SUCCESS;
590 break;
591 case DeassertSlotReset:
592 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
593 Data8 |= BIT6 ;
594 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG02, Data8); // MPCIE_RST0, GPIO02
595 Status = AGESA_SUCCESS;
596 break;
597 }
598 break;
599 }
600 return Status;
601}