xref: /openbmc/u-boot/arch/arm/cpu/pxa/start.S (revision a79854a9)
1/*
2 *  armboot - Startup Code for XScale CPU-core
3 *
4 *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
5 *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
6 *  Copyright (C) 2000	Wolfgang Denk <wd@denx.de>
7 *  Copyright (C) 2001	Alex Zuepke <azu@sysgo.de>
8 *  Copyright (C) 2001	Marius Groger <mag@sysgo.de>
9 *  Copyright (C) 2002	Alex Zupke <azu@sysgo.de>
10 *  Copyright (C) 2002	Gary Jennejohn <garyj@denx.de>
11 *  Copyright (C) 2002	Kyle Harris <kharris@nexus-tech.net>
12 *  Copyright (C) 2003	Kai-Uwe Bloem <kai-uwe.bloem@auerswald.de>
13 *  Copyright (C) 2003	Kshitij <kshitij@ti.com>
14 *  Copyright (C) 2003	Richard Woodruff <r-woodruff2@ti.com>
15 *  Copyright (C) 2003	Robert Schwebel <r.schwebel@pengutronix.de>
16 *  Copyright (C) 2004	Texas Instruments <r-woodruff2@ti.com>
17 *  Copyright (C) 2010	Marek Vasut <marek.vasut@gmail.com>
18 *
19 * SPDX-License-Identifier:	GPL-2.0+
20 */
21
22#include <asm-offsets.h>
23#include <config.h>
24#include <version.h>
25
26#ifdef CONFIG_CPU_PXA25X
27#if ((CONFIG_SYS_INIT_SP_ADDR) != 0xfffff800)
28#error "Init SP address must be set to 0xfffff800 for PXA250"
29#endif
30#endif
31
32.globl _start
33_start: b	reset
34#ifdef CONFIG_SPL_BUILD
35	ldr	pc, _hang
36	ldr	pc, _hang
37	ldr	pc, _hang
38	ldr	pc, _hang
39	ldr	pc, _hang
40	ldr	pc, _hang
41	ldr	pc, _hang
42
43_hang:
44	.word	do_hang
45	.word	0x12345678
46	.word	0x12345678
47	.word	0x12345678
48	.word	0x12345678
49	.word	0x12345678
50	.word	0x12345678
51	.word	0x12345678	/* now 16*4=64 */
52#else
53	ldr	pc, _undefined_instruction
54	ldr	pc, _software_interrupt
55	ldr	pc, _prefetch_abort
56	ldr	pc, _data_abort
57	ldr	pc, _not_used
58	ldr	pc, _irq
59	ldr	pc, _fiq
60
61_undefined_instruction: .word undefined_instruction
62_software_interrupt:	.word software_interrupt
63_prefetch_abort:	.word prefetch_abort
64_data_abort:		.word data_abort
65_not_used:		.word not_used
66_irq:			.word irq
67_fiq:			.word fiq
68_pad:			.word 0x12345678 /* now 16*4=64 */
69#endif	/* CONFIG_SPL_BUILD */
70.global _end_vect
71_end_vect:
72
73	.balignl 16,0xdeadbeef
74/*
75 *************************************************************************
76 *
77 * Startup Code (reset vector)
78 *
79 * do important init only if we don't start from memory!
80 * setup Memory and board specific bits prior to relocation.
81 * relocate armboot to ram
82 * setup stack
83 *
84 *************************************************************************
85 */
86
87.globl _TEXT_BASE
88_TEXT_BASE:
89#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
90	.word	CONFIG_SPL_TEXT_BASE
91#else
92	.word	CONFIG_SYS_TEXT_BASE
93#endif
94
95/*
96 * These are defined in the board-specific linker script.
97 * Subtracting _start from them lets the linker put their
98 * relative position in the executable instead of leaving
99 * them null.
100 */
101.globl _bss_start_ofs
102_bss_start_ofs:
103	.word __bss_start - _start
104
105.globl _bss_end_ofs
106_bss_end_ofs:
107	.word __bss_end - _start
108
109.globl _end_ofs
110_end_ofs:
111	.word _end - _start
112
113#ifdef CONFIG_USE_IRQ
114/* IRQ stack memory (calculated at run-time) */
115.globl IRQ_STACK_START
116IRQ_STACK_START:
117	.word	0x0badc0de
118
119/* IRQ stack memory (calculated at run-time) */
120.globl FIQ_STACK_START
121FIQ_STACK_START:
122	.word 0x0badc0de
123#endif
124
125/* IRQ stack memory (calculated at run-time) + 8 bytes */
126.globl IRQ_STACK_START_IN
127IRQ_STACK_START_IN:
128	.word	0x0badc0de
129
130/*
131 * the actual reset code
132 */
133
134reset:
135	/*
136	 * set the cpu to SVC32 mode
137	 */
138	mrs	r0,cpsr
139	bic	r0,r0,#0x1f
140	orr	r0,r0,#0xd3
141	msr	cpsr,r0
142
143#ifndef CONFIG_SKIP_LOWLEVEL_INIT
144	bl  cpu_init_crit
145#endif
146
147#ifdef	CONFIG_CPU_PXA25X
148	bl	lock_cache_for_stack
149#endif
150
151	bl	_main
152
153/*------------------------------------------------------------------------------*/
154
155	.globl	c_runtime_cpu_setup
156c_runtime_cpu_setup:
157
158#ifdef CONFIG_CPU_PXA25X
159	/*
160	 * Unlock (actually, disable) the cache now that board_init_f
161	 * is done. We could do this earlier but we would need to add
162	 * a new C runtime hook, whereas c_runtime_cpu_setup already
163	 * exists.
164	 * As this routine is just a call to cpu_init_crit, let us
165	 * tail-optimize and do a simple branch here.
166	 */
167	b	cpu_init_crit
168#else
169	bx	lr
170#endif
171
172/*
173 *************************************************************************
174 *
175 * CPU_init_critical registers
176 *
177 * setup important registers
178 * setup memory timing
179 *
180 *************************************************************************
181 */
182#if !defined(CONFIG_SKIP_LOWLEVEL_INIT) || defined(CONFIG_CPU_PXA25X)
183cpu_init_crit:
184	/*
185	 * flush v4 I/D caches
186	 */
187	mov	r0, #0
188	mcr	p15, 0, r0, c7, c7, 0	/* Invalidate I+D+BTB caches */
189	mcr	p15, 0, r0, c8, c7, 0	/* Invalidate Unified TLB */
190
191	/*
192	 * disable MMU stuff and caches
193	 */
194	mrc	p15, 0, r0, c1, c0, 0
195	bic	r0, r0, #0x00003300	@ clear bits 13:12, 9:8 (--VI --RS)
196	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
197	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
198	mcr	p15, 0, r0, c1, c0, 0
199
200	mov	pc, lr		/* back to my caller */
201#endif /* !CONFIG_SKIP_LOWLEVEL_INIT || CONFIG_CPU_PXA25X */
202
203#ifndef CONFIG_SPL_BUILD
204/*
205 *************************************************************************
206 *
207 * Interrupt handling
208 *
209 *************************************************************************
210 */
211@
212@ IRQ stack frame.
213@
214#define S_FRAME_SIZE	72
215
216#define S_OLD_R0	68
217#define S_PSR		64
218#define S_PC		60
219#define S_LR		56
220#define S_SP		52
221
222#define S_IP		48
223#define S_FP		44
224#define S_R10		40
225#define S_R9		36
226#define S_R8		32
227#define S_R7		28
228#define S_R6		24
229#define S_R5		20
230#define S_R4		16
231#define S_R3		12
232#define S_R2		8
233#define S_R1		4
234#define S_R0		0
235
236#define MODE_SVC 0x13
237#define I_BIT	 0x80
238
239/*
240 * use bad_save_user_regs for abort/prefetch/undef/swi ...
241 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
242 */
243
244	.macro	bad_save_user_regs
245	sub	sp, sp, #S_FRAME_SIZE		@ carve out a frame on current user stack
246	stmia	sp, {r0 - r12}			@ Save user registers (now in svc mode) r0-r12
247
248	ldr	r2, IRQ_STACK_START_IN		@ set base 2 words into abort stack
249	ldmia	r2, {r2 - r3}			@ get values for "aborted" pc and cpsr (into parm regs)
250	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
251
252	add	r5, sp, #S_SP
253	mov	r1, lr
254	stmia	r5, {r0 - r3}			@ save sp_SVC, lr_SVC, pc, cpsr
255	mov	r0, sp				@ save current stack into r0 (param register)
256	.endm
257
258	.macro	irq_save_user_regs
259	sub	sp, sp, #S_FRAME_SIZE
260	stmia	sp, {r0 - r12}			@ Calling r0-r12
261	add	r8, sp, #S_PC			@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
262	stmdb	r8, {sp, lr}^			@ Calling SP, LR
263	str	lr, [r8, #0]			@ Save calling PC
264	mrs	r6, spsr
265	str	r6, [r8, #4]			@ Save CPSR
266	str	r0, [r8, #8]			@ Save OLD_R0
267	mov	r0, sp
268	.endm
269
270	.macro	irq_restore_user_regs
271	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
272	mov	r0, r0
273	ldr	lr, [sp, #S_PC]			@ Get PC
274	add	sp, sp, #S_FRAME_SIZE
275	subs	pc, lr, #4			@ return & move spsr_svc into cpsr
276	.endm
277
278	.macro get_bad_stack
279	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack (enter in banked mode)
280
281	str	lr, [r13]			@ save caller lr in position 0 of saved stack
282	mrs	lr, spsr			@ get the spsr
283	str	lr, [r13, #4]			@ save spsr in position 1 of saved stack
284
285	mov	r13, #MODE_SVC			@ prepare SVC-Mode
286	@ msr	spsr_c, r13
287	msr	spsr, r13			@ switch modes, make sure moves will execute
288	mov	lr, pc				@ capture return pc
289	movs	pc, lr				@ jump to next instruction & switch modes.
290	.endm
291
292	.macro get_bad_stack_swi
293	sub	r13, r13, #4			@ space on current stack for scratch reg.
294	str	r0, [r13]			@ save R0's value.
295	ldr	r0, IRQ_STACK_START_IN		@ get data regions start
296	str	lr, [r0]			@ save caller lr in position 0 of saved stack
297	mrs	lr, spsr			@ get the spsr
298	str	lr, [r0, #4]			@ save spsr in position 1 of saved stack
299	ldr	lr, [r0]			@ restore lr
300	ldr	r0, [r13]			@ restore r0
301	add	r13, r13, #4			@ pop stack entry
302	.endm
303
304	.macro get_irq_stack			@ setup IRQ stack
305	ldr	sp, IRQ_STACK_START
306	.endm
307
308	.macro get_fiq_stack			@ setup FIQ stack
309	ldr	sp, FIQ_STACK_START
310	.endm
311#endif	/* CONFIG_SPL_BUILD */
312
313/*
314 * exception handlers
315 */
316#ifdef CONFIG_SPL_BUILD
317	.align	5
318do_hang:
319	ldr	sp, _TEXT_BASE			/* use 32 words about stack */
320	bl	hang				/* hang and never return */
321#else	/* !CONFIG_SPL_BUILD */
322	.align	5
323undefined_instruction:
324	get_bad_stack
325	bad_save_user_regs
326	bl	do_undefined_instruction
327
328	.align	5
329software_interrupt:
330	get_bad_stack_swi
331	bad_save_user_regs
332	bl	do_software_interrupt
333
334	.align	5
335prefetch_abort:
336	get_bad_stack
337	bad_save_user_regs
338	bl	do_prefetch_abort
339
340	.align	5
341data_abort:
342	get_bad_stack
343	bad_save_user_regs
344	bl	do_data_abort
345
346	.align	5
347not_used:
348	get_bad_stack
349	bad_save_user_regs
350	bl	do_not_used
351
352#ifdef CONFIG_USE_IRQ
353
354	.align	5
355irq:
356	get_irq_stack
357	irq_save_user_regs
358	bl	do_irq
359	irq_restore_user_regs
360
361	.align	5
362fiq:
363	get_fiq_stack
364	/* someone ought to write a more effiction fiq_save_user_regs */
365	irq_save_user_regs
366	bl	do_fiq
367	irq_restore_user_regs
368
369#else
370
371	.align	5
372irq:
373	get_bad_stack
374	bad_save_user_regs
375	bl	do_irq
376
377	.align	5
378fiq:
379	get_bad_stack
380	bad_save_user_regs
381	bl	do_fiq
382
383#endif
384	.align 5
385#endif	/* CONFIG_SPL_BUILD */
386
387
388/*
389 * Enable MMU to use DCache as DRAM.
390 *
391 * This is useful on PXA25x and PXA26x in early bootstages, where there is no
392 * other possible memory available to hold stack.
393 */
394#ifdef CONFIG_CPU_PXA25X
395.macro CPWAIT reg
396	mrc	p15, 0, \reg, c2, c0, 0
397	mov	\reg, \reg
398	sub	pc, pc, #4
399.endm
400lock_cache_for_stack:
401	/* Domain access -- enable for all CPs */
402	ldr	r0, =0x0000ffff
403	mcr	p15, 0, r0, c3, c0, 0
404
405	/* Point TTBR to MMU table */
406	ldr	r0, =mmutable
407	mcr	p15, 0, r0, c2, c0, 0
408
409	/* Kick in MMU, ICache, DCache, BTB */
410	mrc	p15, 0, r0, c1, c0, 0
411	bic	r0, #0x1b00
412	bic	r0, #0x0087
413	orr	r0, #0x1800
414	orr	r0, #0x0005
415	mcr	p15, 0, r0, c1, c0, 0
416	CPWAIT	r0
417
418	/* Unlock Icache, Dcache */
419	mcr	p15, 0, r0, c9, c1, 1
420	mcr	p15, 0, r0, c9, c2, 1
421
422	/* Flush Icache, Dcache, BTB */
423	mcr	p15, 0, r0, c7, c7, 0
424
425	/* Unlock I-TLB, D-TLB */
426	mcr	p15, 0, r0, c10, c4, 1
427	mcr	p15, 0, r0, c10, c8, 1
428
429	/* Flush TLB */
430	mcr	p15, 0, r0, c8, c7, 0
431
432	/* Allocate 4096 bytes of Dcache as RAM */
433
434	/* Drain pending loads and stores */
435	mcr	p15, 0, r0, c7, c10, 4
436
437	mov	r4, #0x00
438	mov	r5, #0x00
439	mov	r2, #0x01
440	mcr	p15, 0, r0, c9, c2, 0
441	CPWAIT	r0
442
443	/* 128 lines reserved (128 x 32bytes = 4096 bytes total) */
444	mov	r0, #128
445	ldr	r1, =0xfffff000
446
447alloc:
448	mcr	p15, 0, r1, c7, c2, 5
449	/* Drain pending loads and stores */
450	mcr	p15, 0, r0, c7, c10, 4
451	strd	r4, [r1], #8
452	strd	r4, [r1], #8
453	strd	r4, [r1], #8
454	strd	r4, [r1], #8
455	subs	r0, #0x01
456	bne	alloc
457	/* Drain pending loads and stores */
458	mcr	p15, 0, r0, c7, c10, 4
459	mov	r2, #0x00
460	mcr	p15, 0, r2, c9, c2, 0
461	CPWAIT	r0
462
463	mov	pc, lr
464
465.section .mmutable, "a"
466mmutable:
467	.align	14
468	/* 0x00000000 - 0xffe00000 : 1:1, uncached mapping */
469	.set	__base, 0
470	.rept	0xfff
471	.word	(__base << 20) | 0xc12
472	.set	__base, __base + 1
473	.endr
474
475	/* 0xfff00000 : 1:1, cached mapping */
476	.word	(0xfff << 20) | 0x1c1e
477#endif	/* CONFIG_CPU_PXA25X */
478