xref: /openbmc/u-boot/post/post.c (revision ea909b76)
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 void post_bootmode_init (void)
40 {
41 	int bootmode = post_bootmode_get (0);
42 
43 	if (bootmode == 0) {
44 		bootmode = POST_POWERON;
45 	} else if (bootmode == POST_POWERON) {
46 		bootmode = POST_POWERNORMAL;
47 	} else {
48 		return;
49 	}
50 
51 	post_word_store (BOOTMODE_MAGIC | bootmode);
52 }
53 
54 int post_bootmode_get (unsigned int *last_test)
55 {
56 	unsigned long word = post_word_load ();
57 	int bootmode;
58 
59 	if ((word & 0xFFFF0000) != BOOTMODE_MAGIC) {
60 		return 0;
61 	}
62 
63 	bootmode = word & 0xFF;
64 
65 	if (last_test && (bootmode & POST_POWERTEST)) {
66 		*last_test = (word >> 8) & 0xFF;
67 	}
68 
69 	return bootmode;
70 }
71 
72 void post_bootmode_clear (void)
73 {
74 	post_word_store (0);
75 }
76 
77 static void post_bootmode_test_on (unsigned int last_test)
78 {
79 	unsigned long word = post_word_load ();
80 
81 	word |= POST_POWERTEST;
82 
83 	word |= (last_test & 0xFF) << 8;
84 
85 	post_word_store (word);
86 }
87 
88 static void post_bootmode_test_off (void)
89 {
90 	unsigned long word = post_word_load ();
91 
92 	word &= ~POST_POWERTEST;
93 
94 	post_word_store (word);
95 }
96 
97 static void post_get_flags (int *test_flags)
98 {
99 	int flag[] = { POST_POWERON, POST_POWERNORMAL, POST_POWERFAIL };
100 	char *var[] = { "post_poweron", "post_normal", "post_shutdown" };
101 	int varnum = sizeof (var) / sizeof (var[0]);
102 	char list[128];			/* long enough for POST list */
103 	char *name;
104 	char *s;
105 	int last;
106 	int i, j;
107 
108 	for (j = 0; j < post_list_size; j++) {
109 		test_flags[j] = post_list[j].flags;
110 	}
111 
112 	for (i = 0; i < varnum; i++) {
113 		if (getenv_r (var[i], list, sizeof (list)) <= 0)
114 			continue;
115 
116 		for (j = 0; j < post_list_size; j++) {
117 			test_flags[j] &= ~flag[i];
118 		}
119 
120 		last = 0;
121 		name = list;
122 		while (!last) {
123 			while (*name && *name == ' ')
124 				name++;
125 			if (*name == 0)
126 				break;
127 			s = name + 1;
128 			while (*s && *s != ' ')
129 				s++;
130 			if (*s == 0)
131 				last = 1;
132 			else
133 				*s = 0;
134 
135 			for (j = 0; j < post_list_size; j++) {
136 				if (strcmp (post_list[j].cmd, name) == 0) {
137 					test_flags[j] |= flag[i];
138 					break;
139 				}
140 			}
141 
142 			if (j == post_list_size) {
143 				printf ("No such test: %s\n", name);
144 			}
145 
146 			name = s + 1;
147 		}
148 	}
149 }
150 
151 static int post_run_single (struct post_test *test,
152 				int test_flags, int flags, unsigned int i)
153 {
154 	if ((flags & test_flags & POST_ALWAYS) &&
155 		(flags & test_flags & POST_MEM)) {
156 		WATCHDOG_RESET ();
157 
158 		if (!(flags & POST_REBOOT)) {
159 			if ((test_flags & POST_REBOOT) && !(flags & POST_MANUAL)) {
160 				post_bootmode_test_on (i);
161 			}
162 
163 			post_log ("POST %s ", test->cmd);
164 		}
165 
166 		if ((*test->test) (flags) != 0)
167 			post_log ("FAILED\n");
168 		else
169 			post_log ("PASSED\n");
170 
171 		if ((test_flags & POST_REBOOT) && !(flags & POST_MANUAL)) {
172 			post_bootmode_test_off ();
173 		}
174 
175 		return 0;
176 	} else {
177 		return -1;
178 	}
179 }
180 
181 int post_run (char *name, int flags)
182 {
183 	unsigned int i;
184 	int test_flags[POST_MAX_NUMBER];
185 
186 	post_get_flags (test_flags);
187 
188 	if (name == NULL) {
189 		unsigned int last;
190 
191 		if (post_bootmode_get (&last) & POST_POWERTEST) {
192 			if (last < post_list_size &&
193 				(flags & test_flags[last] & POST_ALWAYS) &&
194 				(flags & test_flags[last] & POST_MEM)) {
195 
196 				post_run_single (post_list + last,
197 						 test_flags[last],
198 						 flags | POST_REBOOT, last);
199 
200 				for (i = last + 1; i < post_list_size; i++) {
201 					post_run_single (post_list + i,
202 							 test_flags[i],
203 							 flags, i);
204 				}
205 			}
206 		} else {
207 			for (i = 0; i < post_list_size; i++) {
208 				post_run_single (post_list + i,
209 						 test_flags[i],
210 						 flags, i);
211 			}
212 		}
213 
214 		return 0;
215 	} else {
216 		for (i = 0; i < post_list_size; i++) {
217 			if (strcmp (post_list[i].cmd, name) == 0)
218 				break;
219 		}
220 
221 		if (i < post_list_size) {
222 			return post_run_single (post_list + i,
223 						test_flags[i],
224 						flags, i);
225 		} else {
226 			return -1;
227 		}
228 	}
229 }
230 
231 static int post_info_single (struct post_test *test, int full)
232 {
233 	if (test->flags & POST_MANUAL) {
234 		if (full)
235 			printf ("%s - %s\n"
236 				"  %s\n", test->cmd, test->name, test->desc);
237 		else
238 			printf ("  %-15s - %s\n", test->cmd, test->name);
239 
240 		return 0;
241 	} else {
242 		return -1;
243 	}
244 }
245 
246 int post_info (char *name)
247 {
248 	unsigned int i;
249 
250 	if (name == NULL) {
251 		for (i = 0; i < post_list_size; i++) {
252 			post_info_single (post_list + i, 0);
253 		}
254 
255 		return 0;
256 	} else {
257 		for (i = 0; i < post_list_size; i++) {
258 			if (strcmp (post_list[i].cmd, name) == 0)
259 				break;
260 		}
261 
262 		if (i < post_list_size) {
263 			return post_info_single (post_list + i, 1);
264 		} else {
265 			return -1;
266 		}
267 	}
268 }
269 
270 int post_log (char *format, ...)
271 {
272 	va_list args;
273 	uint i;
274 	char printbuffer[CFG_PBSIZE];
275 
276 	va_start (args, format);
277 
278 	/* For this to work, printbuffer must be larger than
279 	 * anything we ever want to print.
280 	 */
281 	i = vsprintf (printbuffer, format, args);
282 	va_end (args);
283 
284 #ifdef CONFIG_LOGBUFFER
285 	logbuff_log (printbuffer);
286 #else
287 	/* Send to the stdout file */
288 	puts (printbuffer);
289 #endif
290 
291 	return 0;
292 }
293 
294 void post_reloc (void)
295 {
296 	DECLARE_GLOBAL_DATA_PTR;
297 
298 	unsigned int i;
299 
300 	/*
301 	 * We have to relocate the test table manually
302 	 */
303 	for (i = 0; i < post_list_size; i++) {
304 		ulong addr;
305 		struct post_test *test = post_list + i;
306 
307 		if (test->name) {
308 			addr = (ulong) (test->name) + gd->reloc_off;
309 			test->name = (char *) addr;
310 		}
311 
312 		if (test->cmd) {
313 			addr = (ulong) (test->cmd) + gd->reloc_off;
314 			test->cmd = (char *) addr;
315 		}
316 
317 		if (test->desc) {
318 			addr = (ulong) (test->desc) + gd->reloc_off;
319 			test->desc = (char *) addr;
320 		}
321 
322 		if (test->test) {
323 			addr = (ulong) (test->test) + gd->reloc_off;
324 			test->test = (int (*)(int flags)) addr;
325 		}
326 	}
327 }
328 
329 #endif /* CONFIG_POST */
330