1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <stdint.h>
4 #include <string.h>
5 #include <acpi/acpi.h>
6 #include <bootstate.h>
7 #include <cbfs.h>
8 #include <timestamp.h>
9
10 #include <northbridge/amd/agesa/state_machine.h>
11 #include <northbridge/amd/agesa/agesa_helper.h>
12 #include <northbridge/amd/agesa/BiosCallOuts.h>
13 #include <amdlib.h>
14
15 #include <AMD.h>
16
17 #if ENV_RAMINIT
18 #include <PlatformMemoryConfiguration.h>
19 CONST PSO_ENTRY ROMDATA DefaultPlatformMemoryConfiguration[] = {PSO_END};
20 #endif
21
agesa_locate_image(AMD_CONFIG_PARAMS * StdHeader)22 static void agesa_locate_image(AMD_CONFIG_PARAMS *StdHeader)
23 {
24 const char ModuleIdentifier[] = AGESA_ID;
25 const void *agesa, *image;
26 size_t file_size;
27
28 agesa = cbfs_map((const char *)CONFIG_AGESA_CBFS_NAME, &file_size);
29 if (agesa == NULL)
30 return;
31
32 image = LibAmdLocateImage(agesa, agesa + file_size, 4096,
33 ModuleIdentifier);
34 StdHeader->ImageBasePtr = (void *)image;
35 }
36
agesa_set_interface(struct sysinfo * cb)37 void agesa_set_interface(struct sysinfo *cb)
38 {
39 memset(&cb->StdHeader, 0, sizeof(AMD_CONFIG_PARAMS));
40
41 cb->StdHeader.CalloutPtr = GetBiosCallout;
42
43 agesa_locate_image(&cb->StdHeader);
44 AMD_IMAGE_HEADER *image =
45 (void *)(uintptr_t)cb->StdHeader.ImageBasePtr;
46 ASSERT(image);
47 AMD_MODULE_HEADER *module =
48 (void *)(uintptr_t)image->ModuleInfoOffset;
49 ASSERT(module && module->ModuleDispatcher);
50 }
51
module_dispatch(AGESA_STRUCT_NAME func,AMD_CONFIG_PARAMS * StdHeader)52 AGESA_STATUS module_dispatch(AGESA_STRUCT_NAME func,
53 AMD_CONFIG_PARAMS *StdHeader)
54 {
55 MODULE_ENTRY dispatcher;
56
57 AMD_IMAGE_HEADER *image = (void *)(uintptr_t)StdHeader->ImageBasePtr;
58 AMD_MODULE_HEADER *module = (void *)(uintptr_t)image->ModuleInfoOffset;
59 dispatcher = module->ModuleDispatcher;
60
61 StdHeader->Func = func;
62 return dispatcher(StdHeader);
63 }
64
amd_create_struct(AMD_INTERFACE_PARAMS * aip,AGESA_STRUCT_NAME func,void * buf,size_t len)65 static AGESA_STATUS amd_create_struct(AMD_INTERFACE_PARAMS *aip,
66 AGESA_STRUCT_NAME func, void *buf, size_t len)
67 {
68 aip->AgesaFunctionName = func;
69 aip->AllocationMethod = 0;
70 aip->NewStructPtr = buf;
71 aip->NewStructSize = len;
72 if (buf != NULL && len != 0)
73 aip->AllocationMethod = ByHost;
74
75 return module_dispatch(AMD_CREATE_STRUCT, &aip->StdHeader);
76 }
77
amd_release_struct(AMD_INTERFACE_PARAMS * aip)78 static AGESA_STATUS amd_release_struct(AMD_INTERFACE_PARAMS *aip)
79 {
80 /* Cannot release AMD_LATE_PARAMS until ACPI tables are done. */
81 if (aip->AgesaFunctionName == AMD_INIT_LATE)
82 return AGESA_SUCCESS;
83
84 return module_dispatch(AMD_RELEASE_STRUCT, &aip->StdHeader);
85 }
86
87 /* By design, for each valid AGESA_STRUCT_NAME, AMD_CONFIG_PARAMS
88 * can be evaluated to apply correct typecast based on Func field.
89 */
90
romstage_dispatch(struct sysinfo * cb,AGESA_STRUCT_NAME func,AMD_CONFIG_PARAMS * StdHeader)91 static AGESA_STATUS romstage_dispatch(struct sysinfo *cb,
92 AGESA_STRUCT_NAME func, AMD_CONFIG_PARAMS *StdHeader)
93 {
94 AGESA_STATUS status = AGESA_UNSUPPORTED;
95
96 switch (func)
97 {
98 case AMD_INIT_RESET:
99 {
100 AMD_RESET_PARAMS *param = (void *)StdHeader;
101 platform_BeforeInitReset(cb, param);
102 board_BeforeInitReset(cb, param);
103 status = module_dispatch(func, StdHeader);
104 break;
105 }
106
107 case AMD_INIT_EARLY:
108 {
109 AMD_EARLY_PARAMS *param = (void *)StdHeader;
110 platform_BeforeInitEarly(cb, param);
111 board_BeforeInitEarly(cb, param);
112 status = module_dispatch(func, StdHeader);
113 break;
114 }
115
116 case AMD_INIT_POST:
117 {
118 AMD_POST_PARAMS *param = (void *)StdHeader;
119 platform_BeforeInitPost(cb, param);
120 board_BeforeInitPost(cb, param);
121 status = module_dispatch(func, StdHeader);
122
123 /* FIXME: Detect if TSC frequency really
124 * changed during raminit? */
125 timestamp_rescale_table(1, 4);
126
127 platform_AfterInitPost(cb, param);
128 break;
129 }
130
131 case AMD_INIT_RESUME:
132 {
133 AMD_RESUME_PARAMS *param = (void *)StdHeader;
134 platform_BeforeInitResume(cb, param);
135 status = module_dispatch(func, StdHeader);
136
137 /* FIXME: Detect if TSC frequency really
138 * changed during raminit? */
139 timestamp_rescale_table(1, 4);
140
141 platform_AfterInitResume(cb, param);
142 break;
143 }
144
145 default:
146 {
147 break;
148 }
149 }
150 return status;
151 }
152
ramstage_dispatch(struct sysinfo * cb,AGESA_STRUCT_NAME func,AMD_CONFIG_PARAMS * StdHeader)153 static AGESA_STATUS ramstage_dispatch(struct sysinfo *cb,
154 AGESA_STRUCT_NAME func, AMD_CONFIG_PARAMS *StdHeader)
155 {
156 AGESA_STATUS status = AGESA_UNSUPPORTED;
157
158 switch (func)
159 {
160 case AMD_INIT_ENV:
161 {
162 AMD_ENV_PARAMS *param = (void *)StdHeader;
163 platform_BeforeInitEnv(cb, param);
164 board_BeforeInitEnv(cb, param);
165 status = module_dispatch(func, StdHeader);
166 platform_AfterInitEnv(cb, param);
167 break;
168 }
169
170 case AMD_S3LATE_RESTORE:
171 {
172 AMD_S3LATE_PARAMS *param = (void *)StdHeader;
173 platform_BeforeS3LateRestore(cb, param);
174 status = module_dispatch(func, StdHeader);
175 platform_AfterS3LateRestore(cb, param);
176 break;
177 }
178
179 case AMD_INIT_MID:
180 {
181 AMD_MID_PARAMS *param = (void *)StdHeader;
182 platform_BeforeInitMid(cb, param);
183 board_BeforeInitMid(cb, param);
184 status = module_dispatch(func, StdHeader);
185 break;
186 }
187
188 case AMD_S3_SAVE:
189 {
190 AMD_S3SAVE_PARAMS *param = (void *)StdHeader;
191 status = module_dispatch(func, StdHeader);
192 platform_AfterS3Save(cb, param);
193 break;
194 }
195
196 case AMD_INIT_LATE:
197 {
198 AMD_LATE_PARAMS *param = (void *)StdHeader;
199 platform_BeforeInitLate(cb, param);
200 board_BeforeInitLate(cb, param);
201 status = module_dispatch(func, StdHeader);
202 platform_AfterInitLate(cb, param);
203 completion_InitLate(cb, param);
204 break;
205 }
206
207 default:
208 {
209 break;
210 }
211 }
212 return status;
213 }
214
agesa_execute_state(struct sysinfo * cb,AGESA_STRUCT_NAME func)215 int agesa_execute_state(struct sysinfo *cb, AGESA_STRUCT_NAME func)
216 {
217 AMD_INTERFACE_PARAMS aip;
218 union {
219 AMD_RESET_PARAMS reset;
220 AMD_S3LATE_PARAMS s3late;
221 } agesa_params;
222 void *buf = NULL;
223 size_t len = 0;
224
225 AGESA_STATUS status, final;
226
227 struct agesa_state task;
228 memset(&task, 0, sizeof(task));
229 agesa_state_on_entry(&task, func);
230
231 aip.StdHeader = cb->StdHeader;
232
233 /* For these calls, heap is not available. */
234 if (func == AMD_INIT_RESET || func == AMD_S3LATE_RESTORE) {
235 buf = (void *)&agesa_params;
236 len = sizeof(agesa_params);
237 memcpy(buf, &cb->StdHeader, sizeof(cb->StdHeader));
238 }
239
240 status = amd_create_struct(&aip, func, buf, len);
241 ASSERT(status == AGESA_SUCCESS);
242
243 /* Must call the function buffer was allocated for.*/
244 AMD_CONFIG_PARAMS *StdHeader = aip.NewStructPtr;
245 ASSERT(StdHeader != NULL && StdHeader->Func == func);
246
247 if (CONFIG(AGESA_EXTRA_TIMESTAMPS) && task.ts_entry_id)
248 timestamp_add_now(task.ts_entry_id);
249
250 if (ENV_RAMINIT)
251 final = romstage_dispatch(cb, func, StdHeader);
252
253 if (ENV_RAMSTAGE)
254 final = ramstage_dispatch(cb, func, StdHeader);
255
256 if (CONFIG(AGESA_EXTRA_TIMESTAMPS) && task.ts_exit_id)
257 timestamp_add_now(task.ts_exit_id);
258
259 agesawrapper_trace(final, StdHeader, task.function_name);
260 ASSERT(final < AGESA_FATAL);
261
262 status = amd_release_struct(&aip);
263 ASSERT(status == AGESA_SUCCESS);
264
265 agesa_state_on_exit(&task, &aip.StdHeader);
266
267 return (final < AGESA_FATAL) ? 0 : -1;
268 }
269
270 #if ENV_RAMSTAGE
271
amd_bs_ramstage_init(void * arg)272 static void amd_bs_ramstage_init(void *arg)
273 {
274 struct sysinfo *cb = arg;
275
276 agesa_set_interface(cb);
277
278 if (!acpi_is_wakeup_s3())
279 agesa_execute_state(cb, AMD_INIT_ENV);
280 else {
281 agesa_execute_state(cb, AMD_S3LATE_RESTORE);
282 fchs3earlyrestore(&cb->StdHeader);
283 }
284 }
285
286 void sb_After_Pci_Restore_Init(void);
287
amd_bs_dev_enable(void * arg)288 static void amd_bs_dev_enable(void *arg)
289 {
290 struct sysinfo *cb = arg;
291
292 if (!acpi_is_wakeup_s3())
293 agesa_execute_state(cb, AMD_INIT_MID);
294 }
295
amd_bs_post_device(void * arg)296 static void amd_bs_post_device(void *arg)
297 {
298 struct sysinfo *cb = arg;
299
300 if (acpi_is_wakeup_s3()) {
301 fchs3laterestore(&cb->StdHeader);
302 return;
303 }
304
305 agesa_execute_state(cb, AMD_INIT_LATE);
306
307 if (!acpi_s3_resume_allowed())
308 return;
309
310 agesa_execute_state(cb, AMD_S3_SAVE);
311 }
312
313 static struct sysinfo state_machine;
314
315 BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, amd_bs_ramstage_init,
316 &state_machine);
317
318 BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_ENTRY, amd_bs_dev_enable,
319 &state_machine);
320
321 BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, amd_bs_post_device,
322 &state_machine);
323
324 #endif /* ENV_RAMSTAGE */
325
326 /* Empty stubs for cases board does not need to override anything. */
327 void __weak
board_BeforeInitReset(struct sysinfo * cb,AMD_RESET_PARAMS * Reset)328 board_BeforeInitReset(struct sysinfo *cb, AMD_RESET_PARAMS *Reset) { }
329 void __weak
board_BeforeInitEarly(struct sysinfo * cb,AMD_EARLY_PARAMS * Early)330 board_BeforeInitEarly(struct sysinfo *cb, AMD_EARLY_PARAMS *Early) { }
331 void __weak
board_BeforeInitPost(struct sysinfo * cb,AMD_POST_PARAMS * Post)332 board_BeforeInitPost(struct sysinfo *cb, AMD_POST_PARAMS *Post) { }
333 void __weak
board_BeforeInitEnv(struct sysinfo * cb,AMD_ENV_PARAMS * Env)334 board_BeforeInitEnv(struct sysinfo *cb, AMD_ENV_PARAMS *Env) { }
335 void __weak
board_BeforeInitMid(struct sysinfo * cb,AMD_MID_PARAMS * Mid)336 board_BeforeInitMid(struct sysinfo *cb, AMD_MID_PARAMS *Mid) { }
337 void __weak
board_BeforeInitLate(struct sysinfo * cb,AMD_LATE_PARAMS * Late)338 board_BeforeInitLate(struct sysinfo *cb, AMD_LATE_PARAMS *Late) { }
339
340 AGESA_STATUS __weak
fchs3earlyrestore(AMD_CONFIG_PARAMS * StdHeader)341 fchs3earlyrestore(AMD_CONFIG_PARAMS *StdHeader)
342 {
343 return AGESA_SUCCESS;
344 }
345
346 AGESA_STATUS __weak
fchs3laterestore(AMD_CONFIG_PARAMS * StdHeader)347 fchs3laterestore(AMD_CONFIG_PARAMS *StdHeader)
348 {
349 return AGESA_SUCCESS;
350 }
351