]>
Commit | Line | Data |
---|---|---|
4e5ca3eb WD |
1 | /* |
2 | * (C) Copyright 2000-2003 | |
3 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
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 <watchdog.h> | |
26 | #include <command.h> | |
27 | #include <malloc.h> | |
28 | #include <devices.h> | |
29 | #include <syscall.h> | |
30 | #if (CONFIG_COMMANDS & CFG_CMD_IDE) | |
31 | #include <ide.h> | |
32 | #endif | |
33 | #if (CONFIG_COMMANDS & CFG_CMD_SCSI) | |
34 | #include <scsi.h> | |
35 | #endif | |
36 | #if (CONFIG_COMMANDS & CFG_CMD_KGDB) | |
37 | #include <kgdb.h> | |
38 | #endif | |
39 | #ifdef CONFIG_STATUS_LED | |
40 | #include <status_led.h> | |
41 | #endif | |
42 | #include <net.h> | |
43 | #if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) | |
44 | #include <cmd_bedbug.h> | |
45 | #endif | |
46 | #ifdef CFG_ALLOC_DPRAM | |
47 | #include <commproc.h> | |
48 | #endif | |
49 | #include <version.h> | |
50 | ||
51 | static char *failed = "*** failed ***\n"; | |
52 | ||
53 | #ifdef CONFIG_PCU_E | |
54 | extern flash_info_t flash_info[]; | |
55 | #endif | |
56 | ||
57 | #if defined(CFG_ENV_IS_IN_FLASH) | |
58 | # ifndef CFG_ENV_ADDR | |
59 | # define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET) | |
60 | # endif | |
61 | # ifndef CFG_ENV_SIZE | |
62 | # define CFG_ENV_SIZE CFG_ENV_SECT_SIZE | |
63 | # endif | |
64 | # if (CFG_ENV_ADDR >= CFG_MONITOR_BASE) && \ | |
65 | (CFG_ENV_ADDR+CFG_ENV_SIZE) < (CFG_MONITOR_BASE + CFG_MONITOR_LEN) | |
66 | # define ENV_IS_EMBEDDED | |
67 | # endif | |
68 | #endif /* CFG_ENV_IS_IN_FLASH */ | |
69 | #if ( ((CFG_ENV_ADDR+CFG_ENV_SIZE) < CFG_MONITOR_BASE) || \ | |
70 | (CFG_ENV_ADDR >= (CFG_MONITOR_BASE + CFG_MONITOR_LEN)) ) || \ | |
71 | defined(CFG_ENV_IS_IN_NVRAM) | |
72 | #define TOTAL_MALLOC_LEN (CFG_MALLOC_LEN + CFG_ENV_SIZE) | |
73 | #else | |
74 | #define TOTAL_MALLOC_LEN CFG_MALLOC_LEN | |
75 | #endif | |
76 | ||
77 | /* | |
78 | * Begin and End of memory area for malloc(), and current "brk" | |
79 | */ | |
80 | static ulong mem_malloc_start = 0; | |
81 | static ulong mem_malloc_end = 0; | |
82 | static ulong mem_malloc_brk = 0; | |
83 | ||
84 | /************************************************************************ | |
85 | * Utilities * | |
86 | ************************************************************************ | |
87 | */ | |
88 | ||
89 | /* | |
90 | * The Malloc area is immediately below the monitor copy in DRAM | |
91 | */ | |
92 | static void mem_malloc_init (ulong dest_addr) | |
93 | { | |
94 | mem_malloc_end = dest_addr; | |
95 | mem_malloc_start = dest_addr - TOTAL_MALLOC_LEN; | |
96 | mem_malloc_brk = mem_malloc_start; | |
97 | ||
98 | memset ((void *) mem_malloc_start, 0, | |
99 | mem_malloc_end - mem_malloc_start); | |
100 | } | |
101 | ||
102 | void *sbrk (ptrdiff_t increment) | |
103 | { | |
104 | ulong old = mem_malloc_brk; | |
105 | ulong new = old + increment; | |
106 | ||
107 | if ((new < mem_malloc_start) || (new > mem_malloc_end)) { | |
108 | return (NULL); | |
109 | } | |
110 | mem_malloc_brk = new; | |
111 | return ((void *) old); | |
112 | } | |
113 | ||
114 | char *strmhz (char *buf, long hz) | |
115 | { | |
116 | long l, n; | |
117 | long m; | |
118 | ||
119 | n = hz / 1000000L; | |
120 | ||
121 | l = sprintf (buf, "%ld", n); | |
122 | ||
123 | m = (hz % 1000000L) / 1000L; | |
124 | ||
125 | if (m != 0) | |
126 | sprintf (buf + l, ".%03ld", m); | |
127 | ||
128 | return (buf); | |
129 | } | |
130 | ||
131 | static void syscalls_init (int reloc_off) | |
132 | { | |
133 | ulong *addr; | |
134 | ||
135 | addr = (ulong *) syscall_tbl; | |
136 | syscall_tbl[SYSCALL_MALLOC] = (void *) malloc; | |
137 | syscall_tbl[SYSCALL_FREE] = (void *) free; | |
138 | ||
139 | syscall_tbl[SYSCALL_INSTALL_HDLR] = (void *) irq_install_handler; | |
140 | syscall_tbl[SYSCALL_FREE_HDLR] = (void *) irq_free_handler; | |
141 | ||
142 | addr = (ulong *) 0xc00; /* syscall ISR addr */ | |
143 | ||
144 | /* patch ISR code */ | |
145 | *addr++ |= (ulong) syscall_tbl >> 16; | |
146 | *addr++ |= (ulong) syscall_tbl & 0xFFFF; | |
147 | *addr++ |= NR_SYSCALLS >> 16; | |
148 | *addr++ |= NR_SYSCALLS & 0xFFFF; | |
149 | } | |
150 | ||
151 | /************************************************************************ | |
152 | * | |
153 | * This is the first part of the initialization sequence that is | |
154 | * implemented in C, but still running from ROM. | |
155 | * | |
156 | * The main purpose is to provide a (serial) console interface as | |
157 | * soon as possible (so we can see any error messages), and to | |
158 | * initialize the RAM so that we can relocate the monitor code to | |
159 | * RAM. | |
160 | * | |
161 | * Be aware of the restrictions: global data is read-only, BSS is not | |
162 | * initialized, and stack space is limited to a few kB. | |
163 | * | |
164 | ************************************************************************ | |
165 | */ | |
166 | ||
167 | ||
168 | gd_t *global_data; | |
169 | static gd_t gdata; | |
170 | static bd_t bdata; | |
171 | ||
172 | void board_init_f (ulong bootflag) | |
173 | { | |
174 | DECLARE_GLOBAL_DATA_PTR; | |
175 | ||
176 | bd_t *bd; | |
177 | ulong reg, len, addr, addr_sp, dram_size; | |
178 | int i, baudrate, board_type; | |
179 | char *s, *e; | |
180 | uchar tmp[64]; /* long enough for environment variables */ | |
181 | ||
182 | /* Pointer to initial global data area */ | |
183 | gd = global_data = &gdata; | |
184 | bd = gd->bd = &bdata; | |
185 | ||
186 | init_timebase (); | |
187 | env_init (); | |
188 | ||
189 | i = getenv_r ("baudrate", tmp, sizeof (tmp)); | |
190 | baudrate = | |
191 | (i > 0) ? (int) simple_strtoul (tmp, NULL, | |
192 | 10) : CONFIG_BAUDRATE; | |
193 | bd->bi_baudrate = baudrate; /* Console Baudrate */ | |
194 | ||
195 | /* set up serial port */ | |
196 | serial_init (); | |
197 | ||
198 | /* Initialize the console (before the relocation) */ | |
199 | console_init_f (); | |
200 | ||
201 | #ifdef DEBUG | |
202 | if (sizeof (init_data_t) > CFG_INIT_DATA_SIZE) { | |
203 | printf ("PANIC: sizeof(init_data_t)=%d > CFG_INIT_DATA_SIZE=%d\n", sizeof (init_data_t), CFG_INIT_DATA_SIZE); | |
204 | hang (); | |
205 | } | |
206 | #endif /* DEBUG */ | |
207 | ||
208 | /* now we can use standard printf/puts/getc/tstc functions */ | |
209 | display_options (); | |
210 | ||
211 | puts ("CPU: "); /* Check CPU */ | |
212 | if (checkcpu () < 0) { | |
213 | puts (failed); | |
214 | hang (); | |
215 | } | |
216 | ||
217 | puts ("Board: "); /* Check Board */ | |
218 | if ((board_type = checkboard ()) < 0) { | |
219 | puts (failed); | |
220 | hang (); | |
221 | } | |
222 | ||
223 | puts ("DRAM: "); | |
224 | if ((dram_size = initdram (board_type)) > 0) { | |
225 | printf ("%2ld MB\n", dram_size >> 20); | |
226 | } else { | |
227 | puts (failed); | |
228 | hang (); | |
229 | } | |
230 | ||
231 | #if defined(CFG_DRAM_TEST) | |
232 | if (testdram () != 0) { | |
233 | hang (); | |
234 | } | |
235 | #endif /* CFG_DRAM_TEST */ | |
236 | ||
237 | /* | |
238 | * Now that we have DRAM mapped and working, we can | |
239 | * relocate the code and continue running from DRAM. | |
240 | * | |
241 | * Reserve memory at end of RAM for (top down in that order): | |
242 | * - protected RAM | |
243 | * - LCD framebuffer | |
244 | * - monitor code | |
245 | * - board info struct | |
246 | */ | |
247 | len = get_endaddr () - CFG_MONITOR_BASE; | |
248 | ||
249 | if (len > CFG_MONITOR_LEN) { | |
250 | printf ("*** u-boot size %ld > reserved memory (%d)\n", | |
251 | len, CFG_MONITOR_LEN); | |
252 | hang (); | |
253 | } | |
254 | ||
255 | if (CFG_MONITOR_LEN > len) | |
256 | len = CFG_MONITOR_LEN; | |
257 | ||
258 | addr = CFG_SDRAM_BASE + dram_size; | |
259 | addr -= len; | |
260 | ||
261 | /* | |
262 | * Save local variables to board info struct | |
263 | */ | |
264 | bd->bi_memstart = CFG_SDRAM_BASE; /* start of DRAM memory */ | |
265 | bd->bi_memsize = dram_size; /* size of DRAM memory in bytes */ | |
266 | bd->bi_bootflags = bootflag; /* boot / reboot flag (for LynxOS) */ | |
267 | ||
268 | i = getenv_r ("ethaddr", tmp, sizeof (tmp)); | |
269 | s = (i > 0) ? tmp : NULL; | |
270 | ||
271 | for (reg = 0; reg < 6; ++reg) { | |
272 | bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0; | |
273 | if (s) | |
274 | s = (*e) ? e + 1 : e; | |
275 | } | |
276 | ||
277 | bd->bi_intfreq = get_gclk_freq (); /* Internal Freq, in Hz */ | |
278 | bd->bi_busfreq = get_bus_freq (get_gclk_freq ()); /* Bus Freq, in Hz */ | |
279 | ||
280 | #ifdef CFG_EXTBDINFO | |
281 | strncpy (bd->bi_s_version, "1.2", sizeof (bd->bi_s_version)); | |
282 | strncpy (bd->bi_r_version, PPCBOOT_VERSION, | |
283 | sizeof (bd->bi_r_version)); | |
284 | ||
285 | bd->bi_procfreq = get_gclk_freq (); /* Processor Speed, In Hz */ | |
286 | bd->bi_plb_busfreq = bd->bi_busfreq; | |
287 | #endif | |
288 | ||
289 | board_init_final (addr); | |
290 | ||
291 | } | |
292 | ||
293 | ||
294 | /************************************************************************ | |
295 | * | |
296 | * This is the next part if the initialization sequence: we are now | |
297 | * running from RAM and have a "normal" C environment, i. e. global | |
298 | * data can be written, BSS has been cleared, the stack size in not | |
299 | * that critical any more, etc. | |
300 | * | |
301 | ************************************************************************ | |
302 | */ | |
303 | ||
304 | void board_init_final (ulong dest_addr) | |
305 | { | |
306 | DECLARE_GLOBAL_DATA_PTR; | |
307 | char *s; | |
308 | cmd_tbl_t *cmdtp; | |
309 | ulong flash_size; | |
310 | bd_t *bd; | |
311 | ||
312 | bd = gd->bd; | |
d4ca31c4 | 313 | /* icache_enable(); /XX* it's time to enable the instruction cache */ |
4e5ca3eb WD |
314 | |
315 | /* | |
316 | * Setup trap handlers | |
317 | */ | |
318 | trap_init (dest_addr); | |
319 | ||
320 | puts ("FLASH: "); | |
321 | ||
322 | if ((flash_size = flash_init ()) > 0) { | |
323 | #ifdef CFG_FLASH_CHECKSUM | |
324 | if (flash_size >= (1 << 20)) { | |
325 | printf ("%2ld MB", flash_size >> 20); | |
326 | } else { | |
327 | printf ("%2ld kB", flash_size >> 10); | |
328 | } | |
329 | /* | |
330 | * Compute and print flash CRC if flashchecksum is set to 'y' | |
331 | * | |
332 | * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX | |
333 | */ | |
334 | s = getenv ("flashchecksum"); | |
335 | if (s && (*s == 'y')) { | |
336 | printf (" CRC: %08lX", | |
337 | crc32 (0, | |
338 | (const unsigned char *) CFG_FLASH_BASE, | |
339 | flash_size) | |
340 | ); | |
341 | } | |
342 | putc ('\n'); | |
343 | #else | |
344 | if (flash_size >= (1 << 20)) { | |
345 | printf ("%2ld MB\n", flash_size >> 20); | |
346 | } else { | |
347 | printf ("%2ld kB\n", flash_size >> 10); | |
348 | } | |
349 | #endif /* CFG_FLASH_CHECKSUM */ | |
350 | } else { | |
351 | puts (failed); | |
352 | hang (); | |
353 | } | |
354 | ||
355 | bd->bi_flashstart = CFG_FLASH_BASE; /* update start of FLASH memory */ | |
356 | bd->bi_flashsize = flash_size; /* size of FLASH memory (final value) */ | |
357 | bd->bi_flashoffset = 0x10000; /* reserved area for startup monitor */ | |
358 | ||
359 | WATCHDOG_RESET (); | |
360 | ||
361 | /* initialize higher level parts of CPU like time base and timers */ | |
362 | cpu_init_r (); | |
363 | ||
364 | WATCHDOG_RESET (); | |
365 | ||
366 | /* initialize malloc() area */ | |
367 | mem_malloc_init (dest_addr); | |
368 | ||
369 | #ifdef CONFIG_SPI | |
370 | # if !defined(CFG_ENV_IS_IN_EEPROM) | |
371 | spi_init_f (); | |
372 | # endif | |
373 | spi_init_r (); | |
374 | #endif | |
375 | ||
376 | /* relocate environment function pointers etc. */ | |
377 | env_relocate (); | |
378 | ||
379 | /* IP Address */ | |
380 | bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); | |
381 | ||
382 | WATCHDOG_RESET (); | |
383 | ||
384 | /* allocate syscalls table (console_init_r will fill it in */ | |
385 | syscall_tbl = (void **) malloc (NR_SYSCALLS * sizeof (void *)); | |
386 | ||
387 | /* Initialize the console (after the relocation and devices init) */ | |
388 | ||
389 | ||
390 | #if (CONFIG_COMMANDS & CFG_CMD_NET) && ( \ | |
391 | defined(CONFIG_CCM) || \ | |
392 | defined(CONFIG_EP8260) || \ | |
393 | defined(CONFIG_IP860) || \ | |
394 | defined(CONFIG_IVML24) || \ | |
395 | defined(CONFIG_IVMS8) || \ | |
396 | defined(CONFIG_LWMON) || \ | |
397 | defined(CONFIG_MPC8260ADS) || \ | |
398 | defined(CONFIG_PCU_E) || \ | |
399 | defined(CONFIG_RPXSUPER) || \ | |
400 | defined(CONFIG_SPD823TS) ) | |
401 | ||
402 | WATCHDOG_RESET (); | |
403 | # ifdef DEBUG | |
404 | puts ("Reset Ethernet PHY\n"); | |
405 | # endif | |
406 | reset_phy (); | |
407 | #endif | |
408 | ||
409 | ||
410 | #if (CONFIG_COMMANDS & CFG_CMD_KGDB) | |
411 | WATCHDOG_RESET (); | |
412 | puts ("KGDB: "); | |
413 | kgdb_init (); | |
414 | #endif | |
415 | ||
416 | /* | |
417 | * Enable Interrupts | |
418 | */ | |
419 | interrupt_init (); | |
420 | udelay (20); | |
421 | set_timer (0); | |
422 | ||
423 | /* Insert function pointers now that we have relocated the code */ | |
424 | ||
425 | /* Initialize from environment */ | |
426 | if ((s = getenv ("loadaddr")) != NULL) { | |
427 | load_addr = simple_strtoul (s, NULL, 16); | |
428 | } | |
429 | #if (CONFIG_COMMANDS & CFG_CMD_NET) | |
430 | if ((s = getenv ("bootfile")) != NULL) { | |
431 | copy_filename (BootFile, s, sizeof (BootFile)); | |
432 | } | |
433 | #endif /* CFG_CMD_NET */ | |
434 | ||
435 | WATCHDOG_RESET (); | |
436 | ||
437 | #if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) | |
438 | WATCHDOG_RESET (); | |
439 | puts ("Net: "); | |
440 | eth_initialize (bd); | |
441 | #endif | |
442 | ||
443 | #ifdef CONFIG_LAST_STAGE_INIT | |
444 | WATCHDOG_RESET (); | |
445 | /* | |
446 | * Some parts can be only initialized if all others (like | |
447 | * Interrupts) are up and running (i.e. the PC-style ISA | |
448 | * keyboard). | |
449 | */ | |
450 | last_stage_init (); | |
451 | #endif | |
452 | ||
453 | #if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) | |
454 | WATCHDOG_RESET (); | |
455 | bedbug_init (); | |
456 | #endif | |
457 | ||
458 | #ifdef CONFIG_PRAM | |
459 | /* | |
460 | * Export available size of memory for Linux, | |
461 | * taking into account the protected RAM at top of memory | |
462 | */ | |
463 | { | |
464 | ulong pram; | |
465 | char *s; | |
466 | uchar memsz[32]; | |
467 | ||
468 | if ((s = getenv ("pram")) != NULL) { | |
469 | pram = simple_strtoul (s, NULL, 10); | |
470 | } else { | |
471 | pram = CONFIG_PRAM; | |
472 | } | |
473 | sprintf (memsz, "%ldk", (bd->bi_memsize / 1024) - pram); | |
474 | setenv ("mem", memsz); | |
475 | } | |
476 | #endif | |
477 | ||
478 | /* Initialization complete - start the monitor */ | |
479 | ||
480 | /* main_loop() can return to retry autoboot, if so just run it again. */ | |
481 | for (;;) { | |
482 | WATCHDOG_RESET (); | |
483 | main_loop (); | |
484 | } | |
485 | ||
486 | /* NOTREACHED - no way out of command loop except booting */ | |
487 | } | |
488 | ||
489 | void hang (void) | |
490 | { | |
491 | puts ("### ERROR ### Please RESET the board ###\n"); | |
492 | for (;;); | |
493 | } |