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