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, test_flags[last], 197 flags | POST_REBOOT, last); 198 199 for (i = last + 1; i < post_list_size; i++) { 200 post_run_single (post_list + i, test_flags[i], 201 flags, i); 202 } 203 } 204 } else { 205 for (i = 0; i < post_list_size; i++) { 206 post_run_single (post_list + i, test_flags[i], flags, 207 i); 208 } 209 } 210 211 return 0; 212 } else { 213 for (i = 0; i < post_list_size; i++) { 214 if (strcmp (post_list[i].cmd, name) == 0) 215 break; 216 } 217 218 if (i < post_list_size) { 219 return post_run_single (post_list + i, 220 test_flags[i], 221 flags, i); 222 } else { 223 return -1; 224 } 225 } 226 } 227 228 static int post_info_single (struct post_test *test, int full) 229 { 230 if (test->flags & POST_MANUAL) { 231 if (full) 232 printf ("%s - %s\n" 233 " %s\n", test->cmd, test->name, test->desc); 234 else 235 printf (" %-15s - %s\n", test->cmd, test->name); 236 237 return 0; 238 } else { 239 return -1; 240 } 241 } 242 243 int post_info (char *name) 244 { 245 unsigned int i; 246 247 if (name == NULL) { 248 for (i = 0; i < post_list_size; i++) { 249 post_info_single (post_list + i, 0); 250 } 251 252 return 0; 253 } else { 254 for (i = 0; i < post_list_size; i++) { 255 if (strcmp (post_list[i].cmd, name) == 0) 256 break; 257 } 258 259 if (i < post_list_size) { 260 return post_info_single (post_list + i, 1); 261 } else { 262 return -1; 263 } 264 } 265 } 266 267 int post_log (char *format, ...) 268 { 269 va_list args; 270 uint i; 271 char printbuffer[CFG_PBSIZE]; 272 273 va_start (args, format); 274 275 /* For this to work, printbuffer must be larger than 276 * anything we ever want to print. 277 */ 278 i = vsprintf (printbuffer, format, args); 279 va_end (args); 280 281 #ifdef CONFIG_LOGBUFFER 282 logbuff_log (printbuffer); 283 #else 284 /* Send to the stdout file */ 285 puts (printbuffer); 286 #endif 287 288 return 0; 289 } 290 291 void post_reloc (void) 292 { 293 DECLARE_GLOBAL_DATA_PTR; 294 295 unsigned int i; 296 297 /* 298 * We have to relocate the test table manually 299 */ 300 for (i = 0; i < post_list_size; i++) { 301 ulong addr; 302 struct post_test *test = post_list + i; 303 304 if (test->name) { 305 addr = (ulong) (test->name) + gd->reloc_off; 306 test->name = (char *) addr; 307 } 308 309 if (test->cmd) { 310 addr = (ulong) (test->cmd) + gd->reloc_off; 311 test->cmd = (char *) addr; 312 } 313 314 if (test->desc) { 315 addr = (ulong) (test->desc) + gd->reloc_off; 316 test->desc = (char *) addr; 317 } 318 319 if (test->test) { 320 addr = (ulong) (test->test) + gd->reloc_off; 321 test->test = (int (*)(int flags)) addr; 322 } 323 } 324 } 325 326 #endif /* CONFIG_POST */ 327