* Patch by Fred Klatt, 25 Jun 2004:
[platform/kernel/u-boot.git] / cpu / mpc85xx / start.S
1 /*
2  * Copyright 2004 Freescale Semiconductor.
3  * Copyright (C) 2003  Motorola,Inc.
4  * Xianghua Xiao<X.Xiao@motorola.com>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 /* U-Boot Startup Code for Motorola 85xx PowerPC based Embedded Boards
26  *
27  * The processor starts at 0xfffffffc and the code is first executed in the
28  * last 4K page(0xfffff000-0xffffffff) in flash/rom.
29  *
30  */
31
32 #include <config.h>
33 #include <mpc85xx.h>
34 #include <version.h>
35
36 #define _LINUX_CONFIG_H 1       /* avoid reading Linux autoconf.h file  */
37
38 #include <ppc_asm.tmpl>
39 #include <ppc_defs.h>
40
41 #include <asm/cache.h>
42 #include <asm/mmu.h>
43
44 #ifndef  CONFIG_IDENT_STRING
45 #define  CONFIG_IDENT_STRING ""
46 #endif
47
48 #undef  MSR_KERNEL
49 #define MSR_KERNEL ( MSR_ME  )  /* Machine Check */
50
51 /*
52  * Set up GOT: Global Offset Table
53  *
54  * Use r14 to access the GOT
55  */
56         START_GOT
57         GOT_ENTRY(_GOT2_TABLE_)
58         GOT_ENTRY(_FIXUP_TABLE_)
59
60         GOT_ENTRY(_start)
61         GOT_ENTRY(_start_of_vectors)
62         GOT_ENTRY(_end_of_vectors)
63         GOT_ENTRY(transfer_to_handler)
64
65         GOT_ENTRY(__init_end)
66         GOT_ENTRY(_end)
67         GOT_ENTRY(__bss_start)
68         END_GOT
69
70 /*
71  * e500 Startup -- after reset only the last 4KB of the effective
72  * address space is mapped in the MMU L2 TLB1 Entry0. The .bootpg
73  * section is located at THIS LAST page and basically does three
74  * things: clear some registers, set up exception tables and
75  * add more TLB entries for 'larger spaces'(e.g. the boot rom) to
76  * continue the boot procedure.
77
78  * Once the boot rom is mapped by TLB entries we can proceed
79  * with normal startup.
80  *
81  */
82
83     .section .bootpg,"ax"
84     .globl _start_e500
85
86 _start_e500:
87         mfspr   r0, PVR
88         lis     r1, PVR_85xx_REV1@h
89         ori     r1, r1, PVR_85xx_REV1@l
90         cmpw    r0, r1
91         bne     1f
92
93         /* Semi-bogus errata fixup for Rev 1 */
94         li      r0,0x2000
95         mtspr   977,r0
96
97         /*
98          * Before invalidating MMU L1/L2, read TLB1 Entry 0 and then
99          * write it back immediately to fixup a Rev 1 bug (Errata CPU4)
100          * for this initial TLB1 entry 0, otherwise the TLB1 entry 0
101          * will be invalidated (incorrectly).
102          */
103         lis     r2,0x1000
104         mtspr   MAS0,r2
105         tlbre
106         tlbwe
107         isync
108
109 1:
110         /*
111          * Clear and set up some registers.
112          * Note: Some registers need strict synchronization by
113          * sync/mbar/msync/isync when being "mtspr".
114          * BookE: isync before PID,tlbivax,tlbwe
115          * BookE: isync after MSR,PID; msync_isync after tlbivax & tlbwe
116          * E500:  msync,isync before L1CSR0
117          * E500:  isync after BBEAR,BBTAR,BUCSR,DBCR0,DBCR1,HID0,HID1,
118          *        L1CSR0, L1CSR1, MAS[0,1,2,3,4,6],MMUCSR0, PID[0,1,2],
119          *        SPEFCSR
120          */
121
122         /* invalidate d-cache */
123         mfspr   r0,L1CSR0
124         ori     r0,r0,0x0002
125         msync
126         isync
127         mtspr   L1CSR0,r0
128         isync
129
130         /* disable d-cache */
131         li      r0,0x0
132         mtspr   L1CSR0,r0
133
134         /* invalidate i-cache */
135         mfspr   r0,L1CSR1
136         ori     r0,r0,0x0002
137         mtspr   L1CSR1,r0
138         isync
139
140         /* disable i-cache */
141         li      r0,0x0
142         mtspr   L1CSR1,r0
143         isync
144
145         /* clear registers */
146         li      r0,0
147         mtspr   SRR0,r0
148         mtspr   SRR1,r0
149         mtspr   CSRR0,r0
150         mtspr   CSRR1,r0
151         mtspr   MCSRR0,r0
152         mtspr   MCSRR1,r0
153
154         mtspr   ESR,r0
155         mtspr   MCSR,r0
156         mtspr   DEAR,r0
157
158         mtspr   DBCR0,r0
159         mtspr   DBCR1,r0
160         mtspr   DBCR2,r0
161         mtspr   IAC1,r0
162         mtspr   IAC2,r0
163         mtspr   DAC1,r0
164         mtspr   DAC2,r0
165
166         mfspr   r1,DBSR
167         mtspr   DBSR,r1         /* Clear all valid bits */
168
169         mtspr   PID0,r0
170         mtspr   PID1,r0
171         mtspr   PID2,r0
172         mtspr   TCR,r0
173
174         mtspr   BUCSR,r0        /* disable branch prediction */
175         mtspr   MAS4,r0
176         mtspr   MAS6,r0
177         isync
178
179         /* Setup interrupt vectors */
180         lis     r1,0xfff8
181         mtspr IVPR, r1
182
183         li      r1,0x0100
184         mtspr   IVOR0,r1        /* 0: Critical input */
185         li      r1,0x0200
186         mtspr   IVOR1,r1        /* 1: Machine check */
187         li      r1,0x0300
188         mtspr   IVOR2,r1        /* 2: Data storage */
189         li      r1,0x0400
190         mtspr   IVOR3,r1        /* 3: Instruction storage */
191         li      r1,0x0500
192         mtspr   IVOR4,r1        /* 4: External interrupt */
193         li      r1,0x0600
194         mtspr   IVOR5,r1        /* 5: Alignment */
195         li      r1,0x0700
196         mtspr   IVOR6,r1        /* 6: Program check */
197         li      r1,0x0800
198         mtspr   IVOR7,r1        /* 7: floating point unavailable */
199         li      r1,0x0c00
200         mtspr   IVOR8,r1        /* 8: System call */
201         /* 9: Auxiliary processor unavailable(unsupported) */
202         li      r1,0x1000
203         mtspr   IVOR10,r1       /* 10: Decrementer */
204         li      r1,0x1400
205         mtspr   IVOR13,r1       /* 13: Data TLB error */
206         li      r1,0x1300
207         mtspr   IVOR14,r1       /* 14: Instruction TLB error */
208         li      r1,0x2000
209         mtspr   IVOR15,r1       /* 15: Debug */
210
211         /*
212          * Invalidate MMU L1/L2
213          *
214          * Note: There is a fixup earlier for Errata CPU4 on
215          * Rev 1 parts that must precede this MMU invalidation.
216          */
217         li      r2, 0x001e
218         mtspr   MMUCSR0, r2
219         isync
220
221         /* After reset, CCSRBAR is located at CFG_CCSRBAR_DEFAULT, i.e.
222          * 0xff700000-0xff800000. We need add a TLB1 entry for this 1MB
223          * region before we can access any CCSR registers such as L2
224          * registers, Local Access Registers,etc. We will also re-allocate
225          * CFG_CCSRBAR_DEFAULT to CFG_CCSRBAR immediately after TLB1 setup.
226          *
227          * Please refer to board-specif directory for TLB1 entry configuration.
228          * (e.g. board/<yourboard>/init.S)
229          *
230          */
231         bl      tlb1_entry
232         mr      r5,r0
233         li      r1,0x000f       /* max 16 TLB1 entries */
234         mtctr   r1
235         lwzu    r4,0(r5)        /* how many TLB1 entries we actually use */
236
237 0:      cmpwi   r4,0
238         beq     1f
239         lwzu    r0,4(r5)
240         lwzu    r1,4(r5)
241         lwzu    r2,4(r5)
242         lwzu    r3,4(r5)
243         mtspr   MAS0,r0
244         mtspr   MAS1,r1
245         mtspr   MAS2,r2
246         mtspr   MAS3,r3
247         isync
248         msync
249         tlbwe
250         isync
251         addi    r4,r4,-1
252         bdnz    0b
253
254 1:
255 #if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR)
256         /* Special sequence needed to update CCSRBAR itself */
257         lis     r4, CFG_CCSRBAR_DEFAULT@h
258         ori     r4, r4, CFG_CCSRBAR_DEFAULT@l
259
260         lis     r5, CFG_CCSRBAR@h
261         ori     r5, r5, CFG_CCSRBAR@l
262         srwi    r6,r5,12
263         stw     r6, 0(r4)
264         isync
265
266         lis     r5, 0xffff
267         ori     r5,r5,0xf000
268         lwz     r5, 0(r5)
269         isync
270
271         lis     r3, CFG_CCSRBAR@h
272         lwz     r5, CFG_CCSRBAR@l(r3)
273         isync
274 #endif
275
276         /*  invalidate all TLB0 entries */
277         li      r3,4
278         li      r4,0
279         tlbivax r4,r3
280         /*
281          * To avoid REV1 Errata CPU6 issues, make sure
282          * the instruction following tlbivax is not a store.
283          */
284
285
286         /* set up local access windows, defined at board/<boardname>/init.S */
287         lis     r7,CFG_CCSRBAR@h
288         ori     r7,r7,CFG_CCSRBAR@l
289
290         bl      law_entry
291         mr      r6,r0
292 #if  defined(CONFIG_RAM_AS_FLASH)
293         li      r1,0x0006
294 #else
295         li      r1,0x0007       /*we have 8 LAWs, but reseve one for boot-over-rio-or-pci */
296 #endif
297         mtctr   r1
298         lwzu    r5,0(r6)        /* how many windows we actually use */
299
300 #if defined(CONFIG_RAM_AS_FLASH)
301         li      r2,0x0c48
302         li      r1,0x0c50
303 #else
304         li      r2,0x0c28       /* the first pair is reserved for boot-over-rio-or-pci */
305         li      r1,0x0c30
306 #endif
307
308 0:      cmpwi   r5,0
309         beq     1f
310         lwzu    r4,4(r6)
311         lwzu    r3,4(r6)
312         stwx    r4,r7,r2
313         stwx    r3,r7,r1
314         addi    r5,r5,-1
315         addi    r2,r2,0x0020
316         addi    r1,r1,0x0020
317         bdnz    0b
318
319         /* Jump out the last 4K page and continue to 'normal' start */
320 1:      bl      3f
321         b       _start
322
323 3:      li      r0,0
324         mtspr   SRR1,r0         /* Keep things disabled for now */
325         mflr    r1
326         mtspr   SRR0,r1
327         rfi
328
329 /*
330  * r3 - 1st arg to board_init(): IMMP pointer
331  * r4 - 2nd arg to board_init(): boot flag
332  */
333         .text
334         .long   0x27051956              /* U-BOOT Magic Number                  */
335         .globl  version_string
336 version_string:
337         .ascii U_BOOT_VERSION
338         .ascii " (", __DATE__, " - ", __TIME__, ")"
339         .ascii CONFIG_IDENT_STRING, "\0"
340
341         . = EXC_OFF_SYS_RESET
342         .globl  _start
343 _start:
344         /* Clear and set up some registers. */
345         li      r0,0x0000
346         lis     r1,0xffff
347         mtspr   DEC,r0                  /* prevent dec exceptions */
348         mttbl   r0                      /* prevent fit & wdt exceptions */
349         mttbu   r0
350         mtspr   TSR,r1                  /* clear all timer exception status */
351         mtspr   TCR,r0                  /* disable all */
352         mtspr   ESR,r0                  /* clear exception syndrome register */
353         mtspr   MCSR,r0                 /* machine check syndrome register */
354         mtxer   r0                      /* clear integer exception register */
355         lis     r1,0x0002               /* set CE bit (Critical Exceptions) */
356         ori     r1,r1,0x1200            /* set ME/DE bit */
357         mtmsr   r1                      /* change MSR */
358         isync
359
360         /* Enable Time Base and Select Time Base Clock */
361         lis     r0,HID0_EMCP@h          /* Enable machine check */
362         ori     r0,r0,0x4000            /* time base is processor clock */
363         mtspr   HID0,r0
364
365 #if defined(CONFIG_ADDR_STREAMING)
366         li      r0,0x3000
367 #else
368         li      r0,0x1000
369 #endif
370         mtspr   HID1,r0
371
372         /* Enable Branch Prediction */
373 #if defined(CONFIG_BTB)
374         li      r0,0x201                /* BBFI = 1, BPEN = 1 */
375         mtspr   BUCSR,r0
376 #endif
377
378 #if defined(CFG_INIT_DBCR)
379         lis     r1,0xffff
380         ori     r1,r1,0xffff
381         mtspr   DBSR,r1                 /* Clear all status bits */
382         lis     r0,CFG_INIT_DBCR@h      /* DBCR0[IDM] must be set */
383         ori     r0,r0,CFG_INIT_DBCR@l
384         mtspr   DBCR0,r0
385 #endif
386
387 /* L1 DCache is used for initial RAM */
388         mfspr   r2, L1CSR0
389         ori     r2, r2, 0x0003
390         oris    r2, r2, 0x0001
391         mtspr   L1CSR0, r2      /* enable/invalidate L1 Dcache */
392         isync
393
394         /* Allocate Initial RAM in data cache.
395          */
396         lis     r3, CFG_INIT_RAM_ADDR@h
397         ori     r3, r3, CFG_INIT_RAM_ADDR@l
398         li      r2, 512 /* 512*32=16K */
399         mtctr   r2
400         li      r0, 0
401 1:
402         dcbz    r0, r3
403         dcbtls  0,r0, r3
404         addi    r3, r3, 32
405         bdnz    1b
406
407 #ifndef CFG_RAMBOOT
408         /* Calculate absolute address in FLASH and jump there           */
409         /*--------------------------------------------------------------*/
410         lis     r3, CFG_MONITOR_BASE@h
411         ori     r3, r3, CFG_MONITOR_BASE@l
412         addi    r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
413         mtlr    r3
414         blr
415
416 in_flash:
417 #endif  /* CFG_RAMBOOT */
418
419         /* Setup the stack in initial RAM,could be L2-as-SRAM or L1 dcache*/
420         lis     r1,CFG_INIT_RAM_ADDR@h
421         ori     r1,r1,CFG_INIT_SP_OFFSET@l
422
423         li      r0,0
424         stwu    r0,-4(r1)
425         stwu    r0,-4(r1)               /* Terminate call chain */
426
427         stwu    r1,-8(r1)               /* Save back chain and move SP */
428         lis     r0,RESET_VECTOR@h       /* Address of reset vector */
429         ori     r0,r0, RESET_VECTOR@l
430         stwu    r1,-8(r1)               /* Save back chain and move SP */
431         stw     r0,+12(r1)              /* Save return addr (underflow vect) */
432
433         GET_GOT
434         bl      cpu_init_f
435         bl      icache_enable
436         bl      board_init_f
437         isync
438
439 /* --FIXME-- machine check with MCSRRn and rfmci */
440
441         .globl  _start_of_vectors
442 _start_of_vectors:
443 #if 0
444 /* Critical input. */
445         CRIT_EXCEPTION(0x0100, CritcalInput, CritcalInputException)
446 #endif
447 /* Machine check --FIXME-- Should be MACH_EXCEPTION */
448         CRIT_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
449
450 /* Data Storage exception. */
451         STD_EXCEPTION(0x0300, DataStorage, UnknownException)
452
453 /* Instruction Storage exception. */
454         STD_EXCEPTION(0x0400, InstStorage, UnknownException)
455
456 /* External Interrupt exception. */
457         STD_EXCEPTION(0x0500, ExtInterrupt, UnknownException)
458
459 /* Alignment exception. */
460         . = 0x0600
461 Alignment:
462         EXCEPTION_PROLOG
463         mfspr   r4,DAR
464         stw     r4,_DAR(r21)
465         mfspr   r5,DSISR
466         stw     r5,_DSISR(r21)
467         addi    r3,r1,STACK_FRAME_OVERHEAD
468         li      r20,MSR_KERNEL
469         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
470         lwz     r6,GOT(transfer_to_handler)
471         mtlr    r6
472         blrl
473 .L_Alignment:
474         .long   AlignmentException - _start + EXC_OFF_SYS_RESET
475         .long   int_return - _start + EXC_OFF_SYS_RESET
476
477 /* Program check exception */
478         . = 0x0700
479 ProgramCheck:
480         EXCEPTION_PROLOG
481         addi    r3,r1,STACK_FRAME_OVERHEAD
482         li      r20,MSR_KERNEL
483         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
484         lwz     r6,GOT(transfer_to_handler)
485         mtlr    r6
486         blrl
487 .L_ProgramCheck:
488         .long   ProgramCheckException - _start + EXC_OFF_SYS_RESET
489         .long   int_return - _start + EXC_OFF_SYS_RESET
490
491         /* No FPU on MPC85xx.  This exception is not supposed to happen.
492         */
493         STD_EXCEPTION(0x0800, FPUnavailable, UnknownException)
494         STD_EXCEPTION(0x0900, Decrementer, timer_interrupt)
495         STD_EXCEPTION(0x0a00, Trap_0a, UnknownException)
496         STD_EXCEPTION(0x0b00, Trap_0b, UnknownException)
497
498         . = 0x0c00
499 /*
500  * r0 - SYSCALL number
501  * r3-... arguments
502  */
503 SystemCall:
504         addis   r11,r0,0                /* get functions table addr */
505         ori     r11,r11,0               /* Note: this code is patched in trap_init */
506         addis   r12,r0,0                /* get number of functions */
507         ori     r12,r12,0
508
509         cmplw   0, r0, r12
510         bge     1f
511
512         rlwinm  r0,r0,2,0,31            /* fn_addr = fn_tbl[r0] */
513         add     r11,r11,r0
514         lwz     r11,0(r11)
515
516         li      r20,0xd00-4             /* Get stack pointer */
517         lwz     r12,0(r20)
518         subi    r12,r12,12              /* Adjust stack pointer */
519         li      r0,0xc00+_end_back-SystemCall
520         cmplw   0, r0, r12              /* Check stack overflow */
521         bgt     1f
522         stw     r12,0(r20)
523
524         mflr    r0
525         stw     r0,0(r12)
526         mfspr   r0,SRR0
527         stw     r0,4(r12)
528         mfspr   r0,SRR1
529         stw     r0,8(r12)
530
531         li      r12,0xc00+_back-SystemCall
532         mtlr    r12
533         mtspr   SRR0,r11
534
535 1:      SYNC
536         rfi
537 _back:
538
539         mfmsr   r11                     /* Disable interrupts */
540         li      r12,0
541         ori     r12,r12,MSR_EE
542         andc    r11,r11,r12
543         SYNC                            /* Some chip revs need this... */
544         mtmsr   r11
545         SYNC
546
547         li      r12,0xd00-4             /* restore regs */
548         lwz     r12,0(r12)
549
550         lwz     r11,0(r12)
551         mtlr    r11
552         lwz     r11,4(r12)
553         mtspr   SRR0,r11
554         lwz     r11,8(r12)
555         mtspr   SRR1,r11
556
557         addi    r12,r12,12              /* Adjust stack pointer */
558         li      r20,0xd00-4
559         stw     r12,0(r20)
560
561         SYNC
562         rfi
563 _end_back:
564
565         STD_EXCEPTION(0xd00, SingleStep, UnknownException)
566
567         STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
568         STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
569
570         STD_EXCEPTION(0x1000, PIT, PITException)
571
572         STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
573         STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
574         STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
575         STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
576
577         STD_EXCEPTION(0x1500, Reserved5, UnknownException)
578         STD_EXCEPTION(0x1600, Reserved6, UnknownException)
579         STD_EXCEPTION(0x1700, Reserved7, UnknownException)
580         STD_EXCEPTION(0x1800, Reserved8, UnknownException)
581         STD_EXCEPTION(0x1900, Reserved9, UnknownException)
582         STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
583         STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
584
585         STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
586         STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
587         STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
588         STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
589
590         CRIT_EXCEPTION(0x2000, DebugBreakpoint, DebugException )
591
592         .globl  _end_of_vectors
593 _end_of_vectors:
594
595
596         . = 0x2100
597
598 /*
599  * This code finishes saving the registers to the exception frame
600  * and jumps to the appropriate handler for the exception.
601  * Register r21 is pointer into trap frame, r1 has new stack pointer.
602  */
603         .globl  transfer_to_handler
604 transfer_to_handler:
605         stw     r22,_NIP(r21)
606         lis     r22,MSR_POW@h
607         andc    r23,r23,r22
608         stw     r23,_MSR(r21)
609         SAVE_GPR(7, r21)
610         SAVE_4GPRS(8, r21)
611         SAVE_8GPRS(12, r21)
612         SAVE_8GPRS(24, r21)
613
614         mflr    r23
615         andi.   r24,r23,0x3f00          /* get vector offset */
616         stw     r24,TRAP(r21)
617         li      r22,0
618         stw     r22,RESULT(r21)
619         mtspr   SPRG2,r22               /* r1 is now kernel sp */
620
621         lwz     r24,0(r23)              /* virtual address of handler */
622         lwz     r23,4(r23)              /* where to go when done */
623         mtspr   SRR0,r24
624         mtspr   SRR1,r20
625         mtlr    r23
626         SYNC
627         rfi                             /* jump to handler, enable MMU */
628
629 int_return:
630         mfmsr   r28             /* Disable interrupts */
631         li      r4,0
632         ori     r4,r4,MSR_EE
633         andc    r28,r28,r4
634         SYNC                    /* Some chip revs need this... */
635         mtmsr   r28
636         SYNC
637         lwz     r2,_CTR(r1)
638         lwz     r0,_LINK(r1)
639         mtctr   r2
640         mtlr    r0
641         lwz     r2,_XER(r1)
642         lwz     r0,_CCR(r1)
643         mtspr   XER,r2
644         mtcrf   0xFF,r0
645         REST_10GPRS(3, r1)
646         REST_10GPRS(13, r1)
647         REST_8GPRS(23, r1)
648         REST_GPR(31, r1)
649         lwz     r2,_NIP(r1)     /* Restore environment */
650         lwz     r0,_MSR(r1)
651         mtspr   SRR0,r2
652         mtspr   SRR1,r0
653         lwz     r0,GPR0(r1)
654         lwz     r2,GPR2(r1)
655         lwz     r1,GPR1(r1)
656         SYNC
657         rfi
658
659 crit_return:
660         mfmsr   r28             /* Disable interrupts */
661         li      r4,0
662         ori     r4,r4,MSR_EE
663         andc    r28,r28,r4
664         SYNC                    /* Some chip revs need this... */
665         mtmsr   r28
666         SYNC
667         lwz     r2,_CTR(r1)
668         lwz     r0,_LINK(r1)
669         mtctr   r2
670         mtlr    r0
671         lwz     r2,_XER(r1)
672         lwz     r0,_CCR(r1)
673         mtspr   XER,r2
674         mtcrf   0xFF,r0
675         REST_10GPRS(3, r1)
676         REST_10GPRS(13, r1)
677         REST_8GPRS(23, r1)
678         REST_GPR(31, r1)
679         lwz     r2,_NIP(r1)     /* Restore environment */
680         lwz     r0,_MSR(r1)
681         mtspr   990,r2          /* SRR2 */
682         mtspr   991,r0          /* SRR3 */
683         lwz     r0,GPR0(r1)
684         lwz     r2,GPR2(r1)
685         lwz     r1,GPR1(r1)
686         SYNC
687         rfci
688
689 /* Cache functions.
690 */
691 invalidate_icache:
692         mfspr   r0,L1CSR1
693         ori     r0,r0,0x0002
694         mtspr   L1CSR1,r0
695         isync
696         blr                             /*   entire I cache */
697
698 invalidate_dcache:
699         mfspr   r0,L1CSR0
700         ori     r0,r0,0x0002
701         msync
702         isync
703         mtspr   L1CSR0,r0
704         isync
705         blr
706
707         .globl  icache_enable
708 icache_enable:
709         mflr    r8
710         bl      invalidate_icache
711         mtlr    r8
712         isync
713         mfspr   r4,L1CSR1
714         ori     r4,r4,0x0001
715         oris    r4,r4,0x0001
716         mtspr   L1CSR1,r4
717         isync
718         blr
719
720         .globl  icache_disable
721 icache_disable:
722         mfspr   r0,L1CSR1
723         lis     r1,0xfffffffe@h
724         ori     r1,r1,0xfffffffe@l
725         and     r0,r0,r1
726         mtspr   L1CSR1,r0
727         isync
728         blr
729
730         .globl  icache_status
731 icache_status:
732         mfspr   r3,L1CSR1
733         srwi    r3, r3, 31      /* >>31 => select bit 0 */
734         blr
735
736         .globl  dcache_enable
737 dcache_enable:
738         mflr    r8
739         bl      invalidate_dcache
740         mtlr    r8
741         isync
742         mfspr   r0,L1CSR0
743         ori     r0,r0,0x0001
744         oris    r0,r0,0x0001
745         msync
746         isync
747         mtspr   L1CSR0,r0
748         isync
749         blr
750
751         .globl  dcache_disable
752 dcache_disable:
753         mfspr   r0,L1CSR0
754         lis     r1,0xfffffffe@h
755         ori     r1,r1,0xfffffffe@l
756         and     r0,r0,r1
757         msync
758         isync
759         mtspr   L1CSR0,r0
760         isync
761         blr
762
763         .globl  dcache_status
764 dcache_status:
765         mfspr   r3,L1CSR0
766         srwi    r3, r3, 31      /* >>31 => select bit 0 */
767         blr
768
769         .globl get_pir
770 get_pir:
771         mfspr   r3, PIR
772         blr
773
774         .globl get_pvr
775 get_pvr:
776         mfspr   r3, PVR
777         blr
778
779         .globl get_svr
780 get_svr:
781         mfspr   r3, SVR
782         blr
783
784         .globl wr_tcr
785 wr_tcr:
786         mtspr   TCR, r3
787         blr
788
789 /*------------------------------------------------------------------------------- */
790 /* Function:     in8 */
791 /* Description:  Input 8 bits */
792 /*------------------------------------------------------------------------------- */
793         .globl  in8
794 in8:
795         lbz     r3,0x0000(r3)
796         blr
797
798 /*------------------------------------------------------------------------------- */
799 /* Function:     out8 */
800 /* Description:  Output 8 bits */
801 /*------------------------------------------------------------------------------- */
802         .globl  out8
803 out8:
804         stb     r4,0x0000(r3)
805         blr
806
807 /*------------------------------------------------------------------------------- */
808 /* Function:     out16 */
809 /* Description:  Output 16 bits */
810 /*------------------------------------------------------------------------------- */
811         .globl  out16
812 out16:
813         sth     r4,0x0000(r3)
814         blr
815
816 /*------------------------------------------------------------------------------- */
817 /* Function:     out16r */
818 /* Description:  Byte reverse and output 16 bits */
819 /*------------------------------------------------------------------------------- */
820         .globl  out16r
821 out16r:
822         sthbrx  r4,r0,r3
823         blr
824
825 /*------------------------------------------------------------------------------- */
826 /* Function:     out32 */
827 /* Description:  Output 32 bits */
828 /*------------------------------------------------------------------------------- */
829         .globl  out32
830 out32:
831         stw     r4,0x0000(r3)
832         blr
833
834 /*------------------------------------------------------------------------------- */
835 /* Function:     out32r */
836 /* Description:  Byte reverse and output 32 bits */
837 /*------------------------------------------------------------------------------- */
838         .globl  out32r
839 out32r:
840         stwbrx  r4,r0,r3
841         blr
842
843 /*------------------------------------------------------------------------------- */
844 /* Function:     in16 */
845 /* Description:  Input 16 bits */
846 /*------------------------------------------------------------------------------- */
847         .globl  in16
848 in16:
849         lhz     r3,0x0000(r3)
850         blr
851
852 /*------------------------------------------------------------------------------- */
853 /* Function:     in16r */
854 /* Description:  Input 16 bits and byte reverse */
855 /*------------------------------------------------------------------------------- */
856         .globl  in16r
857 in16r:
858         lhbrx   r3,r0,r3
859         blr
860
861 /*------------------------------------------------------------------------------- */
862 /* Function:     in32 */
863 /* Description:  Input 32 bits */
864 /*------------------------------------------------------------------------------- */
865         .globl  in32
866 in32:
867         lwz     3,0x0000(3)
868         blr
869
870 /*------------------------------------------------------------------------------- */
871 /* Function:     in32r */
872 /* Description:  Input 32 bits and byte reverse */
873 /*------------------------------------------------------------------------------- */
874         .globl  in32r
875 in32r:
876         lwbrx   r3,r0,r3
877         blr
878
879 /*------------------------------------------------------------------------------- */
880 /* Function:     ppcDcbf */
881 /* Description:  Data Cache block flush */
882 /* Input:        r3 = effective address */
883 /* Output:       none. */
884 /*------------------------------------------------------------------------------- */
885         .globl  ppcDcbf
886 ppcDcbf:
887         dcbf    r0,r3
888         blr
889
890 /*------------------------------------------------------------------------------- */
891 /* Function:     ppcDcbi */
892 /* Description:  Data Cache block Invalidate */
893 /* Input:        r3 = effective address */
894 /* Output:       none. */
895 /*------------------------------------------------------------------------------- */
896         .globl  ppcDcbi
897 ppcDcbi:
898         dcbi    r0,r3
899         blr
900
901 /*--------------------------------------------------------------------------
902  * Function:     ppcDcbz
903  * Description:  Data Cache block zero.
904  * Input:        r3 = effective address
905  * Output:       none.
906  *-------------------------------------------------------------------------- */
907
908         .globl  ppcDcbz
909 ppcDcbz:
910         dcbz    r0,r3
911         blr
912
913 /*------------------------------------------------------------------------------- */
914 /* Function:     ppcSync */
915 /* Description:  Processor Synchronize */
916 /* Input:        none. */
917 /* Output:       none. */
918 /*------------------------------------------------------------------------------- */
919         .globl  ppcSync
920 ppcSync:
921         sync
922         blr
923
924 /*------------------------------------------------------------------------------*/
925
926 /*
927  * void relocate_code (addr_sp, gd, addr_moni)
928  *
929  * This "function" does not return, instead it continues in RAM
930  * after relocating the monitor code.
931  *
932  * r3 = dest
933  * r4 = src
934  * r5 = length in bytes
935  * r6 = cachelinesize
936  */
937         .globl  relocate_code
938 relocate_code:
939         mr      r1,  r3         /* Set new stack pointer                */
940         mr      r9,  r4         /* Save copy of Init Data pointer       */
941         mr      r10, r5         /* Save copy of Destination Address     */
942
943         mr      r3,  r5                         /* Destination Address  */
944         lis     r4, CFG_MONITOR_BASE@h          /* Source      Address  */
945         ori     r4, r4, CFG_MONITOR_BASE@l
946         lwz     r5,GOT(__init_end)
947         sub     r5,r5,r4
948         li      r6, CFG_CACHELINE_SIZE          /* Cache Line Size      */
949
950         /*
951          * Fix GOT pointer:
952          *
953          * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
954          *
955          * Offset:
956          */
957         sub     r15, r10, r4
958
959         /* First our own GOT */
960         add     r14, r14, r15
961         /* the the one used by the C code */
962         add     r30, r30, r15
963
964         /*
965          * Now relocate code
966          */
967
968         cmplw   cr1,r3,r4
969         addi    r0,r5,3
970         srwi.   r0,r0,2
971         beq     cr1,4f          /* In place copy is not necessary       */
972         beq     7f              /* Protect against 0 count              */
973         mtctr   r0
974         bge     cr1,2f
975
976         la      r8,-4(r4)
977         la      r7,-4(r3)
978 1:      lwzu    r0,4(r8)
979         stwu    r0,4(r7)
980         bdnz    1b
981         b       4f
982
983 2:      slwi    r0,r0,2
984         add     r8,r4,r0
985         add     r7,r3,r0
986 3:      lwzu    r0,-4(r8)
987         stwu    r0,-4(r7)
988         bdnz    3b
989
990 /*
991  * Now flush the cache: note that we must start from a cache aligned
992  * address. Otherwise we might miss one cache line.
993  */
994 4:      cmpwi   r6,0
995         add     r5,r3,r5
996         beq     7f              /* Always flush prefetch queue in any case */
997         subi    r0,r6,1
998         andc    r3,r3,r0
999         mr      r4,r3
1000 5:      dcbst   0,r4
1001         add     r4,r4,r6
1002         cmplw   r4,r5
1003         blt     5b
1004         sync                    /* Wait for all dcbst to complete on bus */
1005         mr      r4,r3
1006 6:      icbi    0,r4
1007         add     r4,r4,r6
1008         cmplw   r4,r5
1009         blt     6b
1010 7:      sync                    /* Wait for all icbi to complete on bus */
1011         isync
1012
1013 /*
1014  * We are done. Do not return, instead branch to second part of board
1015  * initialization, now running from RAM.
1016  */
1017
1018         addi    r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
1019         mtlr    r0
1020         blr                             /* NEVER RETURNS! */
1021
1022 in_ram:
1023
1024         /*
1025          * Relocation Function, r14 point to got2+0x8000
1026          *
1027          * Adjust got2 pointers, no need to check for 0, this code
1028          * already puts a few entries in the table.
1029          */
1030         li      r0,__got2_entries@sectoff@l
1031         la      r3,GOT(_GOT2_TABLE_)
1032         lwz     r11,GOT(_GOT2_TABLE_)
1033         mtctr   r0
1034         sub     r11,r3,r11
1035         addi    r3,r3,-4
1036 1:      lwzu    r0,4(r3)
1037         add     r0,r0,r11
1038         stw     r0,0(r3)
1039         bdnz    1b
1040
1041         /*
1042          * Now adjust the fixups and the pointers to the fixups
1043          * in case we need to move ourselves again.
1044          */
1045 2:      li      r0,__fixup_entries@sectoff@l
1046         lwz     r3,GOT(_FIXUP_TABLE_)
1047         cmpwi   r0,0
1048         mtctr   r0
1049         addi    r3,r3,-4
1050         beq     4f
1051 3:      lwzu    r4,4(r3)
1052         lwzux   r0,r4,r11
1053         add     r0,r0,r11
1054         stw     r10,0(r3)
1055         stw     r0,0(r4)
1056         bdnz    3b
1057 4:
1058 clear_bss:
1059         /*
1060          * Now clear BSS segment
1061          */
1062         lwz     r3,GOT(__bss_start)
1063         lwz     r4,GOT(_end)
1064
1065         cmplw   0, r3, r4
1066         beq     6f
1067
1068         li      r0, 0
1069 5:
1070         stw     r0, 0(r3)
1071         addi    r3, r3, 4
1072         cmplw   0, r3, r4
1073         bne     5b
1074 6:
1075
1076         mr      r3, r9          /* Init Data pointer            */
1077         mr      r4, r10         /* Destination Address          */
1078         bl      board_init_r
1079
1080         /*
1081          * Copy exception vector code to low memory
1082          *
1083          * r3: dest_addr
1084          * r7: source address, r8: end address, r9: target address
1085          */
1086         .globl  trap_init
1087 trap_init:
1088         lwz     r7, GOT(_start)
1089         lwz     r8, GOT(_end_of_vectors)
1090
1091         li      r9, 0x100               /* reset vector always at 0x100 */
1092
1093         cmplw   0, r7, r8
1094         bgelr                           /* return if r7>=r8 - just in case */
1095
1096         mflr    r4                      /* save link register           */
1097 1:
1098         lwz     r0, 0(r7)
1099         stw     r0, 0(r9)
1100         addi    r7, r7, 4
1101         addi    r9, r9, 4
1102         cmplw   0, r7, r8
1103         bne     1b
1104
1105         /*
1106          * relocate `hdlr' and `int_return' entries
1107          */
1108         li      r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
1109         li      r8, Alignment - _start + EXC_OFF_SYS_RESET
1110 2:
1111         bl      trap_reloc
1112         addi    r7, r7, 0x100           /* next exception vector        */
1113         cmplw   0, r7, r8
1114         blt     2b
1115
1116         li      r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
1117         bl      trap_reloc
1118
1119         li      r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
1120         bl      trap_reloc
1121
1122         li      r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
1123         li      r8, SystemCall - _start + EXC_OFF_SYS_RESET
1124 3:
1125         bl      trap_reloc
1126         addi    r7, r7, 0x100           /* next exception vector        */
1127         cmplw   0, r7, r8
1128         blt     3b
1129
1130         li      r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
1131         li      r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
1132 4:
1133         bl      trap_reloc
1134         addi    r7, r7, 0x100           /* next exception vector        */
1135         cmplw   0, r7, r8
1136         blt     4b
1137
1138         mtlr    r4                      /* restore link register        */
1139         blr
1140
1141         /*
1142          * Function: relocate entries for one exception vector
1143          */
1144 trap_reloc:
1145         lwz     r0, 0(r7)               /* hdlr ...                     */
1146         add     r0, r0, r3              /*  ... += dest_addr            */
1147         stw     r0, 0(r7)
1148
1149         lwz     r0, 4(r7)               /* int_return ...               */
1150         add     r0, r0, r3              /*  ... += dest_addr            */
1151         stw     r0, 4(r7)
1152
1153         blr
1154
1155 #ifdef CFG_INIT_RAM_LOCK
1156 .globl unlock_ram_in_cache
1157 unlock_ram_in_cache:
1158         /* invalidate the INIT_RAM section */
1159         lis     r3, (CFG_INIT_RAM_ADDR & ~31)@h
1160         ori     r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l
1161         li      r2,512
1162         mtctr   r2
1163 1:      icbi    r0, r3
1164         dcbi    r0, r3
1165         addi    r3, r3, 32
1166         bdnz    1b
1167         sync                    /* Wait for all icbi to complete on bus */
1168         isync
1169         blr
1170 #endif