diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc86xx/cache.S')
| -rw-r--r-- | arch/powerpc/cpu/mpc86xx/cache.S | 378 | 
1 files changed, 378 insertions, 0 deletions
| diff --git a/arch/powerpc/cpu/mpc86xx/cache.S b/arch/powerpc/cpu/mpc86xx/cache.S new file mode 100644 index 000000000..0bb058b04 --- /dev/null +++ b/arch/powerpc/cpu/mpc86xx/cache.S @@ -0,0 +1,378 @@ +#include <config.h> +#include <mpc86xx.h> +#include <version.h> + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#ifndef CACHE_LINE_SIZE +# define CACHE_LINE_SIZE L1_CACHE_BYTES +#endif + +#if CACHE_LINE_SIZE == 128 +#define LG_CACHE_LINE_SIZE 7 +#elif CACHE_LINE_SIZE == 32 +#define LG_CACHE_LINE_SIZE 5 +#elif CACHE_LINE_SIZE == 16 +#define LG_CACHE_LINE_SIZE 4 +#elif CACHE_LINE_SIZE == 8 +#define LG_CACHE_LINE_SIZE 3 +#else +# error "Invalid cache line size!" +#endif + +/* + * Most of this code is taken from 74xx_7xx/cache.S + * and then cleaned up a bit + */ + +/* + * Invalidate L1 instruction cache. + */ +_GLOBAL(invalidate_l1_instruction_cache) +	/* use invalidate-all bit in HID0 */ +	mfspr	r3,HID0 +	ori	r3,r3,HID0_ICFI +	mtspr	HID0,r3 +	isync +	blr + +/* + * Invalidate L1 data cache. + */ +_GLOBAL(invalidate_l1_data_cache) +	mfspr	r3,HID0 +	ori	r3,r3,HID0_DCFI +	mtspr	HID0,r3 +	isync +	blr + +/* + * Flush data cache. + */ +_GLOBAL(flush_dcache) +	lis	r3,0 +	lis	r5,CACHE_LINE_SIZE +flush: +	cmp	0,1,r3,r5 +	bge	done +	lwz	r5,0(r3) +	lis	r5,CACHE_LINE_SIZE +	addi	r3,r3,0x4 +	b	flush +done: +	blr +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * This is a no-op on the 601. + * + * flush_icache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_icache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5 +	subf	r4,r3,r4 +	add	r4,r4,r5 +	srwi.	r4,r4,LG_CACHE_LINE_SIZE +	beqlr +	mtctr	r4 +	mr	r6,r3 +1:	dcbst	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbst's to get to ram */ +	mtctr	r4 +2:	icbi	0,r6 +	addi	r6,r6,CACHE_LINE_SIZE +	bdnz	2b +	sync				/* additional sync needed on g4 */ +	isync +	blr +/* + * Write any modified data cache blocks out to memory. + * Does not invalidate the corresponding cache lines (especially for + * any corresponding instruction cache). + * + * clean_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(clean_dcache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5	/* align r3 down to cache line */ +	subf	r4,r3,r4	/* r4 = offset of stop from start of cache line */ +	add	r4,r4,r5	/* r4 += cache_line_size-1 */ +	srwi.	r4,r4,LG_CACHE_LINE_SIZE  /* r4 = number of cache lines to flush */ +	beqlr				  /* if r4 == 0 return */ +	mtctr	r4			  /* ctr = r4 */ + +	sync +1:	dcbst	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbst's to get to ram */ +	blr + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_dcache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5 +	subf	r4,r3,r4 +	add	r4,r4,r5 +	srwi.	r4,r4,LG_CACHE_LINE_SIZE +	beqlr +	mtctr	r4 + +	sync +1:	dcbf	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbf's to get to ram */ +	blr + +/* + * Like above, but invalidate the D-cache.  This is used by the 8xx + * to invalidate the cache so the PPC core doesn't get stale data + * from the CPM (no cache snooping here :-). + * + * invalidate_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(invalidate_dcache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5 +	subf	r4,r3,r4 +	add	r4,r4,r5 +	srwi.	r4,r4,LG_CACHE_LINE_SIZE +	beqlr +	mtctr	r4 + +	sync +1:	dcbi	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbi's to get to ram */ +	blr + +/* + * Flush a particular page from the data cache to RAM. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + *	void __flush_page_to_ram(void *page) + */ +_GLOBAL(__flush_page_to_ram) +	rlwinm	r3,r3,0,0,19		/* Get page base address */ +	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */ +	mtctr	r4 +	mr	r6,r3 +0:	dcbst	0,r3			/* Write line to ram */ +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	0b +	sync +	mtctr	r4 +1:	icbi	0,r6 +	addi	r6,r6,CACHE_LINE_SIZE +	bdnz	1b +	sync +	isync +	blr + +/* + * Flush a particular page from the instruction cache. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + *	void __flush_icache_page(void *page) + */ +_GLOBAL(__flush_icache_page) +	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */ +	mtctr	r4 +1:	icbi	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync +	isync +	blr + +/* + * Clear a page using the dcbz instruction, which doesn't cause any + * memory traffic (except to write out any cache lines which get + * displaced).  This only works on cacheable memory. + */ +_GLOBAL(clear_page) +	li	r0,4096/CACHE_LINE_SIZE +	mtctr	r0 +1:	dcbz	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	blr + +/* + * Enable L1 Instruction cache + */ +_GLOBAL(icache_enable) +	mfspr	r3, HID0 +	li	r5, HID0_ICFI|HID0_ILOCK +	andc	r3, r3, r5 +	ori	r3, r3, HID0_ICE +	ori	r5, r3, HID0_ICFI +	mtspr	HID0, r5 +	mtspr	HID0, r3 +	isync +	blr + +/* + * Disable L1 Instruction cache + */ +_GLOBAL(icache_disable) +	mflr	r4 +	bl	invalidate_l1_instruction_cache		/* uses r3 */ +	sync +	mtlr	r4 +	mfspr	r3, HID0 +	li	r5, 0 +	ori	r5, r5, HID0_ICE +	andc	r3, r3, r5 +	mtspr	HID0, r3 +	isync +	blr + +/* + * Is instruction cache enabled? + */ +_GLOBAL(icache_status) +	mfspr	r3, HID0 +	andi.	r3, r3, HID0_ICE +	blr + + +_GLOBAL(l1dcache_enable) +	mfspr	r3, HID0 +	li	r5, HID0_DCFI|HID0_DLOCK +	andc	r3, r3, r5 +	mtspr	HID0, r3		/* no invalidate, unlock */ +	ori	r3, r3, HID0_DCE +	ori	r5, r3, HID0_DCFI +	mtspr	HID0, r5		/* enable + invalidate */ +	mtspr	HID0, r3		/* enable */ +	sync +	blr + +/* + * Enable data cache(s) - L1 and optionally L2 + * Calls l2cache_enable. LR saved in r5 + */ +_GLOBAL(dcache_enable) +	mfspr	r3, HID0 +	li	r5, HID0_DCFI|HID0_DLOCK +	andc	r3, r3, r5 +	mtspr	HID0, r3		/* no invalidate, unlock */ +	ori	r3, r3, HID0_DCE +	ori	r5, r3, HID0_DCFI +	mtspr	HID0, r5		/* enable + invalidate */ +	mtspr	HID0, r3		/* enable */ +	sync +#ifdef CONFIG_SYS_L2 +	mflr	r5 +	bl	l2cache_enable		/* uses r3 and r4 */ +	sync +	mtlr	r5 +#endif +	blr + + +/* + * Disable data cache(s) - L1 and optionally L2 + * Calls flush_dcache and l2cache_disable_no_flush. + * LR saved in r4 + */ +_GLOBAL(dcache_disable) +	mflr	r4			/* save link register */ +	bl	flush_dcache	/* uses r3 and r5 */ +	sync +	mfspr	r3, HID0 +	li	r5, HID0_DCFI|HID0_DLOCK +	andc	r3, r3, r5 +	mtspr	HID0, r3		/* no invalidate, unlock */ +	li	r5, HID0_DCE|HID0_DCFI +	andc	r3, r3, r5		/* no enable, no invalidate */ +	mtspr	HID0, r3 +	sync +#ifdef CONFIG_SYS_L2 +	bl	l2cache_disable_no_flush /* uses r3 */ +#endif +	mtlr	r4			/* restore link register */ +	blr + +/* + * Is data cache enabled? + */ +_GLOBAL(dcache_status) +	mfspr	r3, HID0 +	andi.	r3, r3, HID0_DCE +	blr + +/* + * Invalidate L2 cache using L2I, assume L2 is enabled + */ +_GLOBAL(l2cache_invalidate) +	mfspr	r3, l2cr +	rlwinm.	r3, r3, 0, 0, 0 +	beq	1f + +	mfspr	r3, l2cr +	rlwinm	r3, r3, 0, 1, 31 + +#ifdef	CONFIG_ALTIVEC +	dssall +#endif +	sync +	mtspr	l2cr, r3 +	sync +1:	mfspr	r3, l2cr +	oris	r3, r3, L2CR_L2I@h +	mtspr	l2cr, r3 + +invl2: +	mfspr	r3, l2cr +	andis.	r3, r3, L2CR_L2I@h +	bne	invl2 +	blr + +/* + * Enable L2 cache + * Calls l2cache_invalidate. LR is saved in r4 + */ +_GLOBAL(l2cache_enable) +	mflr	r4			/* save link register */ +	bl	l2cache_invalidate	/* uses r3 */ +	sync +	lis	r3, L2_ENABLE@h +	ori	r3, r3, L2_ENABLE@l +	mtspr	l2cr, r3 +	isync +	mtlr	r4			/* restore link register */ +	blr + +/* + * Disable L2 cache + * Calls flush_dcache. LR is saved in r4 + */ +_GLOBAL(l2cache_disable) +	mflr	r4			/* save link register */ +	bl	flush_dcache		/* uses r3 and r5 */ +	sync +	mtlr	r4			/* restore link register */ +l2cache_disable_no_flush:		/* provide way to disable L2 w/o flushing */ +	lis	r3, L2_INIT@h +	ori	r3, r3, L2_INIT@l +	mtspr	l2cr, r3 +	isync +	blr |