Skip to content

Commit

Permalink
mips32: detect L1 cache sizes if they're not defined
Browse files Browse the repository at this point in the history
For boards such as the MIPS Malta with an FPGA core card it is desirable
to be able to detect the L1 cache sizes at runtime, since they are not
dependant upon the board but on the FPGA bitstream in use. This patch
performs that detection when the CONFIG_SYS_[DI]CACHE_SIZE macros are
not defined by the board configuration. In cases where the sizes are
detected this patch also removes the restriction that the I-cache &
D-cache line sizes must be the same, as this is not necessarily true.

If the cache sizes are defined by a configuration then they will be
hardcoded as before, so this patch will not add overhead to such
boards.

Signed-off-by: Paul Burton <[email protected]>
  • Loading branch information
paulburton authored and danielschwierzeck committed Nov 9, 2013
1 parent 15c5cdf commit fa476f7
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 19 deletions.
90 changes: 77 additions & 13 deletions arch/mips/cpu/mips32/cache.S
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,6 @@

#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
Expand Down Expand Up @@ -126,12 +117,85 @@ LEAF(mips_init_dcache)
*/
NESTED(mips_cache_reset, 0, ra)
move RA, ra
li t2, CONFIG_SYS_ICACHE_SIZE
li t3, CONFIG_SYS_DCACHE_SIZE

#if !defined(CONFIG_SYS_ICACHE_SIZE) || !defined(CONFIG_SYS_DCACHE_SIZE) || \
!defined(CONFIG_SYS_CACHELINE_SIZE)
/* read Config1 for use below */
mfc0 t5, CP0_CONFIG, 1
#endif

#ifdef CONFIG_SYS_CACHELINE_SIZE
li t7, CONFIG_SYS_CACHELINE_SIZE
li t8, CONFIG_SYS_CACHELINE_SIZE
#else
/* Detect I-cache line size. */
srl t8, t5, MIPS_CONF1_IL_SHIFT
andi t8, t8, (MIPS_CONF1_IL >> MIPS_CONF1_IL_SHIFT)
beqz t8, 1f
li t6, 2
sllv t8, t6, t8

li v0, MIPS_MAX_CACHE_SIZE
1: /* Detect D-cache line size. */
srl t7, t5, MIPS_CONF1_DL_SHIFT
andi t7, t7, (MIPS_CONF1_DL >> MIPS_CONF1_DL_SHIFT)
beqz t7, 1f
li t6, 2
sllv t7, t6, t7
1:
#endif

#ifdef CONFIG_SYS_ICACHE_SIZE
li t2, CONFIG_SYS_ICACHE_SIZE
#else
/* Detect I-cache size. */
srl t6, t5, MIPS_CONF1_IS_SHIFT
andi t6, t6, (MIPS_CONF1_IS >> MIPS_CONF1_IS_SHIFT)
li t4, 32
xori t2, t6, 0x7
beqz t2, 1f
addi t6, t6, 1
sllv t4, t4, t6
1: /* At this point t4 == I-cache sets. */
mul t2, t4, t8
srl t6, t5, MIPS_CONF1_IA_SHIFT
andi t6, t6, (MIPS_CONF1_IA >> MIPS_CONF1_IA_SHIFT)
addi t6, t6, 1
/* At this point t6 == I-cache ways. */
mul t2, t2, t6
#endif

#ifdef CONFIG_SYS_DCACHE_SIZE
li t3, CONFIG_SYS_DCACHE_SIZE
#else
/* Detect D-cache size. */
srl t6, t5, MIPS_CONF1_DS_SHIFT
andi t6, t6, (MIPS_CONF1_DS >> MIPS_CONF1_DS_SHIFT)
li t4, 32
xori t3, t6, 0x7
beqz t3, 1f
addi t6, t6, 1
sllv t4, t4, t6
1: /* At this point t4 == I-cache sets. */
mul t3, t4, t7
srl t6, t5, MIPS_CONF1_DA_SHIFT
andi t6, t6, (MIPS_CONF1_DA >> MIPS_CONF1_DA_SHIFT)
addi t6, t6, 1
/* At this point t6 == I-cache ways. */
mul t3, t3, t6
#endif

/* Determine the largest L1 cache size */
#if defined(CONFIG_SYS_ICACHE_SIZE) && defined(CONFIG_SYS_DCACHE_SIZE)
#if CONFIG_SYS_ICACHE_SIZE > CONFIG_SYS_DCACHE_SIZE
li v0, CONFIG_SYS_ICACHE_SIZE
#else
li v0, CONFIG_SYS_DCACHE_SIZE
#endif
#else
move v0, t2
sltu t1, t2, t3
movn v0, t3, t1
#endif
/*
* Now clear that much memory starting from zero.
*/
Expand Down Expand Up @@ -163,7 +227,7 @@ NESTED(mips_cache_reset, 0, ra)
* then initialize D-cache.
*/
move a1, t3
move a2, t8
move a2, t7
PTR_LA v1, mips_init_dcache
jalr v1

