[U-Boot] [PATCH 12/26] ARM: add relocation support

Heiko Schocher
2010-08-11T18:16:07Z

!! 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

Signed-off-by: Heiko Schocher <hs@denx.de>
---
- changes since previous patch set
- as introducing CONFIG_SYS_ARM_WITHOUT_RELOC, seperate
common arm changes in this patch

arch/arm/config.mk | 8 +
arch/arm/include/asm/config.h | 3 +-
arch/arm/include/asm/global_data.h | 11 +
arch/arm/include/asm/u-boot-arm.h | 14 +-
arch/arm/lib/board.c | 468 +++++++++++++++++++++++++++++++++++-
arch/arm/lib/cache-cp15.c | 37 +++-
arch/arm/lib/interrupts.c | 19 ++-
common/cmd_bdinfo.c | 11 +-
common/cmd_bmp.c | 6 +
common/cmd_i2c.c | 6 +
doc/README.arm-relocation | 321 ++++++++++++++++++++++++
nand_spl/nand_boot.c | 7 +
nand_spl/nand_boot_fsl_nfc.c | 7 +
13 files changed, 910 insertions(+), 8 deletions(-)
create mode 100644 doc/README.arm-relocation

diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index e10dafc..6923f6d 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -33,6 +33,14 @@ STANDALONE_LOAD_ADDR = 0xc100000
endif
endif

+ifndef CONFIG_SYS_ARM_WITHOUT_RELOC
+# needed for relocation
+PLATFORM_RELFLAGS += -fPIC
+endif
+
+ifdef CONFIG_SYS_ARM_WITHOUT_RELOC
+PLATFORM_CPPFLAGS += -DCONFIG_SYS_ARM_WITHOUT_RELOC
+endif
PLATFORM_CPPFLAGS += -DCONFIG_ARM -D__ARM__

# Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h
index b76fd8e..4e8dfd7 100644
--- a/arch/arm/include/asm/config.h
+++ b/arch/arm/include/asm/config.h
@@ -21,7 +21,8 @@
#ifndef _ASM_CONFIG_H_
#define _ASM_CONFIG_H_

+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
/* Relocation to SDRAM works on all ARM boards */
#define CONFIG_RELOC_FIXUP_WORKS
-
+#endif
#endif
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 02cfe45..488bae7 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -53,6 +53,17 @@ typedef struct global_data {
phys_size_t ram_size; /* RAM size */
unsigned long reset_status; /* reset status register at boot */
#endif
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+ unsigned long relocaddr; /* Start address of U-Boot in RAM */
+ phys_size_t ram_size; /* RAM size */
+ unsigned long mon_len; /* monitor len */
+ unsigned long irq_sp; /* irq stack pointer */
+ unsigned long start_addr_sp; /* start_addr_stackpointer */
+ unsigned long reloc_off;
+#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
+ unsigned long tlb_addr;
+#endif
+#endif
void **jt; /* jump table */
} gd_t;

diff --git a/arch/arm/include/asm/u-boot-arm.h b/arch/arm/include/asm/u-boot-arm.h
index 6d2f8bc..faf800a 100644
--- a/arch/arm/include/asm/u-boot-arm.h
+++ b/arch/arm/include/asm/u-boot-arm.h
@@ -30,11 +30,20 @@
#define _U_BOOT_ARM_H_ 1

/* for the following variables, see start.S */
-extern ulong _armboot_start; /* code start */
extern ulong _bss_start; /* code + data end == BSS start */
extern ulong _bss_end; /* BSS end */
extern ulong IRQ_STACK_START; /* top of IRQ stack */
extern ulong FIQ_STACK_START; /* top of FIQ stack */
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+extern ulong _armboot_start; /* code start */
+#else
+extern ulong _TEXT_BASE; /* code start */
+extern ulong _datarel_start;
+extern ulong _datarelrolocal_start;
+extern ulong _datarellocal_start;
+extern ulong _datarelro_start;
+extern ulong IRQ_STACK_START_IN; /* 8 bytes in IRQ stack */
+#endif

/* cpu/.../cpu.c */
int cpu_init(void);
@@ -47,6 +56,9 @@ int arch_misc_init(void);
/* board/.../... */
int board_init(void);
int dram_init (void);
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+void dram_init_banksize (void);
+#endif
void setup_serial_tag (struct tag **params);
void setup_revision_tag (struct tag **params);

diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 54519b0..88c6427 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 */
@@ -444,6 +457,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@%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)
{
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index b2811f3..fe6d459 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -44,17 +44,44 @@ static void cp_delay (void)
asm volatile("" : : : "memory");
}

