diff options
Diffstat (limited to 'cpu/mips/cache.S')
-rw-r--r-- | cpu/mips/cache.S | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S new file mode 100644 index 00000000000..aeb04b3790c --- /dev/null +++ b/cpu/mips/cache.S @@ -0,0 +1,265 @@ +/* + * 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 +* +*/ + .globl mips_cache_lock + .ent mips_cache_lock +mips_cache_lock: + li a1, K0BASE - CFG_DCACHE_SIZE + addu a0, a1 + li a2, CFG_DCACHE_SIZE + li a3, CFG_CACHELINE_SIZE + move a1, a2 + icacheop(a0,a1,a2,a3,0x1d) + + j ra + .end mips_cache_lock + |