|  | /* | 
|  | *  Cache-handling routined for MIPS 4K CPUs | 
|  | * | 
|  | *  Copyright (c) 2003	Wolfgang Denk <wd@denx.de> | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <config.h> | 
|  | #include <version.h> | 
|  | #include <asm/regdef.h> | 
|  | #include <asm/mipsregs.h> | 
|  | #include <asm/addrspace.h> | 
|  | #include <asm/cacheops.h> | 
|  |  | 
|  |  | 
|  | /* 16KB is the maximum size of instruction and data caches on | 
|  | * MIPS 4K. | 
|  | */ | 
|  | #define MIPS_MAX_CACHE_SIZE	0x4000 | 
|  |  | 
|  |  | 
|  | /* | 
|  | * cacheop macro to automate cache operations | 
|  | * first some helpers... | 
|  | */ | 
|  | #define _mincache(size, maxsize) \ | 
|  | bltu  size,maxsize,9f ; \ | 
|  | move  size,maxsize ;    \ | 
|  | 9: | 
|  |  | 
|  | #define _align(minaddr, maxaddr, linesize) \ | 
|  | .set noat ; \ | 
|  | subu  AT,linesize,1 ;   \ | 
|  | not   AT ;        \ | 
|  | and   minaddr,AT ;      \ | 
|  | addu  maxaddr,-1 ;      \ | 
|  | and   maxaddr,AT ;      \ | 
|  | .set at | 
|  |  | 
|  | /* general operations */ | 
|  | #define doop1(op1) \ | 
|  | cache op1,0(a0) | 
|  | #define doop2(op1, op2) \ | 
|  | cache op1,0(a0) ;    \ | 
|  | nop ;          \ | 
|  | cache op2,0(a0) | 
|  |  | 
|  | /* specials for cache initialisation */ | 
|  | #define doop1lw(op1) \ | 
|  | lw zero,0(a0) | 
|  | #define doop1lw1(op1) \ | 
|  | cache op1,0(a0) ;    \ | 
|  | lw zero,0(a0) ;      \ | 
|  | cache op1,0(a0) | 
|  | #define doop121(op1,op2) \ | 
|  | cache op1,0(a0) ;    \ | 
|  | nop;           \ | 
|  | cache op2,0(a0) ;    \ | 
|  | nop;           \ | 
|  | cache op1,0(a0) | 
|  |  | 
|  | #define _oploopn(minaddr, maxaddr, linesize, tag, ops) \ | 
|  | .set  noreorder ;    \ | 
|  | 10:   doop##tag##ops ;  \ | 
|  | bne     minaddr,maxaddr,10b ; \ | 
|  | add      minaddr,linesize ;   \ | 
|  | .set  reorder | 
|  |  | 
|  | /* finally the cache operation macros */ | 
|  | #define vcacheopn(kva, n, cacheSize, cacheLineSize, tag, ops) \ | 
|  | blez  n,11f ;        \ | 
|  | addu  n,kva ;        \ | 
|  | _align(kva, n, cacheLineSize) ; \ | 
|  | _oploopn(kva, n, cacheLineSize, tag, ops) ; \ | 
|  | 11: | 
|  |  | 
|  | #define icacheopn(kva, n, cacheSize, cacheLineSize, tag, ops) \ | 
|  | _mincache(n, cacheSize);   \ | 
|  | blez  n,11f ;        \ | 
|  | addu  n,kva ;        \ | 
|  | _align(kva, n, cacheLineSize) ; \ | 
|  | _oploopn(kva, n, cacheLineSize, tag, ops) ; \ | 
|  | 11: | 
|  |  | 
|  | #define vcacheop(kva, n, cacheSize, cacheLineSize, op) \ | 
|  | vcacheopn(kva, n, cacheSize, cacheLineSize, 1, (op)) | 
|  |  | 
|  | #define icacheop(kva, n, cacheSize, cacheLineSize, op) \ | 
|  | icacheopn(kva, n, cacheSize, cacheLineSize, 1, (op)) | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * mips_cache_reset - low level initialisation of the primary caches | 
|  | * | 
|  | * This routine initialises the primary caches to ensure that they | 
|  | * have good parity.  It must be called by the ROM before any cached locations | 
|  | * are used to prevent the possibility of data with bad parity being written to | 
|  | * memory. | 
|  | * To initialise the instruction cache it is essential that a source of data | 
|  | * with good parity is available. This routine | 
|  | * will initialise an area of memory starting at location zero to be used as | 
|  | * a source of parity. | 
|  | * | 
|  | * RETURNS: N/A | 
|  | * | 
|  | */ | 
|  | .globl	mips_cache_reset | 
|  | .ent	mips_cache_reset | 
|  | mips_cache_reset: | 
|  |  | 
|  | li	t2, CFG_ICACHE_SIZE | 
|  | li	t3, CFG_DCACHE_SIZE | 
|  | li	t4, CFG_CACHELINE_SIZE | 
|  | move	t5, t4 | 
|  |  | 
|  |  | 
|  | li	v0, MIPS_MAX_CACHE_SIZE | 
|  |  | 
|  | /* Now clear that much memory starting from zero. | 
|  | */ | 
|  |  | 
|  | li	a0, KSEG1 | 
|  | addu	a1, a0, v0 | 
|  |  | 
|  | 2:	sw	zero, 0(a0) | 
|  | sw	zero, 4(a0) | 
|  | sw	zero, 8(a0) | 
|  | sw	zero, 12(a0) | 
|  | sw	zero, 16(a0) | 
|  | sw	zero, 20(a0) | 
|  | sw	zero, 24(a0) | 
|  | sw	zero, 28(a0) | 
|  | addu	a0, 32 | 
|  | bltu	a0, a1, 2b | 
|  |  | 
|  | /* Set invalid tag. | 
|  | */ | 
|  |  | 
|  | mtc0	zero, CP0_TAGLO | 
|  |  | 
|  | /* | 
|  | * The caches are probably in an indeterminate state, | 
|  | * so we force good parity into them by doing an | 
|  | * invalidate, load/fill, invalidate for each line. | 
|  | */ | 
|  |  | 
|  | /* Assume bottom of RAM will generate good parity for the cache. | 
|  | */ | 
|  |  | 
|  | li	a0, K0BASE | 
|  | move	a2, t2		# icacheSize | 
|  | move	a3, t4		# icacheLineSize | 
|  | move	a1, a2 | 
|  | icacheopn(a0,a1,a2,a3,121,(Index_Store_Tag_I,Fill)) | 
|  |  | 
|  | /* To support Orion/R4600, we initialise the data cache in 3 passes. | 
|  | */ | 
|  |  | 
|  | /* 1: initialise dcache tags. | 
|  | */ | 
|  |  | 
|  | li	a0, K0BASE | 
|  | move	a2, t3		# dcacheSize | 
|  | move	a3, t5		# dcacheLineSize | 
|  | move	a1, a2 | 
|  | icacheop(a0,a1,a2,a3,Index_Store_Tag_D) | 
|  |  | 
|  | /* 2: fill dcache. | 
|  | */ | 
|  |  | 
|  | li	a0, K0BASE | 
|  | move	a2, t3		# dcacheSize | 
|  | move	a3, t5		# dcacheLineSize | 
|  | move	a1, a2 | 
|  | icacheopn(a0,a1,a2,a3,1lw,(dummy)) | 
|  |  | 
|  | /* 3: clear dcache tags. | 
|  | */ | 
|  |  | 
|  | li	a0, K0BASE | 
|  | move	a2, t3		# dcacheSize | 
|  | move	a3, t5		# dcacheLineSize | 
|  | move	a1, a2 | 
|  | icacheop(a0,a1,a2,a3,Index_Store_Tag_D) | 
|  |  | 
|  | j  ra | 
|  | .end  mips_cache_reset | 
|  |  | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * dcache_status - get cache status | 
|  | * | 
|  | * RETURNS: 0 - cache disabled; 1 - cache enabled | 
|  | * | 
|  | */ | 
|  | .globl	dcache_status | 
|  | .ent	dcache_status | 
|  | dcache_status: | 
|  |  | 
|  | mfc0	v0, CP0_CONFIG | 
|  | andi	v0, v0, 1 | 
|  | j	ra | 
|  |  | 
|  | .end  dcache_status | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * dcache_disable - disable cache | 
|  | * | 
|  | * RETURNS: N/A | 
|  | * | 
|  | */ | 
|  | .globl	dcache_disable | 
|  | .ent	dcache_disable | 
|  | dcache_disable: | 
|  |  | 
|  | mfc0	t0, CP0_CONFIG | 
|  | li	t1, -8 | 
|  | and	t0, t0, t1 | 
|  | ori	t0, t0, CONF_CM_UNCACHED | 
|  | mtc0    t0, CP0_CONFIG | 
|  | j	ra | 
|  |  | 
|  | .end  dcache_disable | 
|  |  | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * mips_cache_lock - lock RAM area pointed to by a0 in cache. | 
|  | * | 
|  | * RETURNS: N/A | 
|  | * | 
|  | */ | 
|  | #if defined(CONFIG_PURPLE) | 
|  | # define	CACHE_LOCK_SIZE	(CFG_DCACHE_SIZE/2) | 
|  | #else | 
|  | # define	CACHE_LOCK_SIZE	(CFG_DCACHE_SIZE) | 
|  | #endif | 
|  | .globl	mips_cache_lock | 
|  | .ent	mips_cache_lock | 
|  | mips_cache_lock: | 
|  | li	a1, K0BASE - CACHE_LOCK_SIZE | 
|  | addu	a0, a1 | 
|  | li	a2, CACHE_LOCK_SIZE | 
|  | li	a3, CFG_CACHELINE_SIZE | 
|  | move	a1, a2 | 
|  | icacheop(a0,a1,a2,a3,0x1d) | 
|  |  | 
|  | j	ra | 
|  | .end	mips_cache_lock |