1/*
2 * Copyright (C) 2005-2008 Atmel Corporation
3 *
4 * See file CREDITS for list of people who contributed to this
5 * project.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22#include <config.h>
23#include <asm/ptrace.h>
24#include <asm/sysreg.h>
25
26#define SYSREG_MMUCR_I_OFFSET	2
27#define SYSREG_MMUCR_S_OFFSET	4
28
29#define SR_INIT (SYSREG_BIT(GM) | SYSREG_BIT(EM) | SYSREG_BIT(M0))
30#define CPUCR_INIT (SYSREG_BIT(BI) | SYSREG_BIT(BE)		\
31		    | SYSREG_BIT(FE) | SYSREG_BIT(RE)		\
32		    | SYSREG_BIT(IBE) | SYSREG_BIT(IEE))
33
34	/*
35	 * To save some space, we use the same entry point for
36	 * exceptions and reset. This avoids lots of alignment padding
37	 * since the reset vector is always suitably aligned.
38	 */
39	.section .exception.text, "ax", @progbits
40	.global	_start
41	.global	_evba
42	.type	_start, @function
43	.type	_evba, @function
44_start:
45	.size	_start, 0
46_evba:
47	.org	0x00
48	rjmp	unknown_exception	/* Unrecoverable exception */
49	.org	0x04
50	rjmp	unknown_exception	/* TLB multiple hit */
51	.org	0x08
52	rjmp	unknown_exception	/* Bus error data fetch */
53	.org	0x0c
54	rjmp	unknown_exception	/* Bus error instruction fetch */
55	.org	0x10
56	rjmp	unknown_exception	/* NMI */
57	.org	0x14
58	rjmp	unknown_exception	/* Instruction address */
59	.org	0x18
60	rjmp	unknown_exception	/* ITLB protection */
61	.org	0x1c
62	rjmp	unknown_exception	/* Breakpoint */
63	.org	0x20
64	rjmp	unknown_exception	/* Illegal opcode */
65	.org	0x24
66	rjmp	unknown_exception	/* Unimplemented instruction */
67	.org	0x28
68	rjmp	unknown_exception	/* Privilege violation */
69	.org	0x2c
70	rjmp	unknown_exception	/* Floating-point */
71	.org	0x30
72	rjmp	unknown_exception	/* Coprocessor absent */
73	.org	0x34
74	rjmp	unknown_exception	/* Data Address (read) */
75	.org	0x38
76	rjmp	unknown_exception	/* Data Address (write) */
77	.org	0x3c
78	rjmp	unknown_exception	/* DTLB Protection (read) */
79	.org	0x40
80	rjmp	unknown_exception	/* DTLB Protection (write) */
81	.org	0x44
82	rjmp	unknown_exception	/* DTLB Modified */
83
84	.org	0x50
85	rjmp	unknown_exception	/* ITLB Miss */
86	.org	0x60
87	rjmp	unknown_exception	/* DTLB Miss (read) */
88	.org	0x70
89	rjmp	unknown_exception	/* DTLB Miss (write) */
90
91	.size	_evba, . - _evba
92
93	.align	2
94	.type	unknown_exception, @function
95unknown_exception:
96	/* Figure out whether we're handling an exception (Exception
97	 * mode) or just booting (Supervisor mode). */
98	csrfcz	SYSREG_M1_OFFSET
99	brcc	at32ap_cpu_bootstrap
100
101	/* This is an exception. Complain. */
102	pushm	r0-r12
103	sub	r8, sp, REG_R12 - REG_R0 - 4
104	mov	r9, lr
105	mfsr	r10, SYSREG_RAR_EX
106	mfsr	r11, SYSREG_RSR_EX
107	pushm	r8-r11
108	mfsr	r12, SYSREG_ECR
109	mov	r11, sp
110	rcall	do_unknown_exception
1111:	rjmp	1b
112
113	/* The COUNT/COMPARE timer interrupt handler */
114	.global	timer_interrupt_handler
115	.type	timer_interrupt_handler,@function
116	.align	2
117timer_interrupt_handler:
118	/*
119	 * Increment timer_overflow and re-write COMPARE with 0xffffffff.
120	 *
121	 * We're running at interrupt level 3, so we don't need to save
122	 * r8-r12 or lr to the stack.
123	 */
124	lda.w	r8, timer_overflow
125	ld.w	r9, r8[0]
126	mov	r10, -1
127	mtsr	SYSREG_COMPARE, r10
128	sub	r9, -1
129	st.w	r8[0], r9
130	rete
131
132	/*
133	 * CPU bootstrap after reset is handled here. SoC code may
134	 * override this in case they need to initialize oscillators,
135	 * etc.
136	 */
137	.section .text.at32ap_cpu_bootstrap, "ax", @progbits
138	.global	at32ap_cpu_bootstrap
139	.weak	at32ap_cpu_bootstrap
140	.type	at32ap_cpu_bootstrap, @function
141	.align	2
142at32ap_cpu_bootstrap:
143	/* Reset the Status Register */
144	mov	r0, lo(SR_INIT)
145	orh	r0, hi(SR_INIT)
146	mtsr	SYSREG_SR, r0
147
148	/* Reset CPUCR and invalidate the BTB */
149	mov	r2, CPUCR_INIT
150	mtsr	SYSREG_CPUCR, r2
151
152	/* Flush the caches */
153	mov	r1, 0
154	cache	r1[4], 8
155	cache	r1[0], 0
156	sync	0
157
158	/* Reset the MMU to default settings */
159	mov	r0, SYSREG_BIT(MMUCR_S) | SYSREG_BIT(MMUCR_I)
160	mtsr	SYSREG_MMUCR, r0
161
162	/* Internal RAM should not need any initialization.  We might
163	   have to initialize external RAM here if the part doesn't
164	   have internal RAM (or we may use the data cache) */
165
166	/* Jump to cacheable segment */
167	lddpc	pc, 1f
168
169	.align	2
1701:	.long	at32ap_low_level_init
171	.size	_start, . - _start
172
173	/* Common CPU bootstrap code after oscillator/cache/etc. init */
174	.section .text.avr32ap_low_level_init, "ax", @progbits
175	.global	at32ap_low_level_init
176	.type	at32ap_low_level_init, @function
177	.align	2
178at32ap_low_level_init:
179	lddpc	sp, sp_init
180
181	/* Initialize the GOT pointer */
182	lddpc	r6, got_init
1833:	rsub	r6, pc
184
185	/* Let's go */
186	rjmp	board_init_f
187
188	.align	2
189	.type	sp_init,@object
190sp_init:
191	.long	CONFIG_SYS_INIT_SP_ADDR
192got_init:
193	.long	3b - _GLOBAL_OFFSET_TABLE_
194
195	/*
196	 * void	relocate_code(new_sp, new_gd, monitor_addr)
197	 *
198	 * Relocate the u-boot image into RAM and continue from there.
199	 * Does not return.
200	 */
201	.section .text.relocate_code,"ax",@progbits
202	.global	relocate_code
203	.type	relocate_code,@function
204relocate_code:
205	mov	sp, r12		/* use new stack */
206	mov	r12, r11	/* save new_gd */
207	mov	r11, r10	/* save destination address */
208
209	/* copy .text section and flush the cache along the way */
210	lda.w	r8, _text
211	lda.w	r9, _etext
212	sub	lr, r10, r8	/* relocation offset */
213
2141:	ldm	r8++, r0-r3
215	stm	r10, r0-r3
216	sub	r10, -16
217	ldm	r8++, r0-r3
218	stm	r10, r0-r3
219	sub	r10, -16
220	cp.w	r8, r9
221	cache	r10[-4], 0x0d	/* dcache clean/invalidate */
222	cache	r10[-4], 0x01	/* icache invalidate */
223	brlt	1b
224
225	/* flush write buffer */
226	sync	0
227
228	/* copy data sections */
229	lda.w	r9, _edata
2301:	ld.d	r0, r8++
231	st.d	r10++, r0
232	cp.w	r8, r9
233	brlt	1b
234
235	/* zero out .bss */
236	mov	r0, 0
237	mov	r1, 0
238	lda.w	r9, _end
239	sub	r9, r8
2401:	st.d	r10++, r0
241	sub	r9, 8
242	brgt	1b
243
244	/* jump to RAM */
245	sub	r0, pc, . - in_ram
246	add	pc, r0, lr
247
248	.align	2
249in_ram:
250	/* find the new GOT and relocate it */
251	lddpc	r6, got_init_reloc
2523:	rsub	r6, pc
253	mov	r8, r6
254	lda.w	r9, _egot
255	lda.w	r10, _got
256	sub	r9, r10
2571:	ld.w	r0, r8[0]
258	add	r0, lr
259	st.w	r8++, r0
260	sub	r9, 4
261	brgt	1b
262
263	/* Move the exception handlers */
264	mfsr	r2, SYSREG_EVBA
265	add	r2, lr
266	mtsr	SYSREG_EVBA, r2
267
268	/* Do the rest of the initialization sequence */
269	call	board_init_r
270
271	.align	2
272got_init_reloc:
273	.long	3b - _GLOBAL_OFFSET_TABLE_
274
275	.size	relocate_code, . - relocate_code
276