xref: /OK3568_Linux_fs/u-boot/arch/powerpc/cpu/mpc86xx/cache.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#include <config.h>
2*4882a593Smuzhiyun#include <mpc86xx.h>
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun#include <ppc_asm.tmpl>
5*4882a593Smuzhiyun#include <ppc_defs.h>
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun#include <asm/cache.h>
8*4882a593Smuzhiyun#include <asm/mmu.h>
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun#ifndef CACHE_LINE_SIZE
11*4882a593Smuzhiyun# define CACHE_LINE_SIZE L1_CACHE_BYTES
12*4882a593Smuzhiyun#endif
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun#if CACHE_LINE_SIZE == 128
15*4882a593Smuzhiyun#define LG_CACHE_LINE_SIZE 7
16*4882a593Smuzhiyun#elif CACHE_LINE_SIZE == 32
17*4882a593Smuzhiyun#define LG_CACHE_LINE_SIZE 5
18*4882a593Smuzhiyun#elif CACHE_LINE_SIZE == 16
19*4882a593Smuzhiyun#define LG_CACHE_LINE_SIZE 4
20*4882a593Smuzhiyun#elif CACHE_LINE_SIZE == 8
21*4882a593Smuzhiyun#define LG_CACHE_LINE_SIZE 3
22*4882a593Smuzhiyun#else
23*4882a593Smuzhiyun# error "Invalid cache line size!"
24*4882a593Smuzhiyun#endif
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun/*
27*4882a593Smuzhiyun * Most of this code is taken from 74xx_7xx/cache.S
28*4882a593Smuzhiyun * and then cleaned up a bit
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun/*
32*4882a593Smuzhiyun * Invalidate L1 instruction cache.
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun_GLOBAL(invalidate_l1_instruction_cache)
35*4882a593Smuzhiyun	/* use invalidate-all bit in HID0 */
36*4882a593Smuzhiyun	mfspr	r3,HID0
37*4882a593Smuzhiyun	ori	r3,r3,HID0_ICFI
38*4882a593Smuzhiyun	mtspr	HID0,r3
39*4882a593Smuzhiyun	isync
40*4882a593Smuzhiyun	blr
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun/*
43*4882a593Smuzhiyun * Invalidate L1 data cache.
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun_GLOBAL(invalidate_l1_data_cache)
46*4882a593Smuzhiyun	mfspr	r3,HID0
47*4882a593Smuzhiyun	ori	r3,r3,HID0_DCFI
48*4882a593Smuzhiyun	mtspr	HID0,r3
49*4882a593Smuzhiyun	isync
50*4882a593Smuzhiyun	blr
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun/*
53*4882a593Smuzhiyun * Flush data cache.
54*4882a593Smuzhiyun */
55*4882a593Smuzhiyun_GLOBAL(flush_dcache)
56*4882a593Smuzhiyun	lis	r3,0
57*4882a593Smuzhiyun	lis	r5,CACHE_LINE_SIZE
58*4882a593Smuzhiyunflush:
59*4882a593Smuzhiyun	cmp	0,1,r3,r5
60*4882a593Smuzhiyun	bge	done
61*4882a593Smuzhiyun	lwz	r5,0(r3)
62*4882a593Smuzhiyun	lis	r5,CACHE_LINE_SIZE
63*4882a593Smuzhiyun	addi	r3,r3,0x4
64*4882a593Smuzhiyun	b	flush
65*4882a593Smuzhiyundone:
66*4882a593Smuzhiyun	blr
67*4882a593Smuzhiyun/*
68*4882a593Smuzhiyun * Write any modified data cache blocks out to memory
69*4882a593Smuzhiyun * and invalidate the corresponding instruction cache blocks.
70*4882a593Smuzhiyun * This is a no-op on the 601.
71*4882a593Smuzhiyun *
72*4882a593Smuzhiyun * flush_icache_range(unsigned long start, unsigned long stop)
73*4882a593Smuzhiyun */
74*4882a593Smuzhiyun_GLOBAL(flush_icache_range)
75*4882a593Smuzhiyun	li	r5,CACHE_LINE_SIZE-1
76*4882a593Smuzhiyun	andc	r3,r3,r5
77*4882a593Smuzhiyun	subf	r4,r3,r4
78*4882a593Smuzhiyun	add	r4,r4,r5
79*4882a593Smuzhiyun	srwi.	r4,r4,LG_CACHE_LINE_SIZE
80*4882a593Smuzhiyun	beqlr
81*4882a593Smuzhiyun	mtctr	r4
82*4882a593Smuzhiyun	mr	r6,r3
83*4882a593Smuzhiyun1:	dcbst	0,r3
84*4882a593Smuzhiyun	addi	r3,r3,CACHE_LINE_SIZE
85*4882a593Smuzhiyun	bdnz	1b
86*4882a593Smuzhiyun	sync				/* wait for dcbst's to get to ram */
87*4882a593Smuzhiyun	mtctr	r4
88*4882a593Smuzhiyun2:	icbi	0,r6
89*4882a593Smuzhiyun	addi	r6,r6,CACHE_LINE_SIZE
90*4882a593Smuzhiyun	bdnz	2b
91*4882a593Smuzhiyun	sync				/* additional sync needed on g4 */
92*4882a593Smuzhiyun	isync
93*4882a593Smuzhiyun	blr
94*4882a593Smuzhiyun/*
95*4882a593Smuzhiyun * Write any modified data cache blocks out to memory.
96*4882a593Smuzhiyun * Does not invalidate the corresponding cache lines (especially for
97*4882a593Smuzhiyun * any corresponding instruction cache).
98*4882a593Smuzhiyun *
99*4882a593Smuzhiyun * clean_dcache_range(unsigned long start, unsigned long stop)
100*4882a593Smuzhiyun */
101*4882a593Smuzhiyun_GLOBAL(clean_dcache_range)
102*4882a593Smuzhiyun	li	r5,CACHE_LINE_SIZE-1
103*4882a593Smuzhiyun	andc	r3,r3,r5	/* align r3 down to cache line */
104*4882a593Smuzhiyun	subf	r4,r3,r4	/* r4 = offset of stop from start of cache line */
105*4882a593Smuzhiyun	add	r4,r4,r5	/* r4 += cache_line_size-1 */
106*4882a593Smuzhiyun	srwi.	r4,r4,LG_CACHE_LINE_SIZE  /* r4 = number of cache lines to flush */
107*4882a593Smuzhiyun	beqlr				  /* if r4 == 0 return */
108*4882a593Smuzhiyun	mtctr	r4			  /* ctr = r4 */
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun	sync
111*4882a593Smuzhiyun1:	dcbst	0,r3
112*4882a593Smuzhiyun	addi	r3,r3,CACHE_LINE_SIZE
113*4882a593Smuzhiyun	bdnz	1b
114*4882a593Smuzhiyun	sync				/* wait for dcbst's to get to ram */
115*4882a593Smuzhiyun	blr
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun/*
118*4882a593Smuzhiyun * Flush a particular page from the data cache to RAM.
119*4882a593Smuzhiyun * Note: this is necessary because the instruction cache does *not*
120*4882a593Smuzhiyun * snoop from the data cache.
121*4882a593Smuzhiyun *
122*4882a593Smuzhiyun *	void __flush_page_to_ram(void *page)
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun_GLOBAL(__flush_page_to_ram)
125*4882a593Smuzhiyun	rlwinm	r3,r3,0,0,19		/* Get page base address */
126*4882a593Smuzhiyun	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
127*4882a593Smuzhiyun	mtctr	r4
128*4882a593Smuzhiyun	mr	r6,r3
129*4882a593Smuzhiyun0:	dcbst	0,r3			/* Write line to ram */
130*4882a593Smuzhiyun	addi	r3,r3,CACHE_LINE_SIZE
131*4882a593Smuzhiyun	bdnz	0b
132*4882a593Smuzhiyun	sync
133*4882a593Smuzhiyun	mtctr	r4
134*4882a593Smuzhiyun1:	icbi	0,r6
135*4882a593Smuzhiyun	addi	r6,r6,CACHE_LINE_SIZE
136*4882a593Smuzhiyun	bdnz	1b
137*4882a593Smuzhiyun	sync
138*4882a593Smuzhiyun	isync
139*4882a593Smuzhiyun	blr
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun/*
142*4882a593Smuzhiyun * Flush a particular page from the instruction cache.
143*4882a593Smuzhiyun * Note: this is necessary because the instruction cache does *not*
144*4882a593Smuzhiyun * snoop from the data cache.
145*4882a593Smuzhiyun *
146*4882a593Smuzhiyun *	void __flush_icache_page(void *page)
147*4882a593Smuzhiyun */
148*4882a593Smuzhiyun_GLOBAL(__flush_icache_page)
149*4882a593Smuzhiyun	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
150*4882a593Smuzhiyun	mtctr	r4
151*4882a593Smuzhiyun1:	icbi	0,r3
152*4882a593Smuzhiyun	addi	r3,r3,CACHE_LINE_SIZE
153*4882a593Smuzhiyun	bdnz	1b
154*4882a593Smuzhiyun	sync
155*4882a593Smuzhiyun	isync
156*4882a593Smuzhiyun	blr
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun/*
159*4882a593Smuzhiyun * Clear a page using the dcbz instruction, which doesn't cause any
160*4882a593Smuzhiyun * memory traffic (except to write out any cache lines which get
161*4882a593Smuzhiyun * displaced).  This only works on cacheable memory.
162*4882a593Smuzhiyun */
163*4882a593Smuzhiyun_GLOBAL(clear_page)
164*4882a593Smuzhiyun	li	r0,4096/CACHE_LINE_SIZE
165*4882a593Smuzhiyun	mtctr	r0
166*4882a593Smuzhiyun1:	dcbz	0,r3
167*4882a593Smuzhiyun	addi	r3,r3,CACHE_LINE_SIZE
168*4882a593Smuzhiyun	bdnz	1b
169*4882a593Smuzhiyun	blr
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun/*
172*4882a593Smuzhiyun * Enable L1 Instruction cache
173*4882a593Smuzhiyun */
174*4882a593Smuzhiyun_GLOBAL(icache_enable)
175*4882a593Smuzhiyun	mfspr	r3, HID0
176*4882a593Smuzhiyun	li	r5, HID0_ICFI|HID0_ILOCK
177*4882a593Smuzhiyun	andc	r3, r3, r5
178*4882a593Smuzhiyun	ori	r3, r3, HID0_ICE
179*4882a593Smuzhiyun	ori	r5, r3, HID0_ICFI
180*4882a593Smuzhiyun	mtspr	HID0, r5
181*4882a593Smuzhiyun	mtspr	HID0, r3
182*4882a593Smuzhiyun	isync
183*4882a593Smuzhiyun	blr
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun/*
186*4882a593Smuzhiyun * Disable L1 Instruction cache
187*4882a593Smuzhiyun */
188*4882a593Smuzhiyun_GLOBAL(icache_disable)
189*4882a593Smuzhiyun	mflr	r4
190*4882a593Smuzhiyun	bl	invalidate_l1_instruction_cache		/* uses r3 */
191*4882a593Smuzhiyun	sync
192*4882a593Smuzhiyun	mtlr	r4
193*4882a593Smuzhiyun	mfspr	r3, HID0
194*4882a593Smuzhiyun	li	r5, 0
195*4882a593Smuzhiyun	ori	r5, r5, HID0_ICE
196*4882a593Smuzhiyun	andc	r3, r3, r5
197*4882a593Smuzhiyun	mtspr	HID0, r3
198*4882a593Smuzhiyun	isync
199*4882a593Smuzhiyun	blr
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun/*
202*4882a593Smuzhiyun * Is instruction cache enabled?
203*4882a593Smuzhiyun */
204*4882a593Smuzhiyun_GLOBAL(icache_status)
205*4882a593Smuzhiyun	mfspr	r3, HID0
206*4882a593Smuzhiyun	andi.	r3, r3, HID0_ICE
207*4882a593Smuzhiyun	blr
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun_GLOBAL(l1dcache_enable)
211*4882a593Smuzhiyun	mfspr	r3, HID0
212*4882a593Smuzhiyun	li	r5, HID0_DCFI|HID0_DLOCK
213*4882a593Smuzhiyun	andc	r3, r3, r5
214*4882a593Smuzhiyun	mtspr	HID0, r3		/* no invalidate, unlock */
215*4882a593Smuzhiyun	ori	r3, r3, HID0_DCE
216*4882a593Smuzhiyun	ori	r5, r3, HID0_DCFI
217*4882a593Smuzhiyun	mtspr	HID0, r5		/* enable + invalidate */
218*4882a593Smuzhiyun	mtspr	HID0, r3		/* enable */
219*4882a593Smuzhiyun	sync
220*4882a593Smuzhiyun	blr
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun/*
223*4882a593Smuzhiyun * Enable data cache(s) - L1 and optionally L2
224*4882a593Smuzhiyun * Calls l2cache_enable. LR saved in r5
225*4882a593Smuzhiyun */
226*4882a593Smuzhiyun_GLOBAL(dcache_enable)
227*4882a593Smuzhiyun	mfspr	r3, HID0
228*4882a593Smuzhiyun	li	r5, HID0_DCFI|HID0_DLOCK
229*4882a593Smuzhiyun	andc	r3, r3, r5
230*4882a593Smuzhiyun	mtspr	HID0, r3		/* no invalidate, unlock */
231*4882a593Smuzhiyun	ori	r3, r3, HID0_DCE
232*4882a593Smuzhiyun	ori	r5, r3, HID0_DCFI
233*4882a593Smuzhiyun	mtspr	HID0, r5		/* enable + invalidate */
234*4882a593Smuzhiyun	mtspr	HID0, r3		/* enable */
235*4882a593Smuzhiyun	sync
236*4882a593Smuzhiyun#ifdef CONFIG_SYS_L2
237*4882a593Smuzhiyun	mflr	r5
238*4882a593Smuzhiyun	bl	l2cache_enable		/* uses r3 and r4 */
239*4882a593Smuzhiyun	sync
240*4882a593Smuzhiyun	mtlr	r5
241*4882a593Smuzhiyun#endif
242*4882a593Smuzhiyun	blr
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun/*
246*4882a593Smuzhiyun * Disable data cache(s) - L1 and optionally L2
247*4882a593Smuzhiyun * Calls flush_dcache and l2cache_disable_no_flush.
248*4882a593Smuzhiyun * LR saved in r4
249*4882a593Smuzhiyun */
250*4882a593Smuzhiyun_GLOBAL(dcache_disable)
251*4882a593Smuzhiyun	mflr	r4			/* save link register */
252*4882a593Smuzhiyun	bl	flush_dcache	/* uses r3 and r5 */
253*4882a593Smuzhiyun	sync
254*4882a593Smuzhiyun	mfspr	r3, HID0
255*4882a593Smuzhiyun	li	r5, HID0_DCFI|HID0_DLOCK
256*4882a593Smuzhiyun	andc	r3, r3, r5
257*4882a593Smuzhiyun	mtspr	HID0, r3		/* no invalidate, unlock */
258*4882a593Smuzhiyun	li	r5, HID0_DCE|HID0_DCFI
259*4882a593Smuzhiyun	andc	r3, r3, r5		/* no enable, no invalidate */
260*4882a593Smuzhiyun	mtspr	HID0, r3
261*4882a593Smuzhiyun	sync
262*4882a593Smuzhiyun#ifdef CONFIG_SYS_L2
263*4882a593Smuzhiyun	bl	l2cache_disable_no_flush /* uses r3 */
264*4882a593Smuzhiyun#endif
265*4882a593Smuzhiyun	mtlr	r4			/* restore link register */
266*4882a593Smuzhiyun	blr
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun/*
269*4882a593Smuzhiyun * Is data cache enabled?
270*4882a593Smuzhiyun */
271*4882a593Smuzhiyun_GLOBAL(dcache_status)
272*4882a593Smuzhiyun	mfspr	r3, HID0
273*4882a593Smuzhiyun	andi.	r3, r3, HID0_DCE
274*4882a593Smuzhiyun	blr
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun/*
277*4882a593Smuzhiyun * Invalidate L2 cache using L2I, assume L2 is enabled
278*4882a593Smuzhiyun */
279*4882a593Smuzhiyun_GLOBAL(l2cache_invalidate)
280*4882a593Smuzhiyun	mfspr	r3, l2cr
281*4882a593Smuzhiyun	rlwinm.	r3, r3, 0, 0, 0
282*4882a593Smuzhiyun	beq	1f
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun	mfspr	r3, l2cr
285*4882a593Smuzhiyun	rlwinm	r3, r3, 0, 1, 31
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun#ifdef	CONFIG_ALTIVEC
288*4882a593Smuzhiyun	dssall
289*4882a593Smuzhiyun#endif
290*4882a593Smuzhiyun	sync
291*4882a593Smuzhiyun	mtspr	l2cr, r3
292*4882a593Smuzhiyun	sync
293*4882a593Smuzhiyun1:	mfspr	r3, l2cr
294*4882a593Smuzhiyun	oris	r3, r3, L2CR_L2I@h
295*4882a593Smuzhiyun	mtspr	l2cr, r3
296*4882a593Smuzhiyun
297*4882a593Smuzhiyuninvl2:
298*4882a593Smuzhiyun	mfspr	r3, l2cr
299*4882a593Smuzhiyun	andis.	r3, r3, L2CR_L2I@h
300*4882a593Smuzhiyun	bne	invl2
301*4882a593Smuzhiyun	blr
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun/*
304*4882a593Smuzhiyun * Enable L2 cache
305*4882a593Smuzhiyun * Calls l2cache_invalidate. LR is saved in r4
306*4882a593Smuzhiyun */
307*4882a593Smuzhiyun_GLOBAL(l2cache_enable)
308*4882a593Smuzhiyun	mflr	r4			/* save link register */
309*4882a593Smuzhiyun	bl	l2cache_invalidate	/* uses r3 */
310*4882a593Smuzhiyun	sync
311*4882a593Smuzhiyun	lis	r3, L2_ENABLE@h
312*4882a593Smuzhiyun	ori	r3, r3, L2_ENABLE@l
313*4882a593Smuzhiyun	mtspr	l2cr, r3
314*4882a593Smuzhiyun	isync
315*4882a593Smuzhiyun	mtlr	r4			/* restore link register */
316*4882a593Smuzhiyun	blr
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun/*
319*4882a593Smuzhiyun * Disable L2 cache
320*4882a593Smuzhiyun * Calls flush_dcache. LR is saved in r4
321*4882a593Smuzhiyun */
322*4882a593Smuzhiyun_GLOBAL(l2cache_disable)
323*4882a593Smuzhiyun	mflr	r4			/* save link register */
324*4882a593Smuzhiyun	bl	flush_dcache		/* uses r3 and r5 */
325*4882a593Smuzhiyun	sync
326*4882a593Smuzhiyun	mtlr	r4			/* restore link register */
327*4882a593Smuzhiyunl2cache_disable_no_flush:		/* provide way to disable L2 w/o flushing */
328*4882a593Smuzhiyun	lis	r3, L2_INIT@h
329*4882a593Smuzhiyun	ori	r3, r3, L2_INIT@l
330*4882a593Smuzhiyun	mtspr	l2cr, r3
331*4882a593Smuzhiyun	isync
332*4882a593Smuzhiyun	blr
333