Initial commit
[wrt350n-kernel.git] / arch / ppc / boot / common / util.S
blob0c5e43c4ae06c39fdbce750fde4707c3a27d9e14
1 /*
2  * Useful bootup functions, which are more easily done in asm than C.
3  *
4  * NOTE:  Be very very careful about the registers you use here.
5  *      We don't follow any ABI calling convention among the
6  *      assembler functions that call each other, especially early
7  *      in the initialization.  Please preserve at least r3 and r4
8  *      for these early functions, as they often contain information
9  *      passed from boot roms into the C decompress function.
10  *
11  * Author: Tom Rini
12  *         trini@mvista.com
13  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
14  *
15  * 2001-2004 (c) MontaVista, Software, Inc.  This file is licensed under
16  * the terms of the GNU General Public License version 2.  This program
17  * is licensed "as is" without any warranty of any kind, whether express
18  * or implied.
19  */
21 #include <asm/processor.h>
22 #include <asm/cache.h>
23 #include <asm/ppc_asm.h>
26         .text
28 #ifdef CONFIG_6xx
29         .globl  disable_6xx_mmu
30 disable_6xx_mmu:
31         /* Establish default MSR value, exception prefix 0xFFF.
32          * If necessary, this function must fix up the LR if we
33          * return to a different address space once the MMU is
34          * disabled.
35          */
36         li      r8,MSR_IP|MSR_FP
37         mtmsr   r8
38         isync
40         /* Test for a 601 */
41         mfpvr   r10
42         srwi    r10,r10,16
43         cmpwi   0,r10,1         /* 601 ? */
44         beq     .clearbats_601
46         /* Clear BATs */
47         li      r8,0
48         mtspr   SPRN_DBAT0U,r8
49         mtspr   SPRN_DBAT0L,r8
50         mtspr   SPRN_DBAT1U,r8
51         mtspr   SPRN_DBAT1L,r8
52         mtspr   SPRN_DBAT2U,r8
53         mtspr   SPRN_DBAT2L,r8
54         mtspr   SPRN_DBAT3U,r8
55         mtspr   SPRN_DBAT3L,r8
56 .clearbats_601:
57         mtspr   SPRN_IBAT0U,r8
58         mtspr   SPRN_IBAT0L,r8
59         mtspr   SPRN_IBAT1U,r8
60         mtspr   SPRN_IBAT1L,r8
61         mtspr   SPRN_IBAT2U,r8
62         mtspr   SPRN_IBAT2L,r8
63         mtspr   SPRN_IBAT3U,r8
64         mtspr   SPRN_IBAT3L,r8
65         isync
66         sync
67         sync
69         /* Set segment registers */
70         li      r8,16           /* load up segment register values */
71         mtctr   r8              /* for context 0 */
72         lis     r8,0x2000       /* Ku = 1, VSID = 0 */
73         li      r10,0
74 3:      mtsrin  r8,r10
75         addi    r8,r8,0x111     /* increment VSID */
76         addis   r10,r10,0x1000  /* address of next segment */
77         bdnz    3b
78         blr
80         .globl  disable_6xx_l1cache
81 disable_6xx_l1cache:
82         /* Enable, invalidate and then disable the L1 icache/dcache. */
83         li      r8,0
84         ori     r8,r8,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI)
85         mfspr   r11,SPRN_HID0
86         or      r11,r11,r8
87         andc    r10,r11,r8
88         isync
89         mtspr   SPRN_HID0,r8
90         sync
91         isync
92         mtspr   SPRN_HID0,r10
93         sync
94         isync
95         blr
96 #endif
98         .globl  _setup_L2CR
99 _setup_L2CR:
101  * We should be skipping this section on CPUs where this results in an
102  * illegal instruction.  If not, please send trini@kernel.crashing.org
103  * the PVR of your CPU.
104  */
105         /* Invalidate/disable L2 cache */
106         sync
107         isync
108         mfspr   r8,SPRN_L2CR
109         rlwinm  r8,r8,0,1,31
110         oris    r8,r8,L2CR_L2I@h
111         sync
112         isync
113         mtspr   SPRN_L2CR,r8
114         sync
115         isync
117         /* Wait for the invalidation to complete */
118         mfspr   r8,SPRN_PVR
119         srwi    r8,r8,16
120         cmplwi  cr0,r8,0x8000                   /* 7450 */
121         cmplwi  cr1,r8,0x8001                   /* 7455 */
122         cmplwi  cr2,r8,0x8002                   /* 7457 */
123         cror    4*cr0+eq,4*cr0+eq,4*cr1+eq      /* Now test if any are true. */
124         cror    4*cr0+eq,4*cr0+eq,4*cr2+eq
125         bne     2f
127 1:      mfspr   r8,SPRN_L2CR    /* On 745x, poll L2I bit (bit 10) */
128         rlwinm. r9,r8,0,10,10
129         bne     1b
130         b       3f
132 2:      mfspr   r8,SPRN_L2CR    /* On 75x & 74[01]0, poll L2IP bit (bit 31) */
133         rlwinm. r9,r8,0,31,31
134         bne     2b
136 3:      rlwinm  r8,r8,0,11,9    /* Turn off L2I bit */
137         sync
138         isync
139         mtspr   SPRN_L2CR,r8
140         sync
141         isync
142         blr
144         .globl  _setup_L3CR
145 _setup_L3CR:
146         /* Invalidate/disable L3 cache */
147         sync
148         isync
149         mfspr   r8,SPRN_L3CR
150         rlwinm  r8,r8,0,1,31
151         ori     r8,r8,L3CR_L3I@l
152         sync
153         isync
154         mtspr   SPRN_L3CR,r8
155         sync
156         isync
158         /* Wait for the invalidation to complete */
159 1:      mfspr   r8,SPRN_L3CR
160         rlwinm. r9,r8,0,21,21
161         bne     1b
163         rlwinm  r8,r8,0,22,20           /* Turn off L3I bit */
164         sync
165         isync
166         mtspr   SPRN_L3CR,r8
167         sync
168         isync
169         blr
172 /* udelay (on non-601 processors) needs to know the period of the
173  * timebase in nanoseconds.  This used to be hardcoded to be 60ns
174  * (period of 66MHz/4).  Now a variable is used that is initialized to
175  * 60 for backward compatibility, but it can be overridden as necessary
176  * with code something like this:
177  *    extern unsigned long timebase_period_ns;
178  *    timebase_period_ns = 1000000000 / bd->bi_tbfreq;
179  */
180         .data
181         .globl timebase_period_ns
182 timebase_period_ns:
183         .long   60
185         .text
187  * Delay for a number of microseconds
188  */
189         .globl  udelay
190 udelay:
191         mfspr   r4,SPRN_PVR
192         srwi    r4,r4,16
193         cmpwi   0,r4,1          /* 601 ? */
194         bne     .udelay_not_601
195 00:     li      r0,86   /* Instructions / microsecond? */
196         mtctr   r0
197 10:     addi    r0,r0,0 /* NOP */
198         bdnz    10b
199         subic.  r3,r3,1
200         bne     00b
201         blr
203 .udelay_not_601:
204         mulli   r4,r3,1000      /* nanoseconds */
205         /*  Change r4 to be the number of ticks using:  
206          *      (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
207          *  timebase_period_ns defaults to 60 (16.6MHz) */
208         lis     r5,timebase_period_ns@ha
209         lwz     r5,timebase_period_ns@l(r5)
210         add     r4,r4,r5
211         addi    r4,r4,-1
212         divw    r4,r4,r5        /* BUS ticks */
213 1:      mftbu   r5
214         mftb    r6
215         mftbu   r7
216         cmpw    0,r5,r7
217         bne     1b              /* Get [synced] base time */
218         addc    r9,r6,r4        /* Compute end time */
219         addze   r8,r5
220 2:      mftbu   r5
221         cmpw    0,r5,r8
222         blt     2b
223         bgt     3f
224         mftb    r6
225         cmpw    0,r6,r9
226         blt     2b
227 3:      blr
229         .section ".relocate_code","xa"
231  * Flush and enable instruction cache
232  * First, flush the data cache in case it was enabled and may be
233  * holding instructions for copy back.
234  */
235         .globl flush_instruction_cache
236 flush_instruction_cache:        
237         mflr    r6
238         bl      flush_data_cache
240 #ifdef CONFIG_8xx
241         lis     r3, IDC_INVALL@h
242         mtspr   SPRN_IC_CST, r3
243         lis     r3, IDC_ENABLE@h
244         mtspr   SPRN_IC_CST, r3
245         lis     r3, IDC_DISABLE@h
246         mtspr   SPRN_DC_CST, r3
247 #elif CONFIG_4xx
248         lis     r3,start@h              # r9 = &_start
249         lis     r4,_etext@ha
250         addi    r4,r4,_etext@l          # r8 = &_etext
251 1:      dcbf    r0,r3                   # Flush the data cache
252         icbi    r0,r3                   # Invalidate the instruction cache
253         addi    r3,r3,0x10              # Increment by one cache line
254         cmplw   cr0,r3,r4               # Are we at the end yet?
255         blt     1b                      # No, keep flushing and invalidating
256 #else
257         /* Enable, invalidate and then disable the L1 icache/dcache. */
258         li      r3,0
259         ori     r3,r3,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI)
260         mfspr   r4,SPRN_HID0
261         or      r5,r4,r3
262         isync
263         mtspr   SPRN_HID0,r5
264         sync
265         isync
266         ori     r5,r4,HID0_ICE  /* Enable cache */
267         mtspr   SPRN_HID0,r5
268         sync
269         isync
270 #endif
271         mtlr    r6
272         blr
274 #define NUM_CACHE_LINES 128*8
275 #define cache_flush_buffer 0x1000
278  * Flush data cache
279  * Do this by just reading lots of stuff into the cache.
280  */
281         .globl flush_data_cache
282 flush_data_cache:       
283         lis     r3,cache_flush_buffer@h
284         ori     r3,r3,cache_flush_buffer@l
285         li      r4,NUM_CACHE_LINES
286         mtctr   r4
287 00:     lwz     r4,0(r3)
288         addi    r3,r3,L1_CACHE_BYTES    /* Next line, please */
289         bdnz    00b
290 10:     blr
292         .previous