xref: /openbmc/u-boot/arch/mips/lib/cache_init.S (revision 536cb7ce1aca10c326ac864b3e1d05ab57b3ec7e)
14a5d8898SPaul Burton/*
24a5d8898SPaul Burton *  Cache-handling routined for MIPS CPUs
34a5d8898SPaul Burton *
44a5d8898SPaul Burton *  Copyright (c) 2003	Wolfgang Denk <wd@denx.de>
54a5d8898SPaul Burton *
64a5d8898SPaul Burton * SPDX-License-Identifier:	GPL-2.0+
74a5d8898SPaul Burton */
84a5d8898SPaul Burton
94a5d8898SPaul Burton#include <asm-offsets.h>
104a5d8898SPaul Burton#include <config.h>
114a5d8898SPaul Burton#include <asm/asm.h>
124a5d8898SPaul Burton#include <asm/regdef.h>
134a5d8898SPaul Burton#include <asm/mipsregs.h>
144a5d8898SPaul Burton#include <asm/addrspace.h>
154a5d8898SPaul Burton#include <asm/cacheops.h>
164a5d8898SPaul Burton
174a5d8898SPaul Burton#ifndef CONFIG_SYS_MIPS_CACHE_MODE
184a5d8898SPaul Burton#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT
194a5d8898SPaul Burton#endif
204a5d8898SPaul Burton
214a5d8898SPaul Burton#ifdef CONFIG_64BIT
224a5d8898SPaul Burton# define RA		ta3
234a5d8898SPaul Burton#else
244a5d8898SPaul Burton# define RA		t7
254a5d8898SPaul Burton#endif
264a5d8898SPaul Burton
274a5d8898SPaul Burton#define INDEX_BASE	CKSEG0
284a5d8898SPaul Burton
294a5d8898SPaul Burton	.macro	f_fill64 dst, offset, val
304a5d8898SPaul Burton	LONG_S	\val, (\offset +  0 * LONGSIZE)(\dst)
314a5d8898SPaul Burton	LONG_S	\val, (\offset +  1 * LONGSIZE)(\dst)
324a5d8898SPaul Burton	LONG_S	\val, (\offset +  2 * LONGSIZE)(\dst)
334a5d8898SPaul Burton	LONG_S	\val, (\offset +  3 * LONGSIZE)(\dst)
344a5d8898SPaul Burton	LONG_S	\val, (\offset +  4 * LONGSIZE)(\dst)
354a5d8898SPaul Burton	LONG_S	\val, (\offset +  5 * LONGSIZE)(\dst)
364a5d8898SPaul Burton	LONG_S	\val, (\offset +  6 * LONGSIZE)(\dst)
374a5d8898SPaul Burton	LONG_S	\val, (\offset +  7 * LONGSIZE)(\dst)
384a5d8898SPaul Burton#if LONGSIZE == 4
394a5d8898SPaul Burton	LONG_S	\val, (\offset +  8 * LONGSIZE)(\dst)
404a5d8898SPaul Burton	LONG_S	\val, (\offset +  9 * LONGSIZE)(\dst)
414a5d8898SPaul Burton	LONG_S	\val, (\offset + 10 * LONGSIZE)(\dst)
424a5d8898SPaul Burton	LONG_S	\val, (\offset + 11 * LONGSIZE)(\dst)
434a5d8898SPaul Burton	LONG_S	\val, (\offset + 12 * LONGSIZE)(\dst)
444a5d8898SPaul Burton	LONG_S	\val, (\offset + 13 * LONGSIZE)(\dst)
454a5d8898SPaul Burton	LONG_S	\val, (\offset + 14 * LONGSIZE)(\dst)
464a5d8898SPaul Burton	LONG_S	\val, (\offset + 15 * LONGSIZE)(\dst)
474a5d8898SPaul Burton#endif
484a5d8898SPaul Burton	.endm
494a5d8898SPaul Burton
504a5d8898SPaul Burton/*
514a5d8898SPaul Burton * mips_init_icache(uint PRId, ulong icache_size, unchar icache_linesz)
524a5d8898SPaul Burton */
534a5d8898SPaul BurtonLEAF(mips_init_icache)
544a5d8898SPaul Burton	blez		a1, 9f
554a5d8898SPaul Burton	mtc0		zero, CP0_TAGLO
564a5d8898SPaul Burton	/* clear tag to invalidate */
574a5d8898SPaul Burton	PTR_LI		t0, INDEX_BASE
584a5d8898SPaul Burton	PTR_ADDU	t1, t0, a1
594a5d8898SPaul Burton1:	cache		INDEX_STORE_TAG_I, 0(t0)
604a5d8898SPaul Burton	PTR_ADDU	t0, a2
614a5d8898SPaul Burton	bne		t0, t1, 1b
624a5d8898SPaul Burton	/* fill once, so data field parity is correct */
634a5d8898SPaul Burton	PTR_LI		t0, INDEX_BASE
644a5d8898SPaul Burton2:	cache		FILL, 0(t0)
654a5d8898SPaul Burton	PTR_ADDU	t0, a2
664a5d8898SPaul Burton	bne		t0, t1, 2b
674a5d8898SPaul Burton	/* invalidate again - prudent but not strictly neccessary */
684a5d8898SPaul Burton	PTR_LI		t0, INDEX_BASE
694a5d8898SPaul Burton1:	cache		INDEX_STORE_TAG_I, 0(t0)
704a5d8898SPaul Burton	PTR_ADDU	t0, a2
714a5d8898SPaul Burton	bne		t0, t1, 1b
724a5d8898SPaul Burton9:	jr		ra
734a5d8898SPaul Burton	END(mips_init_icache)
744a5d8898SPaul Burton
754a5d8898SPaul Burton/*
764a5d8898SPaul Burton * mips_init_dcache(uint PRId, ulong dcache_size, unchar dcache_linesz)
774a5d8898SPaul Burton */
784a5d8898SPaul BurtonLEAF(mips_init_dcache)
794a5d8898SPaul Burton	blez		a1, 9f
804a5d8898SPaul Burton	mtc0		zero, CP0_TAGLO
814a5d8898SPaul Burton	/* clear all tags */
824a5d8898SPaul Burton	PTR_LI		t0, INDEX_BASE
834a5d8898SPaul Burton	PTR_ADDU	t1, t0, a1
844a5d8898SPaul Burton1:	cache		INDEX_STORE_TAG_D, 0(t0)
854a5d8898SPaul Burton	PTR_ADDU	t0, a2
864a5d8898SPaul Burton	bne		t0, t1, 1b
874a5d8898SPaul Burton	/* load from each line (in cached space) */
884a5d8898SPaul Burton	PTR_LI		t0, INDEX_BASE
894a5d8898SPaul Burton2:	LONG_L		zero, 0(t0)
904a5d8898SPaul Burton	PTR_ADDU	t0, a2
914a5d8898SPaul Burton	bne		t0, t1, 2b
924a5d8898SPaul Burton	/* clear all tags */
934a5d8898SPaul Burton	PTR_LI		t0, INDEX_BASE
944a5d8898SPaul Burton1:	cache		INDEX_STORE_TAG_D, 0(t0)
954a5d8898SPaul Burton	PTR_ADDU	t0, a2
964a5d8898SPaul Burton	bne		t0, t1, 1b
974a5d8898SPaul Burton9:	jr		ra
984a5d8898SPaul Burton	END(mips_init_dcache)
994a5d8898SPaul Burton
100*536cb7ceSPaul Burton	.macro	l1_info		sz, line_sz, off
101*536cb7ceSPaul Burton	.set	push
102*536cb7ceSPaul Burton	.set	noat
103*536cb7ceSPaul Burton
104*536cb7ceSPaul Burton	mfc0	$1, CP0_CONFIG, 1
105*536cb7ceSPaul Burton
106*536cb7ceSPaul Burton	/* detect line size */
107*536cb7ceSPaul Burton	srl	\line_sz, $1, \off + MIPS_CONF1_DL_SHIFT - MIPS_CONF1_DA_SHIFT
108*536cb7ceSPaul Burton	andi	\line_sz, \line_sz, (MIPS_CONF1_DL >> MIPS_CONF1_DL_SHIFT)
109*536cb7ceSPaul Burton	move	\sz, zero
110*536cb7ceSPaul Burton	beqz	\line_sz, 10f
111*536cb7ceSPaul Burton	li	\sz, 2
112*536cb7ceSPaul Burton	sllv	\line_sz, \sz, \line_sz
113*536cb7ceSPaul Burton
114*536cb7ceSPaul Burton	/* detect associativity */
115*536cb7ceSPaul Burton	srl	\sz, $1, \off + MIPS_CONF1_DA_SHIFT - MIPS_CONF1_DA_SHIFT
116*536cb7ceSPaul Burton	andi	\sz, \sz, (MIPS_CONF1_DA >> MIPS_CONF1_DA_SHIFT)
117*536cb7ceSPaul Burton	addi	\sz, \sz, 1
118*536cb7ceSPaul Burton
119*536cb7ceSPaul Burton	/* sz *= line_sz */
120*536cb7ceSPaul Burton	mul	\sz, \sz, \line_sz
121*536cb7ceSPaul Burton
122*536cb7ceSPaul Burton	/* detect log32(sets) */
123*536cb7ceSPaul Burton	srl	$1, $1, \off + MIPS_CONF1_DS_SHIFT - MIPS_CONF1_DA_SHIFT
124*536cb7ceSPaul Burton	andi	$1, $1, (MIPS_CONF1_DS >> MIPS_CONF1_DS_SHIFT)
125*536cb7ceSPaul Burton	addiu	$1, $1, 1
126*536cb7ceSPaul Burton	andi	$1, $1, 0x7
127*536cb7ceSPaul Burton
128*536cb7ceSPaul Burton	/* sz <<= log32(sets) */
129*536cb7ceSPaul Burton	sllv	\sz, \sz, $1
130*536cb7ceSPaul Burton
131*536cb7ceSPaul Burton	/* sz *= 32 */
132*536cb7ceSPaul Burton	li	$1, 32
133*536cb7ceSPaul Burton	mul	\sz, \sz, $1
134*536cb7ceSPaul Burton10:
135*536cb7ceSPaul Burton	.set	pop
136*536cb7ceSPaul Burton	.endm
1374a5d8898SPaul Burton/*
1384a5d8898SPaul Burton * mips_cache_reset - low level initialisation of the primary caches
1394a5d8898SPaul Burton *
1404a5d8898SPaul Burton * This routine initialises the primary caches to ensure that they have good
1414a5d8898SPaul Burton * parity.  It must be called by the ROM before any cached locations are used
1424a5d8898SPaul Burton * to prevent the possibility of data with bad parity being written to memory.
1434a5d8898SPaul Burton *
1444a5d8898SPaul Burton * To initialise the instruction cache it is essential that a source of data
1454a5d8898SPaul Burton * with good parity is available. This routine will initialise an area of
1464a5d8898SPaul Burton * memory starting at location zero to be used as a source of parity.
1474a5d8898SPaul Burton *
1484a5d8898SPaul Burton * RETURNS: N/A
1494a5d8898SPaul Burton *
1504a5d8898SPaul Burton */
1514a5d8898SPaul BurtonNESTED(mips_cache_reset, 0, ra)
1524a5d8898SPaul Burton	move	RA, ra
1534a5d8898SPaul Burton
1544a5d8898SPaul Burton#ifdef CONFIG_SYS_ICACHE_SIZE
1554a5d8898SPaul Burton	li	t2, CONFIG_SYS_ICACHE_SIZE
156*536cb7ceSPaul Burton	li	t8, CONFIG_SYS_CACHELINE_SIZE
1574a5d8898SPaul Burton#else
158*536cb7ceSPaul Burton	l1_info	t2, t8, MIPS_CONF1_IA_SHIFT
1594a5d8898SPaul Burton#endif
1604a5d8898SPaul Burton
1614a5d8898SPaul Burton#ifdef CONFIG_SYS_DCACHE_SIZE
1624a5d8898SPaul Burton	li	t3, CONFIG_SYS_DCACHE_SIZE
163*536cb7ceSPaul Burton	li	t9, CONFIG_SYS_CACHELINE_SIZE
1644a5d8898SPaul Burton#else
165*536cb7ceSPaul Burton	l1_info	t3, t9, MIPS_CONF1_DA_SHIFT
1664a5d8898SPaul Burton#endif
1674a5d8898SPaul Burton
1684a5d8898SPaul Burton	/* Determine the largest L1 cache size */
1694a5d8898SPaul Burton#if defined(CONFIG_SYS_ICACHE_SIZE) && defined(CONFIG_SYS_DCACHE_SIZE)
1704a5d8898SPaul Burton#if CONFIG_SYS_ICACHE_SIZE > CONFIG_SYS_DCACHE_SIZE
1714a5d8898SPaul Burton	li	v0, CONFIG_SYS_ICACHE_SIZE
1724a5d8898SPaul Burton#else
1734a5d8898SPaul Burton	li	v0, CONFIG_SYS_DCACHE_SIZE
1744a5d8898SPaul Burton#endif
1754a5d8898SPaul Burton#else
1764a5d8898SPaul Burton	move	v0, t2
1774a5d8898SPaul Burton	sltu	t1, t2, t3
1784a5d8898SPaul Burton	movn	v0, t3, t1
1794a5d8898SPaul Burton#endif
1804a5d8898SPaul Burton	/*
1814a5d8898SPaul Burton	 * Now clear that much memory starting from zero.
1824a5d8898SPaul Burton	 */
1834a5d8898SPaul Burton	PTR_LI		a0, CKSEG1
1844a5d8898SPaul Burton	PTR_ADDU	a1, a0, v0
1854a5d8898SPaul Burton2:	PTR_ADDIU	a0, 64
1864a5d8898SPaul Burton	f_fill64	a0, -64, zero
1874a5d8898SPaul Burton	bne		a0, a1, 2b
1884a5d8898SPaul Burton
1894a5d8898SPaul Burton	/*
1904a5d8898SPaul Burton	 * The caches are probably in an indeterminate state,
1914a5d8898SPaul Burton	 * so we force good parity into them by doing an
1924a5d8898SPaul Burton	 * invalidate, load/fill, invalidate for each line.
1934a5d8898SPaul Burton	 */
1944a5d8898SPaul Burton
1954a5d8898SPaul Burton	/*
1964a5d8898SPaul Burton	 * Assume bottom of RAM will generate good parity for the cache.
1974a5d8898SPaul Burton	 */
1984a5d8898SPaul Burton
1994a5d8898SPaul Burton	/*
2004a5d8898SPaul Burton	 * Initialize the I-cache first,
2014a5d8898SPaul Burton	 */
2024a5d8898SPaul Burton	move	a1, t2
2034a5d8898SPaul Burton	move	a2, t8
2044a5d8898SPaul Burton	PTR_LA	v1, mips_init_icache
2054a5d8898SPaul Burton	jalr	v1
2064a5d8898SPaul Burton
2074a5d8898SPaul Burton	/*
2084a5d8898SPaul Burton	 * then initialize D-cache.
2094a5d8898SPaul Burton	 */
2104a5d8898SPaul Burton	move	a1, t3
2114a5d8898SPaul Burton	move	a2, t9
2124a5d8898SPaul Burton	PTR_LA	v1, mips_init_dcache
2134a5d8898SPaul Burton	jalr	v1
2144a5d8898SPaul Burton
2154a5d8898SPaul Burton	jr	RA
2164a5d8898SPaul Burton	END(mips_cache_reset)
2174a5d8898SPaul Burton
2184a5d8898SPaul Burton/*
2194a5d8898SPaul Burton * dcache_status - get cache status
2204a5d8898SPaul Burton *
2214a5d8898SPaul Burton * RETURNS: 0 - cache disabled; 1 - cache enabled
2224a5d8898SPaul Burton *
2234a5d8898SPaul Burton */
2244a5d8898SPaul BurtonLEAF(dcache_status)
2254a5d8898SPaul Burton	mfc0	t0, CP0_CONFIG
2264a5d8898SPaul Burton	li	t1, CONF_CM_UNCACHED
2274a5d8898SPaul Burton	andi	t0, t0, CONF_CM_CMASK
2284a5d8898SPaul Burton	move	v0, zero
2294a5d8898SPaul Burton	beq	t0, t1, 2f
2304a5d8898SPaul Burton	li	v0, 1
2314a5d8898SPaul Burton2:	jr	ra
2324a5d8898SPaul Burton	END(dcache_status)
2334a5d8898SPaul Burton
2344a5d8898SPaul Burton/*
2354a5d8898SPaul Burton * dcache_disable - disable cache
2364a5d8898SPaul Burton *
2374a5d8898SPaul Burton * RETURNS: N/A
2384a5d8898SPaul Burton *
2394a5d8898SPaul Burton */
2404a5d8898SPaul BurtonLEAF(dcache_disable)
2414a5d8898SPaul Burton	mfc0	t0, CP0_CONFIG
2424a5d8898SPaul Burton	li	t1, -8
2434a5d8898SPaul Burton	and	t0, t0, t1
2444a5d8898SPaul Burton	ori	t0, t0, CONF_CM_UNCACHED
2454a5d8898SPaul Burton	mtc0	t0, CP0_CONFIG
2464a5d8898SPaul Burton	jr	ra
2474a5d8898SPaul Burton	END(dcache_disable)
2484a5d8898SPaul Burton
2494a5d8898SPaul Burton/*
2504a5d8898SPaul Burton * dcache_enable - enable cache
2514a5d8898SPaul Burton *
2524a5d8898SPaul Burton * RETURNS: N/A
2534a5d8898SPaul Burton *
2544a5d8898SPaul Burton */
2554a5d8898SPaul BurtonLEAF(dcache_enable)
2564a5d8898SPaul Burton	mfc0	t0, CP0_CONFIG
2574a5d8898SPaul Burton	ori	t0, CONF_CM_CMASK
2584a5d8898SPaul Burton	xori	t0, CONF_CM_CMASK
2594a5d8898SPaul Burton	ori	t0, CONFIG_SYS_MIPS_CACHE_MODE
2604a5d8898SPaul Burton	mtc0	t0, CP0_CONFIG
2614a5d8898SPaul Burton	jr	ra
2624a5d8898SPaul Burton	END(dcache_enable)
263