Expand Down
73 changes: 67 additions & 6 deletions arch/mips/cpu/mips32/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,89 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return 0;
}

#ifdef CONFIG_SYS_CACHELINE_SIZE

static inline unsigned long icache_line_size(void)
{
return CONFIG_SYS_CACHELINE_SIZE;
}

static inline unsigned long dcache_line_size(void)
{
return CONFIG_SYS_CACHELINE_SIZE;
}

#else /* !CONFIG_SYS_CACHELINE_SIZE */

static inline unsigned long icache_line_size(void)
{
unsigned long conf1, il;
conf1 = read_c0_config1();
il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHIFT;
if (!il)
return 0;
return 2 << il;
}

static inline unsigned long dcache_line_size(void)
{
unsigned long conf1, dl;
conf1 = read_c0_config1();
dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHIFT;
if (!dl)
return 0;
return 2 << dl;
}

#endif /* !CONFIG_SYS_CACHELINE_SIZE */

void flush_cache(ulong start_addr, ulong size)
{
unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
unsigned long addr = start_addr & ~(lsize - 1);
unsigned long aend = (start_addr + size - 1) & ~(lsize - 1);
unsigned long ilsize = icache_line_size();
unsigned long dlsize = dcache_line_size();
unsigned long addr, aend;

/* aend will be miscalculated when size is zero, so we return here */
if (size == 0)
return;

addr = start_addr & ~(dlsize - 1);
aend = (start_addr + size - 1) & ~(dlsize - 1);

if (ilsize == dlsize) {
/* flush I-cache & D-cache simultaneously */
while (1) {
cache_op(HIT_WRITEBACK_INV_D, addr);
cache_op(HIT_INVALIDATE_I, addr);
if (addr == aend)
break;
addr += dlsize;
}
return;
}

/* flush D-cache */
while (1) {
cache_op(HIT_WRITEBACK_INV_D, addr);
if (addr == aend)
break;
addr += dlsize;
}

/* flush I-cache */
addr = start_addr & ~(ilsize - 1);
aend = (start_addr + size - 1) & ~(ilsize - 1);
while (1) {
cache_op(HIT_INVALIDATE_I, addr);
if (addr == aend)
break;
addr += lsize;
addr += ilsize;
}
}

void flush_dcache_range(ulong start_addr, ulong stop)
{
unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
unsigned long lsize = dcache_line_size();
unsigned long addr = start_addr & ~(lsize - 1);
unsigned long aend = (stop - 1) & ~(lsize - 1);

Expand All @@ -69,7 +130,7 @@ void flush_dcache_range(ulong start_addr, ulong stop)

void invalidate_dcache_range(ulong start_addr, ulong stop)
{
unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
unsigned long lsize = dcache_line_size();
unsigned long addr = start_addr & ~(lsize - 1);
unsigned long aend = (stop - 1) & ~(lsize - 1);

Expand Down
6 changes: 6 additions & 0 deletions arch/mips/include/asm/mipsregs.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,11 +494,17 @@
#define MIPS_CONF1_PC (_ULCAST_(1) << 4)
#define MIPS_CONF1_MD (_ULCAST_(1) << 5)
#define MIPS_CONF1_C2 (_ULCAST_(1) << 6)
#define MIPS_CONF1_DA_SHIFT 7
#define MIPS_CONF1_DA (_ULCAST_(7) << 7)
#define MIPS_CONF1_DL_SHIFT 10
#define MIPS_CONF1_DL (_ULCAST_(7) << 10)
#define MIPS_CONF1_DS_SHIFT 13
#define MIPS_CONF1_DS (_ULCAST_(7) << 13)
#define MIPS_CONF1_IA_SHIFT 16
#define MIPS_CONF1_IA (_ULCAST_(7) << 16)
#define MIPS_CONF1_IL_SHIFT 19
#define MIPS_CONF1_IL (_ULCAST_(7) << 19)
#define MIPS_CONF1_IS_SHIFT 22
#define MIPS_CONF1_IS (_ULCAST_(7) << 22)
#define MIPS_CONF1_TLBS (_ULCAST_(63)<< 25)

Expand Down

0 comments on commit fa476f7

Please sign in to comment.