|  | /* | 
|  | * (C) Copyright 2003 | 
|  | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <command.h> | 
|  | #include <malloc.h> | 
|  | #include <devices.h> | 
|  | #include <version.h> | 
|  | #include <net.h> | 
|  | #include <environment.h> | 
|  |  | 
|  | DECLARE_GLOBAL_DATA_PTR; | 
|  |  | 
|  | #if ( ((CFG_ENV_ADDR+CFG_ENV_SIZE) < CFG_MONITOR_BASE) || \ | 
|  | (CFG_ENV_ADDR >= (CFG_MONITOR_BASE + CFG_MONITOR_LEN)) ) || \ | 
|  | defined(CFG_ENV_IS_IN_NVRAM) | 
|  | #define	TOTAL_MALLOC_LEN	(CFG_MALLOC_LEN + CFG_ENV_SIZE) | 
|  | #else | 
|  | #define	TOTAL_MALLOC_LEN	CFG_MALLOC_LEN | 
|  | #endif | 
|  |  | 
|  | #undef DEBUG | 
|  |  | 
|  | extern int timer_init(void); | 
|  |  | 
|  | extern int incaip_set_cpuclk(void); | 
|  |  | 
|  | extern ulong uboot_end_data; | 
|  | extern ulong uboot_end; | 
|  |  | 
|  | ulong monitor_flash_len; | 
|  |  | 
|  | const char version_string[] = | 
|  | U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"; | 
|  |  | 
|  | static char *failed = "*** failed ***\n"; | 
|  |  | 
|  | /* | 
|  | * Begin and End of memory area for malloc(), and current "brk" | 
|  | */ | 
|  | static ulong mem_malloc_start; | 
|  | static ulong mem_malloc_end; | 
|  | static ulong mem_malloc_brk; | 
|  |  | 
|  | /* | 
|  | * mips_io_port_base is the begin of the address space to which x86 style | 
|  | * I/O ports are mapped. | 
|  | */ | 
|  | unsigned long mips_io_port_base = -1; | 
|  |  | 
|  | /* | 
|  | * The Malloc area is immediately below the monitor copy in DRAM | 
|  | */ | 
|  | static void mem_malloc_init (void) | 
|  | { | 
|  | ulong dest_addr = CFG_MONITOR_BASE + gd->reloc_off; | 
|  |  | 
|  | mem_malloc_end = dest_addr; | 
|  | mem_malloc_start = dest_addr - TOTAL_MALLOC_LEN; | 
|  | mem_malloc_brk = mem_malloc_start; | 
|  |  | 
|  | memset ((void *) mem_malloc_start, | 
|  | 0, | 
|  | mem_malloc_end - mem_malloc_start); | 
|  | } | 
|  |  | 
|  | void *sbrk (ptrdiff_t increment) | 
|  | { | 
|  | ulong old = mem_malloc_brk; | 
|  | ulong new = old + increment; | 
|  |  | 
|  | if ((new < mem_malloc_start) || (new > mem_malloc_end)) { | 
|  | return (NULL); | 
|  | } | 
|  | mem_malloc_brk = new; | 
|  | return ((void *) old); | 
|  | } | 
|  |  | 
|  |  | 
|  | static int init_func_ram (void) | 
|  | { | 
|  | #ifdef	CONFIG_BOARD_TYPES | 
|  | int board_type = gd->board_type; | 
|  | #else | 
|  | int board_type = 0;	/* use dummy arg */ | 
|  | #endif | 
|  | puts ("DRAM:  "); | 
|  |  | 
|  | if ((gd->ram_size = initdram (board_type)) > 0) { | 
|  | print_size (gd->ram_size, "\n"); | 
|  | return (0); | 
|  | } | 
|  | puts (failed); | 
|  | return (1); | 
|  | } | 
|  |  | 
|  | static int display_banner(void) | 
|  | { | 
|  |  | 
|  | printf ("\n\n%s\n\n", version_string); | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | static void display_flash_config(ulong size) | 
|  | { | 
|  | puts ("Flash: "); | 
|  | print_size (size, "\n"); | 
|  | } | 
|  |  | 
|  |  | 
|  | static int init_baudrate (void) | 
|  | { | 
|  | char tmp[64];	/* long enough for environment variables */ | 
|  | int i = getenv_r ("baudrate", tmp, sizeof (tmp)); | 
|  |  | 
|  | gd->baudrate = (i > 0) | 
|  | ? (int) simple_strtoul (tmp, NULL, 10) | 
|  | : CONFIG_BAUDRATE; | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Breath some life into the board... | 
|  | * | 
|  | * The first part of initialization is running from Flash memory; | 
|  | * its main purpose is to initialize the RAM so that we | 
|  | * can relocate the monitor code to RAM. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * All attempts to come up with a "common" initialization sequence | 
|  | * that works for all boards and architectures failed: some of the | 
|  | * requirements are just _too_ different. To get rid of the resulting | 
|  | * mess of board dependend #ifdef'ed code we now make the whole | 
|  | * initialization sequence configurable to the user. | 
|  | * | 
|  | * The requirements for any new initalization function is simple: it | 
|  | * receives a pointer to the "global data" structure as it's only | 
|  | * argument, and returns an integer return code, where 0 means | 
|  | * "continue" and != 0 means "fatal error, hang the system". | 
|  | */ | 
|  | typedef int (init_fnc_t) (void); | 
|  |  | 
|  | init_fnc_t *init_sequence[] = { | 
|  | timer_init, | 
|  | env_init,		/* initialize environment */ | 
|  | #ifdef CONFIG_INCA_IP | 
|  | incaip_set_cpuclk,	/* set cpu clock according to environment variable */ | 
|  | #endif | 
|  | init_baudrate,		/* initialze baudrate settings */ | 
|  | serial_init,		/* serial communications setup */ | 
|  | console_init_f, | 
|  | display_banner,		/* say that we are here */ | 
|  | checkboard, | 
|  | init_func_ram, | 
|  | NULL, | 
|  | }; | 
|  |  | 
|  |  | 
|  | void board_init_f(ulong bootflag) | 
|  | { | 
|  | gd_t gd_data, *id; | 
|  | bd_t *bd; | 
|  | init_fnc_t **init_fnc_ptr; | 
|  | ulong addr, addr_sp, len = (ulong)&uboot_end - CFG_MONITOR_BASE; | 
|  | ulong *s; | 
|  | #ifdef CONFIG_PURPLE | 
|  | void copy_code (ulong); | 
|  | #endif | 
|  |  | 
|  | /* Pointer is writable since we allocated a register for it. | 
|  | */ | 
|  | gd = &gd_data; | 
|  | /* compiler optimization barrier needed for GCC >= 3.4 */ | 
|  | __asm__ __volatile__("": : :"memory"); | 
|  |  | 
|  | memset ((void *)gd, 0, sizeof (gd_t)); | 
|  |  | 
|  | for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { | 
|  | if ((*init_fnc_ptr)() != 0) { | 
|  | hang (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Now that we have DRAM mapped and working, we can | 
|  | * relocate the code and continue running from DRAM. | 
|  | */ | 
|  | addr = CFG_SDRAM_BASE + gd->ram_size; | 
|  |  | 
|  | /* We can reserve some RAM "on top" here. | 
|  | */ | 
|  |  | 
|  | /* round down to next 4 kB limit. | 
|  | */ | 
|  | addr &= ~(4096 - 1); | 
|  | debug ("Top of RAM usable for U-Boot at: %08lx\n", addr); | 
|  |  | 
|  | /* Reserve memory for U-Boot code, data & bss | 
|  | * round down to next 16 kB limit | 
|  | */ | 
|  | addr -= len; | 
|  | addr &= ~(16 * 1024 - 1); | 
|  |  | 
|  | debug ("Reserving %ldk for U-Boot at: %08lx\n", len >> 10, addr); | 
|  |  | 
|  | /* Reserve memory for malloc() arena. | 
|  | */ | 
|  | addr_sp = addr - TOTAL_MALLOC_LEN; | 
|  | debug ("Reserving %dk for malloc() at: %08lx\n", | 
|  | TOTAL_MALLOC_LEN >> 10, addr_sp); | 
|  |  | 
|  | /* | 
|  | * (permanently) allocate a Board Info struct | 
|  | * and a permanent copy of the "global" data | 
|  | */ | 
|  | addr_sp -= sizeof(bd_t); | 
|  | bd = (bd_t *)addr_sp; | 
|  | gd->bd = bd; | 
|  | debug ("Reserving %d Bytes for Board Info at: %08lx\n", | 
|  | sizeof(bd_t), addr_sp); | 
|  |  | 
|  | addr_sp -= sizeof(gd_t); | 
|  | id = (gd_t *)addr_sp; | 
|  | debug ("Reserving %d Bytes for Global Data at: %08lx\n", | 
|  | sizeof (gd_t), addr_sp); | 
|  |  | 
|  | /* Reserve memory for boot params. | 
|  | */ | 
|  | addr_sp -= CFG_BOOTPARAMS_LEN; | 
|  | bd->bi_boot_params = addr_sp; | 
|  | debug ("Reserving %dk for boot params() at: %08lx\n", | 
|  | CFG_BOOTPARAMS_LEN >> 10, addr_sp); | 
|  |  | 
|  | /* | 
|  | * Finally, we set up a new (bigger) stack. | 
|  | * | 
|  | * Leave some safety gap for SP, force alignment on 16 byte boundary | 
|  | * Clear initial stack frame | 
|  | */ | 
|  | addr_sp -= 16; | 
|  | addr_sp &= ~0xF; | 
|  | s = (ulong *)addr_sp; | 
|  | *s-- = 0; | 
|  | *s-- = 0; | 
|  | addr_sp = (ulong)s; | 
|  | debug ("Stack Pointer at: %08lx\n", addr_sp); | 
|  |  | 
|  | /* | 
|  | * Save local variables to board info struct | 
|  | */ | 
|  | bd->bi_memstart	= CFG_SDRAM_BASE;	/* start of  DRAM memory */ | 
|  | bd->bi_memsize	= gd->ram_size;		/* size  of  DRAM memory in bytes */ | 
|  | bd->bi_baudrate	= gd->baudrate;		/* Console Baudrate */ | 
|  |  | 
|  | memcpy (id, (void *)gd, sizeof (gd_t)); | 
|  |  | 
|  | /* On the purple board we copy the code in a special way | 
|  | * in order to solve flash problems | 
|  | */ | 
|  | #ifdef CONFIG_PURPLE | 
|  | copy_code(addr); | 
|  | #endif | 
|  |  | 
|  | relocate_code (addr_sp, id, addr); | 
|  |  | 
|  | /* NOTREACHED - relocate_code() does not return */ | 
|  | } | 
|  | /************************************************************************ | 
|  | * | 
|  | * This is the next part if the initialization sequence: we are now | 
|  | * running from RAM and have a "normal" C environment, i. e. global | 
|  | * data can be written, BSS has been cleared, the stack size in not | 
|  | * that critical any more, etc. | 
|  | * | 
|  | ************************************************************************ | 
|  | */ | 
|  |  | 
|  | void board_init_r (gd_t *id, ulong dest_addr) | 
|  | { | 
|  | cmd_tbl_t *cmdtp; | 
|  | ulong size; | 
|  | extern void malloc_bin_reloc (void); | 
|  | #ifndef CFG_ENV_IS_NOWHERE | 
|  | extern char * env_name_spec; | 
|  | #endif | 
|  | char *s, *e; | 
|  | bd_t *bd; | 
|  | int i; | 
|  |  | 
|  | gd = id; | 
|  | gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */ | 
|  |  | 
|  | debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr); | 
|  |  | 
|  | gd->reloc_off = dest_addr - CFG_MONITOR_BASE; | 
|  |  | 
|  | monitor_flash_len = (ulong)&uboot_end_data - dest_addr; | 
|  |  | 
|  | /* | 
|  | * We have to relocate the command table manually | 
|  | */ | 
|  | for (cmdtp = &__u_boot_cmd_start; cmdtp !=  &__u_boot_cmd_end; cmdtp++) { | 
|  | ulong addr; | 
|  |  | 
|  | addr = (ulong) (cmdtp->cmd) + gd->reloc_off; | 
|  | #if 0 | 
|  | printf ("Command \"%s\": 0x%08lx => 0x%08lx\n", | 
|  | cmdtp->name, (ulong) (cmdtp->cmd), addr); | 
|  | #endif | 
|  | cmdtp->cmd = | 
|  | (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr; | 
|  |  | 
|  | addr = (ulong)(cmdtp->name) + gd->reloc_off; | 
|  | cmdtp->name = (char *)addr; | 
|  |  | 
|  | if (cmdtp->usage) { | 
|  | addr = (ulong)(cmdtp->usage) + gd->reloc_off; | 
|  | cmdtp->usage = (char *)addr; | 
|  | } | 
|  | #ifdef	CFG_LONGHELP | 
|  | if (cmdtp->help) { | 
|  | addr = (ulong)(cmdtp->help) + gd->reloc_off; | 
|  | cmdtp->help = (char *)addr; | 
|  | } | 
|  | #endif | 
|  | } | 
|  | /* there are some other pointer constants we must deal with */ | 
|  | #ifndef CFG_ENV_IS_NOWHERE | 
|  | env_name_spec += gd->reloc_off; | 
|  | #endif | 
|  |  | 
|  | /* configure available FLASH banks */ | 
|  | size = flash_init(); | 
|  | display_flash_config (size); | 
|  |  | 
|  | bd = gd->bd; | 
|  | bd->bi_flashstart = CFG_FLASH_BASE; | 
|  | bd->bi_flashsize = size; | 
|  | #if CFG_MONITOR_BASE == CFG_FLASH_BASE | 
|  | bd->bi_flashoffset = monitor_flash_len;	/* reserved area for U-Boot */ | 
|  | #else | 
|  | bd->bi_flashoffset = 0; | 
|  | #endif | 
|  |  | 
|  | /* initialize malloc() area */ | 
|  | mem_malloc_init(); | 
|  | malloc_bin_reloc(); | 
|  |  | 
|  | /* relocate environment function pointers etc. */ | 
|  | env_relocate(); | 
|  |  | 
|  | /* board MAC address */ | 
|  | s = getenv ("ethaddr"); | 
|  | for (i = 0; i < 6; ++i) { | 
|  | bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0; | 
|  | if (s) | 
|  | s = (*e) ? e + 1 : e; | 
|  | } | 
|  |  | 
|  | /* IP Address */ | 
|  | bd->bi_ip_addr = getenv_IPaddr("ipaddr"); | 
|  |  | 
|  | #if defined(CONFIG_PCI) | 
|  | /* | 
|  | * Do pci configuration | 
|  | */ | 
|  | pci_init(); | 
|  | #endif | 
|  |  | 
|  | /** leave this here (after malloc(), environment and PCI are working) **/ | 
|  | /* Initialize devices */ | 
|  | devices_init (); | 
|  |  | 
|  | jumptable_init (); | 
|  |  | 
|  | /* Initialize the console (after the relocation and devices init) */ | 
|  | console_init_r (); | 
|  | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ | 
|  |  | 
|  | /* Initialize from environment */ | 
|  | if ((s = getenv ("loadaddr")) != NULL) { | 
|  | load_addr = simple_strtoul (s, NULL, 16); | 
|  | } | 
|  | #if defined(CONFIG_CMD_NET) | 
|  | if ((s = getenv ("bootfile")) != NULL) { | 
|  | copy_filename (BootFile, s, sizeof (BootFile)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #if defined(CONFIG_MISC_INIT_R) | 
|  | /* miscellaneous platform dependent initialisations */ | 
|  | misc_init_r (); | 
|  | #endif | 
|  |  | 
|  | #if defined(CONFIG_CMD_NET) | 
|  | #if defined(CONFIG_NET_MULTI) | 
|  | puts ("Net:   "); | 
|  | #endif | 
|  | eth_initialize(gd->bd); | 
|  | #endif | 
|  |  | 
|  | /* main_loop() can return to retry autoboot, if so just run it again. */ | 
|  | for (;;) { | 
|  | main_loop (); | 
|  | } | 
|  |  | 
|  | /* NOTREACHED - no way out of command loop except booting */ | 
|  | } | 
|  |  | 
|  | void hang (void) | 
|  | { | 
|  | puts ("### ERROR ### Please RESET the board ###\n"); | 
|  | for (;;); | 
|  | } |