blob: 3fb0e875db9fe11b9e937286fbfab4bd05421318 [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 */
efdesign98d7a696d2011-09-15 15:24:26 -060019
Frank Vibrans69da1b62011-02-14 19:04:45 +000020#include "agesawrapper.h"
21#include "amdlib.h"
efdesign98d7a696d2011-09-15 15:24:26 -060022#include "dimmSpd.h"
Frank Vibrans69da1b62011-02-14 19:04:45 +000023#include "BiosCallOuts.h"
24#include "heapManager.h"
25#include "SB800.h"
26
efdesign98d7a696d2011-09-15 15:24:26 -060027STATIC BIOS_CALLOUT_STRUCT BiosCallouts[] =
Frank Vibrans69da1b62011-02-14 19:04:45 +000028{
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
Frank Vibrans69da1b62011-02-14 19:04:45 +000057 {AGESA_GNB_PCIE_SLOT_RESET,
58 BiosGnbPcieSlotReset
59 },
efdesign98d7a696d2011-09-15 15:24:26 -060060
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 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000076};
77
efdesign98d7a696d2011-09-15 15:24:26 -060078AGESA_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++)
Frank Vibrans69da1b62011-02-14 19:04:45 +000087 {
88 if (BiosCallouts[i].CalloutName == Func)
89 {
efdesign98d7a696d2011-09-15 15:24:26 -060090 CalloutStatus = BiosCallouts[i].CalloutPtr (Func, Data, ConfigPtr);
91 return CalloutStatus;
Frank Vibrans69da1b62011-02-14 19:04:45 +000092 }
93 }
efdesign98d7a696d2011-09-15 15:24:26 -060094
Frank Vibrans69da1b62011-02-14 19:04:45 +000095 return CalloutStatus;
96}
97
98AGESA_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 */
efdesign98d7a696d2011-09-15 15:24:26 -0600156
Frank Vibrans69da1b62011-02-14 19:04:45 +0000157 }
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
efdesign98d7a696d2011-09-15 15:24:26 -0600206 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000207 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
227AGESA_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 {
efdesign98d7a696d2011-09-15 15:24:26 -0600291 /* Otherwise, add freed node to the start of the list
Frank Vibrans69da1b62011-02-14 19:04:45 +0000292 Update NextNodeOffset and BufferSize to include the
293 size of BIOS_BUFFER_NODE
efdesign98d7a696d2011-09-15 15:24:26 -0600294 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000295 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
efdesign98d7a696d2011-09-15 15:24:26 -0600302 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000303 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
efdesign98d7a696d2011-09-15 15:24:26 -0600316 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000317 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
efdesign98d7a696d2011-09-15 15:24:26 -0600330 */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000331 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
346AGESA_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
380AGESA_STATUS BiosRunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
381{
382 AGESA_STATUS Status;
383
efdesign98d7a696d2011-09-15 15:24:26 -0600384 Status = agesawrapper_amdlaterunaptask (Func, Data, ConfigPtr);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000385 return Status;
386}
387
388AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
389{
390 AGESA_STATUS Status;
391 UINT8 Value;
392 UINTN ResetType;
393 AMD_CONFIG_PARAMS *StdHeader;
efdesign98d7a696d2011-09-15 15:24:26 -0600394
Frank Vibrans69da1b62011-02-14 19:04:45 +0000395 ResetType = Data;
396 StdHeader = ConfigPtr;
efdesign98d7a696d2011-09-15 15:24:26 -0600397
Frank Vibrans69da1b62011-02-14 19:04:45 +0000398 //
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;
efdesign98d7a696d2011-09-15 15:24:26 -0600409
Frank Vibrans69da1b62011-02-14 19:04:45 +0000410 case WARM_RESET_IMMEDIATELY:
411 case COLD_RESET_IMMEDIATELY:
412 Value = 0x06;
413 LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
414 break;
efdesign98d7a696d2011-09-15 15:24:26 -0600415
Frank Vibrans69da1b62011-02-14 19:04:45 +0000416 default:
417 break;
418 }
efdesign98d7a696d2011-09-15 15:24:26 -0600419
Frank Vibrans69da1b62011-02-14 19:04:45 +0000420 Status = 0;
421 return Status;
422}
423
424AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
425{
426 AGESA_STATUS Status;
efdesign98d7a696d2011-09-15 15:24:26 -0600427 Status = AmdMemoryReadSPD (Func, Data, (AGESA_READ_SPD_PARAMS *)ConfigPtr);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000428
429 return Status;
430}
431
432AGESA_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. */
437AGESA_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. */
442AGESA_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;
efdesign98d7a696d2011-09-15 15:24:26 -0600452
Frank Vibrans69da1b62011-02-14 19:04:45 +0000453 FcnData = Data;
454 MemData = ConfigPtr;
efdesign98d7a696d2011-09-15 15:24:26 -0600455
Frank Vibrans69da1b62011-02-14 19:04:45 +0000456 Status = AGESA_SUCCESS;
efdesign98d7a696d2011-09-15 15:24:26 -0600457 /* Get SB MMIO Base (AcpiMmioAddr) */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000458 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;
efdesign98d7a696d2011-09-15 15:24:26 -0600466
Frank Vibrans69da1b62011-02-14 19:04:45 +0000467 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);
efdesign98d7a696d2011-09-15 15:24:26 -0600480
Frank Vibrans69da1b62011-02-14 19:04:45 +0000481 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);
efdesign98d7a696d2011-09-15 15:24:26 -0600487
Frank Vibrans69da1b62011-02-14 19:04:45 +0000488 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);
efdesign98d7a696d2011-09-15 15:24:26 -0600494
Frank Vibrans69da1b62011-02-14 19:04:45 +0000495 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}
efdesign98d7a696d2011-09-15 15:24:26 -0600523
524/* Call the host environment interface to provide a user hook opportunity. */
525AGESA_STATUS BiosHookBeforeDramInitRecovery (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
526{
527 return AGESA_SUCCESS;
528}
529
Frank Vibrans69da1b62011-02-14 19:04:45 +0000530/* Call the host environment interface to provide a user hook opportunity. */
531AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
532{
533 return AGESA_SUCCESS;
534}
535/* PCIE slot reset control */
536AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
537{
538 AGESA_STATUS Status;
539 UINTN FcnData;
540 PCIe_SLOT_RESET_INFO *ResetInfo;
efdesign98d7a696d2011-09-15 15:24:26 -0600541
Frank Vibrans69da1b62011-02-14 19:04:45 +0000542 UINT32 GpioMmioAddr;
543 UINT32 AcpiMmioAddr;
544 UINT8 Data8;
545 UINT16 Data16;
efdesign98d7a696d2011-09-15 15:24:26 -0600546
Frank Vibrans69da1b62011-02-14 19:04:45 +0000547 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}