blob: 4db6e753eea568c2b50ef5018136918ceffdff48 [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
Marc Jones36abff12011-11-07 23:26:14 -070012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Frank Vibrans69da1b62011-02-14 19:04:45 +000013 * 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
Marc Jones36abff12011-11-07 23:26:14 -070017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Frank Vibrans69da1b62011-02-14 19:04:45 +000018 */
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{
Marc Jones36abff12011-11-07 23:26:14 -070029 {AGESA_ALLOCATE_BUFFER,
30 BiosAllocateBuffer
31 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000032
Marc Jones36abff12011-11-07 23:26:14 -070033 {AGESA_DEALLOCATE_BUFFER,
34 BiosDeallocateBuffer
35 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000036
Marc Jones36abff12011-11-07 23:26:14 -070037 {AGESA_DO_RESET,
38 BiosReset
39 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000040
Marc Jones36abff12011-11-07 23:26:14 -070041 {AGESA_LOCATE_BUFFER,
42 BiosLocateBuffer
43 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000044
Marc Jones36abff12011-11-07 23:26:14 -070045 {AGESA_READ_SPD,
46 BiosReadSpd
47 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000048
Marc Jones36abff12011-11-07 23:26:14 -070049 {AGESA_READ_SPD_RECOVERY,
50 BiosDefaultRet
51 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000052
Marc Jones36abff12011-11-07 23:26:14 -070053 {AGESA_RUNFUNC_ONAP,
54 BiosRunFuncOnAp
55 },
Frank Vibrans69da1b62011-02-14 19:04:45 +000056
Marc Jones36abff12011-11-07 23:26:14 -070057 {AGESA_GNB_PCIE_SLOT_RESET,
58 BiosGnbPcieSlotReset
59 },
efdesign98d7a696d2011-09-15 15:24:26 -060060
Marc Jones36abff12011-11-07 23:26:14 -070061 {AGESA_HOOKBEFORE_DRAM_INIT,
62 BiosHookBeforeDramInit
63 },
efdesign98d7a696d2011-09-15 15:24:26 -060064
Marc Jones36abff12011-11-07 23:26:14 -070065 {AGESA_HOOKBEFORE_DRAM_INIT_RECOVERY,
66 BiosHookBeforeDramInitRecovery
67 },
efdesign98d7a696d2011-09-15 15:24:26 -060068
Marc Jones36abff12011-11-07 23:26:14 -070069 {AGESA_HOOKBEFORE_DQS_TRAINING,
70 BiosHookBeforeDQSTraining
71 },
efdesign98d7a696d2011-09-15 15:24:26 -060072
Marc Jones36abff12011-11-07 23:26:14 -070073 {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{
Marc Jones36abff12011-11-07 23:26:14 -070080 UINTN i;
81 AGESA_STATUS CalloutStatus;
82 UINTN CallOutCount = sizeof (BiosCallouts) / sizeof (BiosCallouts [0]);
efdesign98d7a696d2011-09-15 15:24:26 -060083
zbaoafd141d2012-03-30 15:32:07 +080084 /*
85 * printk(BIOS_SPEW,"%s function: %x\n", __func__, (u32) Func);
86 */
87
Marc Jones36abff12011-11-07 23:26:14 -070088 CalloutStatus = AGESA_UNSUPPORTED;
efdesign98d7a696d2011-09-15 15:24:26 -060089
Marc Jones36abff12011-11-07 23:26:14 -070090 for (i = 0; i < CallOutCount; i++) {
91 if (BiosCallouts[i].CalloutName == Func) {
92 CalloutStatus = BiosCallouts[i].CalloutPtr (Func, Data, ConfigPtr);
93 return CalloutStatus;
94 }
95 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -070096
Marc Jones36abff12011-11-07 23:26:14 -070097 return CalloutStatus;
Frank Vibrans69da1b62011-02-14 19:04:45 +000098}
99
100AGESA_STATUS BiosAllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
101{
zbaoafd141d2012-03-30 15:32:07 +0800102 UINT32 AvailableHeapSize;
103 UINT8 *BiosHeapBaseAddr;
104 UINT32 CurrNodeOffset;
105 UINT32 PrevNodeOffset;
106 UINT32 FreedNodeOffset;
107 UINT32 BestFitNodeOffset;
108 UINT32 BestFitPrevNodeOffset;
109 UINT32 NextFreeOffset;
110 BIOS_BUFFER_NODE *CurrNodePtr;
111 BIOS_BUFFER_NODE *FreedNodePtr;
112 BIOS_BUFFER_NODE *BestFitNodePtr;
113 BIOS_BUFFER_NODE *BestFitPrevNodePtr;
114 BIOS_BUFFER_NODE *NextFreePtr;
115 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
Marc Jones36abff12011-11-07 23:26:14 -0700116 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000117
Marc Jones36abff12011-11-07 23:26:14 -0700118 AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr);
119 AllocParams->BufferPointer = NULL;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000120
Marc Jones36abff12011-11-07 23:26:14 -0700121 AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER);
zbaof543c7b2012-04-13 13:42:46 +0800122 BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
123 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
124
125 printk(BIOS_SPEW, "%s BiosHeapBaseAddr: %x\n", __func__, (u32) BiosHeapBaseAddr);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000126
Marc Jones36abff12011-11-07 23:26:14 -0700127 if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) {
128 /* First allocation */
129 CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER);
130 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
131 CurrNodePtr->BufferHandle = AllocParams->BufferHandle;
132 CurrNodePtr->BufferSize = AllocParams->BufferLength;
133 CurrNodePtr->NextNodeOffset = 0;
134 AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000135
Marc Jones36abff12011-11-07 23:26:14 -0700136 /* Update the remaining free space */
137 FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE);
138 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
139 FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize;
140 FreedNodePtr->NextNodeOffset = 0;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000141
Marc Jones36abff12011-11-07 23:26:14 -0700142 /* Update the offsets for Allocated and Freed nodes */
143 BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset;
144 BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset;
145 } else {
146 /* Find out whether BufferHandle has been allocated on the heap. */
147 /* If it has, return AGESA_BOUNDS_CHK */
148 CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
149 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000150
Marc Jones36abff12011-11-07 23:26:14 -0700151 while (CurrNodeOffset != 0) {
152 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
153 if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) {
154 return AGESA_BOUNDS_CHK;
155 }
156 CurrNodeOffset = CurrNodePtr->NextNodeOffset;
157 /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points
zbaoafd141d2012-03-30 15:32:07 +0800158 to the end of the allocated nodes list.
Marc Jones36abff12011-11-07 23:26:14 -0700159 */
zbaoafd141d2012-03-30 15:32:07 +0800160
Marc Jones36abff12011-11-07 23:26:14 -0700161 }
162 /* Find the node that best fits the requested buffer size */
163 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
164 PrevNodeOffset = FreedNodeOffset;
165 BestFitNodeOffset = 0;
166 BestFitPrevNodeOffset = 0;
167 while (FreedNodeOffset != 0) {
168 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
169 if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
170 if (BestFitNodeOffset == 0) {
171 /* First node that fits the requested buffer size */
172 BestFitNodeOffset = FreedNodeOffset;
173 BestFitPrevNodeOffset = PrevNodeOffset;
174 } else {
175 /* Find out whether current node is a better fit than the previous nodes */
176 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
177 if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) {
178 BestFitNodeOffset = FreedNodeOffset;
179 BestFitPrevNodeOffset = PrevNodeOffset;
180 }
181 }
182 }
183 PrevNodeOffset = FreedNodeOffset;
184 FreedNodeOffset = FreedNodePtr->NextNodeOffset;
185 } /* end of while loop */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000186
187
Marc Jones36abff12011-11-07 23:26:14 -0700188 if (BestFitNodeOffset == 0) {
189 /* If we could not find a node that fits the requested buffer */
190 /* size, return AGESA_BOUNDS_CHK */
191 return AGESA_BOUNDS_CHK;
192 } else {
193 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
194 BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000195
Marc Jones36abff12011-11-07 23:26:14 -0700196 /* If BestFitNode is larger than the requested buffer, fragment the node further */
197 if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
198 NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000199
Marc Jones36abff12011-11-07 23:26:14 -0700200 NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset);
201 NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE));
202 NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset;
203 } else {
204 /* Otherwise, next free node is NextNodeOffset of BestFitNode */
205 NextFreeOffset = BestFitNodePtr->NextNodeOffset;
206 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000207
Marc Jones36abff12011-11-07 23:26:14 -0700208 /* If BestFitNode is the first buffer in the list, then update
zbaoafd141d2012-03-30 15:32:07 +0800209 StartOfFreedNodes to reflect the new free node
Marc Jones36abff12011-11-07 23:26:14 -0700210 */
211 if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) {
212 BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset;
213 } else {
214 BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset;
215 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000216
Marc Jones36abff12011-11-07 23:26:14 -0700217 /* Add BestFitNode to the list of Allocated nodes */
218 CurrNodePtr->NextNodeOffset = BestFitNodeOffset;
219 BestFitNodePtr->BufferSize = AllocParams->BufferLength;
220 BestFitNodePtr->BufferHandle = AllocParams->BufferHandle;
221 BestFitNodePtr->NextNodeOffset = 0;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000222
Marc Jones36abff12011-11-07 23:26:14 -0700223 /* Remove BestFitNode from list of Freed nodes */
224 AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE);
225 }
226 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000227
Marc Jones36abff12011-11-07 23:26:14 -0700228 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000229}
230
231AGESA_STATUS BiosDeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
232{
233
zbaof543c7b2012-04-13 13:42:46 +0800234 UINT8 *BiosHeapBaseAddr;
235 UINT32 AllocNodeOffset;
236 UINT32 PrevNodeOffset;
237 UINT32 NextNodeOffset;
238 UINT32 FreedNodeOffset;
239 UINT32 EndNodeOffset;
240 BIOS_BUFFER_NODE *AllocNodePtr;
241 BIOS_BUFFER_NODE *PrevNodePtr;
242 BIOS_BUFFER_NODE *FreedNodePtr;
243 BIOS_BUFFER_NODE *NextNodePtr;
244 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
Marc Jones36abff12011-11-07 23:26:14 -0700245 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000246
Marc Jones36abff12011-11-07 23:26:14 -0700247 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000248
zbaof543c7b2012-04-13 13:42:46 +0800249 BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
250 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
251
Marc Jones36abff12011-11-07 23:26:14 -0700252 /* Find target node to deallocate in list of allocated nodes.
zbaof543c7b2012-04-13 13:42:46 +0800253 Return AGESA_BOUNDS_CHK if the BufferHandle is not found
Marc Jones36abff12011-11-07 23:26:14 -0700254 */
255 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
256 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
257 PrevNodeOffset = AllocNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000258
zbaoafd141d2012-03-30 15:32:07 +0800259 while (AllocNodePtr->BufferHandle != AllocParams->BufferHandle) {
Marc Jones36abff12011-11-07 23:26:14 -0700260 if (AllocNodePtr->NextNodeOffset == 0) {
261 return AGESA_BOUNDS_CHK;
262 }
263 PrevNodeOffset = AllocNodeOffset;
264 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
265 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
266 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000267
Marc Jones36abff12011-11-07 23:26:14 -0700268 /* Remove target node from list of allocated nodes */
269 PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
270 PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000271
Marc Jones36abff12011-11-07 23:26:14 -0700272 /* Zero out the buffer, and clear the BufferHandle */
273 LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader));
274 AllocNodePtr->BufferHandle = 0;
275 AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000276
Marc Jones36abff12011-11-07 23:26:14 -0700277 /* Add deallocated node in order to the list of freed nodes */
278 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
279 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000280
Marc Jones36abff12011-11-07 23:26:14 -0700281 EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000282
Marc Jones36abff12011-11-07 23:26:14 -0700283 if (AllocNodeOffset < FreedNodeOffset) {
284 /* Add to the start of the freed list */
285 if (EndNodeOffset == FreedNodeOffset) {
286 /* If the freed node is adjacent to the first node in the list, concatenate both nodes */
287 AllocNodePtr->BufferSize += FreedNodePtr->BufferSize;
288 AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000289
Marc Jones36abff12011-11-07 23:26:14 -0700290 /* Clear the BufferSize and NextNodeOffset of the previous first node */
291 FreedNodePtr->BufferSize = 0;
292 FreedNodePtr->NextNodeOffset = 0;
zbaoafd141d2012-03-30 15:32:07 +0800293
Marc Jones36abff12011-11-07 23:26:14 -0700294 } else {
295 /* Otherwise, add freed node to the start of the list
zbaoafd141d2012-03-30 15:32:07 +0800296 Update NextNodeOffset and BufferSize to include the
297 size of BIOS_BUFFER_NODE
Marc Jones36abff12011-11-07 23:26:14 -0700298 */
299 AllocNodePtr->NextNodeOffset = FreedNodeOffset;
300 }
301 /* Update StartOfFreedNodes to the new first node */
302 BiosHeapBasePtr->StartOfFreedNodes = AllocNodeOffset;
303 } else {
304 /* Traverse list of freed nodes to find where the deallocated node
zbaoafd141d2012-03-30 15:32:07 +0800305 should be place
Marc Jones36abff12011-11-07 23:26:14 -0700306 */
307 NextNodeOffset = FreedNodeOffset;
308 NextNodePtr = FreedNodePtr;
309 while (AllocNodeOffset > NextNodeOffset) {
310 PrevNodeOffset = NextNodeOffset;
311 if (NextNodePtr->NextNodeOffset == 0) {
zbaoafd141d2012-03-30 15:32:07 +0800312 break;
Marc Jones36abff12011-11-07 23:26:14 -0700313 }
314 NextNodeOffset = NextNodePtr->NextNodeOffset;
315 NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
316 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000317
Marc Jones36abff12011-11-07 23:26:14 -0700318 /* If deallocated node is adjacent to the next node,
zbaoafd141d2012-03-30 15:32:07 +0800319 concatenate both nodes
Marc Jones36abff12011-11-07 23:26:14 -0700320 */
321 if (NextNodeOffset == EndNodeOffset) {
322 NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
323 AllocNodePtr->BufferSize += NextNodePtr->BufferSize;
324 AllocNodePtr->NextNodeOffset = NextNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000325
Marc Jones36abff12011-11-07 23:26:14 -0700326 NextNodePtr->BufferSize = 0;
327 NextNodePtr->NextNodeOffset = 0;
328 } else {
329 /*AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; */
330 AllocNodePtr->NextNodeOffset = NextNodeOffset;
331 }
332 /* If deallocated node is adjacent to the previous node,
zbaoafd141d2012-03-30 15:32:07 +0800333 concatenate both nodes
Marc Jones36abff12011-11-07 23:26:14 -0700334 */
335 PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
336 EndNodeOffset = PrevNodeOffset + PrevNodePtr->BufferSize;
337 if (AllocNodeOffset == EndNodeOffset) {
338 PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
339 PrevNodePtr->BufferSize += AllocNodePtr->BufferSize;
zbaoafd141d2012-03-30 15:32:07 +0800340
Marc Jones36abff12011-11-07 23:26:14 -0700341 AllocNodePtr->BufferSize = 0;
342 AllocNodePtr->NextNodeOffset = 0;
343 } else {
344 PrevNodePtr->NextNodeOffset = AllocNodeOffset;
345 }
346 }
347 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000348}
349
350AGESA_STATUS BiosLocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
351{
Marc Jones36abff12011-11-07 23:26:14 -0700352 UINT32 AllocNodeOffset;
353 UINT8 *BiosHeapBaseAddr;
354 BIOS_BUFFER_NODE *AllocNodePtr;
355 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
356 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000357
Marc Jones36abff12011-11-07 23:26:14 -0700358 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000359
zbaof543c7b2012-04-13 13:42:46 +0800360 BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
361 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000362
Marc Jones36abff12011-11-07 23:26:14 -0700363 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
364 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000365
Marc Jones36abff12011-11-07 23:26:14 -0700366 while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) {
367 if (AllocNodePtr->NextNodeOffset == 0) {
368 AllocParams->BufferPointer = NULL;
369 AllocParams->BufferLength = 0;
370 return AGESA_BOUNDS_CHK;
371 } else {
372 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
373 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
374 }
375 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000376
Marc Jones36abff12011-11-07 23:26:14 -0700377 AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE));
378 AllocParams->BufferLength = AllocNodePtr->BufferSize;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000379
Marc Jones36abff12011-11-07 23:26:14 -0700380 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000381
382}
383
384AGESA_STATUS BiosRunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
385{
Marc Jones36abff12011-11-07 23:26:14 -0700386 AGESA_STATUS Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000387
Marc Jones36abff12011-11-07 23:26:14 -0700388 Status = agesawrapper_amdlaterunaptask (Func, Data, ConfigPtr);
389 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000390}
391
392AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
393{
Marc Jones36abff12011-11-07 23:26:14 -0700394 AGESA_STATUS Status;
395 UINT8 Value;
396 UINTN ResetType;
397 AMD_CONFIG_PARAMS *StdHeader;
efdesign98d7a696d2011-09-15 15:24:26 -0600398
Marc Jones36abff12011-11-07 23:26:14 -0700399 ResetType = Data;
400 StdHeader = ConfigPtr;
efdesign98d7a696d2011-09-15 15:24:26 -0600401
Marc Jones36abff12011-11-07 23:26:14 -0700402 //
403 // Perform the RESET based upon the ResetType. In case of
404 // WARM_RESET_WHENVER and COLD_RESET_WHENEVER, the request will go to
405 // AmdResetManager. During the critical condition, where reset is required
406 // immediately, the reset will be invoked directly by writing 0x04 to port
407 // 0xCF9 (Reset Port).
408 //
409 switch (ResetType) {
zbaoafd141d2012-03-30 15:32:07 +0800410 case WARM_RESET_WHENEVER:
411 case COLD_RESET_WHENEVER:
Marc Jones36abff12011-11-07 23:26:14 -0700412 break;
efdesign98d7a696d2011-09-15 15:24:26 -0600413
zbaoafd141d2012-03-30 15:32:07 +0800414 case WARM_RESET_IMMEDIATELY:
415 case COLD_RESET_IMMEDIATELY:
416 Value = 0x06;
417 LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
Marc Jones36abff12011-11-07 23:26:14 -0700418 break;
efdesign98d7a696d2011-09-15 15:24:26 -0600419
zbaoafd141d2012-03-30 15:32:07 +0800420 default:
Marc Jones36abff12011-11-07 23:26:14 -0700421 break;
422 }
efdesign98d7a696d2011-09-15 15:24:26 -0600423
Marc Jones36abff12011-11-07 23:26:14 -0700424 Status = 0;
425 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000426}
427
428AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
429{
Marc Jones36abff12011-11-07 23:26:14 -0700430 AGESA_STATUS Status;
431 Status = AmdMemoryReadSPD (Func, Data, (AGESA_READ_SPD_PARAMS *)ConfigPtr);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000432
Marc Jones36abff12011-11-07 23:26:14 -0700433 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000434}
435
436AGESA_STATUS BiosDefaultRet (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
437{
Marc Jones36abff12011-11-07 23:26:14 -0700438 return AGESA_UNSUPPORTED;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000439}
Marc Jones36abff12011-11-07 23:26:14 -0700440/* Call the host environment interface to provide a user hook opportunity. */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000441AGESA_STATUS BiosHookBeforeDQSTraining (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
442{
Marc Jones36abff12011-11-07 23:26:14 -0700443 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000444}
Marc Jones36abff12011-11-07 23:26:14 -0700445/* Call the host environment interface to provide a user hook opportunity. */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000446AGESA_STATUS BiosHookBeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
447{
Jens Rottmann384ee9f2013-02-18 20:26:50 +0100448 // Unlike e.g. AMD Inagua, Persimmon is unable to vary the RAM voltage.
449 // Make sure the right speed settings are selected.
450 ((MEM_DATA_STRUCT*)ConfigPtr)->ParameterListPtr->DDR3Voltage = VOLT1_5;
451 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000452}
efdesign98d7a696d2011-09-15 15:24:26 -0600453
Marc Jones36abff12011-11-07 23:26:14 -0700454/* Call the host environment interface to provide a user hook opportunity. */
efdesign98d7a696d2011-09-15 15:24:26 -0600455AGESA_STATUS BiosHookBeforeDramInitRecovery (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
456{
Marc Jones36abff12011-11-07 23:26:14 -0700457 return AGESA_SUCCESS;
efdesign98d7a696d2011-09-15 15:24:26 -0600458}
459
Marc Jones36abff12011-11-07 23:26:14 -0700460/* Call the host environment interface to provide a user hook opportunity. */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000461AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
462{
Marc Jones36abff12011-11-07 23:26:14 -0700463 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000464}
465/* PCIE slot reset control */
466AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
467{
Marc Jones36abff12011-11-07 23:26:14 -0700468 AGESA_STATUS Status;
469 UINTN FcnData;
470 PCIe_SLOT_RESET_INFO *ResetInfo;
efdesign98d7a696d2011-09-15 15:24:26 -0600471
Marc Jones36abff12011-11-07 23:26:14 -0700472 UINT32 GpioMmioAddr;
473 UINT32 AcpiMmioAddr;
474 UINT8 Data8;
475 UINT16 Data16;
efdesign98d7a696d2011-09-15 15:24:26 -0600476
Marc Jones36abff12011-11-07 23:26:14 -0700477 FcnData = Data;
478 ResetInfo = ConfigPtr;
479 // Get SB800 MMIO Base (AcpiMmioAddr)
480 WriteIo8(0xCD6, 0x27);
481 Data8 = ReadIo8(0xCD7);
482 Data16=Data8<<8;
483 WriteIo8(0xCD6, 0x26);
484 Data8 = ReadIo8(0xCD7);
485 Data16|=Data8;
486 AcpiMmioAddr = (UINT32)Data16 << 16;
487 Status = AGESA_UNSUPPORTED;
488 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
489 switch (ResetInfo->ResetId)
490 {
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100491 case 46: // GPIO50 = SBGPIO_PCIE_RST# affects LAN0, LAN1, PCIe slot
Marc Jones36abff12011-11-07 23:26:14 -0700492 switch (ResetInfo->ResetControl) {
zbaoafd141d2012-03-30 15:32:07 +0800493 case AssertSlotReset:
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100494 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG50);
Marc Jones36abff12011-11-07 23:26:14 -0700495 Data8 &= ~(UINT8)BIT6 ;
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100496 Write64Mem8(GpioMmioAddr+SB_GPIO_REG50, Data8);
Marc Jones36abff12011-11-07 23:26:14 -0700497 Status = AGESA_SUCCESS;
498 break;
zbaoafd141d2012-03-30 15:32:07 +0800499 case DeassertSlotReset:
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100500 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG50);
Marc Jones36abff12011-11-07 23:26:14 -0700501 Data8 |= BIT6 ;
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100502 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG50, Data8);
Marc Jones36abff12011-11-07 23:26:14 -0700503 Status = AGESA_SUCCESS;
504 break;
505 }
506 break;
507 }
508 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000509}