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