xref: /openbmc/u-boot/arch/arm/cpu/pxa/start.S (revision 7ca6f363)
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#ifdef CONFIG_USE_IRQ
88/* IRQ stack memory (calculated at run-time) */
89.globl IRQ_STACK_START
90IRQ_STACK_START:
91	.word	0x0badc0de
92
93/* IRQ stack memory (calculated at run-time) */
94.globl FIQ_STACK_START
95FIQ_STACK_START:
96	.word 0x0badc0de
97#endif
98
99/* IRQ stack memory (calculated at run-time) + 8 bytes */
100.globl IRQ_STACK_START_IN
101IRQ_STACK_START_IN:
102	.word	0x0badc0de
103
104/*
105 * the actual reset code
106 */
107
108reset:
109	/*
110	 * set the cpu to SVC32 mode
111	 */
112	mrs	r0,cpsr
113	bic	r0,r0,#0x1f
114	orr	r0,r0,#0xd3
115	msr	cpsr,r0
116
117#ifndef CONFIG_SKIP_LOWLEVEL_INIT
118	bl  cpu_init_crit
119#endif
120
121#ifdef	CONFIG_CPU_PXA25X
122	bl	lock_cache_for_stack
123#endif
124
125	bl	_main
126
127/*------------------------------------------------------------------------------*/
128
129	.globl	c_runtime_cpu_setup
130c_runtime_cpu_setup:
131
132#ifdef CONFIG_CPU_PXA25X
133	/*
134	 * Unlock (actually, disable) the cache now that board_init_f
135	 * is done. We could do this earlier but we would need to add
136	 * a new C runtime hook, whereas c_runtime_cpu_setup already
137	 * exists.
138	 * As this routine is just a call to cpu_init_crit, let us
139	 * tail-optimize and do a simple branch here.
140	 */
141	b	cpu_init_crit
142#else
143	bx	lr
144#endif
145
146/*
147 *************************************************************************
148 *
149 * CPU_init_critical registers
150 *
151 * setup important registers
152 * setup memory timing
153 *
154 *************************************************************************
155 */
156#if !defined(CONFIG_SKIP_LOWLEVEL_INIT) || defined(CONFIG_CPU_PXA25X)
157cpu_init_crit:
158	/*
159	 * flush v4 I/D caches
160	 */
161	mov	r0, #0
162	mcr	p15, 0, r0, c7, c7, 0	/* Invalidate I+D+BTB caches */
163	mcr	p15, 0, r0, c8, c7, 0	/* Invalidate Unified TLB */
164
165	/*
166	 * disable MMU stuff and caches
167	 */
168	mrc	p15, 0, r0, c1, c0, 0
169	bic	r0, r0, #0x00003300	@ clear bits 13:12, 9:8 (--VI --RS)
170	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
171	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
172	mcr	p15, 0, r0, c1, c0, 0
173
174	mov	pc, lr		/* back to my caller */
175#endif /* !CONFIG_SKIP_LOWLEVEL_INIT || CONFIG_CPU_PXA25X */
176
177#ifndef CONFIG_SPL_BUILD
178/*
179 *************************************************************************
180 *
181 * Interrupt handling
182 *
183 *************************************************************************
184 */
185@
186@ IRQ stack frame.
187@
188#define S_FRAME_SIZE	72
189
190#define S_OLD_R0	68
191#define S_PSR		64
192#define S_PC		60
193#define S_LR		56
194#define S_SP		52
195
196#define S_IP		48
197#define S_FP		44
198#define S_R10		40
199#define S_R9		36
200#define S_R8		32
201#define S_R7		28
202#define S_R6		24
203#define S_R5		20
204#define S_R4		16
205#define S_R3		12
206#define S_R2		8
207#define S_R1		4
208#define S_R0		0
209
210#define MODE_SVC 0x13
211#define I_BIT	 0x80
212
213/*
214 * use bad_save_user_regs for abort/prefetch/undef/swi ...
215 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
216 */
217
218	.macro	bad_save_user_regs
219	sub	sp, sp, #S_FRAME_SIZE		@ carve out a frame on current user stack
220	stmia	sp, {r0 - r12}			@ Save user registers (now in svc mode) r0-r12
221
222	ldr	r2, IRQ_STACK_START_IN		@ set base 2 words into abort stack
223	ldmia	r2, {r2 - r3}			@ get values for "aborted" pc and cpsr (into parm regs)
224	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
225
226	add	r5, sp, #S_SP
227	mov	r1, lr
228	stmia	r5, {r0 - r3}			@ save sp_SVC, lr_SVC, pc, cpsr
229	mov	r0, sp				@ save current stack into r0 (param register)
230	.endm
231
232	.macro	irq_save_user_regs
233	sub	sp, sp, #S_FRAME_SIZE
234	stmia	sp, {r0 - r12}			@ Calling r0-r12
235	add	r8, sp, #S_PC			@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
236	stmdb	r8, {sp, lr}^			@ Calling SP, LR
237	str	lr, [r8, #0]			@ Save calling PC
238	mrs	r6, spsr
239	str	r6, [r8, #4]			@ Save CPSR
240	str	r0, [r8, #8]			@ Save OLD_R0
241	mov	r0, sp
242	.endm
243
244	.macro	irq_restore_user_regs
245	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
246	mov	r0, r0
247	ldr	lr, [sp, #S_PC]			@ Get PC
248	add	sp, sp, #S_FRAME_SIZE
249	subs	pc, lr, #4			@ return & move spsr_svc into cpsr
250	.endm
251
252	.macro get_bad_stack
253	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack (enter in banked mode)
254
255	str	lr, [r13]			@ save caller lr in position 0 of saved stack
256	mrs	lr, spsr			@ get the spsr
257	str	lr, [r13, #4]			@ save spsr in position 1 of saved stack
258
259	mov	r13, #MODE_SVC			@ prepare SVC-Mode
260	@ msr	spsr_c, r13
261	msr	spsr, r13			@ switch modes, make sure moves will execute
262	mov	lr, pc				@ capture return pc
263	movs	pc, lr				@ jump to next instruction & switch modes.
264	.endm
265
266	.macro get_bad_stack_swi
267	sub	r13, r13, #4			@ space on current stack for scratch reg.
268	str	r0, [r13]			@ save R0's value.
269	ldr	r0, IRQ_STACK_START_IN		@ get data regions start
270	str	lr, [r0]			@ save caller lr in position 0 of saved stack
271	mrs	lr, spsr			@ get the spsr
272	str	lr, [r0, #4]			@ save spsr in position 1 of saved stack
273	ldr	lr, [r0]			@ restore lr
274	ldr	r0, [r13]			@ restore r0
275	add	r13, r13, #4			@ pop stack entry
276	.endm
277
278	.macro get_irq_stack			@ setup IRQ stack
279	ldr	sp, IRQ_STACK_START
280	.endm
281
282	.macro get_fiq_stack			@ setup FIQ stack
283	ldr	sp, FIQ_STACK_START
284	.endm
285#endif	/* CONFIG_SPL_BUILD */
286
287/*
288 * exception handlers
289 */
290#ifdef CONFIG_SPL_BUILD
291	.align	5
292do_hang:
293	bl	hang				/* hang and never return */
294#else	/* !CONFIG_SPL_BUILD */
295	.align	5
296undefined_instruction:
297	get_bad_stack
298	bad_save_user_regs
299	bl	do_undefined_instruction
300
301	.align	5
302software_interrupt:
303	get_bad_stack_swi
304	bad_save_user_regs
305	bl	do_software_interrupt
306
307	.align	5
308prefetch_abort:
309	get_bad_stack
310	bad_save_user_regs
311	bl	do_prefetch_abort
312
313	.align	5
314data_abort:
315	get_bad_stack
316	bad_save_user_regs
317	bl	do_data_abort
318
319	.align	5
320not_used:
321	get_bad_stack
322	bad_save_user_regs
323	bl	do_not_used
324
325#ifdef CONFIG_USE_IRQ
326
327	.align	5
328irq:
329	get_irq_stack
330	irq_save_user_regs
331	bl	do_irq
332	irq_restore_user_regs
333
334	.align	5
335fiq:
336	get_fiq_stack
337	/* someone ought to write a more effiction fiq_save_user_regs */
338	irq_save_user_regs
339	bl	do_fiq
340	irq_restore_user_regs
341
342#else
343
344	.align	5
345irq:
346	get_bad_stack
347	bad_save_user_regs
348	bl	do_irq
349
350	.align	5
351fiq:
352	get_bad_stack
353	bad_save_user_regs
354	bl	do_fiq
355
356#endif
357	.align 5
358#endif	/* CONFIG_SPL_BUILD */
359
360
361/*
362 * Enable MMU to use DCache as DRAM.
363 *
364 * This is useful on PXA25x and PXA26x in early bootstages, where there is no
365 * other possible memory available to hold stack.
366 */
367#ifdef CONFIG_CPU_PXA25X
368.macro CPWAIT reg
369	mrc	p15, 0, \reg, c2, c0, 0
370	mov	\reg, \reg
371	sub	pc, pc, #4
372.endm
373lock_cache_for_stack:
374	/* Domain access -- enable for all CPs */
375	ldr	r0, =0x0000ffff
376	mcr	p15, 0, r0, c3, c0, 0
377
378	/* Point TTBR to MMU table */
379	ldr	r0, =mmutable
380	mcr	p15, 0, r0, c2, c0, 0
381
382	/* Kick in MMU, ICache, DCache, BTB */
383	mrc	p15, 0, r0, c1, c0, 0
384	bic	r0, #0x1b00
385	bic	r0, #0x0087
386	orr	r0, #0x1800
387	orr	r0, #0x0005
388	mcr	p15, 0, r0, c1, c0, 0
389	CPWAIT	r0
390
391	/* Unlock Icache, Dcache */
392	mcr	p15, 0, r0, c9, c1, 1
393	mcr	p15, 0, r0, c9, c2, 1
394
395	/* Flush Icache, Dcache, BTB */
396	mcr	p15, 0, r0, c7, c7, 0
397
398	/* Unlock I-TLB, D-TLB */
399	mcr	p15, 0, r0, c10, c4, 1
400	mcr	p15, 0, r0, c10, c8, 1
401
402	/* Flush TLB */
403	mcr	p15, 0, r0, c8, c7, 0
404
405	/* Allocate 4096 bytes of Dcache as RAM */
406
407	/* Drain pending loads and stores */
408	mcr	p15, 0, r0, c7, c10, 4
409
410	mov	r4, #0x00
411	mov	r5, #0x00
412	mov	r2, #0x01
413	mcr	p15, 0, r0, c9, c2, 0
414	CPWAIT	r0
415
416	/* 128 lines reserved (128 x 32bytes = 4096 bytes total) */
417	mov	r0, #128
418	ldr	r1, =0xfffff000
419
420alloc:
421	mcr	p15, 0, r1, c7, c2, 5
422	/* Drain pending loads and stores */
423	mcr	p15, 0, r0, c7, c10, 4
424	strd	r4, [r1], #8
425	strd	r4, [r1], #8
426	strd	r4, [r1], #8
427	strd	r4, [r1], #8
428	subs	r0, #0x01
429	bne	alloc
430	/* Drain pending loads and stores */
431	mcr	p15, 0, r0, c7, c10, 4
432	mov	r2, #0x00
433	mcr	p15, 0, r2, c9, c2, 0
434	CPWAIT	r0
435
436	mov	pc, lr
437
438.section .mmutable, "a"
439mmutable:
440	.align	14
441	/* 0x00000000 - 0xffe00000 : 1:1, uncached mapping */
442	.set	__base, 0
443	.rept	0xfff
444	.word	(__base << 20) | 0xc12
445	.set	__base, __base + 1
446	.endr
447
448	/* 0xfff00000 : 1:1, cached mapping */
449	.word	(0xfff << 20) | 0x1c1e
450#endif	/* CONFIG_CPU_PXA25X */
451