1 /*
2  * (C) Copyright 2002
3  * Daniel Engstr�m, Omicron Ceti AB, daniel@omicron.se
4  *
5  * (C) Copyright 2002
6  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7  *
8  * (C) Copyright 2002
9  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
10  * Marius Groeger <mgroeger@sysgo.de>
11  *
12  * See file CREDITS for list of people who contributed to this
13  * project.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of
18  * the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28  * MA 02111-1307 USA
29  */
30 
31 #include <common.h>
32 #include <watchdog.h>
33 #include <command.h>
34 #include <stdio_dev.h>
35 #include <timestamp.h>
36 #include <version.h>
37 #include <malloc.h>
38 #include <net.h>
39 #include <ide.h>
40 #include <serial.h>
41 #include <asm/u-boot-i386.h>
42 #include <elf.h>
43 
44 #ifdef CONFIG_BITBANGMII
45 #include <miiphy.h>
46 #endif
47 
48 DECLARE_GLOBAL_DATA_PTR;
49 
50 /* Exports from the Linker Script */
51 extern ulong _i386boot_text_start;
52 extern ulong _i386boot_rel_dyn_start;
53 extern ulong _i386boot_rel_dyn_end;
54 extern ulong _i386boot_bss_start;
55 extern ulong _i386boot_bss_size;
56 
57 void ram_bootstrap (void *, ulong);
58 
59 const char version_string[] =
60 	U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")";
61 
62 /************************************************************************
63  * Init Utilities							*
64  ************************************************************************
65  * Some of this code should be moved into the core functions,
66  * or dropped completely,
67  * but let's get it working (again) first...
68  */
init_baudrate(void)69 static int init_baudrate (void)
70 {
71 	char tmp[64];	/* long enough for environment variables */
72 	int i = getenv_r("baudrate", tmp, 64);
73 
74 	gd->baudrate = (i != 0)
75 			? (int) simple_strtoul (tmp, NULL, 10)
76 			: CONFIG_BAUDRATE;
77 
78 	return (0);
79 }
80 
display_banner(void)81 static int display_banner (void)
82 {
83 
84 	printf ("\n\n%s\n\n", version_string);
85 /*
86 	printf ("U-Boot code: %08lX -> %08lX  data: %08lX -> %08lX\n"
87 		"        BSS: %08lX -> %08lX stack: %08lX -> %08lX\n",
88 		i386boot_start, i386boot_romdata_start-1,
89 		i386boot_romdata_dest, i386boot_romdata_dest+i386boot_romdata_size-1,
90 		i386boot_bss_start, i386boot_bss_start+i386boot_bss_size-1,
91 		i386boot_bss_start+i386boot_bss_size,
92 		i386boot_bss_start+i386boot_bss_size+CONFIG_SYS_STACK_SIZE-1);
93 
94 */
95 
96 	return (0);
97 }
98 
99 /*
100  * WARNING: this code looks "cleaner" than the PowerPC version, but
101  * has the disadvantage that you either get nothing, or everything.
102  * On PowerPC, you might see "DRAM: " before the system hangs - which
103  * gives a simple yet clear indication which part of the
104  * initialization if failing.
105  */
display_dram_config(void)106 static int display_dram_config (void)
107 {
108 	int i;
109 
110 	puts ("DRAM Configuration:\n");
111 
112 	for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
113 		printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
114 		print_size (gd->bd->bi_dram[i].size, "\n");
115 	}
116 
117 	return (0);
118 }
119 
display_flash_config(ulong size)120 static void display_flash_config (ulong size)
121 {
122 	puts ("Flash: ");
123 	print_size (size, "\n");
124 }
125 
126 /*
127  * Breath some life into the board...
128  *
129  * Initialize an SMC for serial comms, and carry out some hardware
130  * tests.
131  *
132  * The first part of initialization is running from Flash memory;
133  * its main purpose is to initialize the RAM so that we
134  * can relocate the monitor code to RAM.
135  */
136 
137 
138 /*
139  * All attempts to come up with a "common" initialization sequence
140  * that works for all boards and architectures failed: some of the
141  * requirements are just _too_ different. To get rid of the resulting
142  * mess of board dependend #ifdef'ed code we now make the whole
143  * initialization sequence configurable to the user.
144  *
145  * The requirements for any new initalization function is simple: it
146  * receives a pointer to the "global data" structure as it's only
147  * argument, and returns an integer return code, where 0 means
148  * "continue" and != 0 means "fatal error, hang the system".
149  */
150 typedef int (init_fnc_t) (void);
151 
152 init_fnc_t *init_sequence[] = {
153 	cpu_init_r,		/* basic cpu dependent setup */
154 	board_early_init_r,	/* basic board dependent setup */
155 	dram_init,		/* configure available RAM banks */
156 	interrupt_init,		/* set up exceptions */
157 	timer_init,
158 	env_init,		/* initialize environment */
159 	init_baudrate,		/* initialze baudrate settings */
160 	serial_init,		/* serial communications setup */
161 	display_banner,
162 	display_dram_config,
163 
164 	NULL,
165 };
166 
167 static gd_t gd_data;
168 gd_t *gd;
169 
170 /*
171  * Load U-Boot into RAM, initialize BSS, perform relocation adjustments
172  */
board_init_f(ulong stack_limit)173 void board_init_f (ulong stack_limit)
174 {
175 	void *text_start = &_i386boot_text_start;
176 	void *u_boot_cmd_end = &__u_boot_cmd_end;
177 	Elf32_Rel *rel_dyn_start = (Elf32_Rel *)&_i386boot_rel_dyn_start;
178 	Elf32_Rel *rel_dyn_end = (Elf32_Rel *)&_i386boot_rel_dyn_end;
179 	void *bss_start = &_i386boot_bss_start;
180 	ulong bss_size = (ulong)&_i386boot_bss_size;
181 
182 	ulong uboot_size;
183 	void *dest_addr;
184 	ulong rel_offset;
185 	Elf32_Rel *re;
186 
187 	void (*start_func)(void *, ulong);
188 
189 	uboot_size = (ulong)u_boot_cmd_end - (ulong)text_start;
190 	dest_addr  = (void *)stack_limit - (uboot_size + (ulong)bss_size);
191 	rel_offset = text_start - dest_addr;
192 	start_func = ram_bootstrap - rel_offset;
193 
194 	/* First stage CPU initialization */
195 	if (cpu_init_f() != 0)
196 		hang();
197 
198 	/* First stage Board initialization */
199 	if (board_early_init_f() != 0)
200 		hang();
201 
202 	/* Copy U-Boot into RAM */
203 	memcpy(dest_addr, text_start, uboot_size);
204 
205 	/* Clear BSS */
206 	memset(bss_start - rel_offset,	0, bss_size);
207 
208 	/* Perform relocation adjustments */
209 	for (re = rel_dyn_start; re < rel_dyn_end; re++)
210 	{
211 		if (re->r_offset >= TEXT_BASE)
212 			if (*(ulong *)re->r_offset >= TEXT_BASE)
213 				*(ulong *)(re->r_offset - rel_offset) -= (Elf32_Addr)rel_offset;
214 	}
215 
216 	/* Enter the relocated U-Boot! */
217 	start_func(dest_addr, rel_offset);
218 	/* NOTREACHED - board_init_f() does not return */
219 	while(1);
220 }
221 
222 /*
223  * We cannot initialize gd_data in board_init_f() because we would be
224  * attempting to write to flash (I have even tried using manual relocation
225  * adjustments on pointers but it just won't work) and board_init_r() does
226  * not have enough arguments to allow us to pass the relocation offset
227  * straight up. This bootstrap function (which runs in RAM) is used to
228  * setup gd_data in order to pass the relocation offset to the rest of
229  * U-Boot.
230  *
231  * TODO: The compiler optimization barrier is intended to stop GCC from
232  * optimizing this function into board_init_f(). It seems to work without
233  * it, but I've left it in to be sure. I think also that the barrier in
234  * board_init_r() is no longer needed, but left it in 'just in case'
235  */
ram_bootstrap(void * dest_addr,ulong rel_offset)236 void ram_bootstrap (void *dest_addr, ulong rel_offset)
237 {
238 	/* compiler optimization barrier needed for GCC >= 3.4 */
239 	__asm__ __volatile__("": : :"memory");
240 
241 	/* tell others: relocation done */
242 	gd_data.reloc_off = rel_offset;
243 	gd_data.flags |= GD_FLG_RELOC;
244 
245 	board_init_r(&gd_data, (ulong)dest_addr);
246 }
247 
board_init_r(gd_t * id,ulong dest_addr)248 void board_init_r(gd_t *id, ulong dest_addr)
249 {
250 	char *s;
251 	int i;
252 	ulong size;
253 	static bd_t bd_data;
254 	init_fnc_t **init_fnc_ptr;
255 
256 	show_boot_progress(0x21);
257 
258 	gd = id;
259 	/* compiler optimization barrier needed for GCC >= 3.4 */
260 	__asm__ __volatile__("": : :"memory");
261 
262 	gd->bd = &bd_data;
263 	memset (gd->bd, 0, sizeof (bd_t));
264 	show_boot_progress(0x22);
265 
266 	gd->baudrate =  CONFIG_BAUDRATE;
267 
268 	mem_malloc_init((((ulong)dest_addr - CONFIG_SYS_MALLOC_LEN)+3)&~3,
269 			CONFIG_SYS_MALLOC_LEN);
270 
271 	for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) {
272 		show_boot_progress(0xa130|i);
273 
274 		if ((*init_fnc_ptr)() != 0) {
275 			hang ();
276 		}
277 	}
278 	show_boot_progress(0x23);
279 
280 #ifdef CONFIG_SERIAL_MULTI
281 	serial_initialize();
282 #endif
283 	/* configure available FLASH banks */
284 	size = flash_init();
285 	display_flash_config(size);
286 	show_boot_progress(0x24);
287 
288 	show_boot_progress(0x25);
289 
290 	/* initialize environment */
291 	env_relocate ();
292 	show_boot_progress(0x26);
293 
294 
295 #ifdef CONFIG_CMD_NET
296 	/* IP Address */
297 	bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
298 #endif
299 
300 #if defined(CONFIG_PCI)
301 	/*
302 	 * Do pci configuration
303 	 */
304 	pci_init();
305 #endif
306 
307 	show_boot_progress(0x27);
308 
309 
310 	stdio_init ();
311 
312 	jumptable_init ();
313 
314 	/* Initialize the console (after the relocation and devices init) */
315 	console_init_r();
316 
317 #ifdef CONFIG_MISC_INIT_R
318 	/* miscellaneous platform dependent initialisations */
319 	misc_init_r();
320 #endif
321 
322 #if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
323 	WATCHDOG_RESET();
324 	puts ("PCMCIA:");
325 	pcmcia_init();
326 #endif
327 
328 #if defined(CONFIG_CMD_KGDB)
329 	WATCHDOG_RESET();
330 	puts("KGDB:  ");
331 	kgdb_init();
332 #endif
333 
334 	/* enable exceptions */
335 	enable_interrupts();
336 	show_boot_progress(0x28);
337 
338 	/* Must happen after interrupts are initialized since
339 	 * an irq handler gets installed
340 	 */
341 #ifdef CONFIG_SERIAL_SOFTWARE_FIFO
342 	serial_buffered_init();
343 #endif
344 
345 #ifdef CONFIG_STATUS_LED
346 	status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING);
347 #endif
348 
349 	udelay(20);
350 
351 	set_timer (0);
352 
353 	/* Initialize from environment */
354 	if ((s = getenv ("loadaddr")) != NULL) {
355 		load_addr = simple_strtoul (s, NULL, 16);
356 	}
357 #if defined(CONFIG_CMD_NET)
358 	if ((s = getenv ("bootfile")) != NULL) {
359 		copy_filename (BootFile, s, sizeof (BootFile));
360 	}
361 #endif
362 
363 	WATCHDOG_RESET();
364 
365 #if defined(CONFIG_CMD_IDE)
366 	WATCHDOG_RESET();
367 	puts("IDE:   ");
368 	ide_init();
369 #endif
370 
371 #if defined(CONFIG_CMD_SCSI)
372 	WATCHDOG_RESET();
373 	puts("SCSI:  ");
374 	scsi_init();
375 #endif
376 
377 #if defined(CONFIG_CMD_DOC)
378 	WATCHDOG_RESET();
379 	puts("DOC:   ");
380 	doc_init();
381 #endif
382 
383 #ifdef CONFIG_BITBANGMII
384 	bb_miiphy_init();
385 #endif
386 #if defined(CONFIG_CMD_NET)
387 #if defined(CONFIG_NET_MULTI)
388 	WATCHDOG_RESET();
389 	puts("Net:   ");
390 #endif
391 	eth_initialize(gd->bd);
392 #endif
393 
394 #if ( defined(CONFIG_CMD_NET)) && (0)
395 	WATCHDOG_RESET();
396 # ifdef DEBUG
397 	puts ("Reset Ethernet PHY\n");
398 # endif
399 	reset_phy();
400 #endif
401 
402 #ifdef CONFIG_LAST_STAGE_INIT
403 	WATCHDOG_RESET();
404 	/*
405 	 * Some parts can be only initialized if all others (like
406 	 * Interrupts) are up and running (i.e. the PC-style ISA
407 	 * keyboard).
408 	 */
409 	last_stage_init();
410 #endif
411 
412 
413 #ifdef CONFIG_POST
414 	post_run (NULL, POST_RAM | post_bootmode_get(0));
415 #endif
416 
417 
418 	show_boot_progress(0x29);
419 
420 	/* main_loop() can return to retry autoboot, if so just run it again. */
421 	for (;;) {
422 		main_loop();
423 	}
424 
425 	/* NOTREACHED - no way out of command loop except booting */
426 }
427 
hang(void)428 void hang (void)
429 {
430 	puts ("### ERROR ### Please RESET the board ###\n");
431 	for (;;);
432 }
433 
do_go_exec(ulong (* entry)(int,char * []),int argc,char * argv[])434 unsigned long do_go_exec (ulong (*entry)(int, char *[]), int argc, char *argv[])
435 {
436 	/*
437 	 * x86 does not use a dedicated register to pass the pointer
438 	 * to the global_data
439 	 */
440 	argv[-1] = (char *)gd;
441 
442 	return (entry) (argc, argv);
443 }
444 
445 void setup_pcat_compatibility(void)
446 	__attribute__((weak, alias("__setup_pcat_compatibility")));
447 
__setup_pcat_compatibility(void)448 void __setup_pcat_compatibility(void)
449 {
450 }
451