[PATCH] ppc64: very basic desktop g5 sound support
[safe/jmp/linux-2.6] / arch / ppc / platforms / pmac_cache.S
1 /*
2  * This file contains low-level cache management functions
3  * used for sleep and CPU speed changes on Apple machines.
4  * (In fact the only thing that is Apple-specific is that we assume
5  * that we can read from ROM at physical address 0xfff00000.)
6  *
7  *    Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
8  *                       Benjamin Herrenschmidt (benh@kernel.crashing.org)
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version
13  * 2 of the License, or (at your option) any later version.
14  *
15  */
16
17 #include <linux/config.h>
18 #include <asm/processor.h>
19 #include <asm/ppc_asm.h>
20 #include <asm/cputable.h>
21
22 /*
23  * Flush and disable all data caches (dL1, L2, L3). This is used
24  * when going to sleep, when doing a PMU based cpufreq transition,
25  * or when "offlining" a CPU on SMP machines. This code is over
26  * paranoid, but I've had enough issues with various CPU revs and
27  * bugs that I decided it was worth beeing over cautious
28  */
29
30 _GLOBAL(flush_disable_caches)
31 #ifndef CONFIG_6xx
32         blr
33 #else
34 BEGIN_FTR_SECTION
35         b       flush_disable_745x
36 END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
37 BEGIN_FTR_SECTION
38         b       flush_disable_75x
39 END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
40         b       __flush_disable_L1
41
42 /* This is the code for G3 and 74[01]0 */
43 flush_disable_75x:
44         mflr    r10
45
46         /* Turn off EE and DR in MSR */
47         mfmsr   r11
48         rlwinm  r0,r11,0,~MSR_EE
49         rlwinm  r0,r0,0,~MSR_DR
50         sync
51         mtmsr   r0
52         isync
53
54         /* Stop DST streams */
55 BEGIN_FTR_SECTION
56         DSSALL
57         sync
58 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
59
60         /* Stop DPM */
61         mfspr   r8,SPRN_HID0            /* Save SPRN_HID0 in r8 */
62         rlwinm  r4,r8,0,12,10           /* Turn off HID0[DPM] */
63         sync
64         mtspr   SPRN_HID0,r4            /* Disable DPM */
65         sync
66
67         /* disp-flush L1 */
68         li      r4,0x4000
69         mtctr   r4
70         lis     r4,0xfff0
71 1:      lwzx    r0,r0,r4
72         addi    r4,r4,32
73         bdnz    1b
74         sync
75         isync
76
77         /* disable / invalidate / enable L1 data */
78         mfspr   r3,SPRN_HID0
79         rlwinm  r0,r0,0,~HID0_DCE
80         mtspr   SPRN_HID0,r3
81         sync
82         isync
83         ori     r3,r3,HID0_DCE|HID0_DCI
84         sync
85         isync
86         mtspr   SPRN_HID0,r3
87         xori    r3,r3,HID0_DCI
88         mtspr   SPRN_HID0,r3
89         sync
90
91         /* Get the current enable bit of the L2CR into r4 */
92         mfspr   r5,SPRN_L2CR
93         /* Set to data-only (pre-745x bit) */
94         oris    r3,r5,L2CR_L2DO@h
95         b       2f
96         /* When disabling L2, code must be in L1 */
97         .balign 32
98 1:      mtspr   SPRN_L2CR,r3
99 3:      sync
100         isync
101         b       1f
102 2:      b       3f
103 3:      sync
104         isync
105         b       1b
106 1:      /* disp-flush L2. The interesting thing here is that the L2 can be
107          * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
108          * but that is probbaly fine. We disp-flush over 4Mb to be safe
109          */
110         lis     r4,2
111         mtctr   r4
112         lis     r4,0xfff0
113 1:      lwzx    r0,r0,r4
114         addi    r4,r4,32
115         bdnz    1b
116         sync
117         isync
118         /* now disable L2 */
119         rlwinm  r5,r5,0,~L2CR_L2E
120         b       2f
121         /* When disabling L2, code must be in L1 */
122         .balign 32
123 1:      mtspr   SPRN_L2CR,r5
124 3:      sync
125         isync
126         b       1f
127 2:      b       3f
128 3:      sync
129         isync
130         b       1b
131 1:      sync
132         isync
133         /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
134         oris    r4,r5,L2CR_L2I@h
135         mtspr   SPRN_L2CR,r4
136         sync
137         isync
138         xoris   r4,r4,L2CR_L2I@h
139         sync
140         mtspr   SPRN_L2CR,r4
141         sync
142
143         /* now disable the L1 data cache */
144         mfspr   r0,SPRN_HID0
145         rlwinm  r0,r0,0,~HID0_DCE
146         mtspr   SPRN_HID0,r0
147         sync
148         isync
149
150         /* Restore HID0[DPM] to whatever it was before */
151         sync
152         mtspr   SPRN_HID0,r8
153         sync
154
155         /* restore DR and EE */
156         sync
157         mtmsr   r11
158         isync
159
160         mtlr    r10
161         blr
162
163 /* This code is for 745x processors */
164 flush_disable_745x:
165         /* Turn off EE and DR in MSR */
166         mfmsr   r11
167         rlwinm  r0,r11,0,~MSR_EE
168         rlwinm  r0,r0,0,~MSR_DR
169         sync
170         mtmsr   r0
171         isync
172
173         /* Stop prefetch streams */
174         DSSALL
175         sync
176
177         /* Disable L2 prefetching */
178         mfspr   r0,SPRN_MSSCR0
179         rlwinm  r0,r0,0,0,29
180         mtspr   SPRN_MSSCR0,r0
181         sync
182         isync
183         lis     r4,0
184         dcbf    0,r4
185         dcbf    0,r4
186         dcbf    0,r4
187         dcbf    0,r4
188         dcbf    0,r4
189         dcbf    0,r4
190         dcbf    0,r4
191         dcbf    0,r4
192
193         /* Due to a bug with the HW flush on some CPU revs, we occasionally
194          * experience data corruption. I'm adding a displacement flush along
195          * with a dcbf loop over a few Mb to "help". The problem isn't totally
196          * fixed by this in theory, but at least, in practice, I couldn't reproduce
197          * it even with a big hammer...
198          */
199
200         lis     r4,0x0002
201         mtctr   r4
202         li      r4,0
203 1:
204         lwzx    r0,r0,r4
205         addi    r4,r4,32                /* Go to start of next cache line */
206         bdnz    1b
207         isync
208
209         /* Now, flush the first 4MB of memory */
210         lis     r4,0x0002
211         mtctr   r4
212         li      r4,0
213         sync
214 1:
215         dcbf    0,r4
216         addi    r4,r4,32                /* Go to start of next cache line */
217         bdnz    1b
218
219         /* Flush and disable the L1 data cache */
220         mfspr   r6,SPRN_LDSTCR
221         lis     r3,0xfff0       /* read from ROM for displacement flush */
222         li      r4,0xfe         /* start with only way 0 unlocked */
223         li      r5,128          /* 128 lines in each way */
224 1:      mtctr   r5
225         rlwimi  r6,r4,0,24,31
226         mtspr   SPRN_LDSTCR,r6
227         sync
228         isync
229 2:      lwz     r0,0(r3)        /* touch each cache line */
230         addi    r3,r3,32
231         bdnz    2b
232         rlwinm  r4,r4,1,24,30   /* move on to the next way */
233         ori     r4,r4,1
234         cmpwi   r4,0xff         /* all done? */
235         bne     1b
236         /* now unlock the L1 data cache */
237         li      r4,0
238         rlwimi  r6,r4,0,24,31
239         sync
240         mtspr   SPRN_LDSTCR,r6
241         sync
242         isync
243
244         /* Flush the L2 cache using the hardware assist */
245         mfspr   r3,SPRN_L2CR
246         cmpwi   r3,0            /* check if it is enabled first */
247         bge     4f
248         oris    r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
249         b       2f
250         /* When disabling/locking L2, code must be in L1 */
251         .balign 32
252 1:      mtspr   SPRN_L2CR,r0    /* lock the L2 cache */
253 3:      sync
254         isync
255         b       1f
256 2:      b       3f
257 3:      sync
258         isync
259         b       1b
260 1:      sync
261         isync
262         ori     r0,r3,L2CR_L2HWF_745x
263         sync
264         mtspr   SPRN_L2CR,r0    /* set the hardware flush bit */
265 3:      mfspr   r0,SPRN_L2CR    /* wait for it to go to 0 */
266         andi.   r0,r0,L2CR_L2HWF_745x
267         bne     3b
268         sync
269         rlwinm  r3,r3,0,~L2CR_L2E
270         b       2f
271         /* When disabling L2, code must be in L1 */
272         .balign 32
273 1:      mtspr   SPRN_L2CR,r3    /* disable the L2 cache */
274 3:      sync
275         isync
276         b       1f
277 2:      b       3f
278 3:      sync
279         isync
280         b       1b
281 1:      sync
282         isync
283         oris    r4,r3,L2CR_L2I@h
284         mtspr   SPRN_L2CR,r4
285         sync
286         isync
287 1:      mfspr   r4,SPRN_L2CR
288         andis.  r0,r4,L2CR_L2I@h
289         bne     1b
290         sync
291
292 BEGIN_FTR_SECTION
293         /* Flush the L3 cache using the hardware assist */
294 4:      mfspr   r3,SPRN_L3CR
295         cmpwi   r3,0            /* check if it is enabled */
296         bge     6f
297         oris    r0,r3,L3CR_L3IO@h
298         ori     r0,r0,L3CR_L3DO
299         sync
300         mtspr   SPRN_L3CR,r0    /* lock the L3 cache */
301         sync
302         isync
303         ori     r0,r0,L3CR_L3HWF
304         sync
305         mtspr   SPRN_L3CR,r0    /* set the hardware flush bit */
306 5:      mfspr   r0,SPRN_L3CR    /* wait for it to go to zero */
307         andi.   r0,r0,L3CR_L3HWF
308         bne     5b
309         rlwinm  r3,r3,0,~L3CR_L3E
310         sync
311         mtspr   SPRN_L3CR,r3    /* disable the L3 cache */
312         sync
313         ori     r4,r3,L3CR_L3I
314         mtspr   SPRN_L3CR,r4
315 1:      mfspr   r4,SPRN_L3CR
316         andi.   r0,r4,L3CR_L3I
317         bne     1b
318         sync
319 END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
320
321 6:      mfspr   r0,SPRN_HID0    /* now disable the L1 data cache */
322         rlwinm  r0,r0,0,~HID0_DCE
323         mtspr   SPRN_HID0,r0
324         sync
325         isync
326         mtmsr   r11             /* restore DR and EE */
327         isync
328         blr
329 #endif  /* CONFIG_6xx */