Merge branch "preempt" in "trunk".
[bertos.git] / bertos / cpu / arm / hw / crtat91sam7_rom.S
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2007 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \version $Id: $
34  *
35  * \author Francesco Sacchi <batt@develer.com>
36  *
37  * \brief AT91SAM7S256 CRT, adapted from NUt/OS, see license below.
38  */
39
40 /*
41  * Copyright (C) 2005-2007 by egnite Software GmbH. All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  *
47  * 1. Redistributions of source code must retain the above copyright
48  *    notice, this list of conditions and the following disclaimer.
49  * 2. Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  * 3. Neither the name of the copyright holders nor the names of
53  *    contributors may be used to endorse or promote products derived
54  *    from this software without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
57  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
58  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
59  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
60  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
61  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
62  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
63  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
64  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
65  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
66  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  *
69  * For additional information see http://www.ethernut.de/
70  *
71  */
72
73 #include <cpu/detect.h>
74 #include "cfg/cfg_arch.h"
75
76
77 #if CPU_FREQ != 48023000L
78         /* Avoid errors on nightly test */
79         #if !defined(ARCH_NIGHTTEST) || !(ARCH & ARCH_NIGHTTEST)
80                 #warning Clock registers set for 48.023MHz operation, revise following code if you want a different clock.
81         #endif
82 #endif
83
84
85 #if CPU_ARM_SAM7S_LARGE || CPU_ARM_SAM7X
86         /*
87          * With a 18.420MHz cristal, master clock is:
88          * (((18.420 * PLL_MUL_VAL + 1) / PLL_DIV_VAL) / AT91MCK_PRES) = 48.023MHz
89          */
90         #define PLL_MUL_VAL  72  /**< Real multiplier value is PLL_MUL_VAL + 1! */
91         #define PLL_DIV_VAL  14
92         #define AT91MCK_PRES PMC_PRES_CLK_2
93
94         /*
95          * Register I/O adresses.
96          */
97         #define MC_BASE             0xFFFFFF00
98         #define MC_FMR_OFF          0x00000060
99         #define MC_FWS_2R3W         0x00000100
100
101         #define AIC_BASE            0xFFFFF000
102         #define AIC_EOICR_OFF       0x00000130
103         #define AIC_IDCR_OFF        0x00000124
104
105         #define WDT_BASE            0xFFFFFD40
106         #define WDT_MR_OFF          0x00000004
107         #define WDT_WDDIS            (1 << 15)
108
109         #define PMC_BASE            0xFFFFFC00
110         #define PMC_PCER_OFF        0x00000010
111         #define PMC_SR_OFF          0x00000068
112         #define PMC_MCKR_OFF        0x00000030
113         #define PMC_MOSCS             (1 << 0)
114         #define PMC_LOCK              (1 << 2)
115         #define PMC_MCKRDY            (1 << 3)
116         #define PMC_CSS_MASK        0x00000003
117         #define PMC_CSS_PLL_CLK     0x00000003
118         #define PMC_PRES_MASK       0x0000001C
119         #define PMC_PRES_CLK_2      0x00000004
120
121         #if CPU_ARM_SAM7S_LARGE
122                 #define PMC_PIO_CLK_EN (1 << 2)
123         #elif CPU_ARM_SAM7X
124                 #define PMC_PIO_CLK_EN ((1 << 2) | (1 << 3))
125         #else
126                 #error CPU not supported
127         #endif
128
129         #define CKGR_MOR_OFF        0x00000020
130         #define CKGR_PLLR_OFF       0x0000002C
131         #define CKGR_MOSCEN           (1 << 0)
132         #define CKGR_MUL_SHIFT              16
133         #define CKGR_PLLCOUNT_SHIFT          8
134
135         #define RSTC_MR             0xFFFFFD08
136         #define RSTC_KEY            0xA5000000
137         #define RSTC_URSTEN           (1 << 0)
138
139         #define ARM_MODE_USR              0x10
140         #define ARM_MODE_FIQ              0x11
141         #define ARM_MODE_IRQ              0x12
142         #define ARM_MODE_SVC              0x13
143         #define ARM_MODE_ABORT            0x17
144         #define ARM_MODE_UNDEF            0x1B
145         #define ARM_MODE_SYS              0x1F
146
147 #else
148         #error No register I/O definition for selected ARM CPU
149 #endif
150 /*\}*/
151
152 /*
153  * Section 0: Vector table and reset entry.
154  */
155         .section .vectors,"ax",%progbits
156
157         .global __vectors
158 __vectors:
159         ldr     pc, [pc, #24]   /* Reset */
160         ldr     pc, [pc, #24]   /* Undefined instruction */
161         ldr     pc, [pc, #24]   /* Software interrupt */
162         ldr     pc, [pc, #24]   /* Prefetch abort */
163         ldr     pc, [pc, #24]   /* Data abort */
164         ldr     pc, [pc, #24]   /* Reserved */
165
166         /*
167          * On IRQ the PC will be loaded from AIC_IVR, which
168          * provides the address previously set in AIC_SVR.
169          * The interrupt routine will be called in ARM_MODE_IRQ
170          * with IRQ disabled and FIQ unchanged.
171          */
172         ldr     pc, [pc, #-0xF20]   /* Interrupt request, auto vectoring. */
173         ldr     pc, [pc, #-0xF20]   /* Fast interrupt request, auto vectoring. */
174
175         .word   _init
176         .word   __undef
177         .word   __swi
178         .word   __prefetch_abort
179         .word   __data_abort
180
181         .weak   __undef
182         .set    __undef, __xcpt_dummy_undef
183         .weak   __swi
184         .set    __swi, __xcpt_dummy_swi
185         .weak   __prefetch_abort
186         .set    __prefetch_abort, __xcpt_dummy_pref
187         .weak   __data_abort
188         .set    __data_abort, __xcpt_dummy_dab
189
190 /**        .global __xcpt_dummy*/
191 __xcpt_dummy_undef:
192         b       __xcpt_dummy_undef
193
194 __xcpt_dummy_swi:
195         b       __xcpt_dummy_swi
196
197 __xcpt_dummy_pref:
198         b       __xcpt_dummy_pref
199
200 __xcpt_dummy_dab:
201         b       __xcpt_dummy_dab
202
203
204         .ltorg
205 /*
206  * Hardware initialization.
207  */
208         .section .init, "ax", %progbits
209         .globl  _init
210 _init:
211         /*
212          * Use 2 cycles for flash access.
213          */
214         ldr     r1, =MC_BASE
215         mov     r0, #MC_FWS_2R3W
216         str     r0, [r1, #MC_FMR_OFF]
217
218         /*
219          * Disable all interrupts. Useful for debugging w/o target reset.
220          */
221         ldr     r1, =AIC_BASE
222         mvn     r0, #0
223         str     r0, [r1, #AIC_EOICR_OFF]
224         str     r0, [r1, #AIC_IDCR_OFF]
225
226         /*
227          * The watchdog is enabled after processor reset. Disable it.
228          */
229         ldr     r1, =WDT_BASE
230         ldr     r0, =WDT_WDDIS
231         str     r0, [r1, #WDT_MR_OFF]
232
233         /*
234          * Enable the main oscillator. Set startup time of 6 * 8 slow
235          * clock cycles and wait until oscillator is stabilized.
236          */
237         ldr     r1, =PMC_BASE
238         mov     r0, #(6 << 8)
239         orr     r0, r0, #CKGR_MOSCEN
240         str     r0, [r1, #CKGR_MOR_OFF]
241 wait_moscs:
242         ldr     r0, [r1, #PMC_SR_OFF]
243         tst     r0, #PMC_MOSCS
244         beq     wait_moscs
245
246         /*
247          * Switch to Slow oscillator clock.
248          */
249         ldr     r0, [r1, #PMC_MCKR_OFF]
250         and     r0, r0, #~PMC_CSS_MASK
251         str     r0, [r1, #PMC_MCKR_OFF]
252 wait_slowosc:
253         ldr     r0, [r1, #PMC_SR_OFF]
254         tst     r0, #PMC_MCKRDY
255         beq     wait_slowosc
256
257         /*
258          * Switch to prescaler div 1 factor.
259          */
260         ldr     r0, [r1, #PMC_MCKR_OFF]
261         and     r0, r0, #~PMC_PRES_MASK
262         str     r0, [r1, #PMC_MCKR_OFF]
263 wait_presc:
264         ldr     r0, [r1, #PMC_SR_OFF]
265         tst     r0, #PMC_MCKRDY
266         beq     wait_presc
267
268         /*
269          * Set PLL:
270          * PLLfreq = crystal / divider * (multiplier + 1)
271          * Wait 28 clock cycles until PLL is locked.
272          */
273         ldr     r0, =((PLL_MUL_VAL << CKGR_MUL_SHIFT) | (28 << CKGR_PLLCOUNT_SHIFT) | PLL_DIV_VAL)
274
275         str     r0, [r1, #CKGR_PLLR_OFF]
276 wait_lock:
277         ldr     r0, [r1, #PMC_SR_OFF]
278         tst     r0, #PMC_LOCK
279         beq     wait_lock
280
281         /*
282          * Set master clock prescaler.
283          */
284         mov     r0, #AT91MCK_PRES
285         str     r0, [r1, #PMC_MCKR_OFF]
286 wait_presrdy:
287         ldr     r0, [r1, #PMC_SR_OFF]
288         tst     r0, #PMC_MCKRDY
289         beq     wait_presrdy
290
291         /*
292          * Switch to PLL clock. Trying to set this together with the
293          * prescaler fails (see datasheets).
294          */
295         ldr     r0, [r1, #PMC_MCKR_OFF]
296         orr     r0, r0, #PMC_CSS_PLL_CLK
297         str     r0, [r1, #PMC_MCKR_OFF]
298 wait_pllsel:
299         ldr     r0, [r1, #PMC_SR_OFF]
300         tst     r0, #PMC_MCKRDY
301         beq     wait_pllsel
302
303         /*
304          * Enable external reset key.
305          */
306         ldr     r0, =(RSTC_KEY | RSTC_URSTEN)
307         ldr     r1, =RSTC_MR
308         str     r0, [r1, #0]
309
310         /*
311          * Set exception stack pointers
312          */
313         ldr     r0, =__stack_fiq_end
314         msr     CPSR_c, #ARM_MODE_FIQ | 0xC0
315         mov     r13, r0
316         ldr     r0, =__stack_irq_end
317         msr     CPSR_c, #ARM_MODE_IRQ | 0xC0
318         mov     r13, r0
319         ldr     r0, =__stack_abt_end
320         msr     CPSR_c, #ARM_MODE_ABORT | 0xC0
321         mov     r13, r0
322         ldr     r0, =__stack_und_end
323         msr     CPSR_c, #ARM_MODE_UNDEF | 0xC0
324         mov     r13, r0
325         ldr     r0, =__stack_svc_end
326         msr     CPSR_c, #ARM_MODE_SVC | 0xC0
327         mov     r13, r0
328
329         /*
330          * Clear .bss
331          */
332         ldr     r1, =__bss_start
333         ldr     r2, =__bss_end
334         ldr     r3, =0
335
336 _40:
337         cmp     r1, r2
338         strne   r3, [r1], #+4
339         bne     _40
340
341         /*
342          * Relocate .data section (Copy from ROM to RAM).
343          */
344         ldr     r1, =__etext
345         ldr     r2, =__data_start
346         ldr     r3, =__data_end
347
348 _41:
349         cmp     r2, r3
350         ldrlo   r0, [r1], #4
351         strlo   r0, [r2], #4
352         blo     _41
353
354         /*
355          * Initialize user stack pointer.
356          */
357         /* msr     CPSR_c, #ARM_MODE_SYS | 0xC0 */
358         ldr     r13, =__stack_end
359
360
361         /*
362          * Enable clock for PIO(s)
363          */
364         ldr     r1, =PMC_BASE
365         mov     r0, #PMC_PIO_CLK_EN
366         str     r0, [r1, #PMC_PCER_OFF]
367
368
369         /*
370          * Jump to main
371          */
372         ldr     r0, =main
373         bx      r0
374
375 End:
376         b       End
377
378         .ltorg