xref: /rk3399_rockchip-uboot/post/post.c (revision 6dff55297283ebe16096e25f2dadb54e4b6fd9fc)
1 /*
2  * (C) Copyright 2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 #include <common.h>
25 #include <console.h>
26 #include <watchdog.h>
27 #include <post.h>
28 
29 #ifdef CONFIG_LOGBUFFER
30 #include <logbuff.h>
31 #endif
32 
33 #ifdef CONFIG_POST
34 
35 #define POST_MAX_NUMBER		32
36 
37 #define BOOTMODE_MAGIC	0xDEAD0000
38 
39 int post_init_f (void)
40 {
41 	DECLARE_GLOBAL_DATA_PTR;
42 
43 	int res = 0;
44 	unsigned int i;
45 
46 	for (i = 0; i < post_list_size; i++) {
47 		struct post_test *test = post_list + i;
48 
49 		if (test->init_f && test->init_f()) {
50 			res = -1;
51 		}
52 	}
53 
54 	gd->post_init_f_time = post_time_ms(0);
55 	if (!gd->post_init_f_time)
56 	{
57 		printf("post/post.c: post_time_ms seems not to be implemented\n");
58 	}
59 
60 	return res;
61 }
62 
63 void post_bootmode_init (void)
64 {
65 	DECLARE_GLOBAL_DATA_PTR;
66 	int bootmode = post_bootmode_get (0);
67 
68 	if (post_hotkeys_pressed(gd) && !(bootmode & POST_POWERTEST)) {
69 		bootmode = POST_SLOWTEST;
70 	} else if (bootmode == 0) {
71 		bootmode = POST_POWERON;
72 	} else if (bootmode == POST_POWERON || bootmode == POST_SLOWTEST) {
73 		bootmode = POST_NORMAL;
74 	} else {
75 		return;
76 	}
77 
78 	post_word_store (BOOTMODE_MAGIC | bootmode);
79 	/* Reset activity record */
80 	gd->post_log_word = 0;
81 }
82 
83 int post_bootmode_get (unsigned int *last_test)
84 {
85 	unsigned long word = post_word_load ();
86 	int bootmode;
87 
88 	if ((word & 0xFFFF0000) != BOOTMODE_MAGIC) {
89 		return 0;
90 	}
91 
92 	bootmode = word & 0xFF;
93 
94 	if (last_test && (bootmode & POST_POWERTEST)) {
95 		*last_test = (word >> 8) & 0xFF;
96 	}
97 
98 	return bootmode;
99 }
100 
101 /* POST tests run before relocation only mark status bits .... */
102 static void post_log_mark_start ( unsigned long testid )
103 {
104 	DECLARE_GLOBAL_DATA_PTR;
105 	gd->post_log_word |= (testid)<<16;
106 }
107 
108 static void post_log_mark_succ ( unsigned long testid )
109 {
110 	DECLARE_GLOBAL_DATA_PTR;
111 	gd->post_log_word |= testid;
112 }
113 
114 /* ... and the messages are output once we are relocated */
115 void post_output_backlog ( void )
116 {
117 	DECLARE_GLOBAL_DATA_PTR;
118 	int j;
119 
120 	for (j = 0; j < post_list_size; j++) {
121 		if (gd->post_log_word & (post_list[j].testid<<16)) {
122 			post_log ("POST %s ", post_list[j].cmd);
123 			if (gd->post_log_word & post_list[j].testid)
124 				post_log ("PASSED\n");
125 			else
126 				post_log ("FAILED\n");
127 		}
128 	}
129 }
130 
131 static void post_bootmode_test_on (unsigned int last_test)
132 {
133 	unsigned long word = post_word_load ();
134 
135 	word |= POST_POWERTEST;
136 
137 	word |= (last_test & 0xFF) << 8;
138 
139 	post_word_store (word);
140 }
141 
142 static void post_bootmode_test_off (void)
143 {
144 	unsigned long word = post_word_load ();
145 
146 	word &= ~POST_POWERTEST;
147 
148 	post_word_store (word);
149 }
150 
151 static void post_get_flags (int *test_flags)
152 {
153 	int  flag[] = {  POST_POWERON,   POST_NORMAL,   POST_SLOWTEST };
154 	char *var[] = { "post_poweron", "post_normal", "post_slowtest" };
155 	int varnum = sizeof (var) / sizeof (var[0]);
156 	char list[128];			/* long enough for POST list */
157 	char *name;
158 	char *s;
159 	int last;
160 	int i, j;
161 
162 	for (j = 0; j < post_list_size; j++) {
163 		test_flags[j] = post_list[j].flags;
164 	}
165 
166 	for (i = 0; i < varnum; i++) {
167 		if (getenv_r (var[i], list, sizeof (list)) <= 0)
168 			continue;
169 
170 		for (j = 0; j < post_list_size; j++) {
171 			test_flags[j] &= ~flag[i];
172 		}
173 
174 		last = 0;
175 		name = list;
176 		while (!last) {
177 			while (*name && *name == ' ')
178 				name++;
179 			if (*name == 0)
180 				break;
181 			s = name + 1;
182 			while (*s && *s != ' ')
183 				s++;
184 			if (*s == 0)
185 				last = 1;
186 			else
187 				*s = 0;
188 
189 			for (j = 0; j < post_list_size; j++) {
190 				if (strcmp (post_list[j].cmd, name) == 0) {
191 					test_flags[j] |= flag[i];
192 					break;
193 				}
194 			}
195 
196 			if (j == post_list_size) {
197 				printf ("No such test: %s\n", name);
198 			}
199 
200 			name = s + 1;
201 		}
202 	}
203 
204 	for (j = 0; j < post_list_size; j++) {
205 		if (test_flags[j] & POST_POWERON) {
206 			test_flags[j] |= POST_SLOWTEST;
207 		}
208 	}
209 }
210 
211 static int post_run_single (struct post_test *test,
212 				int test_flags, int flags, unsigned int i)
213 {
214 	if ((flags & test_flags & POST_ALWAYS) &&
215 		(flags & test_flags & POST_MEM)) {
216 		WATCHDOG_RESET ();
217 
218 		if (!(flags & POST_REBOOT)) {
219 			if ((test_flags & POST_REBOOT) && !(flags & POST_MANUAL)) {
220 				post_bootmode_test_on (i);
221 			}
222 
223 			if (test_flags & POST_PREREL)
224 				post_log_mark_start ( test->testid );
225 			else
226 			post_log ("POST %s ", test->cmd);
227 		}
228 
229 		if (test_flags & POST_PREREL) {
230 			if ((*test->test) (flags) == 0)
231 				post_log_mark_succ ( test->testid );
232 		} else {
233 		if ((*test->test) (flags) != 0)
234 			post_log ("FAILED\n");
235 		else
236 			post_log ("PASSED\n");
237 		}
238 
239 		if ((test_flags & POST_REBOOT) && !(flags & POST_MANUAL)) {
240 			post_bootmode_test_off ();
241 		}
242 
243 		return 0;
244 	} else {
245 		return -1;
246 	}
247 }
248 
249 int post_run (char *name, int flags)
250 {
251 	unsigned int i;
252 	int test_flags[POST_MAX_NUMBER];
253 
254 	post_get_flags (test_flags);
255 
256 	if (name == NULL) {
257 		unsigned int last;
258 
259 		if (post_bootmode_get (&last) & POST_POWERTEST) {
260 			if (last < post_list_size &&
261 				(flags & test_flags[last] & POST_ALWAYS) &&
262 				(flags & test_flags[last] & POST_MEM)) {
263 
264 				post_run_single (post_list + last,
265 						 test_flags[last],
266 						 flags | POST_REBOOT, last);
267 
268 				for (i = last + 1; i < post_list_size; i++) {
269 					post_run_single (post_list + i,
270 							 test_flags[i],
271 							 flags, i);
272 				}
273 			}
274 		} else {
275 			for (i = 0; i < post_list_size; i++) {
276 				post_run_single (post_list + i,
277 						 test_flags[i],
278 						 flags, i);
279 			}
280 		}
281 
282 		return 0;
283 	} else {
284 		for (i = 0; i < post_list_size; i++) {
285 			if (strcmp (post_list[i].cmd, name) == 0)
286 				break;
287 		}
288 
289 		if (i < post_list_size) {
290 			return post_run_single (post_list + i,
291 						test_flags[i],
292 						flags, i);
293 		} else {
294 			return -1;
295 		}
296 	}
297 }
298 
299 static int post_info_single (struct post_test *test, int full)
300 {
301 	if (test->flags & POST_MANUAL) {
302 		if (full)
303 			printf ("%s - %s\n"
304 				"  %s\n", test->cmd, test->name, test->desc);
305 		else
306 			printf ("  %-15s - %s\n", test->cmd, test->name);
307 
308 		return 0;
309 	} else {
310 		return -1;
311 	}
312 }
313 
314 int post_info (char *name)
315 {
316 	unsigned int i;
317 
318 	if (name == NULL) {
319 		for (i = 0; i < post_list_size; i++) {
320 			post_info_single (post_list + i, 0);
321 		}
322 
323 		return 0;
324 	} else {
325 		for (i = 0; i < post_list_size; i++) {
326 			if (strcmp (post_list[i].cmd, name) == 0)
327 				break;
328 		}
329 
330 		if (i < post_list_size) {
331 			return post_info_single (post_list + i, 1);
332 		} else {
333 			return -1;
334 		}
335 	}
336 }
337 
338 int post_log (char *format, ...)
339 {
340 	va_list args;
341 	uint i;
342 	char printbuffer[CFG_PBSIZE];
343 
344 	va_start (args, format);
345 
346 	/* For this to work, printbuffer must be larger than
347 	 * anything we ever want to print.
348 	 */
349 	i = vsprintf (printbuffer, format, args);
350 	va_end (args);
351 
352 #ifdef CONFIG_LOGBUFFER
353 	/* Send to the logbuffer */
354 	logbuff_log (printbuffer);
355 #else
356 	/* Send to the stdout file */
357 	puts (printbuffer);
358 #endif
359 
360 	return 0;
361 }
362 
363 void post_reloc (void)
364 {
365 	DECLARE_GLOBAL_DATA_PTR;
366 
367 	unsigned int i;
368 
369 	/*
370 	 * We have to relocate the test table manually
371 	 */
372 	for (i = 0; i < post_list_size; i++) {
373 		ulong addr;
374 		struct post_test *test = post_list + i;
375 
376 		if (test->name) {
377 			addr = (ulong) (test->name) + gd->reloc_off;
378 			test->name = (char *) addr;
379 		}
380 
381 		if (test->cmd) {
382 			addr = (ulong) (test->cmd) + gd->reloc_off;
383 			test->cmd = (char *) addr;
384 		}
385 
386 		if (test->desc) {
387 			addr = (ulong) (test->desc) + gd->reloc_off;
388 			test->desc = (char *) addr;
389 		}
390 
391 		if (test->test) {
392 			addr = (ulong) (test->test) + gd->reloc_off;
393 			test->test = (int (*)(int flags)) addr;
394 		}
395 
396 		if (test->init_f) {
397 			addr = (ulong) (test->init_f) + gd->reloc_off;
398 			test->init_f = (int (*)(void)) addr;
399 		}
400 
401 		if (test->reloc) {
402 			addr = (ulong) (test->reloc) + gd->reloc_off;
403 			test->reloc = (void (*)(void)) addr;
404 
405 			test->reloc();
406 		}
407 	}
408 }
409 
410 
411 /*
412  * Some tests (e.g. SYSMON) need the time when post_init_f started,
413  * but we cannot use get_timer() at this point.
414  *
415  * On PowerPC we implement it using the timebase register.
416  */
417 unsigned long post_time_ms (unsigned long base)
418 {
419 #ifdef CONFIG_PPC
420 	return (unsigned long)get_ticks () / (get_tbclk () / CFG_HZ) - base;
421 #else
422 	return 0; /* Not implemented yet */
423 #endif
424 }
425 
426 #endif /* CONFIG_POST */
427