uboot/arch/x86/lib/board.c
<<
>>
Prefs
   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 */
  57DECLARE_GLOBAL_DATA_PTR = (gd_t *) (CONFIG_SYS_INIT_GD_ADDR);
  58
  59
  60/* Exports from the Linker Script */
  61extern ulong __text_start;
  62extern ulong __data_end;
  63extern ulong __rel_dyn_start;
  64extern ulong __rel_dyn_end;
  65extern ulong __bss_start;
  66extern 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 */
  75static int init_baudrate (void)
  76{
  77        char tmp[64];   /* long enough for environment variables */
  78        int i = getenv_f("baudrate", tmp, 64);
  79
  80        gd->baudrate = (i != 0)
  81                        ? (int) simple_strtoul (tmp, NULL, 10)
  82                        : CONFIG_BAUDRATE;
  83
  84        return (0);
  85}
  86
  87static int display_banner (void)
  88{
  89
  90        printf ("\n\n%s\n\n", version_string);
  91/*
  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,
  97                i386boot_bss_start+i386boot_bss_size,
  98                i386boot_bss_start+i386boot_bss_size+CONFIG_SYS_STACK_SIZE-1);
  99
 100*/
 101
 102        return (0);
 103}
 104
 105static int display_dram_config (void)
 106{
 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        }
 115
 116        return (0);
 117}
 118
 119static void display_flash_config (ulong size)
 120{
 121        puts ("Flash: ");
 122        print_size (size, "\n");
 123}
 124
 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 */
 148typedef int (init_fnc_t) (void);
 149
 150static int calculate_relocation_address(void);
 151static int copy_uboot_to_ram(void);
 152static int clear_bss(void);
 153static int do_elf_reloc_fixups(void);
 154
 155init_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
 171init_fnc_t *init_sequence_r[] = {
 172        cpu_init_r,             /* basic cpu dependent setup */
 173        board_early_init_r,     /* basic board dependent setup */
 174        dram_init,              /* configure available RAM banks */
 175        interrupt_init,         /* set up exceptions */
 176        timer_init,
 177        display_banner,
 178        display_dram_config,
 179
 180        NULL,
 181};
 182
 183gd_t *gd;
 184
 185static int calculate_relocation_address(void)
 186{
 187        void *text_start = &__text_start;
 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
 205static 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
 217static int clear_bss(void)
 218{
 219        void *bss_start = &__bss_start;
 220        void *bss_end = &__bss_end;
 221
 222        ulong *dst_addr = (ulong *)(bss_start + gd->reloc_off);
 223        ulong *end_addr = (ulong *)(bss_end + gd->reloc_off);;
 224
 225        while (dst_addr < end_addr)
 226                *dst_addr++ = 0x00000000;
 227
 228        return 0;
 229}
 230
 231static 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}
 244
 245/* Load U-Boot into RAM, initialize BSS, perform relocation adjustments */
 246void board_init_f(ulong boot_flags)
 247{
 248        init_fnc_t **init_fnc_ptr;
 249
 250        gd->flags = boot_flags;
 251
 252        for (init_fnc_ptr = init_sequence_f; *init_fnc_ptr; ++init_fnc_ptr) {
 253                if ((*init_fnc_ptr)() != 0)
 254                        hang();
 255        }
 256
 257        gd->flags |= GD_FLG_RELOC;
 258
 259        /* Enter the relocated U-Boot! */
 260        relocate_code(gd->start_addr_sp, gd, gd->relocaddr);
 261
 262        /* NOTREACHED - relocate_code() does not return */
 263        while(1);
 264}
 265
 266void board_init_r(gd_t *id, ulong dest_addr)
 267{
 268        char *s;
 269        ulong size;
 270        static bd_t bd_data;
 271        static gd_t gd_data;
 272        init_fnc_t **init_fnc_ptr;
 273
 274        show_boot_progress(0x21);
 275
 276        /* Global data pointer is now writable */
 277        gd = &gd_data;
 278        memcpy(gd, id, sizeof(gd_t));
 279
 280        /* compiler optimization barrier needed for GCC >= 3.4 */
 281        __asm__ __volatile__("": : :"memory");
 282
 283        gd->bd = &bd_data;
 284        memset (gd->bd, 0, sizeof (bd_t));
 285        show_boot_progress(0x22);
 286
 287        gd->baudrate =  CONFIG_BAUDRATE;
 288
 289        mem_malloc_init((((ulong)dest_addr - CONFIG_SYS_MALLOC_LEN)+3)&~3,
 290                        CONFIG_SYS_MALLOC_LEN);
 291
 292        for (init_fnc_ptr = init_sequence_r; *init_fnc_ptr; ++init_fnc_ptr) {
 293                if ((*init_fnc_ptr)() != 0)
 294                        hang ();
 295        }
 296        show_boot_progress(0x23);
 297
 298#ifdef CONFIG_SERIAL_MULTI
 299        serial_initialize();
 300#endif
 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
 313#ifdef CONFIG_CMD_NET
 314        /* IP Address */
 315        bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
 316#endif
 317
 318#if defined(CONFIG_PCI)
 319        /*
 320         * Do pci configuration
 321         */
 322        pci_init();
 323#endif
 324
 325        show_boot_progress(0x27);
 326
 327
 328        stdio_init ();
 329
 330        jumptable_init ();
 331
 332        /* Initialize the console (after the relocation and devices init) */
 333        console_init_r();
 334
 335#ifdef CONFIG_MISC_INIT_R
 336        /* miscellaneous platform dependent initialisations */
 337        misc_init_r();
 338#endif
 339
 340#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
 341        WATCHDOG_RESET();
 342        puts ("PCMCIA:");
 343        pcmcia_init();
 344#endif
 345
 346#if defined(CONFIG_CMD_KGDB)
 347        WATCHDOG_RESET();
 348        puts("KGDB:  ");
 349        kgdb_init();
 350#endif
 351
 352        /* enable exceptions */
 353        enable_interrupts();
 354        show_boot_progress(0x28);
 355
 356#ifdef CONFIG_STATUS_LED
 357        status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING);
 358#endif
 359
 360        udelay(20);
 361
 362        /* Initialize from environment */
 363        if ((s = getenv ("loadaddr")) != NULL) {
 364                load_addr = simple_strtoul (s, NULL, 16);
 365        }
 366#if defined(CONFIG_CMD_NET)
 367        if ((s = getenv ("bootfile")) != NULL) {
 368                copy_filename (BootFile, s, sizeof (BootFile));
 369        }
 370#endif
 371
 372        WATCHDOG_RESET();
 373
 374#if defined(CONFIG_CMD_IDE)
 375        WATCHDOG_RESET();
 376        puts("IDE:   ");
 377        ide_init();
 378#endif
 379
 380#if defined(CONFIG_CMD_SCSI)
 381        WATCHDOG_RESET();
 382        puts("SCSI:  ");
 383        scsi_init();
 384#endif
 385
 386#if defined(CONFIG_CMD_DOC)
 387        WATCHDOG_RESET();
 388        puts("DOC:   ");
 389        doc_init();
 390#endif
 391
 392#ifdef CONFIG_BITBANGMII
 393        bb_miiphy_init();
 394#endif
 395#if defined(CONFIG_CMD_NET)
 396#if defined(CONFIG_NET_MULTI)
 397        WATCHDOG_RESET();
 398        puts("Net:   ");
 399#endif
 400        eth_initialize(gd->bd);
 401#endif
 402
 403#if ( defined(CONFIG_CMD_NET)) && (0)
 404        WATCHDOG_RESET();
 405# ifdef DEBUG
 406        puts ("Reset Ethernet PHY\n");
 407# endif
 408        reset_phy();
 409#endif
 410
 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
 422#ifdef CONFIG_POST
 423        post_run (NULL, POST_RAM | post_bootmode_get(0));
 424#endif
 425
 426
 427        show_boot_progress(0x29);
 428
 429        /* main_loop() can return to retry autoboot, if so just run it again. */
 430        for (;;) {
 431                main_loop();
 432        }
 433
 434        /* NOTREACHED - no way out of command loop except booting */
 435}
 436
 437void hang (void)
 438{
 439        puts ("### ERROR ### Please RESET the board ###\n");
 440        for (;;);
 441}
 442
 443unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[])
 444{
 445        unsigned long ret = 0;
 446        char **argv_tmp;
 447
 448        /*
 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
 454         */
 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        }
 465
 466        return ret;
 467}
 468
 469void setup_pcat_compatibility(void)
 470        __attribute__((weak, alias("__setup_pcat_compatibility")));
 471
 472void __setup_pcat_compatibility(void)
 473{
 474}
 475