]>
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 | ||
2262cfee WD |
59 | /************************************************************************ |
60 | * Init Utilities * | |
61 | ************************************************************************ | |
62 | * Some of this code should be moved into the core functions, | |
63 | * or dropped completely, | |
64 | * but let's get it working (again) first... | |
65 | */ | |
83088afb | 66 | static int init_baudrate(void) |
2262cfee | 67 | { |
f5ca20c6 SG |
68 | gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE); |
69 | return 0; | |
2262cfee WD |
70 | } |
71 | ||
83088afb | 72 | static int display_banner(void) |
2262cfee WD |
73 | { |
74 | ||
83088afb | 75 | printf("\n\n%s\n\n", version_string); |
2262cfee | 76 | |
83088afb | 77 | return 0; |
2262cfee WD |
78 | } |
79 | ||
83088afb | 80 | static int display_dram_config(void) |
2262cfee | 81 | { |
2262cfee WD |
82 | int i; |
83 | ||
83088afb | 84 | puts("DRAM Configuration:\n"); |
2262cfee | 85 | |
83088afb GR |
86 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { |
87 | printf("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); | |
88 | print_size(gd->bd->bi_dram[i].size, "\n"); | |
2262cfee | 89 | } |
8bde7f77 | 90 | |
83088afb | 91 | return 0; |
2262cfee WD |
92 | } |
93 | ||
a76fc70e | 94 | #ifndef CONFIG_SYS_NO_FLASH |
83088afb | 95 | static void display_flash_config(ulong size) |
2262cfee | 96 | { |
83088afb GR |
97 | puts("Flash: "); |
98 | print_size(size, "\n"); | |
2262cfee | 99 | } |
a76fc70e | 100 | #endif |
2262cfee | 101 | |
2262cfee WD |
102 | /* |
103 | * Breath some life into the board... | |
104 | * | |
105 | * Initialize an SMC for serial comms, and carry out some hardware | |
106 | * tests. | |
107 | * | |
108 | * The first part of initialization is running from Flash memory; | |
109 | * its main purpose is to initialize the RAM so that we | |
110 | * can relocate the monitor code to RAM. | |
111 | */ | |
112 | ||
113 | /* | |
114 | * All attempts to come up with a "common" initialization sequence | |
115 | * that works for all boards and architectures failed: some of the | |
116 | * requirements are just _too_ different. To get rid of the resulting | |
117 | * mess of board dependend #ifdef'ed code we now make the whole | |
118 | * initialization sequence configurable to the user. | |
119 | * | |
120 | * The requirements for any new initalization function is simple: it | |
121 | * receives a pointer to the "global data" structure as it's only | |
122 | * argument, and returns an integer return code, where 0 means | |
123 | * "continue" and != 0 means "fatal error, hang the system". | |
124 | */ | |
125 | typedef int (init_fnc_t) (void); | |
126 | ||
e4f78d78 GR |
127 | static int calculate_relocation_address(void); |
128 | static int copy_uboot_to_ram(void); | |
129 | static int clear_bss(void); | |
130 | static int do_elf_reloc_fixups(void); | |
131 | ||
132 | init_fnc_t *init_sequence_f[] = { | |
133 | cpu_init_f, | |
134 | board_early_init_f, | |
135 | env_init, | |
136 | init_baudrate, | |
137 | serial_init, | |
138 | console_init_f, | |
139 | dram_init_f, | |
140 | calculate_relocation_address, | |
141 | copy_uboot_to_ram, | |
142 | clear_bss, | |
143 | do_elf_reloc_fixups, | |
144 | ||
145 | NULL, | |
146 | }; | |
147 | ||
148 | init_fnc_t *init_sequence_r[] = { | |
1c409bc7 GR |
149 | cpu_init_r, /* basic cpu dependent setup */ |
150 | board_early_init_r, /* basic board dependent setup */ | |
2262cfee | 151 | dram_init, /* configure available RAM banks */ |
2262cfee | 152 | interrupt_init, /* set up exceptions */ |
8bde7f77 | 153 | timer_init, |
2262cfee WD |
154 | display_banner, |
155 | display_dram_config, | |
156 | ||
157 | NULL, | |
158 | }; | |
159 | ||
3ef96ded | 160 | gd_t *gd; |
2262cfee | 161 | |
71a54049 | 162 | static int calculate_relocation_address(void) |
1c409bc7 | 163 | { |
303418cc GR |
164 | ulong text_start = (ulong)&__text_start; |
165 | ulong bss_end = (ulong)&__bss_end; | |
166 | ulong dest_addr; | |
71a54049 GR |
167 | ulong rel_offset; |
168 | ||
169 | /* Calculate destination RAM Address and relocation offset */ | |
303418cc | 170 | dest_addr = gd->ram_size; |
71a54049 GR |
171 | dest_addr -= CONFIG_SYS_STACK_SIZE; |
172 | dest_addr -= (bss_end - text_start); | |
303418cc GR |
173 | |
174 | /* | |
175 | * Round destination address down to 16-byte boundary to keep | |
176 | * IDT and GDT 16-byte aligned | |
177 | */ | |
178 | dest_addr &= ~15; | |
179 | ||
71a54049 GR |
180 | rel_offset = dest_addr - text_start; |
181 | ||
182 | gd->start_addr_sp = gd->ram_size; | |
303418cc | 183 | gd->relocaddr = dest_addr; |
71a54049 GR |
184 | gd->reloc_off = rel_offset; |
185 | ||
186 | return 0; | |
187 | } | |
188 | ||
189 | static int copy_uboot_to_ram(void) | |
190 | { | |
1176a706 | 191 | size_t len = (size_t)&__data_end - (size_t)&__text_start; |
71a54049 | 192 | |
1176a706 | 193 | memcpy((void *)gd->relocaddr, (void *)&__text_start, len); |
71a54049 GR |
194 | |
195 | return 0; | |
196 | } | |
197 | ||
198 | static int clear_bss(void) | |
199 | { | |
1176a706 GR |
200 | ulong dst_addr = (ulong)&__bss_start + gd->reloc_off; |
201 | size_t len = (size_t)&__bss_end - (size_t)&__bss_start; | |
f2ff75c0 | 202 | |
1176a706 | 203 | memset((void *)dst_addr, 0x00, len); |
71a54049 GR |
204 | |
205 | return 0; | |
206 | } | |
1c409bc7 | 207 | |
71a54049 GR |
208 | static int do_elf_reloc_fixups(void) |
209 | { | |
210 | Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); | |
211 | Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end); | |
212 | ||
83088afb GR |
213 | Elf32_Addr *offset_ptr_rom; |
214 | Elf32_Addr *offset_ptr_ram; | |
215 | ||
60a9b6bf GB |
216 | /* The size of the region of u-boot that runs out of RAM. */ |
217 | uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start; | |
218 | ||
71a54049 | 219 | do { |
83088afb GR |
220 | /* Get the location from the relocation entry */ |
221 | offset_ptr_rom = (Elf32_Addr *)re_src->r_offset; | |
222 | ||
223 | /* Check that the location of the relocation is in .text */ | |
224 | if (offset_ptr_rom >= (Elf32_Addr *)CONFIG_SYS_TEXT_BASE) { | |
225 | ||
226 | /* Switch to the in-RAM version */ | |
60a9b6bf GB |
227 | offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + |
228 | gd->reloc_off); | |
83088afb GR |
229 | |
230 | /* Check that the target points into .text */ | |
769db03a GB |
231 | if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE && |
232 | *offset_ptr_ram < | |
233 | (CONFIG_SYS_TEXT_BASE + size)) { | |
83088afb | 234 | *offset_ptr_ram += gd->reloc_off; |
769db03a | 235 | } |
83088afb | 236 | } |
71a54049 GR |
237 | } while (re_src++ < re_end); |
238 | ||
239 | return 0; | |
240 | } | |
96cd6642 | 241 | |
dbf7115a | 242 | /* Load U-Boot into RAM, initialize BSS, perform relocation adjustments */ |
71a54049 GR |
243 | void board_init_f(ulong boot_flags) |
244 | { | |
e4f78d78 | 245 | init_fnc_t **init_fnc_ptr; |
f2ff75c0 | 246 | |
dbf7115a GR |
247 | gd->flags = boot_flags; |
248 | ||
e4f78d78 GR |
249 | for (init_fnc_ptr = init_sequence_f; *init_fnc_ptr; ++init_fnc_ptr) { |
250 | if ((*init_fnc_ptr)() != 0) | |
251 | hang(); | |
252 | } | |
1c409bc7 | 253 | |
2e2613d2 | 254 | gd->flags |= GD_FLG_RELOC; |
161b3589 | 255 | |
f48dd6fc GR |
256 | /* |
257 | * SDRAM is now initialised, U-Boot has been copied into SDRAM, | |
258 | * the BSS has been cleared etc. The final stack can now be setup | |
259 | * in SDRAM. Code execution will continue (momentarily) in Flash, | |
260 | * but with the stack in SDRAM and Global Data in temporary memory | |
261 | * (CPU cache) | |
262 | */ | |
263 | board_init_f_r_trampoline(gd->start_addr_sp); | |
264 | ||
265 | /* NOTREACHED - board_init_f_r_trampoline() does not return */ | |
266 | while (1) | |
267 | ; | |
268 | } | |
269 | ||
270 | void board_init_f_r(void) | |
271 | { | |
272 | /* | |
273 | * Transfer execution from Flash to RAM by calculating the address | |
274 | * of the in-RAM copy of board_init_r() and calling it | |
275 | */ | |
276 | (board_init_r + gd->reloc_off)(gd, gd->relocaddr); | |
161b3589 | 277 | |
f48dd6fc | 278 | /* NOTREACHED - board_init_r() does not return */ |
83088afb GR |
279 | while (1) |
280 | ; | |
1c409bc7 GR |
281 | } |
282 | ||
2fb1bc4f | 283 | void board_init_r(gd_t *id, ulong dest_addr) |
2262cfee | 284 | { |
a76fc70e | 285 | #if defined(CONFIG_CMD_NET) |
2262cfee | 286 | char *s; |
a76fc70e GR |
287 | #endif |
288 | #ifndef CONFIG_SYS_NO_FLASH | |
2262cfee | 289 | ulong size; |
a76fc70e | 290 | #endif |
2262cfee | 291 | static bd_t bd_data; |
2e2613d2 | 292 | static gd_t gd_data; |
2262cfee | 293 | init_fnc_t **init_fnc_ptr; |
8bde7f77 | 294 | |
2262cfee WD |
295 | show_boot_progress(0x21); |
296 | ||
2e2613d2 GR |
297 | /* Global data pointer is now writable */ |
298 | gd = &gd_data; | |
299 | memcpy(gd, id, sizeof(gd_t)); | |
300 | ||
93f6a677 | 301 | /* compiler optimization barrier needed for GCC >= 3.4 */ |
83088afb | 302 | __asm__ __volatile__("" : : : "memory"); |
8bde7f77 | 303 | |
2262cfee | 304 | gd->bd = &bd_data; |
83088afb | 305 | memset(gd->bd, 0, sizeof(bd_t)); |
2262cfee WD |
306 | show_boot_progress(0x22); |
307 | ||
7a8e9bed | 308 | gd->baudrate = CONFIG_BAUDRATE; |
8bde7f77 | 309 | |
2fb1bc4f | 310 | mem_malloc_init((((ulong)dest_addr - CONFIG_SYS_MALLOC_LEN)+3)&~3, |
1c409bc7 GR |
311 | CONFIG_SYS_MALLOC_LEN); |
312 | ||
e4f78d78 GR |
313 | for (init_fnc_ptr = init_sequence_r; *init_fnc_ptr; ++init_fnc_ptr) { |
314 | if ((*init_fnc_ptr)() != 0) | |
83088afb | 315 | hang(); |
2262cfee WD |
316 | } |
317 | show_boot_progress(0x23); | |
318 | ||
bf16500f GR |
319 | #ifdef CONFIG_SERIAL_MULTI |
320 | serial_initialize(); | |
321 | #endif | |
a76fc70e GR |
322 | |
323 | #ifndef CONFIG_SYS_NO_FLASH | |
2262cfee WD |
324 | /* configure available FLASH banks */ |
325 | size = flash_init(); | |
326 | display_flash_config(size); | |
327 | show_boot_progress(0x24); | |
a76fc70e | 328 | #endif |
2262cfee WD |
329 | |
330 | show_boot_progress(0x25); | |
331 | ||
332 | /* initialize environment */ | |
83088afb | 333 | env_relocate(); |
2262cfee WD |
334 | show_boot_progress(0x26); |
335 | ||
336 | ||
535ad2db | 337 | #ifdef CONFIG_CMD_NET |
2262cfee | 338 | /* IP Address */ |
83088afb | 339 | bd_data.bi_ip_addr = getenv_IPaddr("ipaddr"); |
535ad2db | 340 | #endif |
2262cfee | 341 | |
2262cfee WD |
342 | #if defined(CONFIG_PCI) |
343 | /* | |
344 | * Do pci configuration | |
345 | */ | |
346 | pci_init(); | |
347 | #endif | |
348 | ||
349 | show_boot_progress(0x27); | |
350 | ||
351 | ||
83088afb | 352 | stdio_init(); |
2262cfee | 353 | |
83088afb | 354 | jumptable_init(); |
8bde7f77 | 355 | |
2262cfee WD |
356 | /* Initialize the console (after the relocation and devices init) */ |
357 | console_init_r(); | |
2262cfee WD |
358 | |
359 | #ifdef CONFIG_MISC_INIT_R | |
360 | /* miscellaneous platform dependent initialisations */ | |
361 | misc_init_r(); | |
362 | #endif | |
363 | ||
67350568 | 364 | #if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE) |
2262cfee | 365 | WATCHDOG_RESET(); |
83088afb | 366 | puts("PCMCIA:"); |
2262cfee WD |
367 | pcmcia_init(); |
368 | #endif | |
369 | ||
67350568 | 370 | #if defined(CONFIG_CMD_KGDB) |
2262cfee WD |
371 | WATCHDOG_RESET(); |
372 | puts("KGDB: "); | |
373 | kgdb_init(); | |
374 | #endif | |
375 | ||
376 | /* enable exceptions */ | |
7a8e9bed | 377 | enable_interrupts(); |
2262cfee WD |
378 | show_boot_progress(0x28); |
379 | ||
2262cfee | 380 | #ifdef CONFIG_STATUS_LED |
83088afb | 381 | status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING); |
2262cfee WD |
382 | #endif |
383 | ||
7a8e9bed | 384 | udelay(20); |
2262cfee | 385 | |
2262cfee | 386 | /* Initialize from environment */ |
f5ca20c6 | 387 | load_addr = getenv_ulong("loadaddr", 16, load_addr); |
67350568 | 388 | #if defined(CONFIG_CMD_NET) |
83088afb GR |
389 | s = getenv("bootfile"); |
390 | ||
391 | if (s != NULL) | |
392 | copy_filename(BootFile, s, sizeof(BootFile)); | |
b3aff0cb | 393 | #endif |
2262cfee WD |
394 | |
395 | WATCHDOG_RESET(); | |
396 | ||
67350568 | 397 | #if defined(CONFIG_CMD_IDE) |
2262cfee WD |
398 | WATCHDOG_RESET(); |
399 | puts("IDE: "); | |
400 | ide_init(); | |
b3aff0cb | 401 | #endif |
2262cfee | 402 | |
67350568 | 403 | #if defined(CONFIG_CMD_SCSI) |
2262cfee WD |
404 | WATCHDOG_RESET(); |
405 | puts("SCSI: "); | |
406 | scsi_init(); | |
407 | #endif | |
408 | ||
67350568 | 409 | #if defined(CONFIG_CMD_DOC) |
2262cfee | 410 | WATCHDOG_RESET(); |
7a8e9bed | 411 | puts("DOC: "); |
2262cfee WD |
412 | doc_init(); |
413 | #endif | |
414 | ||
310cecb8 LCM |
415 | #ifdef CONFIG_BITBANGMII |
416 | bb_miiphy_init(); | |
417 | #endif | |
67350568 | 418 | #if defined(CONFIG_CMD_NET) |
2262cfee WD |
419 | WATCHDOG_RESET(); |
420 | puts("Net: "); | |
421 | eth_initialize(gd->bd); | |
422 | #endif | |
423 | ||
83088afb | 424 | #if (defined(CONFIG_CMD_NET)) && (0) |
63ff004c MB |
425 | WATCHDOG_RESET(); |
426 | # ifdef DEBUG | |
83088afb | 427 | puts("Reset Ethernet PHY\n"); |
63ff004c MB |
428 | # endif |
429 | reset_phy(); | |
430 | #endif | |
431 | ||
2262cfee WD |
432 | #ifdef CONFIG_LAST_STAGE_INIT |
433 | WATCHDOG_RESET(); | |
434 | /* | |
435 | * Some parts can be only initialized if all others (like | |
436 | * Interrupts) are up and running (i.e. the PC-style ISA | |
437 | * keyboard). | |
438 | */ | |
439 | last_stage_init(); | |
440 | #endif | |
441 | ||
442 | ||
2262cfee | 443 | #ifdef CONFIG_POST |
83088afb | 444 | post_run(NULL, POST_RAM | post_bootmode_get(0)); |
2262cfee | 445 | #endif |
8bde7f77 | 446 | |
2262cfee | 447 | show_boot_progress(0x29); |
8bde7f77 | 448 | |
2262cfee | 449 | /* main_loop() can return to retry autoboot, if so just run it again. */ |
83088afb | 450 | for (;;) |
7a8e9bed | 451 | main_loop(); |
2262cfee WD |
452 | |
453 | /* NOTREACHED - no way out of command loop except booting */ | |
454 | } | |
455 | ||
83088afb | 456 | void hang(void) |
2262cfee | 457 | { |
83088afb GR |
458 | puts("### ERROR ### Please RESET the board ###\n"); |
459 | for (;;) | |
460 | ; | |
2262cfee | 461 | } |
a4986459 | 462 | |
83088afb GR |
463 | unsigned long do_go_exec(ulong (*entry)(int, char * const []), |
464 | int argc, char * const argv[]) | |
a4986459 | 465 | { |
e69c0cba GR |
466 | unsigned long ret = 0; |
467 | char **argv_tmp; | |
468 | ||
a4986459 | 469 | /* |
e69c0cba GR |
470 | * x86 does not use a dedicated register to pass the pointer to |
471 | * the global_data, so it is instead passed as argv[-1]. By using | |
472 | * argv[-1], the called 'Application' can use the contents of | |
473 | * argv natively. However, to safely use argv[-1] a new copy of | |
474 | * argv is needed with the extra element | |
a4986459 | 475 | */ |
e69c0cba GR |
476 | argv_tmp = malloc(sizeof(char *) * (argc + 1)); |
477 | ||
478 | if (argv_tmp) { | |
479 | argv_tmp[0] = (char *)gd; | |
480 | ||
481 | memcpy(&argv_tmp[1], argv, (size_t)(sizeof(char *) * argc)); | |
482 | ||
483 | ret = (entry) (argc, &argv_tmp[1]); | |
484 | free(argv_tmp); | |
485 | } | |
9e08efcf | 486 | |
e69c0cba | 487 | return ret; |
a4986459 | 488 | } |
79ea6b87 GR |
489 | |
490 | void setup_pcat_compatibility(void) | |
491 | __attribute__((weak, alias("__setup_pcat_compatibility"))); | |
492 | ||
493 | void __setup_pcat_compatibility(void) | |
494 | { | |
495 | } |