From f1d2b313c9eb6808d30c16a9eb5251240452a56c Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Fri, 17 Sep 2010 13:10:39 +0200 Subject: ARM: add relocation support !! This breaks support for all arm boards !! To compile in old style, you must define CONFIG_SYS_ARM_WITHOUT_RELOC or you can compile with "CONFIG_SYS_ARM_WITHOUT_RELOC=1 ./MAKEALL board" !! This define will be removed soon, so convert your board to use relocation support Portions of this work were supported by funding from the CE Linux Forum. Signed-off-by: Heiko Schocher Fix boot from NAND for non-ARM systems Signed-off-by: Wolfgang Denk --- arch/arm/lib/board.c | 468 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 467 insertions(+), 1 deletion(-) (limited to 'arch/arm/lib/board.c') diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index e17f182e182..5f2dfd08acf 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -126,7 +126,12 @@ static int init_baudrate (void) { char tmp[64]; /* long enough for environment variables */ int i = getenv_f("baudrate", tmp, sizeof (tmp)); + +#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) + gd->baudrate = (i > 0) +#else gd->bd->bi_baudrate = gd->baudrate = (i > 0) +#endif ? (int) simple_strtoul (tmp, NULL, 10) : CONFIG_BAUDRATE; @@ -137,7 +142,12 @@ static int display_banner (void) { printf ("\n\n%s\n\n", version_string); debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n", - _armboot_start, _bss_start, _bss_end); +#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) + _TEXT_BASE, +#else + _armboot_start, +#endif + _bss_start, _bss_end); #ifdef CONFIG_MODEM_SUPPORT debug ("Modem Support enabled\n"); #endif @@ -180,6 +190,7 @@ static int display_dram_config (void) return (0); } +#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC) #ifndef CONFIG_SYS_NO_FLASH static void display_flash_config (ulong size) { @@ -187,6 +198,7 @@ static void display_flash_config (ulong size) print_size (size, "\n"); } #endif /* CONFIG_SYS_NO_FLASH */ +#endif #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) static int init_func_i2c (void) @@ -234,6 +246,7 @@ typedef int (init_fnc_t) (void); int print_cpuinfo (void); +#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC) init_fnc_t *init_sequence[] = { #if defined(CONFIG_ARCH_CPU_INIT) arch_cpu_init, /* basic arch cpu dependent setup */ @@ -449,6 +462,459 @@ extern void davinci_eth_set_mac_addr (const u_int8_t *addr); /* NOTREACHED - no way out of command loop except booting */ } +#else +void __dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = gd->ram_size; +} +void dram_init_banksize(void) + __attribute__((weak, alias("__dram_init_banksize"))); + +init_fnc_t *init_sequence[] = { +#if defined(CONFIG_ARCH_CPU_INIT) + arch_cpu_init, /* basic arch cpu dependent setup */ +#endif +#if defined(CONFIG_BOARD_EARLY_INIT_F) + board_early_init_f, +#endif + timer_init, /* initialize timer */ +#ifdef CONFIG_FSL_ESDHC + get_clocks, +#endif + env_init, /* initialize environment */ + init_baudrate, /* initialze baudrate settings */ + serial_init, /* serial communications setup */ + console_init_f, /* stage 1 init of console */ + display_banner, /* say that we are here */ +#if defined(CONFIG_DISPLAY_CPUINFO) + print_cpuinfo, /* display cpu info (and speed) */ +#endif +#if defined(CONFIG_DISPLAY_BOARDINFO) + checkboard, /* display board info */ +#endif +#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) + init_func_i2c, +#endif + dram_init, /* configure available RAM banks */ +#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI) + arm_pci_init, +#endif + NULL, +}; + +void board_init_f (ulong bootflag) +{ + bd_t *bd; + init_fnc_t **init_fnc_ptr; + gd_t *id; + ulong addr, addr_sp; + + /* Pointer is writable since we allocated a register for it */ + gd = (gd_t *) (CONFIG_SYS_INIT_SP_ADDR); + /* compiler optimization barrier needed for GCC >= 3.4 */ + __asm__ __volatile__("": : :"memory"); + + memset ((void*)gd, 0, sizeof (gd_t)); + + gd->mon_len = _bss_end - _TEXT_BASE; + + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { + if ((*init_fnc_ptr)() != 0) { + hang (); + } + } + + debug ("monitor len: %08lX\n", gd->mon_len); + /* + * Ram is setup, size stored in gd !! + */ + debug ("ramsize: %08lX\n", gd->ram_size); +#if defined(CONFIG_SYS_MEM_TOP_HIDE) + /* + * Subtract specified amount of memory to hide so that it won't + * get "touched" at all by U-Boot. By fixing up gd->ram_size + * the Linux kernel should now get passed the now "corrected" + * memory size and won't touch it either. This should work + * for arch/ppc and arch/powerpc. Only Linux board ports in + * arch/powerpc with bootwrapper support, that recalculate the + * memory size from the SDRAM controller setup will have to + * get fixed. + */ + gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE; +#endif + + addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; + +#ifdef CONFIG_LOGBUFFER +#ifndef CONFIG_ALT_LB_ADDR + /* reserve kernel log buffer */ + addr -= (LOGBUFF_RESERVE); + debug ("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr); +#endif +#endif + +#ifdef CONFIG_PRAM + /* + * reserve protected RAM + */ + i = getenv_r ("pram", (char *)tmp, sizeof (tmp)); + reg = (i > 0) ? simple_strtoul ((const char *)tmp, NULL, 10) : CONFIG_PRAM; + addr -= (reg << 10); /* size is in kB */ + debug ("Reserving %ldk for protected RAM at %08lx\n", reg, addr); +#endif /* CONFIG_PRAM */ + +#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE)) + /* reserve TLB table */ + addr -= (4096 * 4); + + /* round down to next 64 kB limit */ + addr &= ~(0x10000 - 1); + + gd->tlb_addr = addr; + debug ("TLB table at: %08lx\n", addr); +#endif + + /* round down to next 4 kB limit */ + addr &= ~(4096 - 1); + debug ("Top of RAM usable for U-Boot at: %08lx\n", addr); + +#ifdef CONFIG_VFD +# ifndef PAGE_SIZE +# define PAGE_SIZE 4096 +# endif + /* + * reserve memory for VFD display (always full pages) + */ + addr -= vfd_setmem (addr); + gd->fb_base = addr; +#endif /* CONFIG_VFD */ + +#ifdef CONFIG_LCD + /* reserve memory for LCD display (always full pages) */ + addr = lcd_setmem (addr); + gd->fb_base = addr; +#endif /* CONFIG_LCD */ + + /* + * reserve memory for U-Boot code, data & bss + * round down to next 4 kB limit + */ + addr -= gd->mon_len; + addr &= ~(4096 - 1); + + debug ("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr); + +#ifndef CONFIG_PRELOADER + /* + * 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 %zu Bytes for Board Info at: %08lx\n", + sizeof (bd_t), addr_sp); + addr_sp -= sizeof (gd_t); + id = (gd_t *) addr_sp; + debug ("Reserving %zu Bytes for Global Data at: %08lx\n", + sizeof (gd_t), addr_sp); + + /* setup stackpointer for exeptions */ + gd->irq_sp = addr_sp; +#ifdef CONFIG_USE_IRQ + addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); + debug ("Reserving %zu Bytes for IRQ stack at: %08lx\n", + CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp); +#endif + /* leave 3 words for abort-stack */ + addr_sp -= 3; + + /* 8-byte alignment for ABI compliance */ + addr_sp &= ~0x07; +#else + addr_sp += 128; /* leave 32 words for abort-stack */ + gd->irq_sp = addr_sp; +#endif + + debug ("New Stack Pointer is: %08lx\n", addr_sp); + +#ifdef CONFIG_POST + post_bootmode_init(); + post_run (NULL, POST_ROM | post_bootmode_get(0)); +#endif + + gd->bd->bi_baudrate = gd->baudrate; + /* Ram ist board specific, so move it to board code ... */ + dram_init_banksize(); + display_dram_config(); /* and display it */ + + gd->relocaddr = addr; + gd->start_addr_sp = addr_sp; + gd->reloc_off = addr - _TEXT_BASE; + debug ("relocation Offset is: %08lx\n", gd->reloc_off); + memcpy (id, (void *)gd, sizeof (gd_t)); + + relocate_code (addr_sp, id, addr); + + /* NOTREACHED - relocate_code() does not return */ +} + +#if !defined(CONFIG_SYS_NO_FLASH) +static char *failed = "*** failed ***\n"; +#endif + +/************************************************************************ + * + * 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) +{ + char *s; + bd_t *bd; + ulong malloc_start; +#if !defined(CONFIG_SYS_NO_FLASH) + ulong flash_size; +#endif +#if !defined(CONFIG_RELOC_FIXUP_WORKS) + extern void malloc_bin_reloc (void); +#if defined(CONFIG_CMD_BMP) + extern void bmp_reloc(void); +#endif +#if defined(CONFIG_CMD_I2C) + extern void i2c_reloc(void); +#endif +#endif + + gd = id; + bd = gd->bd; + + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ + + monitor_flash_len = _bss_start - _TEXT_BASE; + debug ("monitor flash len: %08lX\n", monitor_flash_len); + board_init(); /* Setup chipselects */ + +#ifdef CONFIG_SERIAL_MULTI + serial_initialize(); +#endif + + debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr); + +#if !defined(CONFIG_RELOC_FIXUP_WORKS) + /* + * We have to relocate the command table manually + */ + fixup_cmdtable(&__u_boot_cmd_start, + (ulong)(&__u_boot_cmd_end - &__u_boot_cmd_start)); +#if defined(CONFIG_CMD_BMP) + bmp_reloc(); +#endif +#if defined(CONFIG_CMD_I2C) + i2c_reloc(); +#endif +#endif /* !defined(CONFIG_RELOC_FIXUP_WORKS) */ + +#ifdef CONFIG_LOGBUFFER + logbuff_init_ptrs (); +#endif +#ifdef CONFIG_POST + post_output_backlog (); +#ifndef CONFIG_RELOC_FIXUP_WORKS + post_reloc (); +#endif +#endif + + /* The Malloc area is immediately below the monitor copy in DRAM */ + malloc_start = dest_addr - TOTAL_MALLOC_LEN; + mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN); +#if !defined(CONFIG_RELOC_FIXUP_WORKS) + malloc_bin_reloc (); +#endif + +#if !defined(CONFIG_SYS_NO_FLASH) + puts ("FLASH: "); + + if ((flash_size = flash_init ()) > 0) { +# ifdef CONFIG_SYS_FLASH_CHECKSUM + print_size (flash_size, ""); + /* + * Compute and print flash CRC if flashchecksum is set to 'y' + * + * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX + */ + s = getenv ("flashchecksum"); + if (s && (*s == 'y')) { + printf (" CRC: %08X", + crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size) + ); + } + putc ('\n'); +# else /* !CONFIG_SYS_FLASH_CHECKSUM */ + print_size (flash_size, "\n"); +# endif /* CONFIG_SYS_FLASH_CHECKSUM */ + } else { + puts (failed); + hang (); + } +#endif + +#if defined(CONFIG_CMD_NAND) + puts ("NAND: "); + nand_init(); /* go init the NAND */ +#endif + +#if defined(CONFIG_CMD_ONENAND) + onenand_init(); +#endif + +#ifdef CONFIG_HAS_DATAFLASH + AT91F_DataflashInit(); + dataflash_print_info(); +#endif + + /* initialize environment */ + env_relocate (); + +#ifdef CONFIG_VFD + /* must do this after the framebuffer is allocated */ + drv_vfd_init(); +#endif /* CONFIG_VFD */ + + /* IP Address */ + gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); + + stdio_init (); /* get the devices list going. */ + + jumptable_init (); + +#if defined(CONFIG_API) + /* Initialize API */ + api_init (); +#endif + + console_init_r (); /* fully init console as a device */ + +#if defined(CONFIG_ARCH_MISC_INIT) + /* miscellaneous arch dependent initialisations */ + arch_misc_init (); +#endif +#if defined(CONFIG_MISC_INIT_R) + /* miscellaneous platform dependent initialisations */ + misc_init_r (); +#endif + + /* set up exceptions */ + interrupt_init (); + /* enable exceptions */ + enable_interrupts (); + + /* Perform network card initialisation if necessary */ +#ifdef CONFIG_DRIVER_TI_EMAC + /* XXX: this needs to be moved to board init */ +extern void davinci_eth_set_mac_addr (const u_int8_t *addr); + if (getenv ("ethaddr")) { + uchar enetaddr[6]; + eth_getenv_enetaddr("ethaddr", enetaddr); + davinci_eth_set_mac_addr(enetaddr); + } +#endif + +#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96) + /* XXX: this needs to be moved to board init */ + if (getenv ("ethaddr")) { + uchar enetaddr[6]; + eth_getenv_enetaddr("ethaddr", enetaddr); + smc_set_mac_addr(enetaddr); + } +#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */ + + /* 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 + +#ifdef BOARD_LATE_INIT + board_late_init (); +#endif + +#ifdef CONFIG_GENERIC_MMC + puts ("MMC: "); + mmc_initialize (gd->bd); +#endif + +#ifdef CONFIG_BITBANGMII + bb_miiphy_init(); +#endif +#if defined(CONFIG_CMD_NET) +#if defined(CONFIG_NET_MULTI) + puts ("Net: "); +#endif + eth_initialize(gd->bd); +#if defined(CONFIG_RESET_PHY_R) + debug ("Reset Ethernet PHY\n"); + reset_phy(); +#endif +#endif + +#ifdef CONFIG_POST + post_run (NULL, POST_RAM | post_bootmode_get(0)); +#endif + +#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER) + /* + * Export available size of memory for Linux, + * taking into account the protected RAM at top of memory + */ + { + ulong pram; + uchar memsz[32]; +#ifdef CONFIG_PRAM + char *s; + + if ((s = getenv ("pram")) != NULL) { + pram = simple_strtoul (s, NULL, 10); + } else { + pram = CONFIG_PRAM; + } +#else + pram=0; +#endif +#ifdef CONFIG_LOGBUFFER +#ifndef CONFIG_ALT_LB_ADDR + /* Also take the logbuffer into account (pram is in kB) */ + pram += (LOGBUFF_LEN+LOGBUFF_OVERHEAD)/1024; +#endif +#endif + sprintf ((char *)memsz, "%ldk", (bd->bi_memsize / 1024) - pram); + setenv ("mem", (char *)memsz); + } +#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 */ +} +#endif /* defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */ void hang (void) { -- cgit v1.2.3