blob: 7323832eeee72920d6e541369acd577ec89cbf9d [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);
122 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
123 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000124
Marc Jones36abff12011-11-07 23:26:14 -0700125 if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) {
126 /* First allocation */
127 CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER);
128 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
129 CurrNodePtr->BufferHandle = AllocParams->BufferHandle;
130 CurrNodePtr->BufferSize = AllocParams->BufferLength;
131 CurrNodePtr->NextNodeOffset = 0;
132 AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000133
Marc Jones36abff12011-11-07 23:26:14 -0700134 /* Update the remaining free space */
135 FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE);
136 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
137 FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize;
138 FreedNodePtr->NextNodeOffset = 0;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000139
Marc Jones36abff12011-11-07 23:26:14 -0700140 /* Update the offsets for Allocated and Freed nodes */
141 BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset;
142 BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset;
143 } else {
144 /* Find out whether BufferHandle has been allocated on the heap. */
145 /* If it has, return AGESA_BOUNDS_CHK */
146 CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
147 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000148
Marc Jones36abff12011-11-07 23:26:14 -0700149 while (CurrNodeOffset != 0) {
150 CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
151 if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) {
152 return AGESA_BOUNDS_CHK;
153 }
154 CurrNodeOffset = CurrNodePtr->NextNodeOffset;
155 /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points
zbaoafd141d2012-03-30 15:32:07 +0800156 to the end of the allocated nodes list.
Marc Jones36abff12011-11-07 23:26:14 -0700157 */
zbaoafd141d2012-03-30 15:32:07 +0800158
Marc Jones36abff12011-11-07 23:26:14 -0700159 }
160 /* Find the node that best fits the requested buffer size */
161 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
162 PrevNodeOffset = FreedNodeOffset;
163 BestFitNodeOffset = 0;
164 BestFitPrevNodeOffset = 0;
165 while (FreedNodeOffset != 0) {
166 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
167 if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
168 if (BestFitNodeOffset == 0) {
169 /* First node that fits the requested buffer size */
170 BestFitNodeOffset = FreedNodeOffset;
171 BestFitPrevNodeOffset = PrevNodeOffset;
172 } else {
173 /* Find out whether current node is a better fit than the previous nodes */
174 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
175 if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) {
176 BestFitNodeOffset = FreedNodeOffset;
177 BestFitPrevNodeOffset = PrevNodeOffset;
178 }
179 }
180 }
181 PrevNodeOffset = FreedNodeOffset;
182 FreedNodeOffset = FreedNodePtr->NextNodeOffset;
183 } /* end of while loop */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000184
185
Marc Jones36abff12011-11-07 23:26:14 -0700186 if (BestFitNodeOffset == 0) {
187 /* If we could not find a node that fits the requested buffer */
188 /* size, return AGESA_BOUNDS_CHK */
189 return AGESA_BOUNDS_CHK;
190 } else {
191 BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
192 BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000193
Marc Jones36abff12011-11-07 23:26:14 -0700194 /* If BestFitNode is larger than the requested buffer, fragment the node further */
195 if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
196 NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000197
Marc Jones36abff12011-11-07 23:26:14 -0700198 NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset);
199 NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE));
200 NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset;
201 } else {
202 /* Otherwise, next free node is NextNodeOffset of BestFitNode */
203 NextFreeOffset = BestFitNodePtr->NextNodeOffset;
204 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000205
Marc Jones36abff12011-11-07 23:26:14 -0700206 /* If BestFitNode is the first buffer in the list, then update
zbaoafd141d2012-03-30 15:32:07 +0800207 StartOfFreedNodes to reflect the new free node
Marc Jones36abff12011-11-07 23:26:14 -0700208 */
209 if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) {
210 BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset;
211 } else {
212 BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset;
213 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000214
Marc Jones36abff12011-11-07 23:26:14 -0700215 /* Add BestFitNode to the list of Allocated nodes */
216 CurrNodePtr->NextNodeOffset = BestFitNodeOffset;
217 BestFitNodePtr->BufferSize = AllocParams->BufferLength;
218 BestFitNodePtr->BufferHandle = AllocParams->BufferHandle;
219 BestFitNodePtr->NextNodeOffset = 0;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000220
Marc Jones36abff12011-11-07 23:26:14 -0700221 /* Remove BestFitNode from list of Freed nodes */
222 AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE);
223 }
224 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000225
Marc Jones36abff12011-11-07 23:26:14 -0700226 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000227}
228
229AGESA_STATUS BiosDeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
230{
231
Marc Jones36abff12011-11-07 23:26:14 -0700232 UINT8 *BiosHeapBaseAddr;
233 UINT32 AllocNodeOffset;
234 UINT32 PrevNodeOffset;
235 UINT32 NextNodeOffset;
236 UINT32 FreedNodeOffset;
237 UINT32 EndNodeOffset;
238 BIOS_BUFFER_NODE *AllocNodePtr;
239 BIOS_BUFFER_NODE *PrevNodePtr;
240 BIOS_BUFFER_NODE *FreedNodePtr;
241 BIOS_BUFFER_NODE *NextNodePtr;
242 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
243 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000244
Marc Jones36abff12011-11-07 23:26:14 -0700245 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
246 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000247
Marc Jones36abff12011-11-07 23:26:14 -0700248 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000249
Marc Jones36abff12011-11-07 23:26:14 -0700250 /* Find target node to deallocate in list of allocated nodes.
251 Return AGESA_BOUNDS_CHK if the BufferHandle is not found
252 */
253 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
254 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
255 PrevNodeOffset = AllocNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000256
zbaoafd141d2012-03-30 15:32:07 +0800257 while (AllocNodePtr->BufferHandle != AllocParams->BufferHandle) {
Marc Jones36abff12011-11-07 23:26:14 -0700258 if (AllocNodePtr->NextNodeOffset == 0) {
259 return AGESA_BOUNDS_CHK;
260 }
261 PrevNodeOffset = AllocNodeOffset;
262 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
263 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
264 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000265
Marc Jones36abff12011-11-07 23:26:14 -0700266 /* Remove target node from list of allocated nodes */
267 PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
268 PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000269
Marc Jones36abff12011-11-07 23:26:14 -0700270 /* Zero out the buffer, and clear the BufferHandle */
271 LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader));
272 AllocNodePtr->BufferHandle = 0;
273 AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000274
Marc Jones36abff12011-11-07 23:26:14 -0700275 /* Add deallocated node in order to the list of freed nodes */
276 FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
277 FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000278
Marc Jones36abff12011-11-07 23:26:14 -0700279 EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000280
Marc Jones36abff12011-11-07 23:26:14 -0700281 if (AllocNodeOffset < FreedNodeOffset) {
282 /* Add to the start of the freed list */
283 if (EndNodeOffset == FreedNodeOffset) {
284 /* If the freed node is adjacent to the first node in the list, concatenate both nodes */
285 AllocNodePtr->BufferSize += FreedNodePtr->BufferSize;
286 AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000287
Marc Jones36abff12011-11-07 23:26:14 -0700288 /* Clear the BufferSize and NextNodeOffset of the previous first node */
289 FreedNodePtr->BufferSize = 0;
290 FreedNodePtr->NextNodeOffset = 0;
zbaoafd141d2012-03-30 15:32:07 +0800291
Marc Jones36abff12011-11-07 23:26:14 -0700292 } else {
293 /* Otherwise, add freed node to the start of the list
zbaoafd141d2012-03-30 15:32:07 +0800294 Update NextNodeOffset and BufferSize to include the
295 size of BIOS_BUFFER_NODE
Marc Jones36abff12011-11-07 23:26:14 -0700296 */
297 AllocNodePtr->NextNodeOffset = FreedNodeOffset;
298 }
299 /* Update StartOfFreedNodes to the new first node */
300 BiosHeapBasePtr->StartOfFreedNodes = AllocNodeOffset;
301 } else {
302 /* Traverse list of freed nodes to find where the deallocated node
zbaoafd141d2012-03-30 15:32:07 +0800303 should be place
Marc Jones36abff12011-11-07 23:26:14 -0700304 */
305 NextNodeOffset = FreedNodeOffset;
306 NextNodePtr = FreedNodePtr;
307 while (AllocNodeOffset > NextNodeOffset) {
308 PrevNodeOffset = NextNodeOffset;
309 if (NextNodePtr->NextNodeOffset == 0) {
zbaoafd141d2012-03-30 15:32:07 +0800310 break;
Marc Jones36abff12011-11-07 23:26:14 -0700311 }
312 NextNodeOffset = NextNodePtr->NextNodeOffset;
313 NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
314 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000315
Marc Jones36abff12011-11-07 23:26:14 -0700316 /* If deallocated node is adjacent to the next node,
zbaoafd141d2012-03-30 15:32:07 +0800317 concatenate both nodes
Marc Jones36abff12011-11-07 23:26:14 -0700318 */
319 if (NextNodeOffset == EndNodeOffset) {
320 NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
321 AllocNodePtr->BufferSize += NextNodePtr->BufferSize;
322 AllocNodePtr->NextNodeOffset = NextNodePtr->NextNodeOffset;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000323
Marc Jones36abff12011-11-07 23:26:14 -0700324 NextNodePtr->BufferSize = 0;
325 NextNodePtr->NextNodeOffset = 0;
326 } else {
327 /*AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; */
328 AllocNodePtr->NextNodeOffset = NextNodeOffset;
329 }
330 /* If deallocated node is adjacent to the previous node,
zbaoafd141d2012-03-30 15:32:07 +0800331 concatenate both nodes
Marc Jones36abff12011-11-07 23:26:14 -0700332 */
333 PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
334 EndNodeOffset = PrevNodeOffset + PrevNodePtr->BufferSize;
335 if (AllocNodeOffset == EndNodeOffset) {
336 PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
337 PrevNodePtr->BufferSize += AllocNodePtr->BufferSize;
zbaoafd141d2012-03-30 15:32:07 +0800338
Marc Jones36abff12011-11-07 23:26:14 -0700339 AllocNodePtr->BufferSize = 0;
340 AllocNodePtr->NextNodeOffset = 0;
341 } else {
342 PrevNodePtr->NextNodeOffset = AllocNodeOffset;
343 }
344 }
345 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000346}
347
348AGESA_STATUS BiosLocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
349{
Marc Jones36abff12011-11-07 23:26:14 -0700350 UINT32 AllocNodeOffset;
351 UINT8 *BiosHeapBaseAddr;
352 BIOS_BUFFER_NODE *AllocNodePtr;
353 BIOS_HEAP_MANAGER *BiosHeapBasePtr;
354 AGESA_BUFFER_PARAMS *AllocParams;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000355
Marc Jones36abff12011-11-07 23:26:14 -0700356 AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000357
Marc Jones36abff12011-11-07 23:26:14 -0700358 BiosHeapBaseAddr = (UINT8 *) BIOS_HEAP_START_ADDRESS;
359 BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BIOS_HEAP_START_ADDRESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000360
Marc Jones36abff12011-11-07 23:26:14 -0700361 AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
362 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000363
Marc Jones36abff12011-11-07 23:26:14 -0700364 while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) {
365 if (AllocNodePtr->NextNodeOffset == 0) {
366 AllocParams->BufferPointer = NULL;
367 AllocParams->BufferLength = 0;
368 return AGESA_BOUNDS_CHK;
369 } else {
370 AllocNodeOffset = AllocNodePtr->NextNodeOffset;
371 AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
372 }
373 }
Frank Vibrans69da1b62011-02-14 19:04:45 +0000374
Marc Jones36abff12011-11-07 23:26:14 -0700375 AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE));
376 AllocParams->BufferLength = AllocNodePtr->BufferSize;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000377
Marc Jones36abff12011-11-07 23:26:14 -0700378 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000379
380}
381
382AGESA_STATUS BiosRunFuncOnAp (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
383{
Marc Jones36abff12011-11-07 23:26:14 -0700384 AGESA_STATUS Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000385
Marc Jones36abff12011-11-07 23:26:14 -0700386 Status = agesawrapper_amdlaterunaptask (Func, Data, ConfigPtr);
387 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000388}
389
390AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
391{
Marc Jones36abff12011-11-07 23:26:14 -0700392 AGESA_STATUS Status;
393 UINT8 Value;
394 UINTN ResetType;
395 AMD_CONFIG_PARAMS *StdHeader;
efdesign98d7a696d2011-09-15 15:24:26 -0600396
Marc Jones36abff12011-11-07 23:26:14 -0700397 ResetType = Data;
398 StdHeader = ConfigPtr;
efdesign98d7a696d2011-09-15 15:24:26 -0600399
Marc Jones36abff12011-11-07 23:26:14 -0700400 //
401 // Perform the RESET based upon the ResetType. In case of
402 // WARM_RESET_WHENVER and COLD_RESET_WHENEVER, the request will go to
403 // AmdResetManager. During the critical condition, where reset is required
404 // immediately, the reset will be invoked directly by writing 0x04 to port
405 // 0xCF9 (Reset Port).
406 //
407 switch (ResetType) {
zbaoafd141d2012-03-30 15:32:07 +0800408 case WARM_RESET_WHENEVER:
409 case COLD_RESET_WHENEVER:
Marc Jones36abff12011-11-07 23:26:14 -0700410 break;
efdesign98d7a696d2011-09-15 15:24:26 -0600411
zbaoafd141d2012-03-30 15:32:07 +0800412 case WARM_RESET_IMMEDIATELY:
413 case COLD_RESET_IMMEDIATELY:
414 Value = 0x06;
415 LibAmdIoWrite (AccessWidth8, 0xCf9, &Value, StdHeader);
Marc Jones36abff12011-11-07 23:26:14 -0700416 break;
efdesign98d7a696d2011-09-15 15:24:26 -0600417
zbaoafd141d2012-03-30 15:32:07 +0800418 default:
Marc Jones36abff12011-11-07 23:26:14 -0700419 break;
420 }
efdesign98d7a696d2011-09-15 15:24:26 -0600421
Marc Jones36abff12011-11-07 23:26:14 -0700422 Status = 0;
423 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000424}
425
426AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
427{
Marc Jones36abff12011-11-07 23:26:14 -0700428 AGESA_STATUS Status;
429 Status = AmdMemoryReadSPD (Func, Data, (AGESA_READ_SPD_PARAMS *)ConfigPtr);
Frank Vibrans69da1b62011-02-14 19:04:45 +0000430
Marc Jones36abff12011-11-07 23:26:14 -0700431 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000432}
433
434AGESA_STATUS BiosDefaultRet (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
435{
Marc Jones36abff12011-11-07 23:26:14 -0700436 return AGESA_UNSUPPORTED;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000437}
Marc Jones36abff12011-11-07 23:26:14 -0700438/* Call the host environment interface to provide a user hook opportunity. */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000439AGESA_STATUS BiosHookBeforeDQSTraining (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
440{
Marc Jones36abff12011-11-07 23:26:14 -0700441 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000442}
Marc Jones36abff12011-11-07 23:26:14 -0700443/* Call the host environment interface to provide a user hook opportunity. */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000444AGESA_STATUS BiosHookBeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
445{
Marc Jones36abff12011-11-07 23:26:14 -0700446 AGESA_STATUS Status;
447 UINTN FcnData;
448 MEM_DATA_STRUCT *MemData;
449 UINT32 AcpiMmioAddr;
450 UINT32 GpioMmioAddr;
451 UINT8 Data8;
452 UINT16 Data16;
453 UINT8 TempData8;
efdesign98d7a696d2011-09-15 15:24:26 -0600454
Marc Jones36abff12011-11-07 23:26:14 -0700455 FcnData = Data;
456 MemData = ConfigPtr;
efdesign98d7a696d2011-09-15 15:24:26 -0600457
Marc Jones36abff12011-11-07 23:26:14 -0700458 Status = AGESA_SUCCESS;
459 /* Get SB MMIO Base (AcpiMmioAddr) */
460 WriteIo8 (0xCD6, 0x27);
461 Data8 = ReadIo8(0xCD7);
462 Data16 = Data8<<8;
463 WriteIo8 (0xCD6, 0x26);
464 Data8 = ReadIo8(0xCD7);
465 Data16 |= Data8;
466 AcpiMmioAddr = (UINT32)Data16 << 16;
467 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
efdesign98d7a696d2011-09-15 15:24:26 -0600468
Marc Jones36abff12011-11-07 23:26:14 -0700469 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG178);
470 Data8 &= ~BIT5;
471 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
472 TempData8 &= 0x03;
473 TempData8 |= Data8;
474 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700475
Marc Jones36abff12011-11-07 23:26:14 -0700476 Data8 |= BIT2+BIT3;
477 Data8 &= ~BIT4;
478 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
479 TempData8 &= 0x23;
480 TempData8 |= Data8;
481 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, TempData8);
efdesign98d7a696d2011-09-15 15:24:26 -0600482
Marc Jones36abff12011-11-07 23:26:14 -0700483 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG179);
484 Data8 &= ~BIT5;
485 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
486 TempData8 &= 0x03;
487 TempData8 |= Data8;
488 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, TempData8);
efdesign98d7a696d2011-09-15 15:24:26 -0600489
Marc Jones36abff12011-11-07 23:26:14 -0700490 Data8 |= BIT2+BIT3;
491 Data8 &= ~BIT4;
492 TempData8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
493 TempData8 &= 0x23;
494 TempData8 |= Data8;
495 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, TempData8);
efdesign98d7a696d2011-09-15 15:24:26 -0600496
Marc Jones36abff12011-11-07 23:26:14 -0700497 switch(MemData->ParameterListPtr->DDR3Voltage){
498 case VOLT1_35:
499 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
500 Data8 &= ~(UINT8)BIT6;
501 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
502 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
503 Data8 |= (UINT8)BIT6;
504 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
505 break;
506 case VOLT1_25:
507 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
508 Data8 &= ~(UINT8)BIT6;
509 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
510 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
511 Data8 &= ~(UINT8)BIT6;
512 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
513 break;
514 case VOLT1_5:
515 default:
516 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
517 Data8 |= (UINT8)BIT6;
518 Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
519 Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
520 Data8 &= ~(UINT8)BIT6;
521 Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
522 }
523 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000524}
efdesign98d7a696d2011-09-15 15:24:26 -0600525
Marc Jones36abff12011-11-07 23:26:14 -0700526/* Call the host environment interface to provide a user hook opportunity. */
efdesign98d7a696d2011-09-15 15:24:26 -0600527AGESA_STATUS BiosHookBeforeDramInitRecovery (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
528{
Marc Jones36abff12011-11-07 23:26:14 -0700529 return AGESA_SUCCESS;
efdesign98d7a696d2011-09-15 15:24:26 -0600530}
531
Marc Jones36abff12011-11-07 23:26:14 -0700532/* Call the host environment interface to provide a user hook opportunity. */
Frank Vibrans69da1b62011-02-14 19:04:45 +0000533AGESA_STATUS BiosHookBeforeExitSelfRefresh (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
534{
Marc Jones36abff12011-11-07 23:26:14 -0700535 return AGESA_SUCCESS;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000536}
537/* PCIE slot reset control */
538AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
539{
Marc Jones36abff12011-11-07 23:26:14 -0700540 AGESA_STATUS Status;
541 UINTN FcnData;
542 PCIe_SLOT_RESET_INFO *ResetInfo;
efdesign98d7a696d2011-09-15 15:24:26 -0600543
Marc Jones36abff12011-11-07 23:26:14 -0700544 UINT32 GpioMmioAddr;
545 UINT32 AcpiMmioAddr;
546 UINT8 Data8;
547 UINT16 Data16;
efdesign98d7a696d2011-09-15 15:24:26 -0600548
Marc Jones36abff12011-11-07 23:26:14 -0700549 FcnData = Data;
550 ResetInfo = ConfigPtr;
551 // Get SB800 MMIO Base (AcpiMmioAddr)
552 WriteIo8(0xCD6, 0x27);
553 Data8 = ReadIo8(0xCD7);
554 Data16=Data8<<8;
555 WriteIo8(0xCD6, 0x26);
556 Data8 = ReadIo8(0xCD7);
557 Data16|=Data8;
558 AcpiMmioAddr = (UINT32)Data16 << 16;
559 Status = AGESA_UNSUPPORTED;
560 GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
561 switch (ResetInfo->ResetId)
562 {
563 case 4:
564 switch (ResetInfo->ResetControl) {
zbaoafd141d2012-03-30 15:32:07 +0800565 case AssertSlotReset:
Marc Jones36abff12011-11-07 23:26:14 -0700566 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
567 Data8 &= ~(UINT8)BIT6 ;
568 Write64Mem8(GpioMmioAddr+SB_GPIO_REG21, Data8); // MXM_GPIO0. GPIO21
569 Status = AGESA_SUCCESS;
570 break;
zbaoafd141d2012-03-30 15:32:07 +0800571 case DeassertSlotReset:
Marc Jones36abff12011-11-07 23:26:14 -0700572 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG21);
573 Data8 |= BIT6 ;
574 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG21, Data8); // MXM_GPIO0. GPIO21
575 Status = AGESA_SUCCESS;
576 break;
577 }
578 break;
579 case 6:
580 switch (ResetInfo->ResetControl) {
zbaoafd141d2012-03-30 15:32:07 +0800581 case AssertSlotReset:
Marc Jones36abff12011-11-07 23:26:14 -0700582 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
583 Data8 &= ~(UINT8)BIT6 ;
584 Write64Mem8(GpioMmioAddr+SB_GPIO_REG25, Data8); // PCIE_RST#_LAN, GPIO25
585 Status = AGESA_SUCCESS;
586 break;
zbaoafd141d2012-03-30 15:32:07 +0800587 case DeassertSlotReset:
Marc Jones36abff12011-11-07 23:26:14 -0700588 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
589 Data8 |= BIT6 ;
590 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG25, Data8); // PCIE_RST#_LAN, GPIO25
591 Status = AGESA_SUCCESS;
592 break;
593 }
594 break;
595 case 7:
596 switch (ResetInfo->ResetControl) {
zbaoafd141d2012-03-30 15:32:07 +0800597 case AssertSlotReset:
Marc Jones36abff12011-11-07 23:26:14 -0700598 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG02);
599 Data8 &= ~(UINT8)BIT6 ;
600 Write64Mem8(GpioMmioAddr+SB_GPIO_REG02, Data8); // MPCIE_RST0, GPIO02
601 Status = AGESA_SUCCESS;
602 break;
zbaoafd141d2012-03-30 15:32:07 +0800603 case DeassertSlotReset:
Marc Jones36abff12011-11-07 23:26:14 -0700604 Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG25);
605 Data8 |= BIT6 ;
606 Write64Mem8 (GpioMmioAddr+SB_GPIO_REG02, Data8); // MPCIE_RST0, GPIO02
607 Status = AGESA_SUCCESS;
608 break;
609 }
610 break;
611 }
612 return Status;
Frank Vibrans69da1b62011-02-14 19:04:45 +0000613}