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