8963580808650c2334a4c03e480908dade98bad2
[oweals/u-boot.git] / arch / x86 / lib / board.c
1 /*
2  * (C) Copyright 2008-2011
3  * Graeme Russ, <graeme.russ@gmail.com>
4  *
5  * (C) Copyright 2002
6  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
7  *
8  * (C) Copyright 2002
9  * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
10  *
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>
37 #include <stdio_dev.h>
38 #include <version.h>
39 #include <malloc.h>
40 #include <net.h>
41 #include <ide.h>
42 #include <serial.h>
43 #include <asm/u-boot-x86.h>
44 #include <elf.h>
45
46 #ifdef CONFIG_BITBANGMII
47 #include <miiphy.h>
48 #endif
49
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
59
60 /* Exports from the Linker Script */
61 extern ulong __text_start;
62 extern ulong __data_end;
63 extern ulong __rel_dyn_start;
64 extern ulong __rel_dyn_end;
65 extern ulong __bss_start;
66 extern ulong __bss_end;
67
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  */
75 static int init_baudrate (void)
76 {
77         gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
78         return 0;
79 }
80
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 static int display_dram_config (void)
100 {
101         int i;
102
103         puts ("DRAM Configuration:\n");
104
105         for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
106                 printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
107                 print_size (gd->bd->bi_dram[i].size, "\n");
108         }
109
110         return (0);
111 }
112
113 static void display_flash_config (ulong size)
114 {
115         puts ("Flash: ");
116         print_size (size, "\n");
117 }
118
119 /*
120  * Breath some life into the board...
121  *
122  * Initialize an SMC for serial comms, and carry out some hardware
123  * tests.
124  *
125  * The first part of initialization is running from Flash memory;
126  * its main purpose is to initialize the RAM so that we
127  * can relocate the monitor code to RAM.
128  */
129
130 /*
131  * All attempts to come up with a "common" initialization sequence
132  * that works for all boards and architectures failed: some of the
133  * requirements are just _too_ different. To get rid of the resulting
134  * mess of board dependend #ifdef'ed code we now make the whole
135  * initialization sequence configurable to the user.
136  *
137  * The requirements for any new initalization function is simple: it
138  * receives a pointer to the "global data" structure as it's only
139  * argument, and returns an integer return code, where 0 means
140  * "continue" and != 0 means "fatal error, hang the system".
141  */
142 typedef int (init_fnc_t) (void);
143
144 static int calculate_relocation_address(void);
145 static int copy_uboot_to_ram(void);
146 static int clear_bss(void);
147 static int do_elf_reloc_fixups(void);
148
149 init_fnc_t *init_sequence_f[] = {
150         cpu_init_f,
151         board_early_init_f,
152         env_init,
153         init_baudrate,
154         serial_init,
155         console_init_f,
156         dram_init_f,
157         calculate_relocation_address,
158         copy_uboot_to_ram,
159         clear_bss,
160         do_elf_reloc_fixups,
161
162         NULL,
163 };
164
165 init_fnc_t *init_sequence_r[] = {
166         cpu_init_r,             /* basic cpu dependent setup */
167         board_early_init_r,     /* basic board dependent setup */
168         dram_init,              /* configure available RAM banks */
169         interrupt_init,         /* set up exceptions */
170         timer_init,
171         display_banner,
172         display_dram_config,
173
174         NULL,
175 };
176
177 gd_t *gd;
178
179 static int calculate_relocation_address(void)
180 {
181         void *text_start = &__text_start;
182         void *bss_end = &__bss_end;
183         void *dest_addr;
184         ulong rel_offset;
185
186         /* Calculate destination RAM Address and relocation offset */
187         dest_addr = (void *)gd->ram_size;
188         dest_addr -= CONFIG_SYS_STACK_SIZE;
189         dest_addr -= (bss_end - text_start);
190         rel_offset = dest_addr - text_start;
191
192         gd->start_addr_sp = gd->ram_size;
193         gd->relocaddr = (ulong)dest_addr;
194         gd->reloc_off = rel_offset;
195
196         return 0;
197 }
198
199 static int copy_uboot_to_ram(void)
200 {
201         ulong *dst_addr = (ulong *)gd->relocaddr;
202         ulong *src_addr = (ulong *)&__text_start;
203         ulong *end_addr = (ulong *)&__data_end;
204
205         while (src_addr < end_addr)
206                 *dst_addr++ = *src_addr++;
207
208         return 0;
209 }
210
211 static int clear_bss(void)
212 {
213         void *bss_start = &__bss_start;
214         void *bss_end = &__bss_end;
215
216         ulong *dst_addr = (ulong *)(bss_start + gd->reloc_off);
217         ulong *end_addr = (ulong *)(bss_end + gd->reloc_off);;
218
219         while (dst_addr < end_addr)
220                 *dst_addr++ = 0x00000000;
221
222         return 0;
223 }
224
225 static int do_elf_reloc_fixups(void)
226 {
227         Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start);
228         Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end);
229
230         do {
231                 if (re_src->r_offset >= CONFIG_SYS_TEXT_BASE)
232                         if (*(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) >= CONFIG_SYS_TEXT_BASE)
233                                 *(Elf32_Addr *)(re_src->r_offset + gd->reloc_off) += gd->reloc_off;
234         } while (re_src++ < re_end);
235
236         return 0;
237 }
238
239 /* Load U-Boot into RAM, initialize BSS, perform relocation adjustments */
240 void board_init_f(ulong boot_flags)
241 {
242         init_fnc_t **init_fnc_ptr;
243
244         gd->flags = boot_flags;
245
246         for (init_fnc_ptr = init_sequence_f; *init_fnc_ptr; ++init_fnc_ptr) {
247                 if ((*init_fnc_ptr)() != 0)
248                         hang();
249         }
250
251         gd->flags |= GD_FLG_RELOC;
252
253         /* Enter the relocated U-Boot! */
254         relocate_code(gd->start_addr_sp, gd, gd->relocaddr);
255
256         /* NOTREACHED - relocate_code() does not return */
257         while(1);
258 }
259
260 void board_init_r(gd_t *id, ulong dest_addr)
261 {
262         char *s;
263         ulong size;
264         static bd_t bd_data;
265         static gd_t gd_data;
266         init_fnc_t **init_fnc_ptr;
267
268         show_boot_progress(0x21);
269
270         /* Global data pointer is now writable */
271         gd = &gd_data;
272         memcpy(gd, id, sizeof(gd_t));
273
274         /* compiler optimization barrier needed for GCC >= 3.4 */
275         __asm__ __volatile__("": : :"memory");
276
277         gd->bd = &bd_data;
278         memset (gd->bd, 0, sizeof (bd_t));
279         show_boot_progress(0x22);
280
281         gd->baudrate =  CONFIG_BAUDRATE;
282
283         mem_malloc_init((((ulong)dest_addr - CONFIG_SYS_MALLOC_LEN)+3)&~3,
284                         CONFIG_SYS_MALLOC_LEN);
285
286         for (init_fnc_ptr = init_sequence_r; *init_fnc_ptr; ++init_fnc_ptr) {
287                 if ((*init_fnc_ptr)() != 0)
288                         hang ();
289         }
290         show_boot_progress(0x23);
291
292 #ifdef CONFIG_SERIAL_MULTI
293         serial_initialize();
294 #endif
295         /* configure available FLASH banks */
296         size = flash_init();
297         display_flash_config(size);
298         show_boot_progress(0x24);
299
300         show_boot_progress(0x25);
301
302         /* initialize environment */
303         env_relocate ();
304         show_boot_progress(0x26);
305
306
307 #ifdef CONFIG_CMD_NET
308         /* IP Address */
309         bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
310 #endif
311
312 #if defined(CONFIG_PCI)
313         /*
314          * Do pci configuration
315          */
316         pci_init();
317 #endif
318
319         show_boot_progress(0x27);
320
321
322         stdio_init ();
323
324         jumptable_init ();
325
326         /* Initialize the console (after the relocation and devices init) */
327         console_init_r();
328
329 #ifdef CONFIG_MISC_INIT_R
330         /* miscellaneous platform dependent initialisations */
331         misc_init_r();
332 #endif
333
334 #if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
335         WATCHDOG_RESET();
336         puts ("PCMCIA:");
337         pcmcia_init();
338 #endif
339
340 #if defined(CONFIG_CMD_KGDB)
341         WATCHDOG_RESET();
342         puts("KGDB:  ");
343         kgdb_init();
344 #endif
345
346         /* enable exceptions */
347         enable_interrupts();
348         show_boot_progress(0x28);
349
350 #ifdef CONFIG_STATUS_LED
351         status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING);
352 #endif
353
354         udelay(20);
355
356         /* Initialize from environment */
357         load_addr = getenv_ulong("loadaddr", 16, load_addr);
358 #if defined(CONFIG_CMD_NET)
359         if ((s = getenv ("bootfile")) != NULL) {
360                 copy_filename (BootFile, s, sizeof (BootFile));
361         }
362 #endif
363
364         WATCHDOG_RESET();
365
366 #if defined(CONFIG_CMD_IDE)
367         WATCHDOG_RESET();
368         puts("IDE:   ");
369         ide_init();
370 #endif
371
372 #if defined(CONFIG_CMD_SCSI)
373         WATCHDOG_RESET();
374         puts("SCSI:  ");
375         scsi_init();
376 #endif
377
378 #if defined(CONFIG_CMD_DOC)
379         WATCHDOG_RESET();
380         puts("DOC:   ");
381         doc_init();
382 #endif
383
384 #ifdef CONFIG_BITBANGMII
385         bb_miiphy_init();
386 #endif
387 #if defined(CONFIG_CMD_NET)
388         WATCHDOG_RESET();
389         puts("Net:   ");
390         eth_initialize(gd->bd);
391 #endif
392
393 #if ( defined(CONFIG_CMD_NET)) && (0)
394         WATCHDOG_RESET();
395 # ifdef DEBUG
396         puts ("Reset Ethernet PHY\n");
397 # endif
398         reset_phy();
399 #endif
400
401 #ifdef CONFIG_LAST_STAGE_INIT
402         WATCHDOG_RESET();
403         /*
404          * Some parts can be only initialized if all others (like
405          * Interrupts) are up and running (i.e. the PC-style ISA
406          * keyboard).
407          */
408         last_stage_init();
409 #endif
410
411
412 #ifdef CONFIG_POST
413         post_run (NULL, POST_RAM | post_bootmode_get(0));
414 #endif
415
416
417         show_boot_progress(0x29);
418
419         /* main_loop() can return to retry autoboot, if so just run it again. */
420         for (;;) {
421                 main_loop();
422         }
423
424         /* NOTREACHED - no way out of command loop except booting */
425 }
426
427 void hang (void)
428 {
429         puts ("### ERROR ### Please RESET the board ###\n");
430         for (;;);
431 }
432
433 unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[])
434 {
435         unsigned long ret = 0;
436         char **argv_tmp;
437
438         /*
439          * x86 does not use a dedicated register to pass the pointer to
440          * the global_data, so it is instead passed as argv[-1]. By using
441          * argv[-1], the called 'Application' can use the contents of
442          * argv natively. However, to safely use argv[-1] a new copy of
443          * argv is needed with the extra element
444          */
445         argv_tmp = malloc(sizeof(char *) * (argc + 1));
446
447         if (argv_tmp) {
448                 argv_tmp[0] = (char *)gd;
449
450                 memcpy(&argv_tmp[1], argv, (size_t)(sizeof(char *) * argc));
451
452                 ret = (entry) (argc, &argv_tmp[1]);
453                 free(argv_tmp);
454         }
455
456         return ret;
457 }
458
459 void setup_pcat_compatibility(void)
460         __attribute__((weak, alias("__setup_pcat_compatibility")));
461
462 void __setup_pcat_compatibility(void)
463 {
464 }