Blackfin arch: rewrite our reboot code in C
[linux-2.6.git] / arch / blackfin / mach-bf533 / head.S
1 /*
2  * File:         arch/blackfin/mach-bf533/head.S
3  * Based on:
4  * Author:       Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
5  *
6  * Created:      1998
7  * Description:  bf533 startup file
8  *
9  * Modified:
10  *               Copyright 2004-2006 Analog Devices Inc.
11  *
12  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, see the file COPYING, or write
26  * to the Free Software Foundation, Inc.,
27  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
28  */
29
30 #include <linux/linkage.h>
31 #include <linux/init.h>
32 #include <asm/blackfin.h>
33 #include <asm/trace.h>
34 #if CONFIG_BFIN_KERNEL_CLOCK
35 #include <asm/mach-common/clocks.h>
36 #include <asm/mach/mem_init.h>
37 #endif
38 #if CONFIG_DEBUG_KERNEL_START
39 #include <asm/mach-common/def_LPBlackfin.h>
40 #endif
41
42 .global __rambase
43 .global __ramstart
44 .global __ramend
45 .extern ___bss_stop
46 .extern ___bss_start
47 .extern _bf53x_relocate_l1_mem
48
49 #define INITIAL_STACK   0xFFB01000
50
51 __INIT
52
53 ENTRY(__start)
54         /* R0: argument of command line string, passed from uboot, save it */
55         R7 = R0;
56         /* Enable Cycle Counter and Nesting Of Interrupts */
57 #ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES
58         R0 = SYSCFG_SNEN;
59 #else
60         R0 = SYSCFG_SNEN | SYSCFG_CCEN;
61 #endif
62         SYSCFG = R0;
63         R0 = 0;
64
65         /* Clear Out All the data and pointer Registers */
66         R1 = R0;
67         R2 = R0;
68         R3 = R0;
69         R4 = R0;
70         R5 = R0;
71         R6 = R0;
72
73         P0 = R0;
74         P1 = R0;
75         P2 = R0;
76         P3 = R0;
77         P4 = R0;
78         P5 = R0;
79
80         LC0 = r0;
81         LC1 = r0;
82         L0 = r0;
83         L1 = r0;
84         L2 = r0;
85         L3 = r0;
86
87         /* Clear Out All the DAG Registers */
88         B0 = r0;
89         B1 = r0;
90         B2 = r0;
91         B3 = r0;
92
93         I0 = r0;
94         I1 = r0;
95         I2 = r0;
96         I3 = r0;
97
98         M0 = r0;
99         M1 = r0;
100         M2 = r0;
101         M3 = r0;
102
103         trace_buffer_init(p0,r0);
104         P0 = R1;
105         R0 = R1;
106
107 #if CONFIG_DEBUG_KERNEL_START
108
109 /*
110  * Set up a temporary Event Vector Table, so if something bad happens before
111  * the kernel is fully started, it doesn't vector off into the bootloaders
112  * table
113  */
114         P0.l = lo(EVT2);
115         P0.h = hi(EVT2);
116         P1.l = lo(EVT15);
117         P1.h = hi(EVT15);
118         P2.l = debug_kernel_start_trap;
119         P2.h = debug_kernel_start_trap;
120
121         RTS = P2;
122         RTI = P2;
123         RTX = P2;
124         RTN = P2;
125         RTE = P2;
126
127 .Lfill_temp_vector_table:
128         [P0++] = P2;    /* Core Event Vector Table */
129         CC = P0 == P1;
130         if !CC JUMP .Lfill_temp_vector_table
131         P0 = r0;
132         P1 = r0;
133         P2 = r0;
134
135 #endif
136
137         p0.h = hi(FIO_MASKA_C);
138         p0.l = lo(FIO_MASKA_C);
139         r0 = 0xFFFF(Z);
140         w[p0] = r0.L;   /* Disable all interrupts */
141         ssync;
142
143         p0.h = hi(FIO_MASKB_C);
144         p0.l = lo(FIO_MASKB_C);
145         r0 = 0xFFFF(Z);
146         w[p0] = r0.L;   /* Disable all interrupts */
147         ssync;
148
149         /* Turn off the icache */
150         p0.l = LO(IMEM_CONTROL);
151         p0.h = HI(IMEM_CONTROL);
152         R1 = [p0];
153         R0 = ~ENICPLB;
154         R0 = R0 & R1;
155
156         /* Anomaly 05000125 */
157 #if ANOMALY_05000125
158         CLI R2;
159         SSYNC;
160 #endif
161         [p0] = R0;
162         SSYNC;
163 #if ANOMALY_05000125
164         STI R2;
165 #endif
166
167         /* Turn off the dcache */
168         p0.l = LO(DMEM_CONTROL);
169         p0.h = HI(DMEM_CONTROL);
170         R1 = [p0];
171         R0 = ~ENDCPLB;
172         R0 = R0 & R1;
173
174         /* Anomaly 05000125 */
175 #if ANOMALY_05000125
176         CLI R2;
177         SSYNC;
178 #endif
179         [p0] = R0;
180         SSYNC;
181 #if ANOMALY_05000125
182         STI R2;
183 #endif
184
185         /* Initialise UART - when booting from u-boot, the UART is not disabled
186          * so if we dont initalize here, our serial console gets hosed */
187         p0.h = hi(UART_LCR);
188         p0.l = lo(UART_LCR);
189         r0 = 0x0(Z);
190         w[p0] = r0.L;   /* To enable DLL writes */
191         ssync;
192
193         p0.h = hi(UART_DLL);
194         p0.l = lo(UART_DLL);
195         r0 = 0x0(Z);
196         w[p0] = r0.L;
197         ssync;
198
199         p0.h = hi(UART_DLH);
200         p0.l = lo(UART_DLH);
201         r0 = 0x00(Z);
202         w[p0] = r0.L;
203         ssync;
204
205         p0.h = hi(UART_GCTL);
206         p0.l = lo(UART_GCTL);
207         r0 = 0x0(Z);
208         w[p0] = r0.L;   /* To enable UART clock */
209         ssync;
210
211         /* Initialize stack pointer */
212         sp.l = lo(INITIAL_STACK);
213         sp.h = hi(INITIAL_STACK);
214         fp = sp;
215         usp = sp;
216
217         /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
218         call _bf53x_relocate_l1_mem;
219 #if CONFIG_BFIN_KERNEL_CLOCK
220         call _start_dma_code;
221 #endif
222
223         /* Code for initializing Async memory banks */
224
225         p2.h = hi(EBIU_AMBCTL1);
226         p2.l = lo(EBIU_AMBCTL1);
227         r0.h = hi(AMBCTL1VAL);
228         r0.l = lo(AMBCTL1VAL);
229         [p2] = r0;
230         ssync;
231
232         p2.h = hi(EBIU_AMBCTL0);
233         p2.l = lo(EBIU_AMBCTL0);
234         r0.h = hi(AMBCTL0VAL);
235         r0.l = lo(AMBCTL0VAL);
236         [p2] = r0;
237         ssync;
238
239         p2.h = hi(EBIU_AMGCTL);
240         p2.l = lo(EBIU_AMGCTL);
241         r0 = AMGCTLVAL;
242         w[p2] = r0;
243         ssync;
244
245         /* This section keeps the processor in supervisor mode
246          * during kernel boot.  Switches to user mode at end of boot.
247          * See page 3-9 of Hardware Reference manual for documentation.
248          */
249
250         /* EVT15 = _real_start */
251
252         p0.l = lo(EVT15);
253         p0.h = hi(EVT15);
254         p1.l = _real_start;
255         p1.h = _real_start;
256         [p0] = p1;
257         csync;
258
259         p0.l = lo(IMASK);
260         p0.h = hi(IMASK);
261         p1.l = IMASK_IVG15;
262         p1.h = 0x0;
263         [p0] = p1;
264         csync;
265
266         raise 15;
267         p0.l = .LWAIT_HERE;
268         p0.h = .LWAIT_HERE;
269         reti = p0;
270 #if ANOMALY_05000281
271         nop; nop; nop;
272 #endif
273         rti;
274
275 .LWAIT_HERE:
276         jump .LWAIT_HERE;
277 ENDPROC(__start)
278
279 ENTRY(_real_start)
280         [ -- sp ] = reti;
281         p0.l = lo(WDOG_CTL);
282         p0.h = hi(WDOG_CTL);
283         r0 = 0xAD6(z);
284         w[p0] = r0;     /* watchdog off for now */
285         ssync;
286
287         /* Code update for BSS size == 0
288          * Zero out the bss region.
289          */
290
291         p1.l = ___bss_start;
292         p1.h = ___bss_start;
293         p2.l = ___bss_stop;
294         p2.h = ___bss_stop;
295         r0 = 0;
296         p2 -= p1;
297         lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2;
298 .L_clear_bss:
299         B[p1++] = r0;
300
301         /* In case there is a NULL pointer reference
302          * Zero out region before stext
303          */
304
305         p1.l = 0x0;
306         p1.h = 0x0;
307         r0.l = __stext;
308         r0.h = __stext;
309         r0 = r0 >> 1;
310         p2 = r0;
311         r0 = 0;
312         lsetup (.L_clear_zero, .L_clear_zero) lc0 = p2;
313 .L_clear_zero:
314         W[p1++] = r0;
315
316         /* pass the uboot arguments to the global value command line */
317         R0 = R7;
318         call _cmdline_init;
319
320         p1.l = __rambase;
321         p1.h = __rambase;
322         r0.l = __sdata;
323         r0.h = __sdata;
324         [p1] = r0;
325
326         p1.l = __ramstart;
327         p1.h = __ramstart;
328         p3.l = ___bss_stop;
329         p3.h = ___bss_stop;
330
331         r1 = p3;
332         [p1] = r1;
333
334         /*
335          * load the current thread pointer and stack
336          */
337         r1.l = _init_thread_union;
338         r1.h = _init_thread_union;
339
340         r2.l = 0x2000;
341         r2.h = 0x0000;
342         r1 = r1 + r2;
343         sp = r1;
344         usp = sp;
345         fp = sp;
346         jump.l _start_kernel;
347 ENDPROC(_real_start)
348
349 __FINIT
350
351 .section .l1.text
352 #if CONFIG_BFIN_KERNEL_CLOCK
353 ENTRY(_start_dma_code)
354         p0.h = hi(SIC_IWR);
355         p0.l = lo(SIC_IWR);
356         r0.l = 0x1;
357         r0.h = 0x0;
358         [p0] = r0;
359         SSYNC;
360
361         /*
362          *  Set PLL_CTL
363          *   - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
364          *   - [8]     = BYPASS    : BYPASS the PLL, run CLKIN into CCLK/SCLK
365          *   - [7]     = output delay (add 200ps of delay to mem signals)
366          *   - [6]     = input delay (add 200ps of input delay to mem signals)
367          *   - [5]     = PDWN      : 1=All Clocks off
368          *   - [3]     = STOPCK    : 1=Core Clock off
369          *   - [1]     = PLL_OFF   : 1=Disable Power to PLL
370          *   - [0]     = DF        : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
371          *   all other bits set to zero
372          */
373
374         p0.h = hi(PLL_LOCKCNT);
375         p0.l = lo(PLL_LOCKCNT);
376         r0 = 0x300(Z);
377         w[p0] = r0.l;
378         ssync;
379
380         P2.H = hi(EBIU_SDGCTL);
381         P2.L = lo(EBIU_SDGCTL);
382         R0 = [P2];
383         BITSET (R0, 24);
384         [P2] = R0;
385         SSYNC;
386
387         r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
388         r0 = r0 << 9;                    /* Shift it over,                  */
389         r1 = CLKIN_HALF;                 /* Do we need to divide CLKIN by 2?*/
390         r0 = r1 | r0;
391         r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
392         r1 = r1 << 8;                    /* Shift it over                   */
393         r0 = r1 | r0;                    /* add them all together           */
394
395         p0.h = hi(PLL_CTL);
396         p0.l = lo(PLL_CTL);              /* Load the address                */
397         cli r2;                          /* Disable interrupts              */
398         ssync;
399         w[p0] = r0.l;                    /* Set the value                   */
400         idle;                            /* Wait for the PLL to stablize    */
401         sti r2;                          /* Enable interrupts               */
402
403 .Lcheck_again:
404         p0.h = hi(PLL_STAT);
405         p0.l = lo(PLL_STAT);
406         R0 = W[P0](Z);
407         CC = BITTST(R0,5);
408         if ! CC jump .Lcheck_again;
409
410         /* Configure SCLK & CCLK Dividers */
411         r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
412         p0.h = hi(PLL_DIV);
413         p0.l = lo(PLL_DIV);
414         w[p0] = r0.l;
415         ssync;
416
417         p0.l = lo(EBIU_SDRRC);
418         p0.h = hi(EBIU_SDRRC);
419         r0 = mem_SDRRC;
420         w[p0] = r0.l;
421         ssync;
422
423         p0.l = LO(EBIU_SDBCTL);
424         p0.h = HI(EBIU_SDBCTL);     /* SDRAM Memory Bank Control Register */
425         r0 = mem_SDBCTL;
426         w[p0] = r0.l;
427         ssync;
428
429         P2.H = hi(EBIU_SDGCTL);
430         P2.L = lo(EBIU_SDGCTL);
431         R0 = [P2];
432         BITCLR (R0, 24);
433         p0.h = hi(EBIU_SDSTAT);
434         p0.l = lo(EBIU_SDSTAT);
435         r2.l = w[p0];
436         cc = bittst(r2,3);
437         if !cc jump .Lskip;
438         NOP;
439         BITSET (R0, 23);
440 .Lskip:
441         [P2] = R0;
442         SSYNC;
443
444         R0.L = lo(mem_SDGCTL);
445         R0.H = hi(mem_SDGCTL);
446         R1 = [p2];
447         R1 = R1 | R0;
448         [P2] = R1;
449         SSYNC;
450
451         p0.h = hi(SIC_IWR);
452         p0.l = lo(SIC_IWR);
453         r0.l = lo(IWR_ENABLE_ALL);
454         r0.h = hi(IWR_ENABLE_ALL);
455         [p0] = r0;
456         SSYNC;
457
458         RTS;
459 ENDPROC(_start_dma_code)
460 #endif /* CONFIG_BFIN_KERNEL_CLOCK */
461
462 #if CONFIG_DEBUG_KERNEL_START
463 debug_kernel_start_trap:
464         /* Set up a temp stack in L1 - SDRAM might not be working  */
465         P0.L = lo(L1_DATA_A_START + 0x100);
466         P0.H = hi(L1_DATA_A_START + 0x100);
467         SP = P0;
468
469         /* Make sure the Clocks are the way I think they should be */
470         r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
471         r0 = r0 << 9;                    /* Shift it over,                  */
472         r1 = CLKIN_HALF;                 /* Do we need to divide CLKIN by 2?*/
473         r0 = r1 | r0;
474         r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
475         r1 = r1 << 8;                    /* Shift it over                   */
476         r0 = r1 | r0;                    /* add them all together           */
477
478         p0.h = hi(PLL_CTL);
479         p0.l = lo(PLL_CTL);              /* Load the address                */
480         cli r2;                          /* Disable interrupts              */
481         ssync;
482         w[p0] = r0.l;                    /* Set the value                   */
483         idle;                            /* Wait for the PLL to stablize    */
484         sti r2;                          /* Enable interrupts               */
485
486 .Lcheck_again1:
487         p0.h = hi(PLL_STAT);
488         p0.l = lo(PLL_STAT);
489         R0 = W[P0](Z);
490         CC = BITTST(R0,5);
491         if ! CC jump .Lcheck_again1;
492
493         /* Configure SCLK & CCLK Dividers */
494         r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
495         p0.h = hi(PLL_DIV);
496         p0.l = lo(PLL_DIV);
497         w[p0] = r0.l;
498         ssync;
499
500         /* Make sure UART is enabled - you can never be sure */
501
502 /*
503  * Setup for console. Argument comes from the menuconfig
504  */
505
506 #ifdef CONFIG_BAUD_9600
507 #define CONSOLE_BAUD_RATE       9600
508 #elif CONFIG_BAUD_19200
509 #define CONSOLE_BAUD_RATE       19200
510 #elif CONFIG_BAUD_38400
511 #define CONSOLE_BAUD_RATE       38400
512 #elif CONFIG_BAUD_57600
513 #define CONSOLE_BAUD_RATE       57600
514 #elif CONFIG_BAUD_115200
515 #define CONSOLE_BAUD_RATE       115200
516 #endif
517
518         p0.h = hi(UART_GCTL);
519         p0.l = lo(UART_GCTL);
520         r0 = 0x00(Z);
521         w[p0] = r0.L;   /* To Turn off UART clocks */
522         ssync;
523
524         p0.h = hi(UART_LCR);
525         p0.l = lo(UART_LCR);
526         r0 = 0x83(Z);
527         w[p0] = r0.L;   /* To enable DLL writes */
528         ssync;
529
530         R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) / (CONSOLE_BAUD_RATE * 16));
531
532         p0.h = hi(UART_DLL);
533         p0.l = lo(UART_DLL);
534         r0 = 0xFF(Z);
535         r0 = R1 & R0;
536         w[p0] = r0.L;
537         ssync;
538
539         p0.h = hi(UART_DLH);
540         p0.l = lo(UART_DLH);
541         r1 >>= 8 ;
542         w[p0] = r1.L;
543         ssync;
544
545         p0.h = hi(UART_GCTL);
546         p0.l = lo(UART_GCTL);
547         r0 = 0x0(Z);
548         w[p0] = r0.L;   /* To enable UART clock */
549         ssync;
550
551         p0.h = hi(UART_LCR);
552         p0.l = lo(UART_LCR);
553         r0 = 0x03(Z);
554         w[p0] = r0.L;   /* To Turn on UART */
555         ssync;
556
557         p0.h = hi(UART_GCTL);
558         p0.l = lo(UART_GCTL);
559         r0 = 0x01(Z);
560         w[p0] = r0.L;   /* To Turn on UART Clocks */
561         ssync;
562
563         P0.h = hi(UART_THR);
564         P0.l = lo(UART_THR);
565         P1.h = hi(UART_LSR);
566         P1.l = lo(UART_LSR);
567
568         R0.L = 'K';
569         call .Lwait_char;
570         R0.L='e';
571         call .Lwait_char;
572         R0.L='r';
573         call .Lwait_char;
574         R0.L='n'
575         call .Lwait_char;
576         R0.L='e'
577         call .Lwait_char;
578         R0.L='l';
579         call .Lwait_char;
580         R0.L=' ';
581         call .Lwait_char;
582         R0.L='c';
583         call .Lwait_char;
584         R0.L='r';
585         call .Lwait_char;
586         R0.L='a';
587         call .Lwait_char;
588         R0.L='s';
589         call .Lwait_char;
590         R0.L='h';
591         call .Lwait_char;
592         R0.L='\r';
593         call .Lwait_char;
594         R0.L='\n';
595         call .Lwait_char;
596
597         R0.L='S';
598         call .Lwait_char;
599         R0.L='E';
600         call .Lwait_char;
601         R0.L='Q'
602         call .Lwait_char;
603         R0.L='S'
604         call .Lwait_char;
605         R0.L='T';
606         call .Lwait_char;
607         R0.L='A';
608         call .Lwait_char;
609         R0.L='T';
610         call .Lwait_char;
611         R0.L='=';
612         call .Lwait_char;
613         R2 = SEQSTAT;
614         call .Ldump_reg;
615
616         R0.L=' ';
617         call .Lwait_char;
618         R0.L='R';
619         call .Lwait_char;
620         R0.L='E'
621         call .Lwait_char;
622         R0.L='T'
623         call .Lwait_char;
624         R0.L='X';
625         call .Lwait_char;
626         R0.L='=';
627         call .Lwait_char;
628         R2 = RETX;
629         call .Ldump_reg;
630
631         R0.L='\r';
632         call .Lwait_char;
633         R0.L='\n';
634         call .Lwait_char;
635
636 .Ldebug_kernel_start_trap_done:
637         JUMP    .Ldebug_kernel_start_trap_done;
638 .Ldump_reg:
639         R3 = 32;
640         R4 = 0x0F;
641         R5 = ':';  /* one past 9 */
642
643 .Ldump_reg2:
644         R0 = R2;
645         R3 += -4;
646         R0 >>>= R3;
647         R0 = R0 & R4;
648         R0 += 0x30;
649         CC = R0 <= R5;
650         if CC JUMP .Ldump_reg1;
651         R0 += 7;
652
653 .Ldump_reg1:
654         R1.l = W[P1];
655         CC = BITTST(R1, 5);
656         if !CC JUMP .Ldump_reg1;
657         W[P0] = r0;
658
659         CC = R3 == 0;
660         if !CC JUMP .Ldump_reg2
661         RTS;
662
663 .Lwait_char:
664         R1.l = W[P1];
665         CC = BITTST(R1, 5);
666         if !CC JUMP .Lwait_char;
667         W[P0] = r0;
668         RTS;
669
670 #endif  /* CONFIG_DEBUG_KERNEL_START  */
671
672 .data
673
674 /*
675  * Set up the usable of RAM stuff. Size of RAM is determined then
676  * an initial stack set up at the end.
677  */
678
679 .align 4
680 __rambase:
681 .long   0
682 __ramstart:
683 .long   0
684 __ramend:
685 .long   0