diff options
Diffstat (limited to 'arch/arm/cpu/arm720t/start.S')
-rw-r--r-- | arch/arm/cpu/arm720t/start.S | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/arch/arm/cpu/arm720t/start.S b/arch/arm/cpu/arm720t/start.S new file mode 100644 index 0000000..022b873 --- /dev/null +++ b/arch/arm/cpu/arm720t/start.S @@ -0,0 +1,611 @@ +/* + * armboot - Startup Code for ARM720 CPU-core + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.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 <config.h> +#include <version.h> +#include <asm/hardware.h> + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + + +.globl _start +_start: b reset + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort +#ifdef CONFIG_LPC2292 + .word 0xB4405F76 /* 2's complement of the checksum of the vectors */ +#else + ldr pc, _not_used +#endif + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: .word undefined_instruction +_software_interrupt: .word software_interrupt +_prefetch_abort: .word prefetch_abort +_data_abort: .word data_abort +_not_used: .word not_used +_irq: .word irq +_fiq: .word fiq + + .balignl 16,0xdeadbeef + + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from RAM! + * relocate armboot to ram + * setup stack + * jump to second stage + * + ************************************************************************* + */ + +_TEXT_BASE: + .word TEXT_BASE + +.globl _armboot_start +_armboot_start: + .word _start + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + + +/* + * the actual reset code + */ + +reset: + /* + * set the cpu to SVC32 mode + */ + mrs r0,cpsr + bic r0,r0,#0x1f + orr r0,r0,#0x13 + msr cpsr,r0 + + /* + * we do sys-critical inits only at reboot, + * not when booting from ram! + */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + bl cpu_init_crit +#endif + +#ifdef CONFIG_LPC2292 + bl lowlevel_init +#endif + +#ifndef CONFIG_SKIP_RELOCATE_UBOOT +relocate: /* relocate U-Boot to RAM */ + adr r0, _start /* r0 <- current position of code */ + ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ + cmp r0, r1 /* don't reloc during debug */ + beq stack_setup + +#if TEXT_BASE +#ifndef CONFIG_LPC2292 /* already done in lowlevel_init */ + ldr r2, =0x0 /* Relocate the exception vectors */ + cmp r1, r2 /* and associated data to address */ + ldmneia r0!, {r3-r10} /* 0x0. Do nothing if TEXT_BASE is */ + stmneia r2!, {r3-r10} /* 0x0. Copy the first 15 words. */ + ldmneia r0, {r3-r9} + stmneia r2, {r3-r9} + adrne r0, _start /* restore r0 */ +#endif /* !CONFIG_LPC2292 */ +#endif + + ldr r2, _armboot_start + ldr r3, _bss_start + sub r2, r3, r2 /* r2 <- size of armboot */ + add r2, r0, r2 /* r2 <- source end address */ + +copy_loop: + ldmia r0!, {r3-r10} /* copy from source address [r0] */ + stmia r1!, {r3-r10} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + +#endif /* CONFIG_SKIP_RELOCATE_UBOOT */ + + /* Set up the stack */ +stack_setup: + ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ + sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */ +#ifdef CONFIG_USE_IRQ + sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) +#endif + sub sp, r0, #12 /* leave 3 words for abort-stack */ + +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0x00000000 /* clear */ + +clbss_l:str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + + ldr pc, _start_armboot + +_start_armboot: .word start_armboot + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ + +#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_ARMADILLO) + +/* Interupt-Controller base addresses */ +INTMR1: .word 0x80000280 @ 32 bit size +INTMR2: .word 0x80001280 @ 16 bit size +INTMR3: .word 0x80002280 @ 8 bit size + +/* SYSCONs */ +SYSCON1: .word 0x80000100 +SYSCON2: .word 0x80001100 +SYSCON3: .word 0x80002200 + +#define CLKCTL 0x6 /* mask */ +#define CLKCTL_18 0x0 /* 18.432 MHz */ +#define CLKCTL_36 0x2 /* 36.864 MHz */ +#define CLKCTL_49 0x4 /* 49.152 MHz */ +#define CLKCTL_73 0x6 /* 73.728 MHz */ + +#elif defined(CONFIG_LPC2292) +PLLCFG_ADR: .word PLLCFG +PLLFEED_ADR: .word PLLFEED +PLLCON_ADR: .word PLLCON +PLLSTAT_ADR: .word PLLSTAT +VPBDIV_ADR: .word VPBDIV +MEMMAP_ADR: .word MEMMAP + +#endif + +cpu_init_crit: +#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_ARMADILLO) + + /* + * mask all IRQs by clearing all bits in the INTMRs + */ + mov r1, #0x00 + ldr r0, INTMR1 + str r1, [r0] + ldr r0, INTMR2 + str r1, [r0] + ldr r0, INTMR3 + str r1, [r0] + + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * disable MMU stuff and caches + */ + mrc p15,0,r0,c1,c0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x0000008f @ clear bits 7, 3:0 (B--- WCAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + mcr p15,0,r0,c1,c0 +#elif defined(CONFIG_NETARM) + /* + * prior to software reset : need to set pin PORTC4 to be *HRESET + */ + ldr r0, =NETARM_GEN_MODULE_BASE + ldr r1, =(NETARM_GEN_PORT_MODE(0x10) | \ + NETARM_GEN_PORT_DIR(0x10)) + str r1, [r0, #+NETARM_GEN_PORTC] + /* + * software reset : see HW Ref. Guide 8.2.4 : Software Service register + * for an explanation of this process + */ + ldr r0, =NETARM_GEN_MODULE_BASE + ldr r1, =NETARM_GEN_SW_SVC_RESETA + str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] + ldr r1, =NETARM_GEN_SW_SVC_RESETB + str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] + ldr r1, =NETARM_GEN_SW_SVC_RESETA + str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] + ldr r1, =NETARM_GEN_SW_SVC_RESETB + str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] + /* + * setup PLL and System Config + */ + ldr r0, =NETARM_GEN_MODULE_BASE + + ldr r1, =( NETARM_GEN_SYS_CFG_LENDIAN | \ + NETARM_GEN_SYS_CFG_BUSFULL | \ + NETARM_GEN_SYS_CFG_USER_EN | \ + NETARM_GEN_SYS_CFG_ALIGN_ABORT | \ + NETARM_GEN_SYS_CFG_BUSARB_INT | \ + NETARM_GEN_SYS_CFG_BUSMON_EN ) + + str r1, [r0, #+NETARM_GEN_SYSTEM_CONTROL] + +#ifndef CONFIG_NETARM_PLL_BYPASS + ldr r1, =( NETARM_GEN_PLL_CTL_PLLCNT(NETARM_PLL_COUNT_VAL) | \ + NETARM_GEN_PLL_CTL_POLTST_DEF | \ + NETARM_GEN_PLL_CTL_INDIV(1) | \ + NETARM_GEN_PLL_CTL_ICP_DEF | \ + NETARM_GEN_PLL_CTL_OUTDIV(2) ) + str r1, [r0, #+NETARM_GEN_PLL_CONTROL] +#endif + + /* + * mask all IRQs by clearing all bits in the INTMRs + */ + mov r1, #0 + ldr r0, =NETARM_GEN_MODULE_BASE + str r1, [r0, #+NETARM_GEN_INTR_ENABLE] + +#elif defined(CONFIG_S3C4510B) + + /* + * Mask off all IRQ sources + */ + ldr r1, =REG_INTMASK + ldr r0, =0x3FFFFF + str r0, [r1] + + /* + * Disable Cache + */ + ldr r0, =REG_SYSCFG + ldr r1, =0x83ffffa0 /* cache-disabled */ + str r1, [r0] + +#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) + /* No specific initialisation for IntegratorAP/CM720T as yet */ +#elif defined(CONFIG_LPC2292) + /* Set-up PLL */ + mov r3, #0xAA + mov r4, #0x55 + /* First disconnect and disable the PLL */ + ldr r0, PLLCON_ADR + mov r1, #0x00 + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Set new M and P values */ + ldr r0, PLLCFG_ADR + mov r1, #0x23 /* M=4 and P=2 */ + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Then enable the PLL */ + ldr r0, PLLCON_ADR + mov r1, #0x01 /* PLL enable bit */ + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Wait for the lock */ + ldr r0, PLLSTAT_ADR + mov r1, #0x400 /* lock bit */ +lock_loop: + ldr r2, [r0] + and r2, r1, r2 + cmp r2, #0 + beq lock_loop + /* And finally connect the PLL */ + ldr r0, PLLCON_ADR + mov r1, #0x03 /* PLL enable bit and connect bit */ + str r1, [r0] + ldr r0, PLLFEED_ADR /* start feed sequence */ + str r3, [r0] + str r4, [r0] /* feed sequence done */ + /* Set-up VPBDIV register */ + ldr r0, VPBDIV_ADR + mov r1, #0x01 /* VPB clock is same as process clock */ + str r1, [r0] +#else +#error No cpu_init_crit() defined for current CPU type +#endif + +#ifdef CONFIG_ARM7_REVD + /* set clock speed */ + /* !!! we run @ 36 MHz due to a hardware flaw in Rev. D processors */ + /* !!! not doing DRAM refresh properly! */ + ldr r0, SYSCON3 + ldr r1, [r0] + bic r1, r1, #CLKCTL + orr r1, r1, #CLKCTL_36 + str r1, [r0] +#endif + +#ifndef CONFIG_LPC2292 + mov ip, lr + /* + * before relocating, we have to setup RAM timing + * because memory timing is board-dependent, you will + * find a lowlevel_init.S in your board directory. + */ + bl lowlevel_init + mov lr, ip +#endif + + mov pc, lr + + +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ + +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#define MODE_SVC 0x13 +#define I_BIT 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + + .macro bad_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + add r8, sp, #S_PC + + ldr r2, _armboot_start + sub r2, r2, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN) + sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ set base 2 words into abort stack + ldmia r2, {r2 - r4} @ get pc, cpsr, old_r0 + add r0, sp, #S_FRAME_SIZE @ restore sp_SVC + + add r5, sp, #S_SP + mov r1, lr + stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_r + mov r0, sp + .endm + + .macro irq_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Calling SP, LR + str lr, [r8, #0] @ Save calling PC + mrs r6, spsr + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 + mov r0, sp + .endm + + .macro irq_restore_user_regs + ldmia sp, {r0 - lr}^ @ Calling r0 - lr + mov r0, r0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE + subs pc, lr, #4 @ return & move spsr_svc into cpsr + .endm + + .macro get_bad_stack + ldr r13, _armboot_start @ setup our mode stack + sub r13, r13, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN) + sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack + + str lr, [r13] @ save caller lr / spsr + mrs lr, spsr + str lr, [r13, #4] + + mov r13, #MODE_SVC @ prepare SVC-Mode + msr spsr_c, r13 + mov lr, pc + movs pc, lr + .endm + + .macro get_irq_stack @ setup IRQ stack + ldr sp, IRQ_STACK_START + .endm + + .macro get_fiq_stack @ setup FIQ stack + ldr sp, FIQ_STACK_START + .endm + +/* + * exception handlers + */ + .align 5 +undefined_instruction: + get_bad_stack + bad_save_user_regs + bl do_undefined_instruction + + .align 5 +software_interrupt: + get_bad_stack + bad_save_user_regs + bl do_software_interrupt + + .align 5 +prefetch_abort: + get_bad_stack + bad_save_user_regs + bl do_prefetch_abort + + .align 5 +data_abort: + get_bad_stack + bad_save_user_regs + bl do_data_abort + + .align 5 +not_used: + get_bad_stack + bad_save_user_regs + bl do_not_used + +#ifdef CONFIG_USE_IRQ + + .align 5 +irq: + get_irq_stack + irq_save_user_regs + bl do_irq + irq_restore_user_regs + + .align 5 +fiq: + get_fiq_stack + /* someone ought to write a more effiction fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq + irq_restore_user_regs + +#else + + .align 5 +irq: + get_bad_stack + bad_save_user_regs + bl do_irq + + .align 5 +fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq + +#endif + +#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_ARMADILLO) + .align 5 +.globl reset_cpu +reset_cpu: + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate cache + mcr p15, 0, ip, c8, c7, 0 @ flush TLB (v4) + mrc p15, 0, ip, c1, c0, 0 @ get ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x2100 @ ..v....s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 +#elif defined(CONFIG_NETARM) + .align 5 +.globl reset_cpu +reset_cpu: + ldr r1, =NETARM_MEM_MODULE_BASE + ldr r0, [r1, #+NETARM_MEM_CS0_BASE_ADDR] + ldr r1, =0xFFFFF000 + and r0, r1, r0 + ldr r1, =(relocate-TEXT_BASE) + add r0, r1, r0 + ldr r4, =NETARM_GEN_MODULE_BASE + ldr r1, =NETARM_GEN_SW_SVC_RESETA + str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] + ldr r1, =NETARM_GEN_SW_SVC_RESETB + str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] + ldr r1, =NETARM_GEN_SW_SVC_RESETA + str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] + ldr r1, =NETARM_GEN_SW_SVC_RESETB + str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] + mov pc, r0 +#elif defined(CONFIG_S3C4510B) +/* Nothing done here as reseting the CPU is board specific, depending + * on external peripherals such as watchdog timers, etc. */ +#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) + /* No specific reset actions for IntegratorAP/CM720T as yet */ +#elif defined(CONFIG_LPC2292) + .align 5 +.globl reset_cpu +reset_cpu: + mov pc, r0 +#else +#error No reset_cpu() defined for current CPU type +#endif |