blob: 0711d96f17ac1482563f2f11b7a60c84f0f0fb99 [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{
Marc Jones36abff12011-11-07 23:26:14 -0700448 AGESA_STATUS Status;
449 UINTN FcnData;
450 MEM_DATA_STRUCT *MemData;
451 UINT32 AcpiMmioAddr;
452 UINT32 GpioMmioAddr;
453 UINT8 Data8;
454 UINT16 Data16;
455 UINT8 TempData8;
efdesign98d7a696d2011-09-15 15:24:26 -0600456
Marc Jones36abff12011-11-07 23:26:14 -0700457 FcnData = Data;
458 MemData = ConfigPtr;
efdesign98d7a696d2011-09-15 15:24:26 -0600459
Marc Jones36abff12011-11-07 23:26:14 -0700460 Status = AGESA_SUCCESS;
461 /* Get SB MMIO Base (AcpiMmioAddr) */
462 WriteIo8 (0xCD6, 0x27);
463 Data8 = ReadIo8(0xCD7);
464 Data16 = Data8<<8;
465 WriteIo8 (0xCD6, 0x26);
466 Data8 = ReadIo8(0xCD7);
467 Data16 |= Data8;
468 AcpiMmioAddr = (UINT32)Data16 << 16;
469 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
efdesign98d7a696d2011-09-15 15:24:26 -0600470
Marc Jones36abff12011-11-07 23:26:14 -0700471 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG178);
472 Data8 &= ~BIT5;
473 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
474 TempData8 &= 0x03;
475 TempData8 |= Data8;
476 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700477
Marc Jones36abff12011-11-07 23:26:14 -0700478 Data8 |= BIT2+BIT3;
479 Data8 &= ~BIT4;
480 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
481 TempData8 &= 0x23;
482 TempData8 |= Data8;
483 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
efdesign98d7a696d2011-09-15 15:24:26 -0600484
Marc Jones36abff12011-11-07 23:26:14 -0700485 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG179);
486 Data8 &= ~BIT5;
487 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
488 TempData8 &= 0x03;
489 TempData8 |= Data8;
490 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, TempData8);
efdesign98d7a696d2011-09-15 15:24:26 -0600491
Marc Jones36abff12011-11-07 23:26:14 -0700492 Data8 |= BIT2+BIT3;
493 Data8 &= ~BIT4;
494 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
495 TempData8 &= 0x23;
496 TempData8 |= Data8;
497 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, TempData8);
efdesign98d7a696d2011-09-15 15:24:26 -0600498
Marc Jones36abff12011-11-07 23:26:14 -0700499 switch(MemData->ParameterListPtr->DDR3Voltage){
500 case VOLT1_35:
501 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
502 Data8 &= ~(UINT8)BIT6;
503 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
504 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
505 Data8 |= (UINT8)BIT6;
506 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
507 break;
508 case VOLT1_25:
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 break;
516 case VOLT1_5:
517 default:
518 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
519 Data8 |= (UINT8)BIT6;
520 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
521 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
522 Data8 &= ~(UINT8)BIT6;
523 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
524 }
525 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000526}
efdesign98d7a696d2011-09-15 15:24:26 -0600527
Marc Jones36abff12011-11-07 23:26:14 -0700528/* Call the host environment interface to provide a user hook opportunity. */
efdesign98d7a696d2011-09-15 15:24:26 -0600529AGESA_STATUS BiosHookBeforeDramInitRecovery (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
530{
Marc Jones36abff12011-11-07 23:26:14 -0700531 return AGESA_SUCCESS;
efdesign98d7a696d2011-09-15 15:24:26 -0600532}
533
Marc Jones36abff12011-11-07 23:26:14 -0700534/* Call the host environment interface to provide a user hook opportunity. */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000535AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
536{
Marc Jones36abff12011-11-07 23:26:14 -0700537 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000538}
539/* PCIE slot reset control */
540AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
541{
Marc Jones36abff12011-11-07 23:26:14 -0700542 AGESA_STATUS Status;
543 UINTN FcnData;
544 PCIe_SLOT_RESET_INFO *ResetInfo;
efdesign98d7a696d2011-09-15 15:24:26 -0600545
Marc Jones36abff12011-11-07 23:26:14 -0700546 UINT32 GpioMmioAddr;
547 UINT32 AcpiMmioAddr;
548 UINT8 Data8;
549 UINT16 Data16;
efdesign98d7a696d2011-09-15 15:24:26 -0600550
Marc Jones36abff12011-11-07 23:26:14 -0700551 FcnData = Data;
552 ResetInfo = ConfigPtr;
553 // Get SB800 MMIO Base (AcpiMmioAddr)
554 WriteIo8(0xCD6, 0x27);
555 Data8 = ReadIo8(0xCD7);
556 Data16=Data8<<8;
557 WriteIo8(0xCD6, 0x26);
558 Data8 = ReadIo8(0xCD7);
559 Data16|=Data8;
560 AcpiMmioAddr = (UINT32)Data16 << 16;
561 Status = AGESA_UNSUPPORTED;
562 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
563 switch (ResetInfo->ResetId)
564 {
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100565 case 46: // GPIO50 = SBGPIO_PCIE_RST# affects LAN0, LAN1, PCIe slot
Marc Jones36abff12011-11-07 23:26:14 -0700566 switch (ResetInfo->ResetControl) {
zbaoafd141d2012-03-30 15:32:07 +0800567 case AssertSlotReset:
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100568 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG50);
Marc Jones36abff12011-11-07 23:26:14 -0700569 Data8 &= ~(UINT8)BIT6 ;
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100570 Write64Mem8(GpioMmioAddr+SB_GPIO_REG50, Data8);
Marc Jones36abff12011-11-07 23:26:14 -0700571 Status = AGESA_SUCCESS;
572 break;
zbaoafd141d2012-03-30 15:32:07 +0800573 case DeassertSlotReset:
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100574 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG50);
Marc Jones36abff12011-11-07 23:26:14 -0700575 Data8 |= BIT6 ;
Jens Rottmannfa8702c2013-02-18 19:40:33 +0100576 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG50, Data8);
Marc Jones36abff12011-11-07 23:26:14 -0700577 Status = AGESA_SUCCESS;
578 break;
579 }
580 break;
581 }
582 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000583}