blob: a72f96b4c3b1db164d6f4785e261b252435560e4 [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 */
Stefan Reinauer5ff7c132011-10-31 12:56:45 -070019
Frank Vibrans69da1b62011-02-14 19:04:45 +000020#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
28STATIC 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 },
Stefan Reinauer5ff7c132011-10-31 12:56:45 -070061
Frank Vibrans69da1b62011-02-14 19:04:45 +000062 {AGESA_HOOKBEFORE_DQS_TRAINING,
63 BiosHookBeforeDQSTraining
64 },
Stefan Reinauer5ff7c132011-10-31 12:56:45 -070065
Frank Vibrans69da1b62011-02-14 19:04:45 +000066 {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
77AGESA_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
101CONST 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
138AGESA_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
155AGESA_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 */
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700213
Frank Vibrans69da1b62011-02-14 19:04:45 +0000214 }
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
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700263 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000264 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
284AGESA_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 {
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700348 /* Otherwise, add freed node to the start of the list
349 Update NextNodeOffset and BufferSize to include the
Frank Vibrans69da1b62011-02-14 19:04:45 +0000350 size of BIOS_BUFFER_NODE
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700351 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000352 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
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700359 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000360 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
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700373 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000374 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
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700387 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000388 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
403AGESA_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
437AGESA_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
445AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
446{
447 AGESA_STATUS Status;
448 UINT8 Value;
449 UINTN ResetType;
450 AMD_CONFIG_PARAMS *StdHeader;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700451
Frank Vibrans69da1b62011-02-14 19:04:45 +0000452 ResetType = Data;
453 StdHeader = ConfigPtr;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700454
Frank Vibrans69da1b62011-02-14 19:04:45 +0000455 //
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;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700466
Frank Vibrans69da1b62011-02-14 19:04:45 +0000467 case WARM_RESET_IMMEDIATELY:
468 case COLD_RESET_IMMEDIATELY:
469 Value = 0x06;
470 LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
471 break;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700472
Frank Vibrans69da1b62011-02-14 19:04:45 +0000473 default:
474 break;
475 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700476
Frank Vibrans69da1b62011-02-14 19:04:45 +0000477 Status = 0;
478 return Status;
479}
480
481AGESA_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
489AGESA_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. */
494AGESA_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. */
499AGESA_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;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700509
Frank Vibrans69da1b62011-02-14 19:04:45 +0000510 FcnData = Data;
511 MemData = ConfigPtr;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700512
Frank Vibrans69da1b62011-02-14 19:04:45 +0000513 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;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700523
Frank Vibrans69da1b62011-02-14 19:04:45 +0000524 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);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700530
Frank Vibrans69da1b62011-02-14 19:04:45 +0000531 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);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700549
Frank Vibrans69da1b62011-02-14 19:04:45 +0000550 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. */
579AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
580{
581 return AGESA_SUCCESS;
582}
583/* PCIE slot reset control */
584AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
585{
586 AGESA_STATUS Status;
587 UINTN FcnData;
588 PCIe_SLOT_RESET_INFO *ResetInfo;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700589
Frank Vibrans69da1b62011-02-14 19:04:45 +0000590 UINT32 GpioMmioAddr;
591 UINT32 AcpiMmioAddr;
592 UINT8 Data8;
593 UINT16 Data16;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700594
Frank Vibrans69da1b62011-02-14 19:04:45 +0000595 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);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700614 Data8 &= ~(UINT8)BIT6 ;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000615 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);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700620 Data8 |= BIT6 ;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000621 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);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700637 Data8 |= BIT6 ;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000638 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}