xref: /openbmc/u-boot/arch/arm/cpu/arm720t/start.S (revision 3aa7a6a6)
1/*
2 *  armboot - Startup Code for ARM720 CPU-core
3 *
4 *  Copyright (c) 2001	Marius Gröger <mag@sysgo.de>
5 *  Copyright (c) 2002	Alex Züpke <azu@sysgo.de>
6 *
7 * See file CREDITS for list of people who contributed to this
8 * project.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 * MA 02111-1307 USA
24 */
25
26#include <asm-offsets.h>
27#include <config.h>
28#include <version.h>
29#include <asm/hardware.h>
30
31/*
32 *************************************************************************
33 *
34 * Jump vector table as in table 3.1 in [1]
35 *
36 *************************************************************************
37 */
38
39
40.globl _start
41_start: b	reset
42	ldr	pc, _undefined_instruction
43	ldr	pc, _software_interrupt
44	ldr	pc, _prefetch_abort
45	ldr	pc, _data_abort
46#ifdef CONFIG_LPC2292
47	.word	0xB4405F76 /* 2's complement of the checksum of the vectors */
48#else
49	ldr	pc, _not_used
50#endif
51	ldr	pc, _irq
52	ldr	pc, _fiq
53
54#ifdef CONFIG_SPL_BUILD
55_undefined_instruction: .word _undefined_instruction
56_software_interrupt:	.word _software_interrupt
57_prefetch_abort:	.word _prefetch_abort
58_data_abort:		.word _data_abort
59_not_used:		.word _not_used
60_irq:			.word _irq
61_fiq:			.word _fiq
62_pad:			.word 0x12345678 /* now 16*4=64 */
63#else
64_undefined_instruction: .word undefined_instruction
65_software_interrupt:	.word software_interrupt
66_prefetch_abort:	.word prefetch_abort
67_data_abort:		.word data_abort
68_not_used:		.word not_used
69_irq:			.word irq
70_fiq:			.word fiq
71_pad:			.word 0x12345678 /* now 16*4=64 */
72#endif	/* CONFIG_SPL_BUILD */
73
74	.balignl 16,0xdeadbeef
75
76
77/*
78 *************************************************************************
79 *
80 * Startup Code (reset vector)
81 *
82 * do important init only if we don't start from RAM!
83 * relocate armboot to ram
84 * setup stack
85 * jump to second stage
86 *
87 *************************************************************************
88 */
89
90.globl _TEXT_BASE
91_TEXT_BASE:
92#ifdef CONFIG_SPL_BUILD
93	.word	CONFIG_SPL_TEXT_BASE
94#else
95	.word	CONFIG_SYS_TEXT_BASE
96#endif
97
98/*
99 * These are defined in the board-specific linker script.
100 * Subtracting _start from them lets the linker put their
101 * relative position in the executable instead of leaving
102 * them null.
103 */
104.globl _bss_start_ofs
105_bss_start_ofs:
106	.word __bss_start - _start
107
108.globl _bss_end_ofs
109_bss_end_ofs:
110	.word __bss_end__ - _start
111
112.globl _end_ofs
113_end_ofs:
114	.word _end - _start
115
116#ifdef CONFIG_USE_IRQ
117/* IRQ stack memory (calculated at run-time) */
118.globl IRQ_STACK_START
119IRQ_STACK_START:
120	.word	0x0badc0de
121
122/* IRQ stack memory (calculated at run-time) */
123.globl FIQ_STACK_START
124FIQ_STACK_START:
125	.word 0x0badc0de
126#endif
127
128/* IRQ stack memory (calculated at run-time) + 8 bytes */
129.globl IRQ_STACK_START_IN
130IRQ_STACK_START_IN:
131	.word	0x0badc0de
132
133/*
134 * the actual reset code
135 */
136
137reset:
138	/*
139	 * set the cpu to SVC32 mode
140	 */
141	mrs	r0,cpsr
142	bic	r0,r0,#0x1f
143	orr	r0,r0,#0xd3
144	msr	cpsr,r0
145
146	/*
147	 * we do sys-critical inits only at reboot,
148	 * not when booting from ram!
149	 */
150#ifndef CONFIG_SKIP_LOWLEVEL_INIT
151	bl	cpu_init_crit
152#endif
153
154#ifdef CONFIG_LPC2292
155	bl	lowlevel_init
156#endif
157
158/* Set stackpointer in internal RAM to call board_init_f */
159call_board_init_f:
160	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
161	bic	sp, sp, #7 /* 8-byte alignment for ABI compliance */
162	ldr	r0,=0x00000000
163	bl	board_init_f
164
165/*------------------------------------------------------------------------------*/
166
167/*
168 * void relocate_code (addr_sp, gd, addr_moni)
169 *
170 * This "function" does not return, instead it continues in RAM
171 * after relocating the monitor code.
172 *
173 */
174	.globl	relocate_code
175relocate_code:
176	mov	r4, r0	/* save addr_sp */
177	mov	r5, r1	/* save addr of gd */
178	mov	r6, r2	/* save addr of destination */
179
180	/* Set up the stack						    */
181stack_setup:
182	mov	sp, r4
183
184	adr	r0, _start
185	cmp	r0, r6
186	moveq	r9, #0		/* no relocation. relocation offset(r9) = 0 */
187	beq	clear_bss		/* skip relocation */
188	mov	r1, r6			/* r1 <- scratch for copy_loop */
189	ldr	r3, _bss_start_ofs
190	add	r2, r0, r3		/* r2 <- source end address	    */
191
192copy_loop:
193	ldmia	r0!, {r9-r10}		/* copy from source address [r0]    */
194	stmia	r1!, {r9-r10}		/* copy to   target address [r1]    */
195	cmp	r0, r2			/* until source end address [r2]    */
196	blo	copy_loop
197
198#ifndef CONFIG_SPL_BUILD
199	/*
200	 * fix .rel.dyn relocations
201	 */
202	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
203	sub	r9, r6, r0		/* r9 <- relocation offset */
204	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
205	add	r10, r10, r0		/* r10 <- sym table in FLASH */
206	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
207	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
208	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
209	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
210fixloop:
211	ldr	r0, [r2]		/* r0 <- location to fix up, IN FLASH! */
212	add	r0, r0, r9		/* r0 <- location to fix up in RAM */
213	ldr	r1, [r2, #4]
214	and	r7, r1, #0xff
215	cmp	r7, #23			/* relative fixup? */
216	beq	fixrel
217	cmp	r7, #2			/* absolute fixup? */
218	beq	fixabs
219	/* ignore unknown type of fixup */
220	b	fixnext
221fixabs:
222	/* absolute fix: set location to (offset) symbol value */
223	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
224	add	r1, r10, r1		/* r1 <- address of symbol in table */
225	ldr	r1, [r1, #4]		/* r1 <- symbol value */
226	add	r1, r1, r9		/* r1 <- relocated sym addr */
227	b	fixnext
228fixrel:
229	/* relative fix: increase location by offset */
230	ldr	r1, [r0]
231	add	r1, r1, r9
232fixnext:
233	str	r1, [r0]
234	add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */
235	cmp	r2, r3
236	blo	fixloop
237#endif
238
239clear_bss:
240#ifndef CONFIG_SPL_BUILD
241	ldr	r0, _bss_start_ofs
242	ldr	r1, _bss_end_ofs
243	mov	r4, r6			/* reloc addr */
244	add	r0, r0, r4
245	add	r1, r1, r4
246	mov	r2, #0x00000000		/* clear			    */
247
248clbss_l:cmp	r0, r1			/* clear loop... */
249	bhs	clbss_e			/* if reached end of bss, exit */
250	str	r2, [r0]
251	add	r0, r0, #4
252	b	clbss_l
253clbss_e:
254
255	bl coloured_LED_init
256	bl red_led_on
257#endif
258
259/*
260 * We are done. Do not return, instead branch to second part of board
261 * initialization, now running from RAM.
262 */
263	ldr	r0, _board_init_r_ofs
264	adr	r1, _start
265	add	lr, r0, r1
266	add	lr, lr, r9
267	/* setup parameters for board_init_r */
268	mov	r0, r5		/* gd_t */
269	mov	r1, r6		/* dest_addr */
270	/* jump to it ... */
271	mov	pc, lr
272
273_board_init_r_ofs:
274	.word board_init_r - _start
275
276_rel_dyn_start_ofs:
277	.word __rel_dyn_start - _start
278_rel_dyn_end_ofs:
279	.word __rel_dyn_end - _start
280_dynsym_start_ofs:
281	.word __dynsym_start - _start
282
283/*
284 *************************************************************************
285 *
286 * CPU_init_critical registers
287 *
288 * setup important registers
289 * setup memory timing
290 *
291 *************************************************************************
292 */
293
294#if defined(CONFIG_LPC2292)
295PLLCFG_ADR:	.word	PLLCFG
296PLLFEED_ADR:	.word	PLLFEED
297PLLCON_ADR:	.word	PLLCON
298PLLSTAT_ADR:	.word	PLLSTAT
299VPBDIV_ADR:	.word	VPBDIV
300MEMMAP_ADR:	.word	MEMMAP
301
302#endif
303
304cpu_init_crit:
305#if defined(CONFIG_NETARM)
306	/*
307	 * prior to software reset : need to set pin PORTC4 to be *HRESET
308	 */
309	ldr	r0, =NETARM_GEN_MODULE_BASE
310	ldr	r1, =(NETARM_GEN_PORT_MODE(0x10) | \
311			NETARM_GEN_PORT_DIR(0x10))
312	str	r1, [r0, #+NETARM_GEN_PORTC]
313	/*
314	 * software reset : see HW Ref. Guide 8.2.4 : Software Service register
315	 *		    for an explanation of this process
316	 */
317	ldr	r0, =NETARM_GEN_MODULE_BASE
318	ldr	r1, =NETARM_GEN_SW_SVC_RESETA
319	str	r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE]
320	ldr	r1, =NETARM_GEN_SW_SVC_RESETB
321	str	r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE]
322	ldr	r1, =NETARM_GEN_SW_SVC_RESETA
323	str	r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE]
324	ldr	r1, =NETARM_GEN_SW_SVC_RESETB
325	str	r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE]
326	/*
327	 * setup PLL and System Config
328	 */
329	ldr	r0, =NETARM_GEN_MODULE_BASE
330
331	ldr	r1, =(	NETARM_GEN_SYS_CFG_LENDIAN | \
332			NETARM_GEN_SYS_CFG_BUSFULL | \
333			NETARM_GEN_SYS_CFG_USER_EN | \
334			NETARM_GEN_SYS_CFG_ALIGN_ABORT | \
335			NETARM_GEN_SYS_CFG_BUSARB_INT | \
336			NETARM_GEN_SYS_CFG_BUSMON_EN )
337
338	str	r1, [r0, #+NETARM_GEN_SYSTEM_CONTROL]
339
340#ifndef CONFIG_NETARM_PLL_BYPASS
341	ldr	r1, =(	NETARM_GEN_PLL_CTL_PLLCNT(NETARM_PLL_COUNT_VAL) | \
342			NETARM_GEN_PLL_CTL_POLTST_DEF | \
343			NETARM_GEN_PLL_CTL_INDIV(1) | \
344			NETARM_GEN_PLL_CTL_ICP_DEF | \
345			NETARM_GEN_PLL_CTL_OUTDIV(2) )
346	str	r1, [r0, #+NETARM_GEN_PLL_CONTROL]
347#endif
348
349	/*
350	 * mask all IRQs by clearing all bits in the INTMRs
351	 */
352	mov	r1, #0
353	ldr	r0, =NETARM_GEN_MODULE_BASE
354	str	r1, [r0, #+NETARM_GEN_INTR_ENABLE]
355
356#elif defined(CONFIG_S3C4510B)
357
358	/*
359	 * Mask off all IRQ sources
360	 */
361	ldr	r1, =REG_INTMASK
362	ldr	r0, =0x3FFFFF
363	str	r0, [r1]
364
365	/*
366	 * Disable Cache
367	 */
368	ldr r0, =REG_SYSCFG
369	ldr r1, =0x83ffffa0	/* cache-disabled  */
370	str r1, [r0]
371
372#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
373	/* No specific initialisation for IntegratorAP/CM720T as yet */
374#elif defined(CONFIG_LPC2292)
375	/* Set-up PLL */
376	mov	r3, #0xAA
377	mov	r4, #0x55
378	/* First disconnect and disable the PLL */
379	ldr	r0, PLLCON_ADR
380	mov	r1, #0x00
381	str	r1, [r0]
382	ldr	r0, PLLFEED_ADR /* start feed sequence */
383	str	r3, [r0]
384	str	r4, [r0]	/* feed sequence done */
385	/* Set new M and P values */
386	ldr	r0, PLLCFG_ADR
387	mov	r1, #0x23	/* M=4 and P=2 */
388	str	r1, [r0]
389	ldr	r0, PLLFEED_ADR /* start feed sequence */
390	str	r3, [r0]
391	str	r4, [r0]	/* feed sequence done */
392	/* Then enable the PLL */
393	ldr	r0, PLLCON_ADR
394	mov	r1, #0x01	/* PLL enable bit */
395	str	r1, [r0]
396	ldr	r0, PLLFEED_ADR /* start feed sequence */
397	str	r3, [r0]
398	str	r4, [r0]	/* feed sequence done */
399	/* Wait for the lock */
400	ldr	r0, PLLSTAT_ADR
401	mov	r1, #0x400	/* lock bit */
402lock_loop:
403	ldr	r2, [r0]
404	and	r2, r1, r2
405	cmp	r2, #0
406	beq	lock_loop
407	/* And finally connect the PLL */
408	ldr	r0, PLLCON_ADR
409	mov	r1, #0x03	/* PLL enable bit and connect bit */
410	str	r1, [r0]
411	ldr	r0, PLLFEED_ADR /* start feed sequence */
412	str	r3, [r0]
413	str	r4, [r0]	/* feed sequence done */
414	/* Set-up VPBDIV register */
415	ldr	r0, VPBDIV_ADR
416	mov	r1, #0x01	/* VPB clock is same as process clock */
417	str	r1, [r0]
418#elif defined(CONFIG_TEGRA)
419	/* No cpu_init_crit for tegra as yet */
420#else
421#error No cpu_init_crit() defined for current CPU type
422#endif
423
424#ifdef CONFIG_ARM7_REVD
425	/* set clock speed */
426	/* !!! we run @ 36 MHz due to a hardware flaw in Rev. D processors */
427	/* !!! not doing DRAM refresh properly! */
428	ldr	r0, SYSCON3
429	ldr	r1, [r0]
430	bic	r1, r1, #CLKCTL
431	orr	r1, r1, #CLKCTL_36
432	str	r1, [r0]
433#endif
434
435#if !defined(CONFIG_LPC2292) && !defined(CONFIG_TEGRA)
436	mov	ip, lr
437	/*
438	 * before relocating, we have to setup RAM timing
439	 * because memory timing is board-dependent, you will
440	 * find a lowlevel_init.S in your board directory.
441	 */
442	bl	lowlevel_init
443	mov	lr, ip
444#endif
445
446	mov	pc, lr
447
448
449#ifndef CONFIG_SPL_BUILD
450/*
451 *************************************************************************
452 *
453 * Interrupt handling
454 *
455 *************************************************************************
456 */
457
458@
459@ IRQ stack frame.
460@
461#define S_FRAME_SIZE	72
462
463#define S_OLD_R0	68
464#define S_PSR		64
465#define S_PC		60
466#define S_LR		56
467#define S_SP		52
468
469#define S_IP		48
470#define S_FP		44
471#define S_R10		40
472#define S_R9		36
473#define S_R8		32
474#define S_R7		28
475#define S_R6		24
476#define S_R5		20
477#define S_R4		16
478#define S_R3		12
479#define S_R2		8
480#define S_R1		4
481#define S_R0		0
482
483#define MODE_SVC 0x13
484#define I_BIT	 0x80
485
486/*
487 * use bad_save_user_regs for abort/prefetch/undef/swi ...
488 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
489 */
490
491	.macro	bad_save_user_regs
492	sub	sp, sp, #S_FRAME_SIZE
493	stmia	sp, {r0 - r12}			@ Calling r0-r12
494	add	r8, sp, #S_PC
495
496	ldr	r2, IRQ_STACK_START_IN
497	ldmia	r2, {r2 - r4}			@ get pc, cpsr, old_r0
498	add	r0, sp, #S_FRAME_SIZE		@ restore sp_SVC
499
500	add	r5, sp, #S_SP
501	mov	r1, lr
502	stmia	r5, {r0 - r4}			@ save sp_SVC, lr_SVC, pc, cpsr, old_r
503	mov	r0, sp
504	.endm
505
506	.macro	irq_save_user_regs
507	sub	sp, sp, #S_FRAME_SIZE
508	stmia	sp, {r0 - r12}			@ Calling r0-r12
509	add	r8, sp, #S_PC
510	stmdb	r8, {sp, lr}^			@ Calling SP, LR
511	str	lr, [r8, #0]			@ Save calling PC
512	mrs	r6, spsr
513	str	r6, [r8, #4]			@ Save CPSR
514	str	r0, [r8, #8]			@ Save OLD_R0
515	mov	r0, sp
516	.endm
517
518	.macro	irq_restore_user_regs
519	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
520	mov	r0, r0
521	ldr	lr, [sp, #S_PC]			@ Get PC
522	add	sp, sp, #S_FRAME_SIZE
523	subs	pc, lr, #4			@ return & move spsr_svc into cpsr
524	.endm
525
526	.macro get_bad_stack
527	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
528
529	str	lr, [r13]			@ save caller lr / spsr
530	mrs	lr, spsr
531	str	lr, [r13, #4]
532
533	mov	r13, #MODE_SVC			@ prepare SVC-Mode
534	msr	spsr_c, r13
535	mov	lr, pc
536	movs	pc, lr
537	.endm
538
539	.macro get_irq_stack			@ setup IRQ stack
540	ldr	sp, IRQ_STACK_START
541	.endm
542
543	.macro get_fiq_stack			@ setup FIQ stack
544	ldr	sp, FIQ_STACK_START
545	.endm
546
547/*
548 * exception handlers
549 */
550	.align	5
551undefined_instruction:
552	get_bad_stack
553	bad_save_user_regs
554	bl	do_undefined_instruction
555
556	.align	5
557software_interrupt:
558	get_bad_stack
559	bad_save_user_regs
560	bl	do_software_interrupt
561
562	.align	5
563prefetch_abort:
564	get_bad_stack
565	bad_save_user_regs
566	bl	do_prefetch_abort
567
568	.align	5
569data_abort:
570	get_bad_stack
571	bad_save_user_regs
572	bl	do_data_abort
573
574	.align	5
575not_used:
576	get_bad_stack
577	bad_save_user_regs
578	bl	do_not_used
579
580#ifdef CONFIG_USE_IRQ
581
582	.align	5
583irq:
584	get_irq_stack
585	irq_save_user_regs
586	bl	do_irq
587	irq_restore_user_regs
588
589	.align	5
590fiq:
591	get_fiq_stack
592	/* someone ought to write a more effiction fiq_save_user_regs */
593	irq_save_user_regs
594	bl	do_fiq
595	irq_restore_user_regs
596
597#else
598
599	.align	5
600irq:
601	get_bad_stack
602	bad_save_user_regs
603	bl	do_irq
604
605	.align	5
606fiq:
607	get_bad_stack
608	bad_save_user_regs
609	bl	do_fiq
610
611#endif
612#endif /* CONFIG_SPL_BUILD */
613
614#if defined(CONFIG_NETARM)
615	.align	5
616.globl reset_cpu
617reset_cpu:
618	ldr	r1, =NETARM_MEM_MODULE_BASE
619	ldr	r0, [r1, #+NETARM_MEM_CS0_BASE_ADDR]
620	ldr	r1, =0xFFFFF000
621	and	r0, r1, r0
622	ldr	r1, =(relocate-CONFIG_SYS_TEXT_BASE)
623	add	r0, r1, r0
624	ldr	r4, =NETARM_GEN_MODULE_BASE
625	ldr	r1, =NETARM_GEN_SW_SVC_RESETA
626	str	r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE]
627	ldr	r1, =NETARM_GEN_SW_SVC_RESETB
628	str	r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE]
629	ldr	r1, =NETARM_GEN_SW_SVC_RESETA
630	str	r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE]
631	ldr	r1, =NETARM_GEN_SW_SVC_RESETB
632	str	r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE]
633	mov	pc, r0
634#elif defined(CONFIG_S3C4510B)
635/* Nothing done here as reseting the CPU is board specific, depending
636 * on external peripherals such as watchdog timers, etc. */
637#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR)
638	/* No specific reset actions for IntegratorAP/CM720T as yet */
639#elif defined(CONFIG_LPC2292)
640	.align	5
641.globl reset_cpu
642reset_cpu:
643	mov	pc, r0
644#elif defined(CONFIG_TEGRA)
645	/* No specific reset actions for tegra as yet */
646#else
647#error No reset_cpu() defined for current CPU type
648#endif
649