blob: 88bb1be570201ccc4812b8a45ed0d2c321900dc7 [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"
Kerry Sheh01f7ab92012-01-19 13:18:36 +080022#include "dimmSpd.h"
Frank Vibrans69da1b62011-02-14 19:04:45 +000023#include "BiosCallOuts.h"
Frank Vibrans69da1b62011-02-14 19:04:45 +000024#include "heapManager.h"
25#include "SB800.h"
26
Kerry Sheh01f7ab92012-01-19 13:18:36 +080027STATIC BIOS_CALLOUT_STRUCT BiosCallouts[] =
Frank Vibrans69da1b62011-02-14 19:04:45 +000028{
Kerry Shehf03360f2012-01-19 13:25:55 +080029 {AGESA_ALLOCATE_BUFFER,
30 BiosAllocateBuffer
31 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000032
Kerry Shehf03360f2012-01-19 13:25:55 +080033 {AGESA_DEALLOCATE_BUFFER,
34 BiosDeallocateBuffer
35 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000036
Kerry Shehf03360f2012-01-19 13:25:55 +080037 {AGESA_DO_RESET,
38 BiosReset
39 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000040
Kerry Shehf03360f2012-01-19 13:25:55 +080041 {AGESA_LOCATE_BUFFER,
42 BiosLocateBuffer
43 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000044
Kerry Shehf03360f2012-01-19 13:25:55 +080045 {AGESA_READ_SPD,
46 BiosReadSpd
47 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000048
Kerry Shehf03360f2012-01-19 13:25:55 +080049 {AGESA_READ_SPD_RECOVERY,
50 BiosDefaultRet
51 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000052
Kerry Shehf03360f2012-01-19 13:25:55 +080053 {AGESA_RUNFUNC_ONAP,
54 BiosRunFuncOnAp
55 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000056
Kerry Sheh01f7ab92012-01-19 13:18:36 +080057 {AGESA_GNB_PCIE_SLOT_RESET,
Kerry Shehf03360f2012-01-19 13:25:55 +080058 BiosGnbPcieSlotReset
Kerry Sheh01f7ab92012-01-19 13:18:36 +080059 },
60
61 {AGESA_HOOKBEFORE_DRAM_INIT,
Kerry Shehf03360f2012-01-19 13:25:55 +080062 BiosHookBeforeDramInit
Kerry Sheh01f7ab92012-01-19 13:18:36 +080063 },
64
65 {AGESA_HOOKBEFORE_DRAM_INIT_RECOVERY,
Kerry Shehf03360f2012-01-19 13:25:55 +080066 BiosHookBeforeDramInitRecovery
67 },
Stefan Reinauer5ff7c132011-10-31 12:56:45 -070068
Kerry Shehf03360f2012-01-19 13:25:55 +080069 {AGESA_HOOKBEFORE_DQS_TRAINING,
70 BiosHookBeforeDQSTraining
71 },
Stefan Reinauer5ff7c132011-10-31 12:56:45 -070072
Kerry Shehf03360f2012-01-19 13:25:55 +080073 {AGESA_HOOKBEFORE_EXIT_SELF_REF,
74 BiosHookBeforeExitSelfRefresh
75 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000076};
77
78AGESA_STATUS GetBiosCallout (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
79{
Kerry Shehf03360f2012-01-19 13:25:55 +080080 UINTN i;
81 AGESA_STATUS CalloutStatus;
Kerry Sheh01f7ab92012-01-19 13:18:36 +080082 UINTN CallOutCount = sizeof (BiosCallouts) / sizeof (BiosCallouts [0]);
Frank Vibrans69da1b62011-02-14 19:04:45 +000083
Kerry Sheh01f7ab92012-01-19 13:18:36 +080084 CalloutStatus = AGESA_UNSUPPORTED;
Frank Vibrans69da1b62011-02-14 19:04:45 +000085
Kerry Sheh01f7ab92012-01-19 13:18:36 +080086 for (i = 0; i < CallOutCount; i++) {
87 if (BiosCallouts[i].CalloutName == Func) {
Kerry Shehf03360f2012-01-19 13:25:55 +080088 CalloutStatus = BiosCallouts[i].CalloutPtr (Func, Data, ConfigPtr);
89 return CalloutStatus;
90 }
91 }
Frank Vibrans69da1b62011-02-14 19:04:45 +000092
Kerry Sheh01f7ab92012-01-19 13:18:36 +080093 return CalloutStatus;
94}
Frank Vibrans69da1b62011-02-14 19:04:45 +000095
96AGESA_STATUS BiosAllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
97{
Kerry Shehf03360f2012-01-19 13:25:55 +080098 UINT32 AvailableHeapSize;
99 UINT8 *BiosHeapBaseAddr;
100 UINT32 CurrNodeOffset;
101 UINT32 PrevNodeOffset;
102 UINT32 FreedNodeOffset;
103 UINT32 BestFitNodeOffset;
104 UINT32 BestFitPrevNodeOffset;
105 UINT32 NextFreeOffset;
106 BIOS_BUFFER_NODE *CurrNodePtr;
107 BIOS_BUFFER_NODE *FreedNodePtr;
108 BIOS_BUFFER_NODE *BestFitNodePtr;
109 BIOS_BUFFER_NODE *BestFitPrevNodePtr;
110 BIOS_BUFFER_NODE *NextFreePtr;
111 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
112 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000113
Kerry Shehf03360f2012-01-19 13:25:55 +0800114 AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr);
115 AllocParams->BufferPointer = NULL;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000116
Kerry Shehf03360f2012-01-19 13:25:55 +0800117 AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER);
118 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
119 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000120
Kerry Shehf03360f2012-01-19 13:25:55 +0800121 if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) {
122 /* First allocation */
123 CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER);
124 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
125 CurrNodePtr->BufferHandle = AllocParams->BufferHandle;
126 CurrNodePtr->BufferSize = AllocParams->BufferLength;
127 CurrNodePtr->NextNodeOffset = 0;
128 AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000129
Kerry Shehf03360f2012-01-19 13:25:55 +0800130 /* Update the remaining free space */
131 FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE);
132 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
133 FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize;
134 FreedNodePtr->NextNodeOffset = 0;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000135
Kerry Shehf03360f2012-01-19 13:25:55 +0800136 /* Update the offsets for Allocated and Freed nodes */
137 BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset;
138 BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset;
139 } else {
140 /* Find out whether BufferHandle has been allocated on the heap. */
141 /* If it has, return AGESA_BOUNDS_CHK */
142 CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
143 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000144
Kerry Shehf03360f2012-01-19 13:25:55 +0800145 while (CurrNodeOffset != 0) {
146 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
147 if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) {
148 return AGESA_BOUNDS_CHK;
149 }
150 CurrNodeOffset = CurrNodePtr->NextNodeOffset;
151 /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points
152 to the end of the allocated nodes list.
153 */
154 }
155 /* Find the node that best fits the requested buffer size */
156 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
157 PrevNodeOffset = FreedNodeOffset;
158 BestFitNodeOffset = 0;
159 BestFitPrevNodeOffset = 0;
160 while (FreedNodeOffset != 0) {
161 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
162 if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
163 if (BestFitNodeOffset == 0) {
164 /* First node that fits the requested buffer size */
165 BestFitNodeOffset = FreedNodeOffset;
166 BestFitPrevNodeOffset = PrevNodeOffset;
167 } else {
168 /* Find out whether current node is a better fit than the previous nodes */
169 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
170 if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) {
171 BestFitNodeOffset = FreedNodeOffset;
172 BestFitPrevNodeOffset = PrevNodeOffset;
173 }
174 }
175 }
176 PrevNodeOffset = FreedNodeOffset;
177 FreedNodeOffset = FreedNodePtr->NextNodeOffset;
178 } /* end of while loop */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000179
180
Kerry Shehf03360f2012-01-19 13:25:55 +0800181 if (BestFitNodeOffset == 0) {
182 /* If we could not find a node that fits the requested buffer */
183 /* size, return AGESA_BOUNDS_CHK */
184 return AGESA_BOUNDS_CHK;
185 } else {
186 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
187 BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000188
Kerry Shehf03360f2012-01-19 13:25:55 +0800189 /* If BestFitNode is larger than the requested buffer, fragment the node further */
190 if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
191 NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000192
Kerry Shehf03360f2012-01-19 13:25:55 +0800193 NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset);
194 NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE));
195 NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset;
196 } else {
197 /* Otherwise, next free node is NextNodeOffset of BestFitNode */
198 NextFreeOffset = BestFitNodePtr->NextNodeOffset;
199 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000200
Kerry Shehf03360f2012-01-19 13:25:55 +0800201 /* If BestFitNode is the first buffer in the list, then update
202 StartOfFreedNodes to reflect the new free node
203 */
204 if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) {
205 BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset;
206 } else {
207 BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset;
208 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000209
Kerry Shehf03360f2012-01-19 13:25:55 +0800210 /* Add BestFitNode to the list of Allocated nodes */
211 CurrNodePtr->NextNodeOffset = BestFitNodeOffset;
212 BestFitNodePtr->BufferSize = AllocParams->BufferLength;
213 BestFitNodePtr->BufferHandle = AllocParams->BufferHandle;
214 BestFitNodePtr->NextNodeOffset = 0;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000215
Kerry Shehf03360f2012-01-19 13:25:55 +0800216 /* Remove BestFitNode from list of Freed nodes */
217 AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE);
218 }
219 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000220
Kerry Shehf03360f2012-01-19 13:25:55 +0800221 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000222}
223
224AGESA_STATUS BiosDeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
225{
226
Kerry Shehf03360f2012-01-19 13:25:55 +0800227 UINT8 *BiosHeapBaseAddr;
228 UINT32 AllocNodeOffset;
229 UINT32 PrevNodeOffset;
230 UINT32 NextNodeOffset;
231 UINT32 FreedNodeOffset;
232 UINT32 EndNodeOffset;
233 BIOS_BUFFER_NODE *AllocNodePtr;
234 BIOS_BUFFER_NODE *PrevNodePtr;
235 BIOS_BUFFER_NODE *FreedNodePtr;
236 BIOS_BUFFER_NODE *NextNodePtr;
237 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
238 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000239
Kerry Shehf03360f2012-01-19 13:25:55 +0800240 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
241 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000242
Kerry Shehf03360f2012-01-19 13:25:55 +0800243 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000244
Kerry Shehf03360f2012-01-19 13:25:55 +0800245 /* Find target node to deallocate in list of allocated nodes.
246 Return AGESA_BOUNDS_CHK if the BufferHandle is not found
247 */
248 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
249 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
250 PrevNodeOffset = AllocNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000251
Kerry Shehf03360f2012-01-19 13:25:55 +0800252 while (AllocNodePtr->BufferHandle != AllocParams->BufferHandle) {
253 if (AllocNodePtr->NextNodeOffset == 0) {
254 return AGESA_BOUNDS_CHK;
255 }
256 PrevNodeOffset = AllocNodeOffset;
257 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
258 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
259 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000260
Kerry Shehf03360f2012-01-19 13:25:55 +0800261 /* Remove target node from list of allocated nodes */
262 PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
263 PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000264
Kerry Shehf03360f2012-01-19 13:25:55 +0800265 /* Zero out the buffer, and clear the BufferHandle */
266 LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader));
267 AllocNodePtr->BufferHandle = 0;
268 AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000269
Kerry Shehf03360f2012-01-19 13:25:55 +0800270 /* Add deallocated node in order to the list of freed nodes */
271 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
272 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000273
Kerry Shehf03360f2012-01-19 13:25:55 +0800274 EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000275
Kerry Shehf03360f2012-01-19 13:25:55 +0800276 if (AllocNodeOffset < FreedNodeOffset) {
277 /* Add to the start of the freed list */
278 if (EndNodeOffset == FreedNodeOffset) {
279 /* If the freed node is adjacent to the first node in the list, concatenate both nodes */
280 AllocNodePtr->BufferSize += FreedNodePtr->BufferSize;
281 AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000282
Kerry Shehf03360f2012-01-19 13:25:55 +0800283 /* Clear the BufferSize and NextNodeOffset of the previous first node */
284 FreedNodePtr->BufferSize = 0;
285 FreedNodePtr->NextNodeOffset = 0;
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 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000309
Kerry Shehf03360f2012-01-19 13:25:55 +0800310 /* 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;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000317
Kerry Shehf03360f2012-01-19 13:25:55 +0800318 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 AllocNodePtr->BufferSize = 0;
333 AllocNodePtr->NextNodeOffset = 0;
334 } else {
335 PrevNodePtr->NextNodeOffset = AllocNodeOffset;
336 }
337 }
338 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000339}
340
341AGESA_STATUS BiosLocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
342{
Kerry Shehf03360f2012-01-19 13:25:55 +0800343 UINT32 AllocNodeOffset;
344 UINT8 *BiosHeapBaseAddr;
345 BIOS_BUFFER_NODE *AllocNodePtr;
346 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
347 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000348
Kerry Shehf03360f2012-01-19 13:25:55 +0800349 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000350
Kerry Shehf03360f2012-01-19 13:25:55 +0800351 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
352 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000353
Kerry Shehf03360f2012-01-19 13:25:55 +0800354 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
355 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000356
Kerry Shehf03360f2012-01-19 13:25:55 +0800357 while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) {
358 if (AllocNodePtr->NextNodeOffset == 0) {
359 AllocParams->BufferPointer = NULL;
360 AllocParams->BufferLength = 0;
361 return AGESA_BOUNDS_CHK;
362 } else {
363 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
364 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
365 }
366 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000367
Kerry Shehf03360f2012-01-19 13:25:55 +0800368 AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE));
369 AllocParams->BufferLength = AllocNodePtr->BufferSize;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000370
Kerry Shehf03360f2012-01-19 13:25:55 +0800371 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000372
373}
374
375AGESA_STATUS BiosRunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
376{
Kerry Shehf03360f2012-01-19 13:25:55 +0800377 AGESA_STATUS Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000378
Kerry Sheh01f7ab92012-01-19 13:18:36 +0800379 Status = agesawrapper_amdlaterunaptask (Func, Data, ConfigPtr);
Kerry Shehf03360f2012-01-19 13:25:55 +0800380 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000381}
382
383AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
384{
Kerry Shehf03360f2012-01-19 13:25:55 +0800385 AGESA_STATUS Status;
386 UINT8 Value;
387 UINTN ResetType;
388 AMD_CONFIG_PARAMS *StdHeader;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700389
Kerry Shehf03360f2012-01-19 13:25:55 +0800390 ResetType = Data;
391 StdHeader = ConfigPtr;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700392
Kerry Shehf03360f2012-01-19 13:25:55 +0800393 //
394 // Perform the RESET based upon the ResetType. In case of
395 // WARM_RESET_WHENVER and COLD_RESET_WHENEVER, the request will go to
396 // AmdResetManager. During the critical condition, where reset is required
397 // immediately, the reset will be invoked directly by writing 0x04 to port
398 // 0xCF9 (Reset Port).
399 //
400 switch (ResetType) {
401 case WARM_RESET_WHENEVER:
402 case COLD_RESET_WHENEVER:
403 break;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700404
Kerry Shehf03360f2012-01-19 13:25:55 +0800405 case WARM_RESET_IMMEDIATELY:
406 case COLD_RESET_IMMEDIATELY:
407 Value = 0x06;
408 LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
409 break;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700410
Kerry Shehf03360f2012-01-19 13:25:55 +0800411 default:
412 break;
413 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700414
Kerry Shehf03360f2012-01-19 13:25:55 +0800415 Status = 0;
416 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000417}
418
419AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
420{
Kerry Shehf03360f2012-01-19 13:25:55 +0800421 AGESA_STATUS Status;
Kerry Sheh01f7ab92012-01-19 13:18:36 +0800422 Status = AmdMemoryReadSPD (Func, Data, (AGESA_READ_SPD_PARAMS *)ConfigPtr);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000423
Kerry Shehf03360f2012-01-19 13:25:55 +0800424 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000425}
426
427AGESA_STATUS BiosDefaultRet (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
428{
Kerry Shehf03360f2012-01-19 13:25:55 +0800429 return AGESA_UNSUPPORTED;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000430}
431/* Call the host environment interface to provide a user hook opportunity. */
432AGESA_STATUS BiosHookBeforeDQSTraining (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
433{
Kerry Shehf03360f2012-01-19 13:25:55 +0800434 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000435}
436/* Call the host environment interface to provide a user hook opportunity. */
437AGESA_STATUS BiosHookBeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
438{
Kerry Shehf03360f2012-01-19 13:25:55 +0800439 AGESA_STATUS Status;
440 UINTN FcnData;
441 MEM_DATA_STRUCT *MemData;
442 UINT32 AcpiMmioAddr;
443 UINT32 GpioMmioAddr;
444 UINT8 Data8;
445 UINT16 Data16;
446 UINT8 TempData8;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700447
Kerry Shehf03360f2012-01-19 13:25:55 +0800448 FcnData = Data;
449 MemData = ConfigPtr;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700450
Kerry Shehf03360f2012-01-19 13:25:55 +0800451 Status = AGESA_SUCCESS;
Kerry Sheh01f7ab92012-01-19 13:18:36 +0800452 /* Get SB MMIO Base (AcpiMmioAddr) */
Kerry Shehf03360f2012-01-19 13:25:55 +0800453 WriteIo8 (0xCD6, 0x27);
454 Data8 = ReadIo8(0xCD7);
455 Data16 = Data8<<8;
456 WriteIo8 (0xCD6, 0x26);
457 Data8 = ReadIo8(0xCD7);
458 Data16 |= Data8;
459 AcpiMmioAddr = (UINT32)Data16 << 16;
460 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700461
Kerry Shehf03360f2012-01-19 13:25:55 +0800462 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG178);
463 Data8 &= ~BIT5;
464 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
465 TempData8 &= 0x03;
466 TempData8 |= Data8;
467 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700468
Kerry Shehf03360f2012-01-19 13:25:55 +0800469 Data8 |= BIT2+BIT3;
470 Data8 &= ~BIT4;
471 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
472 TempData8 &= 0x23;
473 TempData8 |= Data8;
474 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
Kerry Sheh01f7ab92012-01-19 13:18:36 +0800475
Kerry Shehf03360f2012-01-19 13:25:55 +0800476 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);
Kerry Sheh01f7ab92012-01-19 13:18:36 +0800482
Kerry Shehf03360f2012-01-19 13:25:55 +0800483 Data8 |= BIT2+BIT3;
484 Data8 &= ~BIT4;
485 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
486 TempData8 &= 0x23;
487 TempData8 |= Data8;
488 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, TempData8);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700489
Kerry Shehf03360f2012-01-19 13:25:55 +0800490 switch(MemData->ParameterListPtr->DDR3Voltage){
491 case VOLT1_35:
492 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
493 Data8 &= ~(UINT8)BIT6;
494 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
495 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
496 Data8 |= (UINT8)BIT6;
497 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
498 break;
499 case VOLT1_25:
500 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
501 Data8 &= ~(UINT8)BIT6;
502 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
503 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
504 Data8 &= ~(UINT8)BIT6;
505 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
506 break;
507 case VOLT1_5:
508 default:
509 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
510 Data8 |= (UINT8)BIT6;
511 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
512 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
513 Data8 &= ~(UINT8)BIT6;
514 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
515 }
516 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000517}
Kerry Sheh01f7ab92012-01-19 13:18:36 +0800518
519/* Call the host environment interface to provide a user hook opportunity. */
520AGESA_STATUS BiosHookBeforeDramInitRecovery (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
521{
522 return AGESA_SUCCESS;
523}
524
Frank Vibrans69da1b62011-02-14 19:04:45 +0000525/* Call the host environment interface to provide a user hook opportunity. */
526AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
527{
Kerry Shehf03360f2012-01-19 13:25:55 +0800528 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000529}
530/* PCIE slot reset control */
531AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
532{
Kerry Shehf03360f2012-01-19 13:25:55 +0800533 AGESA_STATUS Status;
534 UINTN FcnData;
535 PCIe_SLOT_RESET_INFO *ResetInfo;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700536
Kerry Shehf03360f2012-01-19 13:25:55 +0800537 UINT32 GpioMmioAddr;
538 UINT32 AcpiMmioAddr;
539 UINT8 Data8;
540 UINT16 Data16;
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700541
Kerry Shehf03360f2012-01-19 13:25:55 +0800542 FcnData = Data;
543 ResetInfo = ConfigPtr;
544 // Get SB800 MMIO Base (AcpiMmioAddr)
545 WriteIo8(0xCD6, 0x27);
546 Data8 = ReadIo8(0xCD7);
547 Data16=Data8<<8;
548 WriteIo8(0xCD6, 0x26);
549 Data8 = ReadIo8(0xCD7);
550 Data16|=Data8;
551 AcpiMmioAddr = (UINT32)Data16 << 16;
552 Status = AGESA_UNSUPPORTED;
553 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
554 switch (ResetInfo->ResetId)
555 {
556 case 4:
557 switch (ResetInfo->ResetControl) {
558 case AssertSlotReset:
559 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
560 Data8 &= ~(UINT8)BIT6 ;
561 Write64Mem8(GpioMmioAddr+SB_GPIO_REG21, Data8); // MXM_GPIO0. GPIO21
562 Status = AGESA_SUCCESS;
563 break;
564 case DeassertSlotReset:
565 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
566 Data8 |= BIT6 ;
567 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG21, Data8); // MXM_GPIO0. GPIO21
568 Status = AGESA_SUCCESS;
569 break;
570 }
571 break;
572 case 6:
573 switch (ResetInfo->ResetControl) {
574 case AssertSlotReset:
575 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
576 Data8 &= ~(UINT8)BIT6 ;
577 Write64Mem8(GpioMmioAddr+SB_GPIO_REG25, Data8); // PCIE_RST#_LAN, GPIO25
578 Status = AGESA_SUCCESS;
579 break;
580 case DeassertSlotReset:
581 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
582 Data8 |= BIT6 ;
583 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG25, Data8); // PCIE_RST#_LAN, GPIO25
584 Status = AGESA_SUCCESS;
585 break;
586 }
587 break;
588 case 7:
589 switch (ResetInfo->ResetControl) {
590 case AssertSlotReset:
591 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG02);
592 Data8 &= ~(UINT8)BIT6 ;
593 Write64Mem8(GpioMmioAddr+SB_GPIO_REG02, Data8); // MPCIE_RST0, GPIO02
594 Status = AGESA_SUCCESS;
595 break;
596 case DeassertSlotReset:
Jens Rottmannf87855c2013-02-18 18:56:48 +0100597 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG02);
Kerry Shehf03360f2012-01-19 13:25:55 +0800598 Data8 |= BIT6 ;
599 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG02, Data8); // MPCIE_RST0, GPIO02
600 Status = AGESA_SUCCESS;
601 break;
602 }
603 break;
604 }
605 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000606}