]>
Commit | Line | Data |
---|---|---|
2262cfee | 1 | /* |
dbf7115a GR |
2 | * (C) Copyright 2008-2011 |
3 | * Graeme Russ, <graeme.russ@gmail.com> | |
4 | * | |
2262cfee | 5 | * (C) Copyright 2002 |
fa82f871 | 6 | * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> |
8bde7f77 | 7 | * |
2262cfee | 8 | * (C) Copyright 2002 |
dbf7115a | 9 | * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> |
8bde7f77 | 10 | * |
2262cfee WD |
11 | * (C) Copyright 2002 |
12 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
13 | * Marius Groeger <mgroeger@sysgo.de> | |
14 | * | |
15 | * See file CREDITS for list of people who contributed to this | |
16 | * project. | |
17 | * | |
18 | * This program is free software; you can redistribute it and/or | |
19 | * modify it under the terms of the GNU General Public License as | |
20 | * published by the Free Software Foundation; either version 2 of | |
21 | * the License, or (at your option) any later version. | |
22 | * | |
23 | * This program is distributed in the hope that it will be useful, | |
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
26 | * GNU General Public License for more details. | |
27 | * | |
28 | * You should have received a copy of the GNU General Public License | |
29 | * along with this program; if not, write to the Free Software | |
30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
31 | * MA 02111-1307 USA | |
32 | */ | |
33 | ||
34 | #include <common.h> | |
35 | #include <watchdog.h> | |
36 | #include <command.h> | |
52cb4d4f | 37 | #include <stdio_dev.h> |
2262cfee WD |
38 | #include <version.h> |
39 | #include <malloc.h> | |
2262cfee WD |
40 | #include <net.h> |
41 | #include <ide.h> | |
bf16500f | 42 | #include <serial.h> |
fea25720 | 43 | #include <asm/u-boot-x86.h> |
1c409bc7 | 44 | #include <elf.h> |
2262cfee | 45 | |
310cecb8 LCM |
46 | #ifdef CONFIG_BITBANGMII |
47 | #include <miiphy.h> | |
48 | #endif | |
49 | ||
2e2613d2 GR |
50 | /* |
51 | * Pointer to initial global data area | |
52 | * | |
53 | * Here we initialize it. | |
54 | */ | |
55 | #undef XTRN_DECLARE_GLOBAL_DATA_PTR | |
56 | #define XTRN_DECLARE_GLOBAL_DATA_PTR /* empty = allocate here */ | |
57 | DECLARE_GLOBAL_DATA_PTR = (gd_t *) (CONFIG_SYS_INIT_GD_ADDR); | |
58 | ||
d87080b7 | 59 | |
1c409bc7 | 60 | /* Exports from the Linker Script */ |
067f9b10 | 61 | extern ulong __text_start; |
22191426 | 62 | extern ulong __data_end; |
067f9b10 GR |
63 | extern ulong __rel_dyn_start; |
64 | extern ulong __rel_dyn_end; | |
65 | extern ulong __bss_start; | |
f2ff75c0 | 66 | extern ulong __bss_end; |
2fb1bc4f | 67 | |
2262cfee WD |
68 | /************************************************************************ |
69 | * Init Utilities * | |
70 | ************************************************************************ | |
71 | * Some of this code should be moved into the core functions, | |
72 | * or dropped completely, | |
73 | * but let's get it working (again) first... | |
74 | */ | |
2262cfee WD |
75 | static int init_baudrate (void) |
76 | { | |
7a8e9bed | 77 | char tmp[64]; /* long enough for environment variables */ |
cdb74977 | 78 | int i = getenv_f("baudrate", tmp, 64); |
2262cfee | 79 | |
7a8e9bed | 80 | gd->baudrate = (i != 0) |
2262cfee WD |
81 | ? (int) simple_strtoul (tmp, NULL, 10) |
82 | : CONFIG_BAUDRATE; | |
83 | ||
84 | return (0); | |
85 | } | |
86 | ||
87 | static int display_banner (void) | |
88 | { | |
89 | ||
90 | printf ("\n\n%s\n\n", version_string); | |
1c409bc7 | 91 | /* |
2262cfee WD |
92 | printf ("U-Boot code: %08lX -> %08lX data: %08lX -> %08lX\n" |
93 | " BSS: %08lX -> %08lX stack: %08lX -> %08lX\n", | |
94 | i386boot_start, i386boot_romdata_start-1, | |
95 | i386boot_romdata_dest, i386boot_romdata_dest+i386boot_romdata_size-1, | |
96 | i386boot_bss_start, i386boot_bss_start+i386boot_bss_size-1, | |
8bde7f77 | 97 | i386boot_bss_start+i386boot_bss_size, |
6d0f6bcf | 98 | i386boot_bss_start+i386boot_bss_size+CONFIG_SYS_STACK_SIZE-1); |
8bde7f77 | 99 | |
1c409bc7 | 100 | */ |
2262cfee WD |
101 | |
102 | return (0); | |
103 | } | |
104 | ||
2262cfee WD |
105 | static int display_dram_config (void) |
106 | { | |
2262cfee WD |
107 | int i; |
108 | ||
109 | puts ("DRAM Configuration:\n"); | |
110 | ||
111 | for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) { | |
112 | printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); | |
113 | print_size (gd->bd->bi_dram[i].size, "\n"); | |
114 | } | |
8bde7f77 | 115 | |
2262cfee WD |
116 | return (0); |
117 | } | |
118 | ||
119 | static void display_flash_config (ulong size) | |
120 | { | |
121 | puts ("Flash: "); | |
122 | print_size (size, "\n"); | |
123 | } | |
124 | ||
2262cfee WD |
125 | /* |
126 | * Breath some life into the board... | |
127 | * | |
128 | * Initialize an SMC for serial comms, and carry out some hardware | |
129 | * tests. | |
130 | * | |
131 | * The first part of initialization is running from Flash memory; | |
132 | * its main purpose is to initialize the RAM so that we | |
133 | * can relocate the monitor code to RAM. | |
134 | */ | |
135 | ||
136 | /* | |
137 | * All attempts to come up with a "common" initialization sequence | |
138 | * that works for all boards and architectures failed: some of the | |
139 | * requirements are just _too_ different. To get rid of the resulting | |
140 | * mess of board dependend #ifdef'ed code we now make the whole | |
141 | * initialization sequence configurable to the user. | |
142 | * | |
143 | * The requirements for any new initalization function is simple: it | |
144 | * receives a pointer to the "global data" structure as it's only | |
145 | * argument, and returns an integer return code, where 0 means | |
146 | * "continue" and != 0 means "fatal error, hang the system". | |
147 | */ | |
148 | typedef int (init_fnc_t) (void); | |
149 | ||
e4f78d78 GR |
150 | static int calculate_relocation_address(void); |
151 | static int copy_uboot_to_ram(void); | |
152 | static int clear_bss(void); | |
153 | static int do_elf_reloc_fixups(void); | |
154 | ||
155 | init_fnc_t *init_sequence_f[] = { | |
156 | cpu_init_f, | |
157 | board_early_init_f, | |
158 | env_init, | |
159 | init_baudrate, | |
160 | serial_init, | |
161 | console_init_f, | |
162 | dram_init_f, | |
163 | calculate_relocation_address, | |
164 | copy_uboot_to_ram, | |
165 | clear_bss, | |
166 | do_elf_reloc_fixups, | |
167 | ||
168 | NULL, | |
169 | }; | |
170 | ||
171 | init_fnc_t *init_sequence_r[] = { | |
1c409bc7 GR |
172 | cpu_init_r, /* basic cpu dependent setup */ |
173 | board_early_init_r, /* basic board dependent setup */ | |
2262cfee | 174 | dram_init, /* configure available RAM banks */ |
2262cfee | 175 | interrupt_init, /* set up exceptions */ |
8bde7f77 | 176 | timer_init, |
2262cfee WD |
177 | display_banner, |
178 | display_dram_config, | |
179 | ||
180 | NULL, | |
181 | }; | |
182 | ||
3ef96ded | 183 | gd_t *gd; |
2262cfee | 184 | |
71a54049 | 185 | static int calculate_relocation_address(void) |
1c409bc7 | 186 | { |
067f9b10 | 187 | void *text_start = &__text_start; |
71a54049 GR |
188 | void *bss_end = &__bss_end; |
189 | void *dest_addr; | |
190 | ulong rel_offset; | |
191 | ||
192 | /* Calculate destination RAM Address and relocation offset */ | |
193 | dest_addr = (void *)gd->ram_size; | |
194 | dest_addr -= CONFIG_SYS_STACK_SIZE; | |
195 | dest_addr -= (bss_end - text_start); | |
196 | rel_offset = dest_addr - text_start; | |
197 | ||
198 | gd->start_addr_sp = gd->ram_size; | |
199 | gd->relocaddr = (ulong)dest_addr; | |
200 | gd->reloc_off = rel_offset; | |
201 | ||
202 | return 0; | |
203 | } | |
204 | ||
205 | static int copy_uboot_to_ram(void) | |
206 | { | |
207 | ulong *dst_addr = (ulong *)gd->relocaddr; | |
208 | ulong *src_addr = (ulong *)&__text_start; | |
209 | ulong *end_addr = (ulong *)&__data_end; | |
210 | ||
211 | while (src_addr < end_addr) | |
212 | *dst_addr++ = *src_addr++; | |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
217 | static int clear_bss(void) | |
218 | { | |
067f9b10 | 219 | void *bss_start = &__bss_start; |
f2ff75c0 GR |
220 | void *bss_end = &__bss_end; |
221 | ||
71a54049 GR |
222 | ulong *dst_addr = (ulong *)(bss_start + gd->reloc_off); |
223 | ulong *end_addr = (ulong *)(bss_end + gd->reloc_off);; | |
1c409bc7 | 224 | |
71a54049 GR |
225 | while (dst_addr < end_addr) |
226 | *dst_addr++ = 0x00000000; | |
227 | ||
228 | return 0; | |
229 | } | |
1c409bc7 | 230 | |
71a54049 GR |
231 | static int do_elf_reloc_fixups(void) |
232 | { | |
233 | Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); | |
234 | Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end); | |
235 | ||
236 | do { | |
237 | if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE) | |
238 | if (*(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) >= CONFIG_SYS_TEXT_BASE) | |
239 | *(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) += gd->reloc_off; | |
240 | } while (re_src++ < re_end); | |
241 | ||
242 | return 0; | |
243 | } | |
96cd6642 | 244 | |
dbf7115a | 245 | /* Load U-Boot into RAM, initialize BSS, perform relocation adjustments */ |
71a54049 GR |
246 | void board_init_f(ulong boot_flags) |
247 | { | |
e4f78d78 | 248 | init_fnc_t **init_fnc_ptr; |
f2ff75c0 | 249 | |
dbf7115a GR |
250 | gd->flags = boot_flags; |
251 | ||
e4f78d78 GR |
252 | for (init_fnc_ptr = init_sequence_f; *init_fnc_ptr; ++init_fnc_ptr) { |
253 | if ((*init_fnc_ptr)() != 0) | |
254 | hang(); | |
255 | } | |
1c409bc7 | 256 | |
2e2613d2 | 257 | gd->flags |= GD_FLG_RELOC; |
161b3589 | 258 | |
2fb1bc4f | 259 | /* Enter the relocated U-Boot! */ |
71a54049 | 260 | relocate_code(gd->start_addr_sp, gd, gd->relocaddr); |
161b3589 | 261 | |
fb002908 | 262 | /* NOTREACHED - relocate_code() does not return */ |
1c409bc7 GR |
263 | while(1); |
264 | } | |
265 | ||
2fb1bc4f | 266 | void board_init_r(gd_t *id, ulong dest_addr) |
2262cfee | 267 | { |
2262cfee | 268 | char *s; |
2262cfee | 269 | ulong size; |
2262cfee | 270 | static bd_t bd_data; |
2e2613d2 | 271 | static gd_t gd_data; |
2262cfee | 272 | init_fnc_t **init_fnc_ptr; |
8bde7f77 | 273 | |
2262cfee WD |
274 | show_boot_progress(0x21); |
275 | ||
2e2613d2 GR |
276 | /* Global data pointer is now writable */ |
277 | gd = &gd_data; | |
278 | memcpy(gd, id, sizeof(gd_t)); | |
279 | ||
93f6a677 WD |
280 | /* compiler optimization barrier needed for GCC >= 3.4 */ |
281 | __asm__ __volatile__("": : :"memory"); | |
8bde7f77 | 282 | |
2262cfee WD |
283 | gd->bd = &bd_data; |
284 | memset (gd->bd, 0, sizeof (bd_t)); | |
285 | show_boot_progress(0x22); | |
286 | ||
7a8e9bed | 287 | gd->baudrate = CONFIG_BAUDRATE; |
8bde7f77 | 288 | |
2fb1bc4f | 289 | mem_malloc_init((((ulong)dest_addr - CONFIG_SYS_MALLOC_LEN)+3)&~3, |
1c409bc7 GR |
290 | CONFIG_SYS_MALLOC_LEN); |
291 | ||
e4f78d78 GR |
292 | for (init_fnc_ptr = init_sequence_r; *init_fnc_ptr; ++init_fnc_ptr) { |
293 | if ((*init_fnc_ptr)() != 0) | |
2262cfee | 294 | hang (); |
2262cfee WD |
295 | } |
296 | show_boot_progress(0x23); | |
297 | ||
bf16500f GR |
298 | #ifdef CONFIG_SERIAL_MULTI |
299 | serial_initialize(); | |
300 | #endif | |
2262cfee WD |
301 | /* configure available FLASH banks */ |
302 | size = flash_init(); | |
303 | display_flash_config(size); | |
304 | show_boot_progress(0x24); | |
305 | ||
306 | show_boot_progress(0x25); | |
307 | ||
308 | /* initialize environment */ | |
309 | env_relocate (); | |
310 | show_boot_progress(0x26); | |
311 | ||
312 | ||
535ad2db | 313 | #ifdef CONFIG_CMD_NET |
2262cfee WD |
314 | /* IP Address */ |
315 | bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr"); | |
535ad2db | 316 | #endif |
2262cfee | 317 | |
2262cfee WD |
318 | #if defined(CONFIG_PCI) |
319 | /* | |
320 | * Do pci configuration | |
321 | */ | |
322 | pci_init(); | |
323 | #endif | |
324 | ||
325 | show_boot_progress(0x27); | |
326 | ||
327 | ||
52cb4d4f | 328 | stdio_init (); |
2262cfee | 329 | |
27b207fd | 330 | jumptable_init (); |
8bde7f77 | 331 | |
2262cfee WD |
332 | /* Initialize the console (after the relocation and devices init) */ |
333 | console_init_r(); | |
2262cfee WD |
334 | |
335 | #ifdef CONFIG_MISC_INIT_R | |
336 | /* miscellaneous platform dependent initialisations */ | |
337 | misc_init_r(); | |
338 | #endif | |
339 | ||
67350568 | 340 | #if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE) |
2262cfee WD |
341 | WATCHDOG_RESET(); |
342 | puts ("PCMCIA:"); | |
343 | pcmcia_init(); | |
344 | #endif | |
345 | ||
67350568 | 346 | #if defined(CONFIG_CMD_KGDB) |
2262cfee WD |
347 | WATCHDOG_RESET(); |
348 | puts("KGDB: "); | |
349 | kgdb_init(); | |
350 | #endif | |
351 | ||
352 | /* enable exceptions */ | |
7a8e9bed | 353 | enable_interrupts(); |
2262cfee WD |
354 | show_boot_progress(0x28); |
355 | ||
2262cfee WD |
356 | #ifdef CONFIG_STATUS_LED |
357 | status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING); | |
358 | #endif | |
359 | ||
7a8e9bed | 360 | udelay(20); |
2262cfee | 361 | |
2262cfee WD |
362 | /* Initialize from environment */ |
363 | if ((s = getenv ("loadaddr")) != NULL) { | |
364 | load_addr = simple_strtoul (s, NULL, 16); | |
365 | } | |
67350568 | 366 | #if defined(CONFIG_CMD_NET) |
2262cfee WD |
367 | if ((s = getenv ("bootfile")) != NULL) { |
368 | copy_filename (BootFile, s, sizeof (BootFile)); | |
369 | } | |
b3aff0cb | 370 | #endif |
2262cfee WD |
371 | |
372 | WATCHDOG_RESET(); | |
373 | ||
67350568 | 374 | #if defined(CONFIG_CMD_IDE) |
2262cfee WD |
375 | WATCHDOG_RESET(); |
376 | puts("IDE: "); | |
377 | ide_init(); | |
b3aff0cb | 378 | #endif |
2262cfee | 379 | |
67350568 | 380 | #if defined(CONFIG_CMD_SCSI) |
2262cfee WD |
381 | WATCHDOG_RESET(); |
382 | puts("SCSI: "); | |
383 | scsi_init(); | |
384 | #endif | |
385 | ||
67350568 | 386 | #if defined(CONFIG_CMD_DOC) |
2262cfee | 387 | WATCHDOG_RESET(); |
7a8e9bed | 388 | puts("DOC: "); |
2262cfee WD |
389 | doc_init(); |
390 | #endif | |
391 | ||
310cecb8 LCM |
392 | #ifdef CONFIG_BITBANGMII |
393 | bb_miiphy_init(); | |
394 | #endif | |
67350568 | 395 | #if defined(CONFIG_CMD_NET) |
63ff004c | 396 | #if defined(CONFIG_NET_MULTI) |
2262cfee WD |
397 | WATCHDOG_RESET(); |
398 | puts("Net: "); | |
63ff004c | 399 | #endif |
2262cfee WD |
400 | eth_initialize(gd->bd); |
401 | #endif | |
402 | ||
67350568 | 403 | #if ( defined(CONFIG_CMD_NET)) && (0) |
63ff004c MB |
404 | WATCHDOG_RESET(); |
405 | # ifdef DEBUG | |
406 | puts ("Reset Ethernet PHY\n"); | |
407 | # endif | |
408 | reset_phy(); | |
409 | #endif | |
410 | ||
2262cfee WD |
411 | #ifdef CONFIG_LAST_STAGE_INIT |
412 | WATCHDOG_RESET(); | |
413 | /* | |
414 | * Some parts can be only initialized if all others (like | |
415 | * Interrupts) are up and running (i.e. the PC-style ISA | |
416 | * keyboard). | |
417 | */ | |
418 | last_stage_init(); | |
419 | #endif | |
420 | ||
421 | ||
2262cfee WD |
422 | #ifdef CONFIG_POST |
423 | post_run (NULL, POST_RAM | post_bootmode_get(0)); | |
2262cfee | 424 | #endif |
8bde7f77 WD |
425 | |
426 | ||
2262cfee | 427 | show_boot_progress(0x29); |
8bde7f77 | 428 | |
2262cfee WD |
429 | /* main_loop() can return to retry autoboot, if so just run it again. */ |
430 | for (;;) { | |
7a8e9bed | 431 | main_loop(); |
2262cfee WD |
432 | } |
433 | ||
434 | /* NOTREACHED - no way out of command loop except booting */ | |
435 | } | |
436 | ||
437 | void hang (void) | |
438 | { | |
439 | puts ("### ERROR ### Please RESET the board ###\n"); | |
440 | for (;;); | |
441 | } | |
a4986459 | 442 | |
e69c0cba | 443 | unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[]) |
a4986459 | 444 | { |
e69c0cba GR |
445 | unsigned long ret = 0; |
446 | char **argv_tmp; | |
447 | ||
a4986459 | 448 | /* |
e69c0cba GR |
449 | * x86 does not use a dedicated register to pass the pointer to |
450 | * the global_data, so it is instead passed as argv[-1]. By using | |
451 | * argv[-1], the called 'Application' can use the contents of | |
452 | * argv natively. However, to safely use argv[-1] a new copy of | |
453 | * argv is needed with the extra element | |
a4986459 | 454 | */ |
e69c0cba GR |
455 | argv_tmp = malloc(sizeof(char *) * (argc + 1)); |
456 | ||
457 | if (argv_tmp) { | |
458 | argv_tmp[0] = (char *)gd; | |
459 | ||
460 | memcpy(&argv_tmp[1], argv, (size_t)(sizeof(char *) * argc)); | |
461 | ||
462 | ret = (entry) (argc, &argv_tmp[1]); | |
463 | free(argv_tmp); | |
464 | } | |
9e08efcf | 465 | |
e69c0cba | 466 | return ret; |
a4986459 | 467 | } |
79ea6b87 GR |
468 | |
469 | void setup_pcat_compatibility(void) | |
470 | __attribute__((weak, alias("__setup_pcat_compatibility"))); | |
471 | ||
472 | void __setup_pcat_compatibility(void) | |
473 | { | |
474 | } |