/* AT91SAM7 low-level startup outines for OpenPCD / OpenPICC DFU loader * (C) 2006 by Harald Welte * * 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 * */ /*------------------------------------------------------------------------------ //*- ATMEL Microcontroller Software Support - ROUSSET - //*------------------------------------------------------------------------------ //* The software is delivered "AS IS" without warranty or condition of any //* kind, either express, implied or statutory. This includes without //* limitation any warranty or condition with respect to merchantability or //* fitness for any particular purpose, or against the infringements of //* intellectual property rights of others. //*----------------------------------------------------------------------------- //*- File source : Cstartup.s //*- Object : Generic CStartup for KEIL and GCC No Use REMAP //*- Compilation flag : None //*- //*- 1.0 18/Oct/04 JPP : Creation //*- 1.1 21/Feb/05 JPP : Set Interrupt //*- 1.1 01/Apr/05 JPP : save SPSR //*-----------------------------------------------------------------------------*/ /* Enable DFU by press of hardware POI_BOOTLDR switch */ #define CONFIG_DFU_SWITCH /* Enable DFU by magic value in RAM and software reset */ #define CONFIG_DFU_MAGIC //#define DEBUG_LL #define PIOA_PER 0xFFFFF400 #define PIOA_OER 0xFFFFF410 #define PIOA_SODR 0xFFFFF430 #define PIOA_CODR 0xFFFFF434 #define LED1 25 /* this only works on OpenPICC, not Olimex */ #ifdef DEBUG_LL /* Debugging macros for switching on/off LED1 (green) */ .macro led1on ldr r2, =PIOA_CODR mov r1, #(1 << LED1) str r1, [r2] .endm .macro led1off ldr r2, =PIOA_SODR mov r1, #(1 << LED1) str r1, [r2] .endm .macro ledinit ldr r2, =PIOA_PER mov r1, #(1 << LED1) str r1, [r2] ldr r2, =PIOA_OER str r1, [r2] led1off .endm #else .macro ledinit .endm .macro led1on .endm .macro led1off .endm #endif .equ IRQ_Stack_Size, 0x00000400 .equ FIQ_Stack_Size, 0x00000400 .equ AIC_IVR, (256) .equ AIC_FVR, (260) .equ AIC_EOICR, (304) .equ AIC_MCR_RCR, (0xf00) .equ AT91C_BASE_AIC, (0xFFFFF000) .equ AT91C_PMC_PCER, (0xFFFFFC10) .equ AT91C_BASE_PIOA, (0xFFFFF400) .equ AT91C_ID_PIOA, (2) .equ PIOA_PDSR, (0x3c) #if defined(PCD) .equ PIO_BOOTLDR, (1 << 27) #elif defined(PICC) .equ PIO_BOOTLDR, (1 << 6) #elif defined(OLIMEX) /* Olimex SAM7-Pxxx boards have a button B1 on PA19 that is low-active */ .equ PIO_BOOTLDR, (1 << 19) #define CONFIG_DFU_SWITCH_INV #elif defined(SIMTRACE) .equ PIO_BOOTLDR, (1 << 31) #define CONFIG_DFU_SWITCH_INV #else #error please define PIO_BOOTLDR for your board #endif /* #include "AT91SAM7S64_inc.h" */ /* Exception Vectors in RAM */ .text .arm .section .vectram, "ax" .global _remap_call_dfu .func _remap_call_dfu _remap_call_dfu: led1on /* Remap RAM to 0x00000000 for DFU */ ldr r1, =AT91C_BASE_AIC mov r2, #0x01 str r2, [r1, #AIC_MCR_RCR] ldr r4, =dfu_main bx r4 .size _remap_call_dfu, . - _remap_call_dfu .endfunc #;------------------------------------------------------------------------------ #;- Section Definition #;----------------- #;- Section #;- .internal_ram_top Top_Stack: used by the cstartup for vector initalisation #;- management defined by ld and affect from ldscript #;------------------------------------------------------------------------------ .section .internal_ram_top .code 32 .align 0 .global Top_Stack Top_Stack: /*------------------------------------------------------------------------------ *- Area Definition *------------------------------------------------------------------------------ * .text is used instead of .section .text so it works with arm-aout too. */ .section .reset .text reset: /*------------------------------------------------------------------------------ //*- Exception vectors //*-------------------- //*- These vectors can be read at address 0 or at RAM address //*- They ABSOLUTELY requires to be in relative addresssing mode in order to //*- guarantee a valid jump. For the moment, all are just looping. //*- If an exception occurs before remap, this would result in an infinite loop. //*- To ensure if a exeption occurs before start application to infinite loop. //*------------------------------------------------------------------------------*/ B InitReset /* 0x00 Reset handler */ undefvec: B undefvec /* 0x04 Undefined Instruction */ swivec: B swivec /* 0x08 Software Interrupt */ pabtvec: B pabtvec /* 0x0C Prefetch Abort */ dabtvec: b dabtvec /* 0x10 Data Abort */ rsvdvec: b rsvdvec /* 0x14 reserved */ irqvec: b IRQ_Handler_Entry /* 0x18 IRQ */ fiqvec: ldr pc, [pc, #-0xF20] /* 0x1c FIQ */ dfu_state_dummy: .word 0 .global IRQ_Handler_Entry .func IRQ_Handler_Entry FIQ_Handler_Entry: /*- Switch in SVC/User Mode to allow User Stack access for C code */ /* because the FIQ is not yet acknowledged*/ /*- Save and r0 in FIQ_Register */ mov r9, r0 ldr r0, [r8, #AIC_FVR] msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_SVC /*- Save scratch/used registers and LR in User Stack */ stmfd sp!, { r1-r3, r12, lr} /*- Branch to the routine pointed by the AIC_FVR */ mov r14, pc bx r0 /*- Restore scratch/used registers and LR from User Stack */ ldmia sp!, { r1-r3, r12, lr} /*- Leave Interrupts disabled and switch back in FIQ mode */ msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_FIQ /*- Restore the R0 ARM_MODE_SVC register */ mov r0,r9 /*- Restore the Program Counter using the LR_fiq directly in the PC */ subs pc, lr, #4 IRQ_Handler_Entry: /*- Manage Exception Entry */ /*- Adjust and save LR_irq in IRQ stack */ sub lr, lr, #4 stmfd sp!, {lr} /*- Save SPSR need to be saved for nested interrupt */ mrs r14, SPSR stmfd sp!, {r14} /*- Save and r0 in IRQ stack */ stmfd sp!, {r0} /*- Write in the IVR to support Protect Mode */ /*- No effect in Normal Mode */ /*- De-assert the NIRQ and clear the source in Protect Mode */ ldr r14, =AT91C_BASE_AIC ldr r0 , [r14, #AIC_IVR] str r14, [r14, #AIC_IVR] /*- Enable Interrupt and Switch in Supervisor Mode */ msr CPSR_c, #ARM_MODE_SVC /*- Save scratch/used registers and LR in User Stack */ stmfd sp!, { r1-r3, r12, r14} /*- Branch to the routine pointed by the AIC_IVR */ mov r14, pc bx r0 /*- Restore scratch/used registers and LR from User Stack*/ ldmia sp!, { r1-r3, r12, r14} /*- Disable Interrupt and switch back in IRQ mode */ msr CPSR_c, #I_BIT | ARM_MODE_IRQ /*- Mark the End of Interrupt on the AIC */ ldr r14, =AT91C_BASE_AIC str r14, [r14, #AIC_EOICR] /*- Restore SPSR_irq and r0 from IRQ stack */ ldmia sp!, {r0} /*- Restore SPSR_irq and r0 from IRQ stack */ ldmia sp!, {r14} msr SPSR_cxsf, r14 /*- Restore adjusted LR_irq from IRQ stack directly in the PC */ ldmia sp!, {pc}^ .size IRQ_Handler_Entry, . - IRQ_Handler_Entry .endfunc .align 0 .RAM_TOP: .word Top_Stack .global _startup .func _startup InitReset: /*------------------------------------------------------------------------------ /*- Low level Init (PMC, AIC, ? ....) by C function AT91F_LowLevelInit /*------------------------------------------------------------------------------*/ .extern AT91F_LowLevelInit /*- minumum C initialization */ /*- call AT91F_LowLevelInit( void) */ ldr r13,.RAM_TOP /* temporary stack in internal RAM */ /*--Call Low level init function in ABSOLUTE through the Interworking */ ldr r0,=AT91F_LowLevelInit mov lr, pc bx r0 ledinit /*------------------------------------------------------------------------------ //*- Top of Stack Definition //*------------------------- //*- Interrupt and Supervisor Stack are located at the top of internal memory in //*- order to speed the exception handling context saving and restoring. //*- ARM_MODE_SVC (Application, C) Stack is located at the top of the external memory. //*------------------------------------------------------------------------------*/ .EQU ARM_MODE_FIQ, 0x11 .EQU ARM_MODE_IRQ, 0x12 .EQU ARM_MODE_SVC, 0x13 .EQU I_BIT, 0x80 .EQU F_BIT, 0x40 #define AT91C_RSTC_RSR 0xFFFFFD04 #define AT91C_RSTC_RSTTYP_SOFTWARE (0x03 << 8) #define DFU_STATE_appDETACH 1 /*------------------------------------------------------------------------------ //*- Setup the stack for each mode //*-------------------------------*/ mov r0,r13 /*- Set up Fast Interrupt Mode and set FIQ Mode Stack*/ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT mov r13, r0 sub r0, r0, #FIQ_Stack_Size /*- Init the FIQ register*/ ldr r8, =AT91C_BASE_AIC /*- Set up Interrupt Mode and set IRQ Mode Stack*/ msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT mov r13, r0 /* Init stack IRQ */ sub r0, r0, #IRQ_Stack_Size /*- Set up Supervisor Mode and set Supervisor Mode Stack*/ msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT mov r13, r0 /* Init stack Sup */ /* - Enable Interrupts and FIQ */ msr CPSR_c, #ARM_MODE_SVC #ifdef CONFIG_DFU_MAGIC ldr r1, =AT91C_RSTC_RSR ldr r2, [r1] #and r2, r2, AT91C_RSTC_RSTTYP tst r2, #AT91C_RSTC_RSTTYP_SOFTWARE beq dfu_magic_end ldr r1, =dfu_state ldr r2, [r1] cmp r2, #DFU_STATE_appDETACH beq _reloc_dfu dfu_magic_end: #endif # Relocate DFU .data.shared section (Copy from ROM to RAM) LDR R1, =_etext LDR R2, =_data_shared LDR R3, =_edata_shared LoopRelDS: CMP R2, R3 LDRLO R0, [R1], #4 STRLO R0, [R2], #4 BLO LoopRelDS /* # Clear DFU .bss section (Zero init) MOV R0, #0 LDR R1, =__bss_start__ LDR R2, =__bss_end__ LoopZI: CMP R1, R2 STRLO R0, [R1], #4 BLO LoopZI */ /* prepare c function call to main */ mov r0, #0 /* argc = 0 */ ldr lr, =exit ldr r10, =0x00104000 #ifdef CONFIG_DFU_SWITCH /* check whether bootloader button is pressed */ ldr r1, =AT91C_PMC_PCER mov r2, #(1 << AT91C_ID_PIOA) str r2, [r1] ldr r1, =AT91C_BASE_PIOA ldr r2, [r1, #PIOA_PDSR] tst r2, #PIO_BOOTLDR #ifdef CONFIG_DFU_SWITCH_INV beq _reloc_dfu #else bne _reloc_dfu #endif /* SWITCH_INV */ #endif bx r10 _reloc_dfu: /* Relocate DFU .data section (Copy from ROM to RAM) */ LDR R1, =_data_flash LDR R2, =_data LDR R3, =_edata LoopRel: CMP R2, R3 LDRLO R0, [R1], #4 STRLO R0, [R2], #4 BLO LoopRel /* Clear DFU .bss section (Zero init) */ MOV R0, #0 LDR R1, =__bss_start__ LDR R2, =__bss_end__ LoopZI: CMP R1, R2 STRLO R0, [R1], #4 BLO LoopZI /* relocate DFU .text into RAM */ ldr r1, =0x00100000 ldr r2, =0x00200000 ldr r3, =_etext add r3, r3, r2 loop_rel_t: cmp r2, r3 ldrlo r4, [r1], #4 strlo r4, [r2], #4 blo loop_rel_t ldr r4, =_remap_call_dfu bx r4 .size InitReset,.-InitReset .endfunc /* "exit" dummy to avoid sbrk write read etc. needed by the newlib default "exit" */ .global exit .func exit exit: b . .size exit, . - exit .endfunc /*--------------------------------------------------------------- //* ?EXEPTION_VECTOR //* This module is only linked if needed for closing files. //*---------------------------------------------------------------*/ .global AT91F_Default_FIQ_handler .func AT91F_Default_FIQ_handler AT91F_Default_FIQ_handler: b AT91F_Default_FIQ_handler .size AT91F_Default_FIQ_handler, . - AT91F_Default_FIQ_handler .endfunc .global AT91F_Default_IRQ_handler .func AT91F_Default_IRQ_handler AT91F_Default_IRQ_handler: b AT91F_Default_IRQ_handler .size AT91F_Default_IRQ_handler, . - AT91F_Default_IRQ_handler .endfunc .global AT91F_Spurious_handler .func AT91F_Spurious_handler AT91F_Spurious_handler: b AT91F_Spurious_handler .size AT91F_Spurious_handler, . - AT91F_Spurious_handler .endfunc .end