]> git.ipfire.org Git - thirdparty/u-boot.git/blame - post/post.c
configs: k2g_evm: Enable DFU on K2G EVM
[thirdparty/u-boot.git] / post / post.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
a042ac84
WD
2/*
3 * (C) Copyright 2002
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
a042ac84
WD
5 */
6
7#include <common.h>
52cb4d4f 8#include <stdio_dev.h>
a042ac84 9#include <watchdog.h>
c90a4dd7 10#include <div64.h>
a042ac84
WD
11#include <post.h>
12
9146d138
MF
13#ifdef CONFIG_SYS_POST_HOTKEYS_GPIO
14#include <asm/gpio.h>
15#endif
16
d87080b7
WD
17DECLARE_GLOBAL_DATA_PTR;
18
a042ac84
WD
19#define POST_MAX_NUMBER 32
20
21#define BOOTMODE_MAGIC 0xDEAD0000
22
e92372c8 23int post_init_f(void)
4532cb69 24{
4532cb69
WD
25 int res = 0;
26 unsigned int i;
27
28 for (i = 0; i < post_list_size; i++) {
29 struct post_test *test = post_list + i;
30
50da8376 31 if (test->init_f && test->init_f())
4532cb69 32 res = -1;
4532cb69 33 }
8bde7f77 34
4532cb69
WD
35 gd->post_init_f_time = post_time_ms(0);
36 if (!gd->post_init_f_time)
e92372c8 37 printf("%s: post_time_ms not implemented\n", __FILE__);
4532cb69
WD
38
39 return res;
40}
41
39ff7d5f
SR
42/*
43 * Supply a default implementation for post_hotkeys_pressed() for boards
44 * without hotkey support. We always return 0 here, so that the
45 * long-running tests won't be started.
46 *
47 * Boards with hotkey support can override this weak default function
48 * by defining one in their board specific code.
49 */
002ad7b8 50__weak int post_hotkeys_pressed(void)
39ff7d5f 51{
9146d138
MF
52#ifdef CONFIG_SYS_POST_HOTKEYS_GPIO
53 int ret;
54 unsigned gpio = CONFIG_SYS_POST_HOTKEYS_GPIO;
55
56 ret = gpio_request(gpio, "hotkeys");
57 if (ret) {
58 printf("POST: gpio hotkey request failed\n");
59 return 0;
60 }
61
62 gpio_direction_input(gpio);
63 ret = gpio_get_value(gpio);
64 gpio_free(gpio);
65
66 return ret;
67#endif
68
39ff7d5f
SR
69 return 0; /* No hotkeys supported */
70}
39ff7d5f 71
e92372c8 72void post_bootmode_init(void)
a042ac84 73{
e92372c8 74 int bootmode = post_bootmode_get(0);
27b207fd 75 int newword;
42d1f039 76
e92372c8 77 if (post_hotkeys_pressed() && !(bootmode & POST_POWERTEST))
27b207fd 78 newword = BOOTMODE_MAGIC | POST_SLOWTEST;
e92372c8 79 else if (bootmode == 0)
27b207fd 80 newword = BOOTMODE_MAGIC | POST_POWERON;
e92372c8 81 else if (bootmode == POST_POWERON || bootmode == POST_SLOWTEST)
27b207fd 82 newword = BOOTMODE_MAGIC | POST_NORMAL;
e92372c8 83 else
27b207fd 84 /* Use old value */
50da8376 85 newword = post_word_load() & ~POST_COLDBOOT;
a042ac84 86
27b207fd 87 if (bootmode == 0)
27b207fd
WD
88 /* We are booting after power-on */
89 newword |= POST_COLDBOOT;
27b207fd 90
e92372c8 91 post_word_store(newword);
27b207fd 92
228f29ac
WD
93 /* Reset activity record */
94 gd->post_log_word = 0;
79843950 95 gd->post_log_res = 0;
a042ac84
WD
96}
97
e92372c8 98int post_bootmode_get(unsigned int *last_test)
a042ac84 99{
e92372c8 100 unsigned long word = post_word_load();
a042ac84
WD
101 int bootmode;
102
e92372c8 103 if ((word & 0xFFFF0000) != BOOTMODE_MAGIC)
a042ac84 104 return 0;
a042ac84 105
27b207fd 106 bootmode = word & 0x7F;
a042ac84 107
e92372c8 108 if (last_test && (bootmode & POST_POWERTEST))
a042ac84 109 *last_test = (word >> 8) & 0xFF;
a042ac84
WD
110
111 return bootmode;
112}
113
228f29ac 114/* POST tests run before relocation only mark status bits .... */
e92372c8 115static void post_log_mark_start(unsigned long testid)
228f29ac 116{
79843950 117 gd->post_log_word |= testid;
228f29ac
WD
118}
119
e92372c8 120static void post_log_mark_succ(unsigned long testid)
228f29ac 121{
79843950 122 gd->post_log_res |= testid;
228f29ac
WD
123}
124
125/* ... and the messages are output once we are relocated */
e92372c8 126void post_output_backlog(void)
228f29ac 127{
228f29ac
WD
128 int j;
129
130 for (j = 0; j < post_list_size; j++) {
79843950 131 if (gd->post_log_word & (post_list[j].testid)) {
50da8376 132 post_log("POST %s ", post_list[j].cmd);
79843950 133 if (gd->post_log_res & post_list[j].testid)
50da8376 134 post_log("PASSED\n");
63e73c9a 135 else {
e92372c8 136 post_log("FAILED\n");
770605e4 137 bootstage_error(BOOTSTAGE_ID_POST_FAIL_R);
63e73c9a 138 }
228f29ac
WD
139 }
140 }
141}
142
e92372c8 143static void post_bootmode_test_on(unsigned int last_test)
a042ac84 144{
e92372c8 145 unsigned long word = post_word_load();
a042ac84
WD
146
147 word |= POST_POWERTEST;
148
149 word |= (last_test & 0xFF) << 8;
150
e92372c8 151 post_word_store(word);
a042ac84
WD
152}
153
e92372c8 154static void post_bootmode_test_off(void)
a042ac84 155{
e92372c8 156 unsigned long word = post_word_load();
a042ac84
WD
157
158 word &= ~POST_POWERTEST;
159
e92372c8 160 post_word_store(word);
a042ac84
WD
161}
162
212a0caf
VL
163#ifndef CONFIG_POST_SKIP_ENV_FLAGS
164static void post_get_env_flags(int *test_flags)
a042ac84 165{
e262efe3
YT
166 int flag[] = { POST_POWERON, POST_NORMAL, POST_SLOWTEST,
167 POST_CRITICAL };
168 char *var[] = { "post_poweron", "post_normal", "post_slowtest",
169 "post_critical" };
d2397817 170 int varnum = ARRAY_SIZE(var);
a042ac84
WD
171 char list[128]; /* long enough for POST list */
172 char *name;
173 char *s;
174 int last;
175 int i, j;
176
a042ac84 177 for (i = 0; i < varnum; i++) {
00caae6d 178 if (env_get_f(var[i], list, sizeof(list)) <= 0)
a042ac84
WD
179 continue;
180
50da8376 181 for (j = 0; j < post_list_size; j++)
a042ac84 182 test_flags[j] &= ~flag[i];
a042ac84
WD
183
184 last = 0;
185 name = list;
186 while (!last) {
187 while (*name && *name == ' ')
188 name++;
189 if (*name == 0)
190 break;
191 s = name + 1;
192 while (*s && *s != ' ')
193 s++;
194 if (*s == 0)
195 last = 1;
196 else
197 *s = 0;
198
199 for (j = 0; j < post_list_size; j++) {
50da8376 200 if (strcmp(post_list[j].cmd, name) == 0) {
a042ac84
WD
201 test_flags[j] |= flag[i];
202 break;
203 }
204 }
205
e92372c8 206 if (j == post_list_size)
50da8376 207 printf("No such test: %s\n", name);
a042ac84
WD
208
209 name = s + 1;
210 }
211 }
212a0caf
VL
212}
213#endif
214
215static void post_get_flags(int *test_flags)
216{
217 int j;
218
219 for (j = 0; j < post_list_size; j++)
220 test_flags[j] = post_list[j].flags;
221
222#ifndef CONFIG_POST_SKIP_ENV_FLAGS
223 post_get_env_flags(test_flags);
224#endif
6dff5529 225
e92372c8
HS
226 for (j = 0; j < post_list_size; j++)
227 if (test_flags[j] & POST_POWERON)
6dff5529 228 test_flags[j] |= POST_SLOWTEST;
a042ac84
WD
229}
230
002ad7b8 231__weak void show_post_progress(unsigned int test_num, int before, int result)
e070a56c
MZ
232{
233}
e070a56c 234
e92372c8 235static int post_run_single(struct post_test *test,
a042ac84
WD
236 int test_flags, int flags, unsigned int i)
237{
238 if ((flags & test_flags & POST_ALWAYS) &&
239 (flags & test_flags & POST_MEM)) {
50da8376 240 WATCHDOG_RESET();
a042ac84
WD
241
242 if (!(flags & POST_REBOOT)) {
e92372c8
HS
243 if ((test_flags & POST_REBOOT) &&
244 !(flags & POST_MANUAL)) {
245 post_bootmode_test_on(
e262efe3
YT
246 (gd->flags & GD_FLG_POSTFAIL) ?
247 POST_FAIL_SAVE | i : i);
a042ac84
WD
248 }
249
228f29ac 250 if (test_flags & POST_PREREL)
e92372c8 251 post_log_mark_start(test->testid);
228f29ac 252 else
e92372c8 253 post_log("POST %s ", test->cmd);
a042ac84
WD
254 }
255
e070a56c
MZ
256 show_post_progress(i, POST_BEFORE, POST_FAILED);
257
228f29ac 258 if (test_flags & POST_PREREL) {
50da8376 259 if ((*test->test)(flags) == 0) {
e92372c8 260 post_log_mark_succ(test->testid);
e070a56c 261 show_post_progress(i, POST_AFTER, POST_PASSED);
50da8376 262 } else {
e070a56c 263 show_post_progress(i, POST_AFTER, POST_FAILED);
28a38506
YT
264 if (test_flags & POST_CRITICAL)
265 gd->flags |= GD_FLG_POSTFAIL;
266 if (test_flags & POST_STOP)
267 gd->flags |= GD_FLG_POSTSTOP;
268 }
228f29ac 269 } else {
975afc34
JK
270 if ((*test->test)(flags) != 0) {
271 post_log("FAILED\n");
770605e4 272 bootstage_error(BOOTSTAGE_ID_POST_FAIL_R);
975afc34
JK
273 show_post_progress(i, POST_AFTER, POST_FAILED);
274 if (test_flags & POST_CRITICAL)
275 gd->flags |= GD_FLG_POSTFAIL;
276 if (test_flags & POST_STOP)
277 gd->flags |= GD_FLG_POSTSTOP;
278 } else {
279 post_log("PASSED\n");
280 show_post_progress(i, POST_AFTER, POST_PASSED);
281 }
228f29ac 282 }
a042ac84 283
50da8376 284 if ((test_flags & POST_REBOOT) && !(flags & POST_MANUAL))
e92372c8 285 post_bootmode_test_off();
a042ac84
WD
286
287 return 0;
288 } else {
289 return -1;
290 }
291}
292
50da8376 293int post_run(char *name, int flags)
a042ac84
WD
294{
295 unsigned int i;
296 int test_flags[POST_MAX_NUMBER];
297
e92372c8 298 post_get_flags(test_flags);
a042ac84
WD
299
300 if (name == NULL) {
301 unsigned int last;
302
28a38506
YT
303 if (gd->flags & GD_FLG_POSTSTOP)
304 return 0;
305
e92372c8 306 if (post_bootmode_get(&last) & POST_POWERTEST) {
e262efe3
YT
307 if (last & POST_FAIL_SAVE) {
308 last &= ~POST_FAIL_SAVE;
309 gd->flags |= GD_FLG_POSTFAIL;
310 }
a042ac84
WD
311 if (last < post_list_size &&
312 (flags & test_flags[last] & POST_ALWAYS) &&
313 (flags & test_flags[last] & POST_MEM)) {
314
e92372c8 315 post_run_single(post_list + last,
ea909b76
WD
316 test_flags[last],
317 flags | POST_REBOOT, last);
a042ac84
WD
318
319 for (i = last + 1; i < post_list_size; i++) {
28a38506
YT
320 if (gd->flags & GD_FLG_POSTSTOP)
321 break;
e92372c8 322 post_run_single(post_list + i,
ea909b76
WD
323 test_flags[i],
324 flags, i);
a042ac84
WD
325 }
326 }
327 } else {
328 for (i = 0; i < post_list_size; i++) {
28a38506
YT
329 if (gd->flags & GD_FLG_POSTSTOP)
330 break;
e92372c8 331 post_run_single(post_list + i,
ea909b76
WD
332 test_flags[i],
333 flags, i);
a042ac84
WD
334 }
335 }
336
337 return 0;
338 } else {
339 for (i = 0; i < post_list_size; i++) {
50da8376 340 if (strcmp(post_list[i].cmd, name) == 0)
a042ac84
WD
341 break;
342 }
343
344 if (i < post_list_size) {
5744ddc6 345 WATCHDOG_RESET();
e92372c8 346 return post_run_single(post_list + i,
a042ac84
WD
347 test_flags[i],
348 flags, i);
349 } else {
350 return -1;
351 }
352 }
353}
354
e92372c8 355static int post_info_single(struct post_test *test, int full)
a042ac84
WD
356{
357 if (test->flags & POST_MANUAL) {
358 if (full)
e92372c8 359 printf("%s - %s\n"
a042ac84
WD
360 " %s\n", test->cmd, test->name, test->desc);
361 else
e92372c8 362 printf(" %-15s - %s\n", test->cmd, test->name);
a042ac84
WD
363
364 return 0;
365 } else {
366 return -1;
367 }
368}
369
50da8376 370int post_info(char *name)
a042ac84
WD
371{
372 unsigned int i;
373
374 if (name == NULL) {
e92372c8
HS
375 for (i = 0; i < post_list_size; i++)
376 post_info_single(post_list + i, 0);
a042ac84
WD
377
378 return 0;
379 } else {
380 for (i = 0; i < post_list_size; i++) {
50da8376 381 if (strcmp(post_list[i].cmd, name) == 0)
a042ac84
WD
382 break;
383 }
384
50da8376 385 if (i < post_list_size)
e92372c8 386 return post_info_single(post_list + i, 1);
50da8376 387 else
a042ac84 388 return -1;
a042ac84
WD
389 }
390}
391
e92372c8 392int post_log(char *format, ...)
a042ac84
WD
393{
394 va_list args;
6d0f6bcf 395 char printbuffer[CONFIG_SYS_PBSIZE];
a042ac84 396
50da8376 397 va_start(args, format);
a042ac84
WD
398
399 /* For this to work, printbuffer must be larger than
400 * anything we ever want to print.
401 */
4d6402b0 402 vsprintf(printbuffer, format, args);
50da8376 403 va_end(args);
a042ac84
WD
404
405 /* Send to the stdout file */
e92372c8 406 puts(printbuffer);
a042ac84
WD
407
408 return 0;
409}
410
2e5167cc 411#ifdef CONFIG_NEEDS_MANUAL_RELOC
e92372c8 412void post_reloc(void)
a042ac84 413{
a042ac84
WD
414 unsigned int i;
415
416 /*
417 * We have to relocate the test table manually
418 */
419 for (i = 0; i < post_list_size; i++) {
420 ulong addr;
421 struct post_test *test = post_list + i;
422
423 if (test->name) {
50da8376 424 addr = (ulong)(test->name) + gd->reloc_off;
e92372c8 425 test->name = (char *)addr;
a042ac84
WD
426 }
427
428 if (test->cmd) {
50da8376 429 addr = (ulong)(test->cmd) + gd->reloc_off;
e92372c8 430 test->cmd = (char *)addr;
a042ac84
WD
431 }
432
433 if (test->desc) {
50da8376 434 addr = (ulong)(test->desc) + gd->reloc_off;
e92372c8 435 test->desc = (char *)addr;
a042ac84
WD
436 }
437
438 if (test->test) {
50da8376 439 addr = (ulong)(test->test) + gd->reloc_off;
a042ac84
WD
440 test->test = (int (*)(int flags)) addr;
441 }
4532cb69
WD
442
443 if (test->init_f) {
50da8376 444 addr = (ulong)(test->init_f) + gd->reloc_off;
4532cb69
WD
445 test->init_f = (int (*)(void)) addr;
446 }
447
448 if (test->reloc) {
50da8376 449 addr = (ulong)(test->reloc) + gd->reloc_off;
4532cb69 450 test->reloc = (void (*)(void)) addr;
8bde7f77 451
4532cb69
WD
452 test->reloc();
453 }
a042ac84
WD
454 }
455}
521af04d 456#endif
a042ac84 457
4532cb69
WD
458
459/*
460 * Some tests (e.g. SYSMON) need the time when post_init_f started,
461 * but we cannot use get_timer() at this point.
462 *
463 * On PowerPC we implement it using the timebase register.
464 */
e92372c8 465unsigned long post_time_ms(unsigned long base)
4532cb69 466{
ea3310e8 467#if defined(CONFIG_PPC) || defined(CONFIG_ARM)
c90a4dd7 468 return (unsigned long)lldiv(get_ticks(), get_tbclk() / CONFIG_SYS_HZ)
e92372c8 469 - base;
4532cb69 470#else
ad5bb451 471#warning "Not implemented yet"
4532cb69
WD
472 return 0; /* Not implemented yet */
473#endif
474}