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