]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - lib_blackfin/post.c
Fix compilation error for omap2420h4_config.
[karo-tx-uboot.git] / lib_blackfin / post.c
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                 printf
57                     ("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         int newword;
68
69         if (post_hotkeys_pressed() && !(bootmode & POST_POWERTEST)) {
70                 newword = BOOTMODE_MAGIC | POST_SLOWTEST;
71         } else if (bootmode == 0) {
72                 newword = BOOTMODE_MAGIC | POST_POWERON;
73         } else if (bootmode == POST_POWERON || bootmode == POST_SLOWTEST) {
74                 newword = BOOTMODE_MAGIC | POST_NORMAL;
75         } else {
76                 /* Use old value */
77                 newword = post_word_load() & ~POST_COLDBOOT;
78         }
79
80         if (bootmode == 0) {
81                 /* We are booting after power-on */
82                 newword |= POST_COLDBOOT;
83         }
84
85         post_word_store(newword);
86
87         /* Reset activity record */
88         gd->post_log_word = 0;
89 }
90
91 int post_bootmode_get(unsigned int *last_test)
92 {
93         unsigned long word = post_word_load();
94         int bootmode;
95
96         if ((word & 0xFFFF0000) != BOOTMODE_MAGIC) {
97                 return 0;
98         }
99
100         bootmode = word & 0x7F;
101
102         if (last_test && (bootmode & POST_POWERTEST)) {
103                 *last_test = (word >> 8) & 0xFF;
104         }
105
106         return bootmode;
107 }
108
109 /* POST tests run before relocation only mark status bits .... */
110 static void post_log_mark_start(unsigned long testid)
111 {
112         DECLARE_GLOBAL_DATA_PTR;
113         gd->post_log_word |= (testid) << 16;
114 }
115
116 static void post_log_mark_succ(unsigned long testid)
117 {
118         DECLARE_GLOBAL_DATA_PTR;
119         gd->post_log_word |= testid;
120 }
121
122 /* ... and the messages are output once we are relocated */
123 void post_output_backlog(void)
124 {
125         DECLARE_GLOBAL_DATA_PTR;
126         int j;
127
128         for (j = 0; j < post_list_size; j++) {
129                 if (gd->post_log_word & (post_list[j].testid << 16)) {
130                         post_log("POST %s ", post_list[j].cmd);
131                         if (gd->post_log_word & post_list[j].testid)
132                                 post_log("PASSED\n");
133                         else {
134                                 post_log("FAILED\n");
135                                 show_boot_progress (-31);
136                         }
137                 }
138         }
139 }
140
141 static void post_bootmode_test_on(unsigned int last_test)
142 {
143         unsigned long word = post_word_load();
144
145         word |= POST_POWERTEST;
146
147         word |= (last_test & 0xFF) << 8;
148
149         post_word_store(word);
150 }
151
152 static void post_bootmode_test_off(void)
153 {
154         unsigned long word = post_word_load();
155
156         word &= ~POST_POWERTEST;
157
158         post_word_store(word);
159 }
160
161 static void post_get_flags(int *test_flags)
162 {
163         int flag[] = { POST_POWERON, POST_NORMAL, POST_SLOWTEST };
164         char *var[] = { "post_poweron", "post_normal", "post_slowtest" };
165         int varnum = sizeof(var) / sizeof(var[0]);
166         char list[128];         /* long enough for POST list */
167         char *name;
168         char *s;
169         int last;
170         int i, j;
171
172         for (j = 0; j < post_list_size; j++) {
173                 test_flags[j] = post_list[j].flags;
174         }
175
176         for (i = 0; i < varnum; i++) {
177                 if (getenv_r(var[i], list, sizeof(list)) <= 0)
178                         continue;
179
180                 for (j = 0; j < post_list_size; j++) {
181                         test_flags[j] &= ~flag[i];
182                 }
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++) {
200                                 if (strcmp(post_list[j].cmd, name) == 0) {
201                                         test_flags[j] |= flag[i];
202                                         break;
203                                 }
204                         }
205
206                         if (j == post_list_size) {
207                                 printf("No such test: %s\n", name);
208                         }
209
210                         name = s + 1;
211                 }
212         }
213
214         for (j = 0; j < post_list_size; j++) {
215                 if (test_flags[j] & POST_POWERON) {
216                         test_flags[j] |= POST_SLOWTEST;
217                 }
218         }
219 }
220
221 static int post_run_single(struct post_test *test,
222                            int test_flags, int flags, unsigned int i)
223 {
224         if ((flags & test_flags & POST_ALWAYS) &&
225             (flags & test_flags & POST_MEM)) {
226                 WATCHDOG_RESET();
227
228                 if (!(flags & POST_REBOOT)) {
229                         if ((test_flags & POST_REBOOT)
230                             && !(flags & POST_MANUAL)) {
231                                 post_bootmode_test_on(i);
232                         }
233
234                         if (test_flags & POST_PREREL)
235                                 post_log_mark_start(test->testid);
236                         else
237                                 post_log("POST %s ", test->cmd);
238                 }
239
240                 if (test_flags & POST_PREREL) {
241                         if ((*test->test) (flags) == 0)
242                                 post_log_mark_succ(test->testid);
243                 } else {
244                         if ((*test->test) (flags) != 0) {
245                                 post_log("FAILED\n");
246                                 show_boot_progress (-32);
247                         } else
248                                 post_log("PASSED\n");
249                 }
250
251                 if ((test_flags & POST_REBOOT) && !(flags & POST_MANUAL)) {
252                         post_bootmode_test_off();
253                 }
254
255                 return 0;
256         } else {
257                 return -1;
258         }
259 }
260
261 int post_run(char *name, int flags)
262 {
263         unsigned int i;
264         int test_flags[POST_MAX_NUMBER];
265
266         post_get_flags(test_flags);
267
268         if (name == NULL) {
269                 unsigned int last;
270
271                 if (post_bootmode_get(&last) & POST_POWERTEST) {
272                         if (last < post_list_size &&
273                             (flags & test_flags[last] & POST_ALWAYS) &&
274                             (flags & test_flags[last] & POST_MEM)) {
275
276                                 post_run_single(post_list + last,
277                                                 test_flags[last],
278                                                 flags | POST_REBOOT, last);
279
280                                 for (i = last + 1; i < post_list_size; i++) {
281                                         post_run_single(post_list + i,
282                                                         test_flags[i],
283                                                         flags, i);
284                                 }
285                         }
286                 } else {
287                         for (i = 0; i < post_list_size; i++) {
288                                 post_run_single(post_list + i,
289                                                 test_flags[i], flags, i);
290                         }
291                 }
292
293                 return 0;
294         } else {
295                 for (i = 0; i < post_list_size; i++) {
296                         if (strcmp(post_list[i].cmd, name) == 0)
297                                 break;
298                 }
299
300                 if (i < post_list_size) {
301                         return post_run_single(post_list + i,
302                                                test_flags[i], flags, i);
303                 } else {
304                         return -1;
305                 }
306         }
307 }
308
309 static int post_info_single(struct post_test *test, int full)
310 {
311         if (test->flags & POST_MANUAL) {
312                 if (full)
313                         printf("%s - %s\n"
314                                "  %s\n", test->cmd, test->name, test->desc);
315                 else
316                         printf("  %-15s - %s\n", test->cmd, test->name);
317
318                 return 0;
319         } else {
320                 return -1;
321         }
322 }
323
324 int post_info(char *name)
325 {
326         unsigned int i;
327
328         if (name == NULL) {
329                 for (i = 0; i < post_list_size; i++) {
330                         post_info_single(post_list + i, 0);
331                 }
332
333                 return 0;
334         } else {
335                 for (i = 0; i < post_list_size; i++) {
336                         if (strcmp(post_list[i].cmd, name) == 0)
337                                 break;
338                 }
339
340                 if (i < post_list_size) {
341                         return post_info_single(post_list + i, 1);
342                 } else {
343                         return -1;
344                 }
345         }
346 }
347
348 int post_log(char *format, ...)
349 {
350         va_list args;
351         uint i;
352         char printbuffer[CFG_PBSIZE];
353
354         va_start(args, format);
355
356         /* For this to work, printbuffer must be larger than
357          * anything we ever want to print.
358          */
359         i = vsprintf(printbuffer, format, args);
360         va_end(args);
361
362 #ifdef CONFIG_LOGBUFFER
363         /* Send to the logbuffer */
364         logbuff_log(printbuffer);
365 #else
366         /* Send to the stdout file */
367         puts(printbuffer);
368 #endif
369
370         return 0;
371 }
372
373 void post_reloc(void)
374 {
375         DECLARE_GLOBAL_DATA_PTR;
376
377         unsigned int i;
378
379         /*
380          * We have to relocate the test table manually
381          */
382         for (i = 0; i < post_list_size; i++) {
383                 ulong addr;
384                 struct post_test *test = post_list + i;
385
386                 if (test->name) {
387                         addr = (ulong) (test->name) + gd->reloc_off;
388                         test->name = (char *)addr;
389                 }
390
391                 if (test->cmd) {
392                         addr = (ulong) (test->cmd) + gd->reloc_off;
393                         test->cmd = (char *)addr;
394                 }
395
396                 if (test->desc) {
397                         addr = (ulong) (test->desc) + gd->reloc_off;
398                         test->desc = (char *)addr;
399                 }
400
401                 if (test->test) {
402                         addr = (ulong) (test->test) + gd->reloc_off;
403                         test->test = (int (*)(int flags))addr;
404                 }
405
406                 if (test->init_f) {
407                         addr = (ulong) (test->init_f) + gd->reloc_off;
408                         test->init_f = (int (*)(void))addr;
409                 }
410
411                 if (test->reloc) {
412                         addr = (ulong) (test->reloc) + gd->reloc_off;
413                         test->reloc = (void (*)(void))addr;
414
415                         test->reloc();
416                 }
417         }
418 }
419
420 /*
421  * Some tests (e.g. SYSMON) need the time when post_init_f started,
422  * but we cannot use get_timer() at this point.
423  *
424  * On PowerPC we implement it using the timebase register.
425  */
426 unsigned long post_time_ms(unsigned long base)
427 {
428         return (unsigned long)get_ticks() / (get_tbclk() / CFG_HZ) - base;
429 }
430
431 #endif                          /* CONFIG_POST */