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