-/* to activate the MMU we need to set up virtual memory: use 1M areas in bss */
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+static inline void dram_bank_mmu_setup(int bank)
+{
+ u32 *page_table = (u32 *)gd->tlb_addr;
+ bd_t *bd = gd->bd;
+ int i;
+
+ debug("%s: bank: %d\n", __func__, bank);
+ for (i = bd->bi_dram[bank].start >> 20;
+ i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
+ i++) {
+ page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP;
+ }
+}
+#endif
+
+/* to activate the MMU we need to set up virtual memory: use 1M areas */
static inline void mmu_setup(void)
{
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+ u32 *page_table = (u32 *)gd->tlb_addr;
+#else
static u32 __attribute__((aligned(16384))) page_table[4096];
bd_t *bd = gd->bd;
- int i, j;
+ int j;
+#endif
+ int i;
u32 reg;

/* Set up an identity-mapping for all 4GB, rw for everyone */
for (i = 0; i < 4096; i++)
page_table[i] = i << 20 | (3 << 10) | 0x12;
+
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ dram_bank_mmu_setup(i);
+ }
+#else
/* Then, enable cacheable and bufferable for RAM only */
for (j = 0; j < CONFIG_NR_DRAM_BANKS; j++) {
for (i = bd->bi_dram[j].start >> 20;
@@ -63,6 +90,7 @@ static inline void mmu_setup(void)
page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP;
}
}
+#endif

/* Copy the page table address to cp15 */
asm volatile("mcr p15, 0, %0, c2, c0, 0"
@@ -74,7 +102,6 @@ static inline void mmu_setup(void)
reg = get_cr(); /* get control reg. */
cp_delay();
set_cr(reg | CR_M);
-
}

/* cache_bit must be either CR_I or CR_C */
@@ -96,6 +123,10 @@ static void cache_disable(uint32_t cache_bit)
uint32_t reg;

