diff options
Diffstat (limited to 'arch/arm/lib')
-rw-r--r-- | arch/arm/lib/board.c | 468 | ||||
-rw-r--r-- | arch/arm/lib/cache-cp15.c | 82 | ||||
-rw-r--r-- | arch/arm/lib/cache.c | 13 | ||||
-rw-r--r-- | arch/arm/lib/interrupts.c | 19 |
4 files changed, 579 insertions, 3 deletions
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index e17f182e18..5f2dfd08ac 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) { diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c index 62ed54fb4d..fe6d45987b 100644 --- a/arch/arm/lib/cache-cp15.c +++ b/arch/arm/lib/cache-cp15.c @@ -25,6 +25,15 @@ #include <asm/system.h> #if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE)) + +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) +#define CACHE_SETUP 0x1a +#else +#define CACHE_SETUP 0x1e +#endif + +DECLARE_GLOBAL_DATA_PTR; + static void cp_delay (void) { volatile int i; @@ -32,6 +41,67 @@ static void cp_delay (void) /* copro seems to need some delay between reading and writing */ for (i = 0; i < 100; i++) nop(); + asm volatile("" : : : "memory"); +} + +#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 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; + i < (bd->bi_dram[j].start + bd->bi_dram[j].size) >> 20; + i++) { + 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" + : : "r" (page_table) : "memory"); + /* Set the access control to all-supervisor */ + asm volatile("mcr p15, 0, %0, c3, c0, 0" + : : "r" (~0)); + /* and enable the mmu */ + reg = get_cr(); /* get control reg. */ + cp_delay(); + set_cr(reg | CR_M); } /* cache_bit must be either CR_I or CR_C */ @@ -39,6 +109,9 @@ static void cache_enable(uint32_t cache_bit) { uint32_t reg; + /* The data cache is not active unless the mmu is enabled too */ + if (cache_bit == CR_C) + mmu_setup(); reg = get_cr(); /* get control reg. */ cp_delay(); set_cr(reg | cache_bit); @@ -49,6 +122,15 @@ 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); + } reg = get_cr(); cp_delay(); set_cr(reg & ~cache_bit); diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index 61ee9d3b13..55b633ee00 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -27,10 +27,21 @@ void flush_cache (unsigned long dummy1, unsigned long dummy2) { -#ifdef CONFIG_OMAP2420 +#if defined(CONFIG_OMAP2420) || defined(CONFIG_ARM1136) void arm1136_cache_flush(void); arm1136_cache_flush(); #endif +#ifdef CONFIG_ARM926EJS + /* test and clean, page 2-23 of arm926ejs manual */ + asm("0: mrc p15, 0, r15, c7, c10, 3\n\t" "bne 0b\n" : : : "memory"); + /* disable write buffer as well (page 2-22) */ + asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)); +#endif +#ifdef CONFIG_ARMCORTEXA8 + void v7_flush_cache_all(void); + + v7_flush_cache_all(); +#endif return; } diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c index 1f2b815611..9a21e7b40a 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; |