summaryrefslogtreecommitdiff
path: root/firmware/src/start/Cstartup.S
blob: e262b8f759f5df40f2a29ce90133a91cc00c926a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
/* AT91SAM7 low-level startup outines for OpenPCD / OpenPICC DFU loader
 * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
 *
 *  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   _startup, . - _startup
        .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

personal git repositories of Harald Welte. Your mileage may vary