blob: b7f012403439fc85ad5bdfb1704e5582e6ab4001 [file] [log] [blame]
efdesign9895b66112011-07-20 13:23:04 -06001/*
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 */
19
20#include "agesawrapper.h"
21#include "amdlib.h"
22#include "BiosCallOuts.h"
23#include "Ids.h"
24#include "OptionsIds.h"
25#include "heapManager.h"
26
27STATIC BIOS_CALLOUT_STRUCT BiosCallouts[REQUIRED_CALLOUTS] =
28{
29 {
30 AGESA_ALLOCATE_BUFFER,
31 BiosAllocateBuffer
32 },
33
34 {
35 AGESA_DEALLOCATE_BUFFER,
36 BiosDeallocateBuffer
37 },
38
39 {
40 AGESA_DO_RESET,
41 BiosReset
42 },
43
44 {
45 AGESA_LOCATE_BUFFER,
46 BiosLocateBuffer
47 },
48
49 {
50 AGESA_READ_SPD,
51 BiosReadSpd
52 },
53
54 {
55 AGESA_READ_SPD_RECOVERY,
56 BiosDefaultRet
57 },
58
59 {
60 AGESA_RUNFUNC_ONAP,
61 BiosRunFuncOnAp
62 },
63
64 {
65 AGESA_GET_IDS_INIT_DATA,
66 BiosGetIdsInitData
67 },
68
69 {
70 AGESA_HOOKBEFORE_DQS_TRAINING,
71 BiosHookBeforeDQSTraining
72 },
73
74 {
75 AGESA_HOOKBEFORE_DRAM_INIT,
76 BiosHookBeforeDramInit
77 },
78 {
79 AGESA_HOOKBEFORE_EXIT_SELF_REF,
80 BiosHookBeforeExitSelfRefresh
81 },
82};
83
84extern AGESA_STATUS AmdMemoryReadSPD (UINT32 unused1, UINT32 unused2, AGESA_READ_SPD_PARAMS *info);
85
86AGESA_STATUS GetBiosCallout (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
87{
88 UINTN i;
89 AGESA_STATUS CalloutStatus;
90
91 for (i = 0; i < REQUIRED_CALLOUTS; i++) {
92 if (BiosCallouts[i].CalloutName == Func) {
93 break;
94 }
95 }
96
97 if(i >= REQUIRED_CALLOUTS) {
98 return AGESA_UNSUPPORTED;
99 }
100
101 CalloutStatus = BiosCallouts[i].CalloutPtr (Func, Data, ConfigPtr);
102
103 return CalloutStatus;
104}
105
106
107CONST IDS_NV_ITEM IdsData[] =
108{
109 /*{
110 AGESA_IDS_NV_MAIN_PLL_CON,
111 0x1
112 },
113 {
114 AGESA_IDS_NV_MAIN_PLL_FID_EN,
115 0x1
116 },
117 {
118 AGESA_IDS_NV_MAIN_PLL_FID,
119 0x8
120 },
121
122 {
123 AGESA_IDS_NV_CUSTOM_NB_PSTATE,
124 },
125 {
126 AGESA_IDS_NV_CUSTOM_NB_P0_DIV_CTRL,
127 },
128 {
129 AGESA_IDS_NV_CUSTOM_NB_P1_DIV_CTRL,
130 },
131 {
132 AGESA_IDS_NV_FORCE_NB_PSTATE,
133 },
134 */
135 {
136 0xFFFF,
137 0xFFFF
138 }
139};
140
141#define NUM_IDS_ENTRIES (sizeof (IdsData) / sizeof (IDS_NV_ITEM))
142
143AGESA_STATUS BiosGetIdsInitData (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
144{
145 UINTN i;
146 IDS_NV_ITEM *IdsPtr;
147
148 IdsPtr = ((IDS_CALLOUT_STRUCT *) ConfigPtr)->IdsNvPtr;
149
150 if (Data == IDS_CALLOUT_INIT) {
151 for (i = 0; i < NUM_IDS_ENTRIES; i++) {
152 IdsPtr[i].IdsNvValue = IdsData[i].IdsNvValue;
153 IdsPtr[i].IdsNvId = IdsData[i].IdsNvId;
154 }
155 }
156 return AGESA_SUCCESS;
157}
158
159
160AGESA_STATUS BiosAllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
161{
162 UINT32 AvailableHeapSize;
163 UINT8 *BiosHeapBaseAddr;
164 UINT32 CurrNodeOffset;
165 UINT32 PrevNodeOffset;
166 UINT32 FreedNodeOffset;
167 UINT32 BestFitNodeOffset;
168 UINT32 BestFitPrevNodeOffset;
169 UINT32 NextFreeOffset;
170 BIOS_BUFFER_NODE *CurrNodePtr;
171 BIOS_BUFFER_NODE *FreedNodePtr;
172 BIOS_BUFFER_NODE *BestFitNodePtr;
173 BIOS_BUFFER_NODE *BestFitPrevNodePtr;
174 BIOS_BUFFER_NODE *NextFreePtr;
175 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
176 AGESA_BUFFER_PARAMS *AllocParams;
177
178 AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr);
179 AllocParams->BufferPointer = NULL;
180
181 AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER);
182 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
183 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
184
185 if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) {
186 /* First allocation */
187 CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER);
188 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
189 CurrNodePtr->BufferHandle = AllocParams->BufferHandle;
190 CurrNodePtr->BufferSize = AllocParams->BufferLength;
191 CurrNodePtr->NextNodeOffset = 0;
192 AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE);
193
194 /* Update the remaining free space */
195 FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE);
196 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
197 FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize;
198 FreedNodePtr->NextNodeOffset = 0;
199
200 /* Update the offsets for Allocated and Freed nodes */
201 BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset;
202 BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset;
203 } else {
204 /* Find out whether BufferHandle has been allocated on the heap. */
205 /* If it has, return AGESA_BOUNDS_CHK */
206 CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
207 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
208
209 while (CurrNodeOffset != 0) {
210 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
211 if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) {
212 return AGESA_BOUNDS_CHK;
213 }
214 CurrNodeOffset = CurrNodePtr->NextNodeOffset;
215 /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points
216 to the end of the allocated nodes list.
217 */
218
219 }
220 /* Find the node that best fits the requested buffer size */
221 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
222 PrevNodeOffset = FreedNodeOffset;
223 BestFitNodeOffset = 0;
224 BestFitPrevNodeOffset = 0;
225 while (FreedNodeOffset != 0) {
226 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
227 if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
228 if (BestFitNodeOffset == 0) {
229 /* First node that fits the requested buffer size */
230 BestFitNodeOffset = FreedNodeOffset;
231 BestFitPrevNodeOffset = PrevNodeOffset;
232 } else {
233 /* Find out whether current node is a better fit than the previous nodes */
234 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
235 if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) {
236 BestFitNodeOffset = FreedNodeOffset;
237 BestFitPrevNodeOffset = PrevNodeOffset;
238 }
239 }
240 }
241 PrevNodeOffset = FreedNodeOffset;
242 FreedNodeOffset = FreedNodePtr->NextNodeOffset;
243 } /* end of while loop */
244
245
246 if (BestFitNodeOffset == 0) {
247 /* If we could not find a node that fits the requested buffer */
248 /* size, return AGESA_BOUNDS_CHK */
249 return AGESA_BOUNDS_CHK;
250 } else {
251 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
252 BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset);
253
254 /* If BestFitNode is larger than the requested buffer, fragment the node further */
255 if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
256 NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE);
257
258 NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset);
259 NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE));
260 NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset;
261 } else {
262 /* Otherwise, next free node is NextNodeOffset of BestFitNode */
263 NextFreeOffset = BestFitNodePtr->NextNodeOffset;
264 }
265
266 /* If BestFitNode is the first buffer in the list, then update
267 StartOfFreedNodes to reflect the new free node
268 */
269 if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) {
270 BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset;
271 } else {
272 BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset;
273 }
274
275 /* Add BestFitNode to the list of Allocated nodes */
276 CurrNodePtr->NextNodeOffset = BestFitNodeOffset;
277 BestFitNodePtr->BufferSize = AllocParams->BufferLength;
278 BestFitNodePtr->BufferHandle = AllocParams->BufferHandle;
279 BestFitNodePtr->NextNodeOffset = 0;
280
281 /* Remove BestFitNode from list of Freed nodes */
282 AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE);
283 }
284 }
285
286 return AGESA_SUCCESS;
287}
288
289AGESA_STATUS BiosDeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
290{
291
292 UINT8 *BiosHeapBaseAddr;
293 UINT32 AllocNodeOffset;
294 UINT32 PrevNodeOffset;
295 UINT32 NextNodeOffset;
296 UINT32 FreedNodeOffset;
297 UINT32 EndNodeOffset;
298 BIOS_BUFFER_NODE *AllocNodePtr;
299 BIOS_BUFFER_NODE *PrevNodePtr;
300 BIOS_BUFFER_NODE *FreedNodePtr;
301 BIOS_BUFFER_NODE *NextNodePtr;
302 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
303 AGESA_BUFFER_PARAMS *AllocParams;
304
305 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
306 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
307
308 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
309
310 /* Find target node to deallocate in list of allocated nodes.
311 Return AGESA_BOUNDS_CHK if the BufferHandle is not found
312 */
313 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
314 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
315 PrevNodeOffset = AllocNodeOffset;
316
317 while (AllocNodePtr->BufferHandle != AllocParams->BufferHandle) {
318 if (AllocNodePtr->NextNodeOffset == 0) {
319 return AGESA_BOUNDS_CHK;
320 }
321 PrevNodeOffset = AllocNodeOffset;
322 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
323 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
324 }
325
326 /* Remove target node from list of allocated nodes */
327 PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
328 PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
329
330 /* Zero out the buffer, and clear the BufferHandle */
331 LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader));
332 AllocNodePtr->BufferHandle = 0;
333 AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE);
334
335 /* Add deallocated node in order to the list of freed nodes */
336 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
337 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
338
339 EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize;
340
341 if (AllocNodeOffset < FreedNodeOffset) {
342 /* Add to the start of the freed list */
343 if (EndNodeOffset == FreedNodeOffset) {
344 /* If the freed node is adjacent to the first node in the list, concatenate both nodes */
345 AllocNodePtr->BufferSize += FreedNodePtr->BufferSize;
346 AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset;
347
348 /* Clear the BufferSize and NextNodeOffset of the previous first node */
349 FreedNodePtr->BufferSize = 0;
350 FreedNodePtr->NextNodeOffset = 0;
351
352 } else {
353 /* Otherwise, add freed node to the start of the list
354 Update NextNodeOffset and BufferSize to include the
355 size of BIOS_BUFFER_NODE
356 */
357 AllocNodePtr->NextNodeOffset = FreedNodeOffset;
358 }
359 /* Update StartOfFreedNodes to the new first node */
360 BiosHeapBasePtr->StartOfFreedNodes = AllocNodeOffset;
361 } else {
362 /* Traverse list of freed nodes to find where the deallocated node
363 should be place
364 */
365 NextNodeOffset = FreedNodeOffset;
366 NextNodePtr = FreedNodePtr;
367 while (AllocNodeOffset > NextNodeOffset) {
368 PrevNodeOffset = NextNodeOffset;
369 if (NextNodePtr->NextNodeOffset == 0) {
370 break;
371 }
372 NextNodeOffset = NextNodePtr->NextNodeOffset;
373 NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
374 }
375
376 /* If deallocated node is adjacent to the next node,
377 concatenate both nodes
378 */
379 if (NextNodeOffset == EndNodeOffset) {
380 NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
381 AllocNodePtr->BufferSize += NextNodePtr->BufferSize;
382 AllocNodePtr->NextNodeOffset = NextNodePtr->NextNodeOffset;
383
384 NextNodePtr->BufferSize = 0;
385 NextNodePtr->NextNodeOffset = 0;
386 } else {
387 /*AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; */
388 AllocNodePtr->NextNodeOffset = NextNodeOffset;
389 }
390 /* If deallocated node is adjacent to the previous node,
391 concatenate both nodes
392 */
393 PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
394 EndNodeOffset = PrevNodeOffset + PrevNodePtr->BufferSize;
395 if (AllocNodeOffset == EndNodeOffset) {
396 PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
397 PrevNodePtr->BufferSize += AllocNodePtr->BufferSize;
398
399 AllocNodePtr->BufferSize = 0;
400 AllocNodePtr->NextNodeOffset = 0;
401 } else {
402 PrevNodePtr->NextNodeOffset = AllocNodeOffset;
403 }
404 }
405 return AGESA_SUCCESS;
406}
407
408AGESA_STATUS BiosLocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
409{
410 UINT32 AllocNodeOffset;
411 UINT8 *BiosHeapBaseAddr;
412 BIOS_BUFFER_NODE *AllocNodePtr;
413 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
414 AGESA_BUFFER_PARAMS *AllocParams;
415
416 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
417
418 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
419 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
420
421 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
422 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
423
424 while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) {
425 if (AllocNodePtr->NextNodeOffset == 0) {
426 AllocParams->BufferPointer = NULL;
427 AllocParams->BufferLength = 0;
428 return AGESA_BOUNDS_CHK;
429 } else {
430 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
431 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
432 }
433 }
434
435 AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE));
436 AllocParams->BufferLength = AllocNodePtr->BufferSize;
437
438 return AGESA_SUCCESS;
439
440}
441
442AGESA_STATUS BiosRunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
443{
444 AGESA_STATUS Status;
445
446 Status = agesawrapper_amdlaterunaptask (Data, ConfigPtr);
447 return Status;
448}
449
450AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
451{
452 AGESA_STATUS Status;
453 UINT8 Value;
454 UINTN ResetType;
455 AMD_CONFIG_PARAMS *StdHeader;
456
457 ResetType = Data;
458 StdHeader = ConfigPtr;
459
460 //
461 // Perform the RESET based upon the ResetType. In case of
462 // WARM_RESET_WHENVER and COLD_RESET_WHENEVER, the request will go to
463 // AmdResetManager. During the critical condition, where reset is required
464 // immediately, the reset will be invoked directly by writing 0x04 to port
465 // 0xCF9 (Reset Port).
466 //
467 switch (ResetType) {
468 case WARM_RESET_WHENEVER:
469 case COLD_RESET_WHENEVER:
470 break;
471
472 case WARM_RESET_IMMEDIATELY:
473 case COLD_RESET_IMMEDIATELY:
474 Value = 0x06;
475 LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
476 break;
477
478 default:
479 break;
480 }
481
482 Status = 0;
483 return Status;
484}
485
486AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
487{
488 AGESA_STATUS Status;
489 Status = AmdMemoryReadSPD (Func, Data, ConfigPtr);
490
491 return Status;
492}
493
494AGESA_STATUS BiosDefaultRet (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
495{
496 return AGESA_UNSUPPORTED;
497}
498
499/* Call the host environment interface to provide a user hook opportunity. */
500AGESA_STATUS BiosHookBeforeDQSTraining (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
501{
502 return AGESA_SUCCESS;
503}
504
505/* Call the host environment interface to provide a user hook opportunity. */
506AGESA_STATUS BiosHookBeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
507{
508 return AGESA_SUCCESS;
509}
510
511/* Call the host environment interface to provide a user hook opportunity. */
512AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
513{
514 return AGESA_SUCCESS;
515}
516