Blackfin arch: Fix bug - 561 SMP kernel can't boot from jffs2
[linux-2.6] / arch / blackfin / mach-common / head.S
1 /*
2  * Common Blackfin startup code
3  *
4  * Copyright 2004-2008 Analog Devices Inc.
5  *
6  * Enter bugs at http://blackfin.uclinux.org/
7  *
8  * Licensed under the GPL-2 or later.
9  */
10
11 #include <linux/linkage.h>
12 #include <linux/init.h>
13 #include <asm/blackfin.h>
14 #include <asm/thread_info.h>
15 #include <asm/trace.h>
16 #include <asm/asm-offsets.h>
17
18 __INIT
19
20 ENTRY(__init_clear_bss)
21         r2 = r2 - r1;
22         cc = r2 == 0;
23         if cc jump .L_bss_done;
24         r2 >>= 2;
25         p1 = r1;
26         p2 = r2;
27         lsetup (1f, 1f) lc0 = p2;
28 1:      [p1++] = r0;
29 .L_bss_done:
30         rts;
31 ENDPROC(__init_clear_bss)
32
33 #define INITIAL_STACK   (L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
34
35 ENTRY(__start)
36         /* R0: argument of command line string, passed from uboot, save it */
37         R7 = R0;
38         /* Enable Cycle Counter and Nesting Of Interrupts */
39 #ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES
40         R0 = SYSCFG_SNEN;
41 #else
42         R0 = SYSCFG_SNEN | SYSCFG_CCEN;
43 #endif
44         SYSCFG = R0;
45         R0 = 0;
46
47         /* Clear Out All the data and pointer Registers */
48         R1 = R0;
49         R2 = R0;
50         R3 = R0;
51         R4 = R0;
52         R5 = R0;
53         R6 = R0;
54
55         P0 = R0;
56         P1 = R0;
57         P2 = R0;
58         P3 = R0;
59         P4 = R0;
60         P5 = R0;
61
62         LC0 = r0;
63         LC1 = r0;
64         L0 = r0;
65         L1 = r0;
66         L2 = r0;
67         L3 = r0;
68
69         /* Clear Out All the DAG Registers */
70         B0 = r0;
71         B1 = r0;
72         B2 = r0;
73         B3 = r0;
74
75         I0 = r0;
76         I1 = r0;
77         I2 = r0;
78         I3 = r0;
79
80         M0 = r0;
81         M1 = r0;
82         M2 = r0;
83         M3 = r0;
84
85         /*
86          * Clear ITEST_COMMAND and DTEST_COMMAND registers,
87          * Leaving these as non-zero can confuse the emulator
88          */
89         p0.L = LO(DTEST_COMMAND);
90         p0.H = HI(DTEST_COMMAND);
91         [p0] = R0;
92         [p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0;
93         CSYNC;
94
95         trace_buffer_init(p0,r0);
96         P0 = R1;
97         R0 = R1;
98
99         /* Turn off the icache */
100         p0.l = LO(IMEM_CONTROL);
101         p0.h = HI(IMEM_CONTROL);
102         R1 = [p0];
103         R0 = ~ENICPLB;
104         R0 = R0 & R1;
105         [p0] = R0;
106         SSYNC;
107
108         /* Turn off the dcache */
109         p0.l = LO(DMEM_CONTROL);
110         p0.h = HI(DMEM_CONTROL);
111         R1 = [p0];
112         R0 = ~ENDCPLB;
113         R0 = R0 & R1;
114         [p0] = R0;
115         SSYNC;
116
117         /* in case of double faults, save a few things */
118         p0.l = _init_retx;
119         p0.h = _init_retx;
120         R0 = RETX;
121         [P0] = R0;
122
123 #ifdef CONFIG_DEBUG_DOUBLEFAULT
124         /* Only save these if we are storing them,
125          * This happens here, since L1 gets clobbered
126          * below
127          */
128         GET_PDA(p0, r0);
129         r7 = [p0 + PDA_RETX];
130         p1.l = _init_saved_retx;
131         p1.h = _init_saved_retx;
132         [p1] = r7;
133
134         r7 = [p0 + PDA_DCPLB];
135         p1.l = _init_saved_dcplb_fault_addr;
136         p1.h = _init_saved_dcplb_fault_addr;
137         [p1] = r7;
138
139         r7 = [p0 + PDA_ICPLB];
140         p1.l = _init_saved_icplb_fault_addr;
141         p1.h = _init_saved_icplb_fault_addr;
142         [p1] = r7;
143
144         r7 = [p0 + PDA_SEQSTAT];
145         p1.l = _init_saved_seqstat;
146         p1.h = _init_saved_seqstat;
147         [p1] = r7;
148 #endif
149
150         /* Initialize stack pointer */
151         sp.l = lo(INITIAL_STACK);
152         sp.h = hi(INITIAL_STACK);
153         fp = sp;
154         usp = sp;
155
156 #ifdef CONFIG_EARLY_PRINTK
157         call _init_early_exception_vectors;
158 #endif
159
160         r0 = 0 (x);
161         /* Zero out all of the fun bss regions */
162 #if L1_DATA_A_LENGTH > 0
163         r1.l = __sbss_l1;
164         r1.h = __sbss_l1;
165         r2.l = __ebss_l1;
166         r2.h = __ebss_l1;
167         call __init_clear_bss
168 #endif
169 #if L1_DATA_B_LENGTH > 0
170         r1.l = __sbss_b_l1;
171         r1.h = __sbss_b_l1;
172         r2.l = __ebss_b_l1;
173         r2.h = __ebss_b_l1;
174         call __init_clear_bss
175 #endif
176 #if L2_LENGTH > 0
177         r1.l = __sbss_l2;
178         r1.h = __sbss_l2;
179         r2.l = __ebss_l2;
180         r2.h = __ebss_l2;
181         call __init_clear_bss
182 #endif
183         r1.l = ___bss_start;
184         r1.h = ___bss_start;
185         r2.l = ___bss_stop;
186         r2.h = ___bss_stop;
187         call __init_clear_bss
188
189         /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
190         call _bfin_relocate_l1_mem;
191 #ifdef CONFIG_BFIN_KERNEL_CLOCK
192         call _init_clocks;
193 #endif
194
195         /* This section keeps the processor in supervisor mode
196          * during kernel boot.  Switches to user mode at end of boot.
197          * See page 3-9 of Hardware Reference manual for documentation.
198          */
199
200         /* EVT15 = _real_start */
201
202         p0.l = lo(EVT15);
203         p0.h = hi(EVT15);
204         p1.l = _real_start;
205         p1.h = _real_start;
206         [p0] = p1;
207         csync;
208
209         r0 = EVT_IVG15 (z);
210         sti r0;
211
212         raise 15;
213         p0.l = .LWAIT_HERE;
214         p0.h = .LWAIT_HERE;
215         reti = p0;
216 #if ANOMALY_05000281
217         nop; nop; nop;
218 #endif
219         rti;
220
221 .LWAIT_HERE:
222         jump .LWAIT_HERE;
223 ENDPROC(__start)
224
225 /* A little BF561 glue ... */
226 #ifndef WDOG_CTL
227 # define WDOG_CTL WDOGA_CTL
228 #endif
229
230 ENTRY(_real_start)
231         /* Enable nested interrupts */
232         [--sp] = reti;
233
234         /* watchdog off for now */
235         p0.l = lo(WDOG_CTL);
236         p0.h = hi(WDOG_CTL);
237         r0 = 0xAD6(z);
238         w[p0] = r0;
239         ssync;
240
241         /* Pass the u-boot arguments to the global value command line */
242         R0 = R7;
243         call _cmdline_init;
244
245         /* Load the current thread pointer and stack */
246         sp.l = _init_thread_union;
247         sp.h = _init_thread_union;
248         p1 = THREAD_SIZE (z);
249         sp = sp + p1;
250         usp = sp;
251         fp = sp;
252         sp += -12;
253         call _init_pda
254         sp += 12;
255         jump.l _start_kernel;
256 ENDPROC(_real_start)
257
258 __FINIT