mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-19 11:18:28 +00:00
25ddd1fb0a
CONFIG_SYS_GBL_DATA_SIZE has always been just a bad workarond for not being able to use "sizeof(struct global_data)" in assembler files. Recent experience has shown that manual synchronization is not reliable enough. This patch renames CONFIG_SYS_GBL_DATA_SIZE into GENERATED_GBL_DATA_SIZE which gets automatically generated by the asm-offsets tool. In the result, all definitions of this value can be deleted from the board config files. We have to make sure that all files that reference such data include the new <asm-offsets.h> file. No other changes have been done yet, but it is obvious that similar changes / simplifications can be done for other, related macro definitions as well. Signed-off-by: Wolfgang Denk <wd@denx.de> Acked-by: Kumar Gala <galak@kernel.crashing.org>
332 lines
8.1 KiB
ArmAsm
332 lines
8.1 KiB
ArmAsm
/*
|
|
* Cache-handling routined for MIPS 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 <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 t8
|
|
|
|
/*
|
|
* 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
|
|
|
|
/*
|
|
* 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))
|
|
|
|
.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 t4, CONFIG_SYS_CACHELINE_SIZE
|
|
move t5, t4
|
|
|
|
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, t4
|
|
PTR_LA t7, mips_init_icache
|
|
jalr t7
|
|
|
|
/*
|
|
* then initialize D-cache.
|
|
*/
|
|
move a1, t3
|
|
move a2, t5
|
|
PTR_LA t7, mips_init_dcache
|
|
jalr t7
|
|
|
|
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)
|
|
|
|
#ifdef CONFIG_SYS_INIT_RAM_LOCK_MIPS
|
|
/*******************************************************************************
|
|
*
|
|
* mips_cache_lock - lock RAM area pointed to by a0 in cache.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
*/
|
|
#if defined(CONFIG_PURPLE)
|
|
# define CACHE_LOCK_SIZE (CONFIG_SYS_DCACHE_SIZE/2)
|
|
#else
|
|
# define CACHE_LOCK_SIZE (CONFIG_SYS_DCACHE_SIZE)
|
|
#endif
|
|
.globl mips_cache_lock
|
|
.ent mips_cache_lock
|
|
mips_cache_lock:
|
|
li a1, CKSEG0 - CACHE_LOCK_SIZE
|
|
addu a0, a1
|
|
li a2, CACHE_LOCK_SIZE
|
|
li a3, CONFIG_SYS_CACHELINE_SIZE
|
|
move a1, a2
|
|
icacheop(a0,a1,a2,a3,0x1d)
|
|
|
|
jr ra
|
|
|
|
.end mips_cache_lock
|
|
#endif /* CONFIG_SYS_INIT_RAM_LOCK_MIPS */
|