if (cache_bit == CR_C) {
+ /* if cache isn;t enabled no need to disable */
+ reg = get_cr();
+ if ((reg & CR_C) != CR_C)
+ return;
/* if disabling data cache, disable mmu too */
cache_bit |= CR_M;
flush_cache(0, ~0);
diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
index 1f2b815..9a21e7b 100644
--- a/arch/arm/lib/interrupts.c
+++ b/arch/arm/lib/interrupts.c
@@ -38,15 +38,20 @@
#include <common.h>
#include <asm/proc-armv/ptrace.h>

-#ifdef CONFIG_USE_IRQ
DECLARE_GLOBAL_DATA_PTR;

+#ifdef CONFIG_USE_IRQ
int interrupt_init (void)
{
/*
* setup up stacks if necessary
*/
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+ IRQ_STACK_START = gd->irq_sp - 4;
+ IRQ_STACK_START_IN = gd->irq_sp + 8;
+#else
IRQ_STACK_START = _armboot_start - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_GBL_DATA_SIZE - 4;
+#endif
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;

return arch_interrupt_init();
@@ -81,6 +86,18 @@ int disable_interrupts (void)
return (old & 0x80) == 0;
}
#else
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+int interrupt_init (void)
+{
+ /*
+ * setup up stacks if necessary
+ */
+ IRQ_STACK_START_IN = gd->irq_sp + 8;
+
+ return 0;
+}
+#endif
+
void enable_interrupts (void)
{
return;
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c
index cc81543..4c3040a 100644
--- a/common/cmd_bdinfo.c
+++ b/common/cmd_bdinfo.c
@@ -343,7 +343,16 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
printf ("ip_addr = %pI4\n", &bd->bi_ip_addr);
#endif
printf ("baudrate = %d bps\n", bd->bi_baudrate);
-
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
+ print_num ("TLB addr", gd->tlb_addr);
+#endif
+ print_num ("relocaddr", gd->relocaddr);
+ print_num ("reloc off", gd->reloc_off);
+ print_num ("irq_sp", gd->irq_sp); /* irq stack pointer */
+ print_num ("sp start ", gd->start_addr_sp);
+ print_num ("FB base ", gd->fb_base);
+#endif
return 0;
}

diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c
index d51cc55..6fa8a15 100644
--- a/common/cmd_bmp.c
+++ b/common/cmd_bmp.c
@@ -137,6 +137,12 @@ static cmd_tbl_t cmd_bmp_sub[] = {
U_BOOT_CMD_MKENT(display, 5, 0, do_bmp_display, "", ""),
};

+#ifndef CONFIG_RELOC_FIXUP_WORKS
+void bmp_reloc(void) {
+ fixup_cmdtable(cmd_bmp_sub, ARRAY_SIZE(cmd_bmp_sub));
+}
+#endif
+
/*
* Subroutine: do_bmp
*
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 5e9135e..48de54b 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -1287,6 +1287,12 @@ static cmd_tbl_t cmd_i2c_sub[] = {
U_BOOT_CMD_MKENT(speed, 1, 1, do_i2c_bus_speed, "", ""),
};

+#ifndef CONFIG_RELOC_FIXUP_WORKS
+void i2c_reloc(void) {
+ fixup_cmdtable(cmd_i2c_sub, ARRAY_SIZE(cmd_i2c_sub));
+}
+#endif
+
static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
cmd_tbl_t *c;
diff --git a/doc/README.arm-relocation b/doc/README.arm-relocation
new file mode 100644
index 0000000..6be1a12
--- /dev/null
+++ b/doc/README.arm-relocation
@@ -0,0 +1,321 @@
+To make relocation on arm working, the following changes are done:
+
+Add new compilerflag:
+
+-fPIC
+
+ -> compiler generates position independent code
+
+changes in board code:
+
+- dram_init:
+ - bd pointer is now at this point not accessible, so only
+ detect the real dramsize, and store it in gd->ram_size.
+ best detected with get_ram_size();
+ ToDo: move there also the dram initialization on boards where
+ it is possible.
+ - setup the bd_t dram bank info in the new function
+ dram_init_banksize().
+
+- board.c code is adapted from ppc code
+
+- undef CONFIG_RELOC_FIXUP_WORKS
+
+ -> cmdtabl, and subcommand table must be handled from "hand"
+ collected in section "__datarellocal_start".
+
+ - How To fixup the sections:
+
+ __datarel_start, __datarelrolocal_start, __datarellocal_start and
+ __datarelro_start
+
+ automatically? Then it should be possible to define again
+ CONFIG_RELOC_FIXUP_WORKS
+
+- irq stack setup is now not longer on a fix position, instead it is
+ calculated in board_init_f, and stored in gd->irq_sp
+
+-------------------------------------------------------------------------------------
+
+To compile a board without relocation, define CONFIG_SYS_ARM_WITHOUT_RELOC
+This possibility will removed!! So please fix your board to compile without
+CONFIG_SYS_ARM_WITHOUT_RELOC defined!!!
+
+-------------------------------------------------------------------------------------
+
+ToDo:
+
+- fill in bd_t infos (check)
+- adapt all boards
+
+- maybe adapt TEXT_BASE (this must be checked from board maintainers)
+ This *must* be done for boards, which boot from NOR flash
+
+ on other boards if TEXT_BASE = relocation baseaddr, this saves
+ one copying from u-boot code.
+
+- new function dram_init_banksize() is actual board specific. Maybe
+ we make a weak default function in arch/arm/lib/board.c ?
+
+-------------------------------------------------------------------------------------
+
+Relocation with NAND_SPL (example for the tx25):
+
+- cpu copies the first page from NAND to 0xbb000000 (IMX_NFC_BASE)
+ and start with code execution on this address.
+
+- The First page contains u-boot code from u-boot:nand_spl/nand_boot_fsl_nfc.c
+ which inits the dram, cpu registers, reloacte itself to TEXT_BASE and loads
+ the "real" u-boot to CONFIG_SYS_NAND_U_BOOT_DST and starts execution
+ @CONFIG_SYS_NAND_U_BOOT_START
+
+- This u-boot does no ram int, nor cpu register setup. Just looks
+ where it have to relocate and relocate itself to this address.
+ If relocate address = TEXT_BASE(not the same, as the TEXT_BASE
+ from the nand_spl code), no need to copy, just go on with bss clear
+ and jump to board_init_r.
+
+-------------------------------------------------------------------------------------
+
+Relocation:
+How to translate flash addresses in GOT to ram addresses.
+This is automagically done from code, but this example
+shows, how this magic code works ;-)
+(example on the qong board)
+
+Find a variable:
+
+a) search it in System.map
+(for example flash_info)
+
+a005b4c0 B BootpID
+a005b4c4 B BootpTry
+a005b4c8 b slave
+a005b4cc B flash_info
+^^^^^^^^
+a005c908 b saved_sector.4002
+a005c910 b cfi_mtd_info
+a005c9c0 b cfi_mtd_names
+a005c9d0 B mtd_table
+
+---------------------------------------
+
+b) create hexdump from u-boot code:
+
+hexdump -C u-boot > gnlmpfhex
+
+---------------------------------------
+
+c) search the variables address in the hexdump
+
+
+*
+0005fc80 00 00 00 00 00 00 00 00 2c 06 01 a0 18 cd 05 a0 |........,.......|
+0005fc90 9c d4 05 a0 bc b4 05 a0 1c 7f 05 a0 f0 05 01 a0 |................|
+0005fca0 08 5a 04 a0 1c ab 05 a0 ec a4 05 a0 98 c3 01 a0 |.Z..............|
+0005fcb0 a0 d6 05 a0 04 71 05 a0 c0 f9 00 a0 3c cd 05 a0 |.....q......<...|
+0005fcc0 cc b4 05 a0 f0 fa 00 a0 f0 d6 05 a0 10 86 05 a0 |................|
+ ^^^^^^^^^^^
+0005fcd0 a4 16 06 a0 dc 64 05 a0 18 86 05 a0 52 48 05 a0 |.....d......RH..|
+0005fce0 c0 86 05 a0 24 6e 02 a0 b4 6c 05 a0 b0 94 01 a0 |....$n...l......|
+0005fcf0 1c 86 05 a0 50 85 05 a0 d4 0c 06 a0 bc 0b 06 a0 |....P...........|
+
+
+-> 0005fcc0
+
+----------------------------------------
+
+d) know we calculate this address in RAM
+
+
+ 8ff08000 (new address of code in RAM *1)
+
++ 0005fcc0
+
+- 00008000 (offset of text *2)
+
+----------
+
+ 8ff5fcc0 -> Addr GOT in RAM
+
+*1:
+activate debug and look for the line:
+Now running in RAM - U-Boot at: 8ff08000
+ ^^^^^^^^
+ new address of u-boot code in RAM
+
+*2:
+Section Headers:
+ [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
+ [ 0] NULL 00000000 000000 000000 00 0 0 0
+ [ 1] .text PROGBITS a0000000 008000 04599c 00 AX 0 0 32
+ ^^^^^^
+ Offset of text
+
+----------------------------------------
+
+e) now we look in 8ff5fcc0 (RAM)
+
+
+QongEVB>md 0x8ff5fcc0
+8ff5fcc0 : a005b4cc a000faf0 a005d6f0 a0058610 ................
+ ^^^^^^^^
+ Bingo, here we have the old flash address (when relocation
+ is working, here is the fixed ram address. see @ f, how
+ it gets calculated)
+
+
+----------------------------------------
+
+f) now translate it in the new RAM address
+
+ a005b4cc
+
+- a0000000 TextBase
+
++ 8ff08000 new address of u-boot in ram
+----------
+ 8ff634cc
+
+QongEVB>mm 0x8ff5fcc0 0x8ff634cc 1
+QongEVB>md 0x8ff5fcc0
+8ff5fcc0 : 8ff634cc a000faf0 a005d6f0 a0058610 .4..............
+8ff5fcd0 : a00616a4 a00564dc a0058618 a0054852 .....d......RH..
+
+As this must be done for all address in the GOT, the u-boot
+code did this automagically ... :-)
+
+----------------------------------------------
+
+g) check if the new address is really in the bss section:
+
+bss start:
+8ff6054c (8ff08000 + 0005854C monitorlen)
+
+bss end:
+8ff698ac (8ff08000 + 618AC)
+
+8ff634cc is in bss :-)
+
+----------------------------------------------
+
+h) u-boot prints:
+
+important addresses:
+
+U-Boot code: A0000000 -> A005854C BSS: -> A00618AC TextBase 0xa0000000
+Now running in RAM - U-Boot at: 8ff08000 relocBase 0x8ff08000
+
+
+---------
+
+U-Boot 2010.06-rc2-00002-gf8fbb25-dirty (Jun 18 2010 - 17:07:19)
+
+U-Boot code: A0000000 -> A005854C BSS: -> A00618AC
+CPU: Freescale i.MX31 at 398 MHz
+Board: DAVE/DENX Qong
+mon: FFFFFFFF gd->monLen: 000618AC
+Top of RAM usable for U-Boot at: 90000000
+LCD panel info: 640 x 480, 16 bit/pix
+Reserving 600k for LCD Framebuffer at: 8ff6a000
+Reserving 390k for U-Boot at: 8ff08000
+Reserving 1280k for malloc() at: 8fdc8000
+Reserving 28 Bytes for Board Info at: 8fdc7fe4
+Reserving 48 Bytes for Global Data at: 8fdc7fb4
+New Stack Pointer is: 8fdc7fb0
+RAM Configuration:
+Bank #0: 80000000 256 MiB
+mon: 0005854C gd->monLen: 000618AC
+Now running in RAM - U-Boot at: 8ff08000
+
+-------------------------------------------------------------------------------------
+
+Debugging u-boot in RAM:
+(example on the qong board)
+
+a) add in config.mk:
+
+PLATFORM_CPPFLAGS += -DDEBUG
+
+-----------------
+
+b) start debugger
+
+arm-linux-gdb u-boot
+
+[hs at pollux u-boot]$ arm-linux-gdb u-boot
+GNU gdb Red Hat Linux (6.7-2rh)
+Copyright (C) 2007 Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law. Type "show copying"
+and "show warranty" for details.
+This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-linux".
+The target architecture is set automatically (currently arm)
+..
+(gdb)
+
+-----------------
+
+c) connect to target
+
+target remote bdi10:2001
+
+(gdb) target remote bdi10:2001
+Remote debugging using bdi10:2001
+0x8ff17f10 in ?? ()
+(gdb)
+
+-----------------
+
+d) discard symbol-file
+
+(gdb) symbol-file
+Discard symbol table from `/home/hs/celf/u-boot/u-boot'? (y or n) y
+No symbol file now.
+(gdb)
+
+-----------------
+
+e) load new symbol table:
+
+(gdb) add-symbol-file u-boot 0x8ff08000
+add symbol table from file "u-boot" at
+ .text_addr = 0x8ff08000
+(y or n) y
+Reading symbols from /home/hs/celf/u-boot/u-boot...done.
+(gdb) c
+Continuing.
+^C
+Program received signal SIGSTOP, Stopped (signal).
+0x8ff17f18 in serial_getc () at serial_mxc.c:192
+192 while (__REG(UART_PHYS + UTS) & UTS_RXEMPTY);
+(gdb)
+
+add-symbol-file u-boot 0x8ff08000
+ ^^^^^^^^^^
+ get this address from u-boot debug printfs
+
+U-Boot 2010.06-rc2-00009-gf77b8b8-dirty (Jun 22 2010 - 09:43:46)
+
+U-Boot code: A0000000 -> A0058BAC BSS: -> A0061F10
+CPU: Freescale i.MX31 at 398 MHz
+Board: DAVE/DENX Qong
+mon: FFFFFFFF gd->monLen: 00061F10
+Top of RAM usable for U-Boot at: 90000000
+LCD panel info: 640 x 480, 16 bit/pix
+Reserving 600k for LCD Framebuffer at: 8ff6a000
+Reserving 391k for U-Boot at: 8ff08000
+ ^^^^^^^^
+Reserving 1280k for malloc() at: 8fdc8000
+Reserving 24 Bytes for Board Info at: 8fdc7fe8
+Reserving 52 Bytes for Global Data at: 8fdc7fb4
+New Stack Pointer is: 8fdc7fb0
+RAM Configuration:
+Bank #0: 80000000 256 MiB
+relocation Offset is: eff08000
+mon: 00058BAC gd->monLen: 00061F10
+Now running in RAM - U-Boot at: 8ff08000
+ ^^^^^^^^
+
+Now you can use gdb as usual :-)
diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c
index b9fd6f5..18ecbe1 100644
--- a/nand_spl/nand_boot.c
+++ b/nand_spl/nand_boot.c
@@ -221,6 +221,13 @@ static int nand_load(struct mtd_info *mtd, unsigned int offs,
return 0;
}

+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+void board_init_f (ulong bootflag)
+{
+ relocate_code (TEXT_BASE - TOTAL_MALLOC_LEN, NULL, TEXT_BASE);
+}
+#endif
+
/*
* The main entry for NAND booting. It's necessary that SDRAM is already
* configured and available since this code loads the main U-Boot image
diff --git a/nand_spl/nand_boot_fsl_nfc.c b/nand_spl/nand_boot_fsl_nfc.c
index ea3566b..3105657 100644
--- a/nand_spl/nand_boot_fsl_nfc.c
+++ b/nand_spl/nand_boot_fsl_nfc.c
@@ -263,6 +263,13 @@ static int nand_load(unsigned int from, unsigned int size, unsigned char *buf)
return 0;
}

+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+void board_init_f (ulong bootflag)
+{
+ relocate_code (TEXT_BASE - TOTAL_MALLOC_LEN, NULL, TEXT_BASE);
+}
+#endif
+
/*
* The main entry for NAND booting. It's necessary that SDRAM is already
* configured and available since this code loads the main U-Boot image
--
1.6.2.5

--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany