|  | /* | 
|  | *  Cache-handling routined for MIPS CPUs | 
|  | * | 
|  | *  Copyright (c) 2003	Wolfgang Denk <wd@denx.de> | 
|  | * | 
|  | * SPDX-License-Identifier:	GPL-2.0+ | 
|  | */ | 
|  |  | 
|  | #include <asm-offsets.h> | 
|  | #include <config.h> | 
|  | #include <asm/asm.h> | 
|  | #include <asm/regdef.h> | 
|  | #include <asm/mipsregs.h> | 
|  | #include <asm/addrspace.h> | 
|  | #include <asm/cacheops.h> | 
|  |  | 
|  | #define RA		t9 | 
|  |  | 
|  | /* | 
|  | * 16kB is the maximum size of instruction and data caches on MIPS 4K, | 
|  | * 64kB is on 4KE, 24K, 5K, etc. Set bigger size for convenience. | 
|  | * | 
|  | * Note that the above size is the maximum size of primary cache. U-Boot | 
|  | * doesn't have L2 cache support for now. | 
|  | */ | 
|  | #define MIPS_MAX_CACHE_SIZE	0x10000 | 
|  |  | 
|  | #define INDEX_BASE	CKSEG0 | 
|  |  | 
|  | .macro	cache_op op addr | 
|  | .set	push | 
|  | .set	noreorder | 
|  | .set	mips3 | 
|  | cache	\op, 0(\addr) | 
|  | .set	pop | 
|  | .endm | 
|  |  | 
|  | .macro	f_fill64 dst, offset, val | 
|  | LONG_S	\val, (\offset +  0 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  1 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  2 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  3 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  4 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  5 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  6 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  7 * LONGSIZE)(\dst) | 
|  | #if LONGSIZE == 4 | 
|  | LONG_S	\val, (\offset +  8 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset +  9 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset + 10 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset + 11 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset + 12 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset + 13 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset + 14 * LONGSIZE)(\dst) | 
|  | LONG_S	\val, (\offset + 15 * LONGSIZE)(\dst) | 
|  | #endif | 
|  | .endm | 
|  |  | 
|  | /* | 
|  | * mips_init_icache(uint PRId, ulong icache_size, unchar icache_linesz) | 
|  | */ | 
|  | LEAF(mips_init_icache) | 
|  | blez		a1, 9f | 
|  | mtc0		zero, CP0_TAGLO | 
|  | /* clear tag to invalidate */ | 
|  | PTR_LI		t0, INDEX_BASE | 
|  | PTR_ADDU	t1, t0, a1 | 
|  | 1:	cache_op	INDEX_STORE_TAG_I t0 | 
|  | PTR_ADDU	t0, a2 | 
|  | bne		t0, t1, 1b | 
|  | /* fill once, so data field parity is correct */ | 
|  | PTR_LI		t0, INDEX_BASE | 
|  | 2:	cache_op	FILL t0 | 
|  | PTR_ADDU	t0, a2 | 
|  | bne		t0, t1, 2b | 
|  | /* invalidate again - prudent but not strictly neccessary */ | 
|  | PTR_LI		t0, INDEX_BASE | 
|  | 1:	cache_op	INDEX_STORE_TAG_I t0 | 
|  | PTR_ADDU	t0, a2 | 
|  | bne		t0, t1, 1b | 
|  | 9:	jr		ra | 
|  | END(mips_init_icache) | 
|  |  | 
|  | /* | 
|  | * mips_init_dcache(uint PRId, ulong dcache_size, unchar dcache_linesz) | 
|  | */ | 
|  | LEAF(mips_init_dcache) | 
|  | blez		a1, 9f | 
|  | mtc0		zero, CP0_TAGLO | 
|  | /* clear all tags */ | 
|  | PTR_LI		t0, INDEX_BASE | 
|  | PTR_ADDU	t1, t0, a1 | 
|  | 1:	cache_op	INDEX_STORE_TAG_D t0 | 
|  | PTR_ADDU	t0, a2 | 
|  | bne		t0, t1, 1b | 
|  | /* load from each line (in cached space) */ | 
|  | PTR_LI		t0, INDEX_BASE | 
|  | 2:	LONG_L		zero, 0(t0) | 
|  | PTR_ADDU	t0, a2 | 
|  | bne		t0, t1, 2b | 
|  | /* clear all tags */ | 
|  | PTR_LI		t0, INDEX_BASE | 
|  | 1:	cache_op	INDEX_STORE_TAG_D t0 | 
|  | PTR_ADDU	t0, a2 | 
|  | bne		t0, t1, 1b | 
|  | 9:	jr		ra | 
|  | END(mips_init_dcache) | 
|  |  | 
|  | /* | 
|  | * 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 | 
|  | * | 
|  | */ | 
|  | NESTED(mips_cache_reset, 0, ra) | 
|  | move	RA, ra | 
|  | li	t2, CONFIG_SYS_ICACHE_SIZE | 
|  | li	t3, CONFIG_SYS_DCACHE_SIZE | 
|  | li	t8, CONFIG_SYS_CACHELINE_SIZE | 
|  |  | 
|  | li	v0, MIPS_MAX_CACHE_SIZE | 
|  |  | 
|  | /* | 
|  | * Now clear that much memory starting from zero. | 
|  | */ | 
|  | PTR_LI		a0, CKSEG1 | 
|  | PTR_ADDU	a1, a0, v0 | 
|  | 2:	PTR_ADDIU	a0, 64 | 
|  | f_fill64	a0, -64, zero | 
|  | bne		a0, a1, 2b | 
|  |  | 
|  | /* | 
|  | * 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. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Initialize the I-cache first, | 
|  | */ | 
|  | move	a1, t2 | 
|  | move	a2, t8 | 
|  | PTR_LA	v1, mips_init_icache | 
|  | jalr	v1 | 
|  |  | 
|  | /* | 
|  | * then initialize D-cache. | 
|  | */ | 
|  | move	a1, t3 | 
|  | move	a2, t8 | 
|  | PTR_LA	v1, mips_init_dcache | 
|  | jalr	v1 | 
|  |  | 
|  | jr	RA | 
|  | END(mips_cache_reset) | 
|  |  | 
|  | /* | 
|  | * dcache_status - get cache status | 
|  | * | 
|  | * RETURNS: 0 - cache disabled; 1 - cache enabled | 
|  | * | 
|  | */ | 
|  | LEAF(dcache_status) | 
|  | mfc0	t0, CP0_CONFIG | 
|  | li	t1, CONF_CM_UNCACHED | 
|  | andi	t0, t0, CONF_CM_CMASK | 
|  | move	v0, zero | 
|  | beq	t0, t1, 2f | 
|  | li	v0, 1 | 
|  | 2:	jr	ra | 
|  | END(dcache_status) | 
|  |  | 
|  | /* | 
|  | * dcache_disable - disable cache | 
|  | * | 
|  | * RETURNS: N/A | 
|  | * | 
|  | */ | 
|  | LEAF(dcache_disable) | 
|  | mfc0	t0, CP0_CONFIG | 
|  | li	t1, -8 | 
|  | and	t0, t0, t1 | 
|  | ori	t0, t0, CONF_CM_UNCACHED | 
|  | mtc0	t0, CP0_CONFIG | 
|  | jr	ra | 
|  | END(dcache_disable) | 
|  |  | 
|  | /* | 
|  | * dcache_enable - enable cache | 
|  | * | 
|  | * RETURNS: N/A | 
|  | * | 
|  | */ | 
|  | LEAF(dcache_enable) | 
|  | mfc0	t0, CP0_CONFIG | 
|  | ori	t0, CONF_CM_CMASK | 
|  | xori	t0, CONF_CM_CMASK | 
|  | ori	t0, CONF_CM_CACHABLE_NONCOHERENT | 
|  | mtc0	t0, CP0_CONFIG | 
|  | jr	ra | 
|  | END(dcache_enable) |